mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-20 02:28:31 +01:00
38fb64130d
This allows external integrations ( btcpay docker fragments) to highlight specific plugins as recommended to be installed. Also moved the remote option to a config option instead of a url query param to avoid messy situations where users could get deceived with a generated url. The dockerfiles also have an additional csproj to build and the plugin dir was renamed correctly from extensions to plugins
193 lines
8.9 KiB
Plaintext
193 lines
8.9 KiB
Plaintext
@using BTCPayServer.Configuration
|
|
@model BTCPayServer.Controllers.ServerController.ListPluginsViewModel
|
|
@inject BTCPayServerOptions BTCPayServerOptions
|
|
@{
|
|
ViewData.SetActivePageAndTitle(ServerNavPages.Plugins);
|
|
var installed = Model.Installed.Select(plugin => plugin.Identifier);
|
|
var availableAndNotInstalled = Model.Available.Where(plugin => !installed.Contains(plugin.Identifier)).Select(plugin => (plugin, BTCPayServerOptions.RecommendedPlugins.Contains(plugin.Identifier.ToLowerInvariant()))).OrderBy(tuple => tuple.Item1);
|
|
}
|
|
|
|
<partial name="_StatusMessage"/>
|
|
|
|
@if (Model.Commands.Any())
|
|
{
|
|
<div class="alert alert-info mb-5">
|
|
You need to restart BTCPay Server in order to update your active plugins.
|
|
@if (Model.CanShowRestart)
|
|
{
|
|
<form method="post" asp-action="Maintenance" class="mt-2">
|
|
<button type="submit" name="command" value="restart" class="btn btn-info" asp-action="Maintenance">Restart now</button>
|
|
</form>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
@if (Model.Installed.Any())
|
|
{
|
|
<h3 class="mb-3">Installed Plugins</h3>
|
|
<div class="row mb-4">
|
|
@foreach (var plugin in Model.Installed)
|
|
{
|
|
var matchedAvailable = Model.Available.SingleOrDefault(availablePlugin => availablePlugin.Identifier == plugin.Identifier);
|
|
var updateAvailable = matchedAvailable != null && plugin.Version < matchedAvailable.Version;
|
|
<div class="col col-12 col-lg-6 mb-4">
|
|
<div class="card h-100">
|
|
<div class="card-body">
|
|
<h4 class="card-title">@plugin.Name</h4>
|
|
<h5 class="card-subtitle mb-3 text-muted d-flex align-items-center">
|
|
@plugin.Version
|
|
@if (plugin.SystemPlugin)
|
|
{
|
|
<div class="badge badge-secondary ml-2">System plugin</div>
|
|
}
|
|
else if (updateAvailable)
|
|
{
|
|
<div class="badge badge-secondary ml-2">@matchedAvailable.Version available</div>
|
|
}
|
|
</h5>
|
|
<p class="card-text">@plugin.Description</p>
|
|
</div>
|
|
@if (!plugin.SystemPlugin)
|
|
{
|
|
<div class="card-footer border-0 pb-3 d-flex">
|
|
@if (Model.Commands.Any(tuple => tuple.plugin.Equals(plugin.Identifier, StringComparison.InvariantCultureIgnoreCase)))
|
|
{
|
|
<form asp-action="CancelPluginCommands" asp-route-plugin="@plugin.Identifier">
|
|
<button type="submit" class="btn btn-outline-secondary">Cancel pending action</button>
|
|
</form>
|
|
}
|
|
else
|
|
{
|
|
@if (updateAvailable)
|
|
{
|
|
<form asp-action="InstallPlugin" asp-route-plugin="@plugin.Identifier" class="mr-3">
|
|
<button type="submit" class="btn btn-secondary">Update</button>
|
|
</form>
|
|
}
|
|
<form asp-action="UnInstallPlugin" asp-route-plugin="@plugin.Identifier">
|
|
<button type="submit" class="btn btn-outline-danger">Uninstall</button>
|
|
</form>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
@if (availableAndNotInstalled.Any())
|
|
{
|
|
<h3 class="mb-3">Available Plugins</h3>
|
|
<div class="row mb-4">
|
|
@foreach (var pluginT in availableAndNotInstalled)
|
|
{
|
|
var plugin = pluginT.Item1;
|
|
<div class="col col-12 col-lg-6 mb-4">
|
|
<div class="card h-100">
|
|
<div class="card-body">
|
|
<h4 class="card-title">@plugin.Name</h4>
|
|
<h5 class="card-subtitle mb-3 text-muted d-flex justify-content-between">
|
|
<span>@plugin.Version</span>
|
|
@if (pluginT.Item2)
|
|
{
|
|
<span data-toggle="tooltip" title="This plugin has been recommended to be installed by your deployment method.">Recommended <span class="fa fa-question-circle-o"></span></span>
|
|
}
|
|
</h5>
|
|
<p class="card-text">@plugin.Description</p>
|
|
</div>
|
|
<div class="card-footer border-0 pb-3">
|
|
@if (Model.Commands.Any(tuple => tuple.plugin.Equals(plugin.Identifier, StringComparison.InvariantCultureIgnoreCase)))
|
|
{
|
|
<form asp-action="CancelPluginCommands" asp-route-plugin="@plugin.Identifier">
|
|
<button type="submit" class="btn btn-outline-secondary">Cancel pending install</button>
|
|
</form>
|
|
}
|
|
else
|
|
{
|
|
<form asp-action="InstallPlugin" asp-route-plugin="@plugin.Identifier">
|
|
<button type="submit" class="btn btn-primary">Install</button>
|
|
</form>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
<div class="mb-4">
|
|
<button class="btn btn-link text-secondary mb-2" type="button" data-toggle="collapse" data-target="#manual-upload">
|
|
Upload plugin
|
|
</button>
|
|
<div class="row collapse" id="manual-upload">
|
|
<div class="col col-12 col-lg-6 mb-4">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h4 class="card-title">Add plugin manually</h4>
|
|
<div class="alert alert-warning my-3">
|
|
<h6 class="mr-1">This is an extremely dangerous operation!</h6>
|
|
Only upload plugins from trusted sources.
|
|
</div>
|
|
<form method="post" enctype="multipart/form-data" asp-action="UploadPlugin">
|
|
<div class="form-group">
|
|
<div class="custom-file">
|
|
<input type="file" class="custom-file-input form-control-file" required name="files" accept=".btcpay" id="files">
|
|
<label class="custom-file-label" for="files">Choose file</label>
|
|
</div>
|
|
</div>
|
|
<button class="btn btn-primary" type="submit">Upload</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if (Model.Commands.Any())
|
|
{
|
|
<div class="mb-4">
|
|
<button class="btn btn-link text-secondary mb-2" type="button" data-toggle="collapse" data-target="#pending-actions">
|
|
Pending actions
|
|
</button>
|
|
<div class="row collapse" id="pending-actions">
|
|
<div class="col col-12 col-lg-6 mb-4">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h4 class="card-title">Pending actions</h4>
|
|
<ul class="list-group list-group-flush">
|
|
@foreach (var extComm in Model.Commands.GroupBy(tuple => tuple.plugin))
|
|
{
|
|
<li class="list-group-item px-0">
|
|
<div class="d-flex flex-wrap align-items-center justify-content-between">
|
|
<span class="my-2 mr-3">@extComm.Key</span>
|
|
<form asp-action="CancelPluginCommands" asp-route-plugin="@extComm.Key">
|
|
<button type="submit" class="btn btn-outline-secondary">Cancel pending @extComm.Last().command</button>
|
|
</form>
|
|
</div>
|
|
</li>
|
|
}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@section Scripts {
|
|
<script>
|
|
$(document).ready(function () {
|
|
$(".custom-file-input").on("change", function () {
|
|
var label = $(this).next("label");
|
|
var el = $(this).get(0);
|
|
if (el.files.length > 0) {
|
|
var fileName = el.files[0].name;
|
|
label.addClass("selected").html(fileName);
|
|
} else {
|
|
label.removeClass("selected").html("Choose file");
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
}
|