Merge branch 'v2' into v2_ImprovedAdminPage
This commit is contained in:
commit
158115bb3b
14 changed files with 167 additions and 28 deletions
15
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
15
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
|
@ -33,7 +33,7 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Panel Version
|
label: Panel Version
|
||||||
description: Version number of your Panel (latest is not a version)
|
description: Version number of your Panel (latest is not a version)
|
||||||
placeholder: 1.4.0
|
placeholder: v2 EA
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
@ -42,16 +42,7 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Daemon Version
|
label: Daemon Version
|
||||||
description: Version number of your Daemon (latest is not a version)
|
description: Version number of your Daemon (latest is not a version)
|
||||||
placeholder: 1.4.2
|
placeholder: v2 EA
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: wings-version
|
|
||||||
attributes:
|
|
||||||
label: Wings Version
|
|
||||||
description: Version number of your Wings (latest is not a version)
|
|
||||||
placeholder: 1.4.2
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
@ -93,4 +84,4 @@ body:
|
||||||
- label: I have provided all relevant details, including the specific game and Docker images I am using if this issue is related to running a server.
|
- label: I have provided all relevant details, including the specific game and Docker images I am using if this issue is related to running a server.
|
||||||
required: true
|
required: true
|
||||||
- label: I have checked in the Discord server and believe this is a bug with the software, and not a configuration issue with my specific system.
|
- label: I have checked in the Discord server and believe this is a bug with the software, and not a configuration issue with my specific system.
|
||||||
required: true
|
required: true
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -400,4 +400,5 @@ FodyWeavers.xsd
|
||||||
storage/
|
storage/
|
||||||
.idea/.idea.Moonlight/.idea/dataSources.xml
|
.idea/.idea.Moonlight/.idea/dataSources.xml
|
||||||
Moonlight/wwwroot/css/theme.css
|
Moonlight/wwwroot/css/theme.css
|
||||||
Moonlight/wwwroot/css/theme.css.map
|
Moonlight/wwwroot/css/theme.css.map
|
||||||
|
.idea/.idea.Moonlight/.idea/discord.xml
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
@inherits ErrorBoundaryBase
|
@inherits ErrorBoundaryBase
|
||||||
|
|
||||||
@if (Crashed || CurrentException != null)
|
@if (Crashed || Exception != null)
|
||||||
{
|
{
|
||||||
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development" || (IdentityService.IsLoggedIn && IdentityService.CurrentUser.Permissions >= 9000))
|
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development" || (IdentityService.IsLoggedIn && IdentityService.CurrentUser.Permissions >= 9000))
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-3 text-center d-flex align-items-center">
|
<div class="col-auto text-center d-flex align-items-center px-5">
|
||||||
<i class="bx bx-lg text-white align-middle @(Icon)"></i>
|
<i class="bx bx-lg text-white align-middle @(Icon)"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-9">
|
<div class="col">
|
||||||
<div class="fw-semibold text-primary fs-2">
|
<div class="fw-semibold text-primary fs-2">
|
||||||
@Value
|
@Value
|
||||||
</div>
|
</div>
|
||||||
<div class="fs-4 mt-2">
|
<div class="fs-4 mt-2 text-white">
|
||||||
@Description
|
@Description
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
private async Task Load(LazyLoader arg)
|
private async Task Load(LazyLoader arg)
|
||||||
{
|
{
|
||||||
await arg.SetText("Loading Information...");
|
await arg.SetText("Loading statistics...");
|
||||||
|
|
||||||
var componentImplementations = await PluginService.GetImplementations<IAdminDashboardComponent>();
|
var componentImplementations = await PluginService.GetImplementations<IAdminDashboardComponent>();
|
||||||
|
|
||||||
|
|
|
@ -54,9 +54,12 @@ public class FileManagerFeature : MoonlightFeature
|
||||||
await pluginService.RegisterImplementation<IFileManagerContextAction>(new RenameContextAction());
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new RenameContextAction());
|
||||||
await pluginService.RegisterImplementation<IFileManagerContextAction>(new MoveContextAction());
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new MoveContextAction());
|
||||||
await pluginService.RegisterImplementation<IFileManagerContextAction>(new DownloadContextAction());
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new DownloadContextAction());
|
||||||
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new ArchiveContextAction());
|
||||||
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new ExtractContextAction());
|
||||||
await pluginService.RegisterImplementation<IFileManagerContextAction>(new DeleteContextAction());
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new DeleteContextAction());
|
||||||
|
|
||||||
await pluginService.RegisterImplementation<IFileManagerSelectionAction>(new MoveSelectionAction());
|
await pluginService.RegisterImplementation<IFileManagerSelectionAction>(new MoveSelectionAction());
|
||||||
|
await pluginService.RegisterImplementation<IFileManagerSelectionAction>(new ArchiveSelectionAction());
|
||||||
await pluginService.RegisterImplementation<IFileManagerSelectionAction>(new DeleteSelectionAction());
|
await pluginService.RegisterImplementation<IFileManagerSelectionAction>(new DeleteSelectionAction());
|
||||||
|
|
||||||
await pluginService.RegisterImplementation<IFileManagerCreateAction>(new CreateFileAction());
|
await pluginService.RegisterImplementation<IFileManagerCreateAction>(new CreateFileAction());
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
using MoonCore.Exceptions;
|
||||||
|
using MoonCore.Helpers;
|
||||||
|
using MoonCoreUI.Services;
|
||||||
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
|
namespace Moonlight.Features.FileManager.Implementations;
|
||||||
|
|
||||||
|
public class ArchiveContextAction : IFileManagerContextAction
|
||||||
|
{
|
||||||
|
public string Name => "Archive";
|
||||||
|
public string Icon => "bxs-archive-in";
|
||||||
|
public string Color => "warning";
|
||||||
|
public Func<FileEntry, bool> Filter => _ => true;
|
||||||
|
|
||||||
|
public async Task Execute(BaseFileAccess access, UI.Components.FileManager fileManager, FileEntry entry,
|
||||||
|
IServiceProvider provider)
|
||||||
|
{
|
||||||
|
var archiveAccess = access.Actions as IArchiveFileActions;
|
||||||
|
|
||||||
|
if (archiveAccess == null)
|
||||||
|
throw new DisplayException("This file access does not support archiving");
|
||||||
|
|
||||||
|
var alertService = provider.GetRequiredService<AlertService>();
|
||||||
|
|
||||||
|
var fileName = await alertService.Text("Enter the archive file name", "",
|
||||||
|
Formatter.FormatDate(DateTime.UtcNow) + ".tar.gz");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(fileName) || fileName.Contains("..")) // => canceled
|
||||||
|
return;
|
||||||
|
|
||||||
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
|
await toastService.CreateProgress("fileManagerArchive", "Archiving... Please be patient");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await archiveAccess.Archive(
|
||||||
|
access.CurrentDirectory + fileName,
|
||||||
|
new[] { access.CurrentDirectory + entry.Name }
|
||||||
|
);
|
||||||
|
|
||||||
|
await toastService.Success("Successfully created archive");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Warn($"An error occured while archiving item ({entry.Name}):");
|
||||||
|
Logger.Warn(e);
|
||||||
|
|
||||||
|
await toastService.Danger("An unknown error occured while creating archive");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await toastService.RemoveProgress("fileManagerArchive");
|
||||||
|
}
|
||||||
|
|
||||||
|
await fileManager.View.Refresh();
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,10 +14,7 @@ public class ArchiveSelectionAction : IFileManagerSelectionAction
|
||||||
public async Task Execute(BaseFileAccess access, UI.Components.FileManager fileManager, FileEntry[] entries,
|
public async Task Execute(BaseFileAccess access, UI.Components.FileManager fileManager, FileEntry[] entries,
|
||||||
IServiceProvider provider)
|
IServiceProvider provider)
|
||||||
{
|
{
|
||||||
if (!access.Actions.GetType().IsAssignableFrom(typeof(IArchiveFileActions)))
|
var archiveAccess = access.Actions as IArchiveFileActions;
|
||||||
throw new DisplayException("This file access does not support archiving");
|
|
||||||
|
|
||||||
var archiveAccess = access as IArchiveFileActions;
|
|
||||||
|
|
||||||
if (archiveAccess == null)
|
if (archiveAccess == null)
|
||||||
throw new DisplayException("This file access does not support archiving");
|
throw new DisplayException("This file access does not support archiving");
|
||||||
|
@ -29,10 +26,30 @@ public class ArchiveSelectionAction : IFileManagerSelectionAction
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(fileName) || fileName.Contains("..")) // => canceled
|
if (string.IsNullOrEmpty(fileName) || fileName.Contains("..")) // => canceled
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
await archiveAccess.Archive(
|
await toastService.CreateProgress("fileManagerArchive", "Archiving... Please be patient");
|
||||||
access.CurrentDirectory + fileName,
|
|
||||||
entries.Select(x => access.CurrentDirectory + x.Name).ToArray()
|
try
|
||||||
);
|
{
|
||||||
|
await archiveAccess.Archive(
|
||||||
|
access.CurrentDirectory + fileName,
|
||||||
|
entries.Select(x => access.CurrentDirectory + x.Name).ToArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
await toastService.Success("Successfully created archive");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Warn($"An error occured while archiving items ({entries.Length}):");
|
||||||
|
Logger.Warn(e);
|
||||||
|
|
||||||
|
await toastService.Danger("An unknown error occured while creating archive");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await toastService.RemoveProgress("fileManagerArchive");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
using MoonCore.Exceptions;
|
||||||
|
using MoonCore.Helpers;
|
||||||
|
using MoonCoreUI.Services;
|
||||||
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
|
namespace Moonlight.Features.FileManager.Implementations;
|
||||||
|
|
||||||
|
public class ExtractContextAction : IFileManagerContextAction
|
||||||
|
{
|
||||||
|
public string Name => "Extract";
|
||||||
|
public string Icon => "bxs-archive-out";
|
||||||
|
public string Color => "warning";
|
||||||
|
public Func<FileEntry, bool> Filter => entry => entry.IsFile && entry.Name.EndsWith(".tar.gz");
|
||||||
|
public async Task Execute(BaseFileAccess access, UI.Components.FileManager fileManager, FileEntry entry, IServiceProvider provider)
|
||||||
|
{
|
||||||
|
var archiveAccess = access.Actions as IArchiveFileActions;
|
||||||
|
|
||||||
|
if (archiveAccess == null)
|
||||||
|
throw new DisplayException("This file access does not support archiving");
|
||||||
|
|
||||||
|
await fileManager.OpenFolderSelect("Select where you want to extract the content of the archive", async destination =>
|
||||||
|
{
|
||||||
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
|
await toastService.CreateProgress("fileManagerExtract", "Extracting... Please be patient");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await archiveAccess.Extract(
|
||||||
|
access.CurrentDirectory + entry.Name,
|
||||||
|
destination
|
||||||
|
);
|
||||||
|
|
||||||
|
await toastService.Success("Successfully extracted archive");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Warn($"An error occured while extracting archive ({entry.Name}):");
|
||||||
|
Logger.Warn(e);
|
||||||
|
|
||||||
|
await toastService.Danger("An unknown error occured while extracting archive");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await toastService.RemoveProgress("fileManagerExtract");
|
||||||
|
}
|
||||||
|
|
||||||
|
await fileManager.View.Refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,4 +3,5 @@ namespace Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
public interface IArchiveFileActions
|
public interface IArchiveFileActions
|
||||||
{
|
{
|
||||||
public Task Archive(string path, string[] files);
|
public Task Archive(string path, string[] files);
|
||||||
|
public Task Extract(string path, string destination);
|
||||||
}
|
}
|
|
@ -95,7 +95,8 @@ else
|
||||||
OnEntryClicked="OnEntryClicked"
|
OnEntryClicked="OnEntryClicked"
|
||||||
OnNavigateUpClicked="OnNavigateUpClicked"
|
OnNavigateUpClicked="OnNavigateUpClicked"
|
||||||
OnSelectionChanged="OnSelectionChanged"
|
OnSelectionChanged="OnSelectionChanged"
|
||||||
EnableContextMenu="true">
|
EnableContextMenu="true"
|
||||||
|
ShowUploadPrompt="true">
|
||||||
<ContextMenuTemplate>
|
<ContextMenuTemplate>
|
||||||
@foreach (var action in ContextActions)
|
@foreach (var action in ContextActions)
|
||||||
{
|
{
|
||||||
|
|
|
@ -210,7 +210,7 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@if (Entries.Length == 0)
|
@if (Entries.Length == 0 && ShowUploadPrompt)
|
||||||
{
|
{
|
||||||
<div class="py-4">
|
<div class="py-4">
|
||||||
<IconAlert Color="primary" Title="No files and folders found" Icon="bx-cloud-upload">
|
<IconAlert Color="primary" Title="No files and folders found" Icon="bx-cloud-upload">
|
||||||
|
@ -240,6 +240,7 @@
|
||||||
[Parameter] public bool ShowDate { get; set; } = true;
|
[Parameter] public bool ShowDate { get; set; } = true;
|
||||||
[Parameter] public bool ShowSelect { get; set; } = true;
|
[Parameter] public bool ShowSelect { get; set; } = true;
|
||||||
[Parameter] public bool ShowNavigateUp { get; set; } = true;
|
[Parameter] public bool ShowNavigateUp { get; set; } = true;
|
||||||
|
[Parameter] public bool ShowUploadPrompt { get; set; } = false;
|
||||||
|
|
||||||
[Parameter] public RenderFragment<FileEntry>? ContextMenuTemplate { get; set; }
|
[Parameter] public RenderFragment<FileEntry>? ContextMenuTemplate { get; set; }
|
||||||
[Parameter] public bool EnableContextMenu { get; set; } = false;
|
[Parameter] public bool EnableContextMenu { get; set; } = false;
|
||||||
|
|
|
@ -47,6 +47,11 @@ public class ServerApiFileActions : IFileActions, IArchiveFileActions
|
||||||
{
|
{
|
||||||
await ApiClient.Post($"archive?path={path}&provider=tar.gz", files);
|
await ApiClient.Post($"archive?path={path}&provider=tar.gz", files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Extract(string path, string destination)
|
||||||
|
{
|
||||||
|
await ApiClient.Post($"extract?path={path}&destination={destination}&provider=tar.gz");
|
||||||
|
}
|
||||||
|
|
||||||
public IFileActions Clone() => new ServerApiFileActions(Endpoint, Token, ServerId);
|
public IFileActions Clone() => new ServerApiFileActions(Endpoint, Token, ServerId);
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,13 @@
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using Moonlight.Features.Servers.Configuration
|
@using Moonlight.Features.Servers.Configuration
|
||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
|
@using Moonlight.Core.Services
|
||||||
|
|
||||||
@inject Repository<Server> ServerRepository
|
@inject Repository<Server> ServerRepository
|
||||||
@inject ServerService ServerService
|
@inject ServerService ServerService
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
|
@inject IdentityService IdentityService
|
||||||
@inject ConfigService<ServersConfiguration> ConfigService
|
@inject ConfigService<ServersConfiguration> ConfigService
|
||||||
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
@ -217,6 +219,12 @@
|
||||||
.Include(x => x.Owner)
|
.Include(x => x.Owner)
|
||||||
.First(x => x.Id == Id);
|
.First(x => x.Id == Id);
|
||||||
|
|
||||||
|
if (Server.Owner.Id != IdentityService.CurrentUser.Id && IdentityService.CurrentUser.Permissions < 5000)
|
||||||
|
{
|
||||||
|
Server = null!;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await lazyLoader.SetText("Establishing a connection to the server");
|
await lazyLoader.SetText("Establishing a connection to the server");
|
||||||
|
|
||||||
// Create console wrapper
|
// Create console wrapper
|
||||||
|
|
Loading…
Reference in a new issue