Implemented basic plugin store and improved plugin system
This commit is contained in:
6
Moonlight/App/Models/Misc/OfficialMoonlightPlugin.cs
Normal file
6
Moonlight/App/Models/Misc/OfficialMoonlightPlugin.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Moonlight.App.Models.Misc;
|
||||||
|
|
||||||
|
public class OfficialMoonlightPlugin
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
@@ -16,6 +16,13 @@ public static class Permissions
|
|||||||
Description = "View statistical information about the moonlight instance"
|
Description = "View statistical information about the moonlight instance"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static Permission AdminSysPlugins = new()
|
||||||
|
{
|
||||||
|
Index = 2,
|
||||||
|
Name = "Admin system plugins",
|
||||||
|
Description = "View and install plugins"
|
||||||
|
};
|
||||||
|
|
||||||
public static Permission AdminDomains = new()
|
public static Permission AdminDomains = new()
|
||||||
{
|
{
|
||||||
Index = 4,
|
Index = 4,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Moonlight.App.Plugin.UI;
|
using Moonlight.App.Plugin.UI.Servers;
|
||||||
using Moonlight.App.Plugin.UI.Servers;
|
|
||||||
using Moonlight.App.Plugin.UI.Webspaces;
|
using Moonlight.App.Plugin.UI.Webspaces;
|
||||||
|
|
||||||
namespace Moonlight.App.Plugin;
|
namespace Moonlight.App.Plugin;
|
||||||
@@ -12,4 +11,5 @@ public abstract class MoonlightPlugin
|
|||||||
|
|
||||||
public Func<ServerPageContext, Task>? OnBuildServerPage { get; set; }
|
public Func<ServerPageContext, Task>? OnBuildServerPage { get; set; }
|
||||||
public Func<WebspacePageContext, Task>? OnBuildWebspacePage { get; set; }
|
public Func<WebspacePageContext, Task>? OnBuildWebspacePage { get; set; }
|
||||||
|
public Func<IServiceCollection, Task>? OnBuildServices { get; set; }
|
||||||
}
|
}
|
||||||
@@ -8,4 +8,5 @@ public class ServerPageContext
|
|||||||
public List<ServerSetting> Settings { get; set; } = new();
|
public List<ServerSetting> Settings { get; set; } = new();
|
||||||
public Server Server { get; set; }
|
public Server Server { get; set; }
|
||||||
public User User { get; set; }
|
public User User { get; set; }
|
||||||
|
public string[] ImageTags { get; set; }
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,7 @@ public class StorageService
|
|||||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "resources"));
|
Directory.CreateDirectory(PathBuilder.Dir("storage", "resources"));
|
||||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "backups"));
|
Directory.CreateDirectory(PathBuilder.Dir("storage", "backups"));
|
||||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "logs"));
|
Directory.CreateDirectory(PathBuilder.Dir("storage", "logs"));
|
||||||
|
Directory.CreateDirectory(PathBuilder.Dir("storage", "plugins"));
|
||||||
|
|
||||||
if(IsEmpty(PathBuilder.Dir("storage", "resources")))
|
if(IsEmpty(PathBuilder.Dir("storage", "resources")))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class MoonlightService
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var client = new GitHubClient(new ProductHeaderValue("Moonlight"));
|
var client = new GitHubClient(new ProductHeaderValue("Moonlight-Panel"));
|
||||||
|
|
||||||
var pullRequests = await client.PullRequest.GetAllForRepository("Moonlight-Panel", "Moonlight", new PullRequestRequest
|
var pullRequests = await client.PullRequest.GetAllForRepository("Moonlight-Panel", "Moonlight", new PullRequestRequest
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,25 +1,57 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Moonlight.App.Database.Entities;
|
using System.Runtime.Loader;
|
||||||
using Moonlight.App.Helpers;
|
using Moonlight.App.Helpers;
|
||||||
using Moonlight.App.Plugin;
|
using Moonlight.App.Plugin;
|
||||||
using Moonlight.App.Plugin.UI;
|
|
||||||
using Moonlight.App.Plugin.UI.Servers;
|
using Moonlight.App.Plugin.UI.Servers;
|
||||||
using Moonlight.App.Plugin.UI.Webspaces;
|
using Moonlight.App.Plugin.UI.Webspaces;
|
||||||
|
|
||||||
namespace Moonlight.App.Services;
|
namespace Moonlight.App.Services.Plugins;
|
||||||
|
|
||||||
public class PluginService
|
public class PluginService
|
||||||
{
|
{
|
||||||
public List<MoonlightPlugin> Plugins { get; set; }
|
public List<MoonlightPlugin> Plugins { get; private set; }
|
||||||
|
public Dictionary<MoonlightPlugin, string> PluginFiles { get; private set; }
|
||||||
|
|
||||||
|
private AssemblyLoadContext LoadContext;
|
||||||
|
|
||||||
public PluginService()
|
public PluginService()
|
||||||
{
|
{
|
||||||
LoadPlugins();
|
LoadContext = new(null, true);
|
||||||
|
ReloadPlugins().Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadPlugins()
|
private Task UnloadPlugins()
|
||||||
{
|
{
|
||||||
Plugins = new();
|
Plugins = new();
|
||||||
|
PluginFiles = new();
|
||||||
|
|
||||||
|
if(LoadContext.Assemblies.Any())
|
||||||
|
LoadContext.Unload();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ReloadPlugins()
|
||||||
|
{
|
||||||
|
await UnloadPlugins();
|
||||||
|
|
||||||
|
// Try to update all plugins ending with .dll.cache
|
||||||
|
foreach (var pluginFile in Directory.EnumerateFiles(
|
||||||
|
PathBuilder.Dir(Directory.GetCurrentDirectory(), "storage", "plugins"))
|
||||||
|
.Where(x => x.EndsWith(".dll.cache")))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var realPath = pluginFile.Replace(".cache", "");
|
||||||
|
File.Copy(pluginFile, realPath, true);
|
||||||
|
File.Delete(pluginFile);
|
||||||
|
Logger.Info($"Updated plugin {realPath} on startup");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var pluginType = typeof(MoonlightPlugin);
|
var pluginType = typeof(MoonlightPlugin);
|
||||||
|
|
||||||
@@ -27,7 +59,7 @@ public class PluginService
|
|||||||
PathBuilder.Dir(Directory.GetCurrentDirectory(), "storage", "plugins"))
|
PathBuilder.Dir(Directory.GetCurrentDirectory(), "storage", "plugins"))
|
||||||
.Where(x => x.EndsWith(".dll")))
|
.Where(x => x.EndsWith(".dll")))
|
||||||
{
|
{
|
||||||
var assembly = Assembly.LoadFile(pluginFile);
|
var assembly = LoadContext.LoadFromAssemblyPath(pluginFile);
|
||||||
|
|
||||||
foreach (var type in assembly.GetTypes())
|
foreach (var type in assembly.GetTypes())
|
||||||
{
|
{
|
||||||
@@ -38,6 +70,7 @@ public class PluginService
|
|||||||
Logger.Info($"Loaded plugin '{plugin.Name}' ({plugin.Version}) by {plugin.Author}");
|
Logger.Info($"Loaded plugin '{plugin.Name}' ({plugin.Version}) by {plugin.Author}");
|
||||||
|
|
||||||
Plugins.Add(plugin);
|
Plugins.Add(plugin);
|
||||||
|
PluginFiles.Add(plugin, pluginFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,4 +99,13 @@ public class PluginService
|
|||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task BuildServices(IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
foreach (var plugin in Plugins)
|
||||||
|
{
|
||||||
|
if (plugin.OnBuildServices != null)
|
||||||
|
await plugin.OnBuildServices.Invoke(serviceCollection);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
63
Moonlight/App/Services/Plugins/PluginStoreService.cs
Normal file
63
Moonlight/App/Services/Plugins/PluginStoreService.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Moonlight.App.Helpers;
|
||||||
|
using Moonlight.App.Models.Misc;
|
||||||
|
using Octokit;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Services.Plugins;
|
||||||
|
|
||||||
|
public class PluginStoreService
|
||||||
|
{
|
||||||
|
private readonly GitHubClient Client;
|
||||||
|
private readonly PluginService PluginService;
|
||||||
|
|
||||||
|
public PluginStoreService(PluginService pluginService)
|
||||||
|
{
|
||||||
|
PluginService = pluginService;
|
||||||
|
Client = new(new ProductHeaderValue("Moonlight-Panel"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OfficialMoonlightPlugin[]> GetPlugins()
|
||||||
|
{
|
||||||
|
var items = await Client.Repository.Content.GetAllContents("Moonlight-Panel", "OfficialPlugins");
|
||||||
|
|
||||||
|
if (items == null)
|
||||||
|
{
|
||||||
|
Logger.Fatal("Unable to read plugin repo contents");
|
||||||
|
return Array.Empty<OfficialMoonlightPlugin>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
.Where(x => x.Type == ContentType.Dir)
|
||||||
|
.Select(x => new OfficialMoonlightPlugin()
|
||||||
|
{
|
||||||
|
Name = x.Name
|
||||||
|
})
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetPluginReadme(OfficialMoonlightPlugin plugin)
|
||||||
|
{
|
||||||
|
var rawReadme = await Client.Repository.Content
|
||||||
|
.GetRawContent("Moonlight-Panel", "OfficialPlugins", $"{plugin.Name}/README.md");
|
||||||
|
|
||||||
|
if (rawReadme == null)
|
||||||
|
return "Error";
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetString(rawReadme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InstallPlugin(OfficialMoonlightPlugin plugin, bool updating = false)
|
||||||
|
{
|
||||||
|
var rawPlugin = await Client.Repository.Content
|
||||||
|
.GetRawContent("Moonlight-Panel", "OfficialPlugins", $"{plugin.Name}/{plugin.Name}.dll");
|
||||||
|
|
||||||
|
if (updating)
|
||||||
|
{
|
||||||
|
await File.WriteAllBytesAsync(PathBuilder.File("storage", "plugins", $"{plugin.Name}.dll.cache"), rawPlugin);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await File.WriteAllBytesAsync(PathBuilder.File("storage", "plugins", $"{plugin.Name}.dll"), rawPlugin);
|
||||||
|
await PluginService.ReloadPlugins();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ using Moonlight.App.Services.Interop;
|
|||||||
using Moonlight.App.Services.Mail;
|
using Moonlight.App.Services.Mail;
|
||||||
using Moonlight.App.Services.Minecraft;
|
using Moonlight.App.Services.Minecraft;
|
||||||
using Moonlight.App.Services.Notifications;
|
using Moonlight.App.Services.Notifications;
|
||||||
|
using Moonlight.App.Services.Plugins;
|
||||||
using Moonlight.App.Services.Sessions;
|
using Moonlight.App.Services.Sessions;
|
||||||
using Moonlight.App.Services.Statistics;
|
using Moonlight.App.Services.Statistics;
|
||||||
using Moonlight.App.Services.SupportChat;
|
using Moonlight.App.Services.SupportChat;
|
||||||
@@ -110,6 +111,9 @@ namespace Moonlight
|
|||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
var pluginService = new PluginService();
|
||||||
|
await pluginService.BuildServices(builder.Services);
|
||||||
|
|
||||||
// Switch to logging.net injection
|
// Switch to logging.net injection
|
||||||
// TODO: Enable in production
|
// TODO: Enable in production
|
||||||
builder.Logging.ClearProviders();
|
builder.Logging.ClearProviders();
|
||||||
@@ -208,6 +212,7 @@ namespace Moonlight
|
|||||||
builder.Services.AddScoped<PopupService>();
|
builder.Services.AddScoped<PopupService>();
|
||||||
builder.Services.AddScoped<SubscriptionService>();
|
builder.Services.AddScoped<SubscriptionService>();
|
||||||
builder.Services.AddScoped<BillingService>();
|
builder.Services.AddScoped<BillingService>();
|
||||||
|
builder.Services.AddSingleton<PluginStoreService>();
|
||||||
|
|
||||||
builder.Services.AddScoped<SessionClientService>();
|
builder.Services.AddScoped<SessionClientService>();
|
||||||
builder.Services.AddSingleton<SessionServerService>();
|
builder.Services.AddSingleton<SessionServerService>();
|
||||||
@@ -239,7 +244,8 @@ namespace Moonlight
|
|||||||
builder.Services.AddSingleton<MalwareScanService>();
|
builder.Services.AddSingleton<MalwareScanService>();
|
||||||
builder.Services.AddSingleton<TelemetryService>();
|
builder.Services.AddSingleton<TelemetryService>();
|
||||||
builder.Services.AddSingleton<TempMailService>();
|
builder.Services.AddSingleton<TempMailService>();
|
||||||
builder.Services.AddSingleton<PluginService>();
|
|
||||||
|
builder.Services.AddSingleton(pluginService);
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
builder.Services.AddSingleton<MoonlightService>();
|
builder.Services.AddSingleton<MoonlightService>();
|
||||||
@@ -290,7 +296,6 @@ namespace Moonlight
|
|||||||
_ = app.Services.GetRequiredService<MalwareScanService>();
|
_ = app.Services.GetRequiredService<MalwareScanService>();
|
||||||
_ = app.Services.GetRequiredService<TelemetryService>();
|
_ = app.Services.GetRequiredService<TelemetryService>();
|
||||||
_ = app.Services.GetRequiredService<TempMailService>();
|
_ = app.Services.GetRequiredService<TempMailService>();
|
||||||
_ = app.Services.GetRequiredService<PluginService>();
|
|
||||||
|
|
||||||
_ = app.Services.GetRequiredService<MoonlightService>();
|
_ = app.Services.GetRequiredService<MoonlightService>();
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,11 @@
|
|||||||
<TL>Mail</TL>
|
<TL>Mail</TL>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item mt-2">
|
||||||
|
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 10 ? "active" : "")" href="/admin/system/plugins">
|
||||||
|
<TL>Plugins</TL>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,6 +40,8 @@
|
|||||||
{
|
{
|
||||||
SecurityLogs = SecurityLogRepository
|
SecurityLogs = SecurityLogRepository
|
||||||
.Get()
|
.Get()
|
||||||
|
.ToArray()
|
||||||
|
.OrderByDescending(x => x.CreatedAt)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|||||||
138
Moonlight/Shared/Views/Admin/Sys/Plugins.razor
Normal file
138
Moonlight/Shared/Views/Admin/Sys/Plugins.razor
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
@page "/admin/system/plugins"
|
||||||
|
|
||||||
|
@using Moonlight.Shared.Components.Navigations
|
||||||
|
@using Moonlight.App.Services.Plugins
|
||||||
|
@using BlazorTable
|
||||||
|
@using Moonlight.App.Models.Misc
|
||||||
|
@using Moonlight.App.Plugin
|
||||||
|
@using Moonlight.App.Services
|
||||||
|
@using Moonlight.App.Services.Interop
|
||||||
|
|
||||||
|
@inject PluginStoreService PluginStoreService
|
||||||
|
@inject SmartTranslateService SmartTranslateService
|
||||||
|
@inject PluginService PluginService
|
||||||
|
@inject ToastService ToastService
|
||||||
|
@inject ModalService ModalService
|
||||||
|
|
||||||
|
@attribute [PermissionRequired(nameof(Permissions.AdminSysPlugins))]
|
||||||
|
|
||||||
|
<AdminSystemNavigation Index="10"/>
|
||||||
|
|
||||||
|
<div class="card mb-5">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="card-title">
|
||||||
|
<TL>Installed plugins</TL>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<Table TableItem="MoonlightPlugin" Items="PluginService.Plugins" PageSize="25" TableClass="table table-row-bordered table-row-gray-100 align-middle gs-0 gy-3" TableHeadClass="fw-bold text-muted">
|
||||||
|
<Column TableItem="MoonlightPlugin" Title="@(SmartTranslateService.Translate("Name"))" Field="@(x => x.Name)" Filterable="true" Sortable="false"/>
|
||||||
|
<Column TableItem="MoonlightPlugin" Title="@(SmartTranslateService.Translate("Author"))" Field="@(x => x.Author)" Filterable="true" Sortable="false"/>
|
||||||
|
<Column TableItem="MoonlightPlugin" Title="@(SmartTranslateService.Translate("Version"))" Field="@(x => x.Version)" Filterable="true" Sortable="false"/>
|
||||||
|
<Column TableItem="MoonlightPlugin" Title="@(SmartTranslateService.Translate("Path"))" Field="@(x => x.Name)" Filterable="false" Sortable="false">
|
||||||
|
<Template>
|
||||||
|
@{
|
||||||
|
var path = PluginService.PluginFiles[context];
|
||||||
|
}
|
||||||
|
|
||||||
|
<span>@(path)</span>
|
||||||
|
</Template>
|
||||||
|
</Column>
|
||||||
|
<Pager ShowPageNumber="true" ShowTotalCount="true"/>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="card-title">
|
||||||
|
<TL>Official plugins</TL>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<LazyLoader @ref="PluginsLazyLoader" Load="LoadOfficialPlugins">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<Table TableItem="OfficialMoonlightPlugin" Items="PluginList" PageSize="25" TableClass="table table-row-bordered table-row-gray-100 align-middle gs-0 gy-3" TableHeadClass="fw-bold text-muted">
|
||||||
|
<Column TableItem="OfficialMoonlightPlugin" Width="80%" Title="@(SmartTranslateService.Translate("Name"))" Field="@(x => x.Name)" Filterable="true" Sortable="false"/>
|
||||||
|
<Column TableItem="OfficialMoonlightPlugin" Width="10%" Title="" Field="@(x => x.Name)" Filterable="false" Sortable="false">
|
||||||
|
<Template>
|
||||||
|
<WButton Text="@(SmartTranslateService.Translate("Show readme"))"
|
||||||
|
CssClasses="btn-secondary"
|
||||||
|
OnClick="() => ShowOfficialPluginReadme(context)"/>
|
||||||
|
</Template>
|
||||||
|
</Column>
|
||||||
|
<Column TableItem="OfficialMoonlightPlugin" Width="10%" Title="" Field="@(x => x.Name)" Filterable="false" Sortable="false">
|
||||||
|
<Template>
|
||||||
|
@if (PluginService.PluginFiles.Values.Any(x =>
|
||||||
|
Path.GetFileName(x).Replace(".dll", "") == context.Name))
|
||||||
|
{
|
||||||
|
<WButton Text="@(SmartTranslateService.Translate("Update"))"
|
||||||
|
WorkingText="@(SmartTranslateService.Translate("Updating"))"
|
||||||
|
CssClasses="btn-primary"
|
||||||
|
OnClick="() => UpdateOfficialPlugin(context)"/>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<WButton Text="@(SmartTranslateService.Translate("Install"))"
|
||||||
|
WorkingText="@(SmartTranslateService.Translate("Installing"))"
|
||||||
|
CssClasses="btn-primary"
|
||||||
|
OnClick="() => InstallOfficialPlugin(context)"/>
|
||||||
|
}
|
||||||
|
</Template>
|
||||||
|
</Column>
|
||||||
|
<Pager ShowPageNumber="true" ShowTotalCount="true"/>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</LazyLoader>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="pluginReadme" class="modal" style="display: none">
|
||||||
|
<div class="modal-dialog modal-dialog-centered modal-xl">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">
|
||||||
|
<TL>Plugin readme</TL>
|
||||||
|
</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
@((MarkupString)Markdig.Markdown.ToHtml(PluginReadme))
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
private LazyLoader PluginsLazyLoader;
|
||||||
|
private OfficialMoonlightPlugin[] PluginList;
|
||||||
|
private string PluginReadme = "";
|
||||||
|
|
||||||
|
private async Task LoadOfficialPlugins(LazyLoader lazyLoader)
|
||||||
|
{
|
||||||
|
PluginList = await PluginStoreService.GetPlugins();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ShowOfficialPluginReadme(OfficialMoonlightPlugin plugin)
|
||||||
|
{
|
||||||
|
PluginReadme = await PluginStoreService.GetPluginReadme(plugin);
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
await ModalService.Show("pluginReadme");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InstallOfficialPlugin(OfficialMoonlightPlugin plugin)
|
||||||
|
{
|
||||||
|
await PluginStoreService.InstallPlugin(plugin);
|
||||||
|
await ToastService.Success(SmartTranslateService.Translate("Successfully installed plugin"));
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateOfficialPlugin(OfficialMoonlightPlugin plugin)
|
||||||
|
{
|
||||||
|
await PluginStoreService.InstallPlugin(plugin, true);
|
||||||
|
await ToastService.Success(SmartTranslateService.Translate("Successfully installed plugin. You need to reboot to apply changes"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
@using Moonlight.App.Plugin.UI.Servers
|
@using Moonlight.App.Plugin.UI.Servers
|
||||||
@using Moonlight.App.Repositories
|
@using Moonlight.App.Repositories
|
||||||
@using Moonlight.App.Services
|
@using Moonlight.App.Services
|
||||||
|
@using Moonlight.App.Services.Plugins
|
||||||
@using Moonlight.App.Services.Sessions
|
@using Moonlight.App.Services.Sessions
|
||||||
@using Moonlight.Shared.Components.Xterm
|
@using Moonlight.Shared.Components.Xterm
|
||||||
@using Moonlight.Shared.Views.Server.Settings
|
@using Moonlight.Shared.Views.Server.Settings
|
||||||
@@ -240,7 +241,8 @@
|
|||||||
Context = new ServerPageContext()
|
Context = new ServerPageContext()
|
||||||
{
|
{
|
||||||
Server = CurrentServer,
|
Server = CurrentServer,
|
||||||
User = IdentityService.User
|
User = IdentityService.User,
|
||||||
|
ImageTags = Tags
|
||||||
};
|
};
|
||||||
|
|
||||||
Context.Tabs.Add(new()
|
Context.Tabs.Add(new()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using Moonlight.App.Helpers
|
@using Moonlight.App.Helpers
|
||||||
@using Moonlight.App.Plugin.UI.Webspaces
|
@using Moonlight.App.Plugin.UI.Webspaces
|
||||||
|
@using Moonlight.App.Services.Plugins
|
||||||
@using Moonlight.App.Services.Sessions
|
@using Moonlight.App.Services.Sessions
|
||||||
|
|
||||||
@inject Repository<WebSpace> WebSpaceRepository
|
@inject Repository<WebSpace> WebSpaceRepository
|
||||||
|
|||||||
Reference in New Issue
Block a user