2020-11-05 10:21:09 +01:00
@using BTCPayServer.Configuration
2022-01-25 11:15:15 +01:00
@using BTCPayServer.Plugins
2023-01-16 20:12:51 +09:00
@model BTCPayServer.Controllers.UIServerController.ListPluginsViewModel
2020-11-05 10:21:09 +01:00
@inject BTCPayServerOptions BTCPayServerOptions
2023-12-13 12:36:23 +01:00
@inject PluginService PluginService
2020-10-21 14:02:20 +02:00
@{
2021-12-31 08:36:38 +01:00
Layout = "_Layout";
2021-12-16 11:17:02 +01:00
ViewData.SetActivePage(ServerNavPages.Plugins);
2023-12-13 12:36:23 +01:00
var installed = Model.Installed.ToDictionary(plugin => plugin.Identifier, plugin => plugin.Version);
2022-01-25 11:15:15 +01:00
var availableAndNotInstalledx = Model.Available
2023-12-13 12:36:23 +01:00
.Where(plugin => !installed.ContainsKey(plugin.Identifier))
2022-01-25 11:15:15 +01:00
.GroupBy(plugin => plugin.Identifier)
2021-09-09 13:11:59 +02:00
.ToList();
2020-11-05 15:43:14 +01:00
2022-01-25 11:15:15 +01:00
var availableAndNotInstalled = new List<PluginService.AvailablePlugin>();
foreach (var availableAndNotInstalledItem in availableAndNotInstalledx)
{
var ordered = availableAndNotInstalledItem.OrderByDescending(plugin => plugin.Version).ToArray();
2023-12-13 12:36:23 +01:00
availableAndNotInstalled.Add(ordered.FirstOrDefault(availablePlugin => PluginManager.DependenciesMet(availablePlugin.Dependencies, installed)) ?? ordered.FirstOrDefault());
2022-01-25 11:15:15 +01:00
}
2023-01-16 20:12:51 +09:00
2020-11-05 15:43:14 +01:00
bool DependentOn(string plugin)
{
foreach (var installedPlugin in Model.Installed)
{
if (installedPlugin.Dependencies.Any(dep => dep.Identifier.Equals(plugin, StringComparison.InvariantCultureIgnoreCase)))
{
return true;
}
}
var pendingInstalls = Model.Commands.Where(tuple => tuple.command != "uninstall").Select(tuple => tuple.plugin).Distinct();
foreach (var pendingInstall in pendingInstalls)
{
if (Model.Available.Any(availablePlugin => availablePlugin.Identifier.Equals(pendingInstall, StringComparison.InvariantCultureIgnoreCase) &&
availablePlugin.Dependencies.Any(dep => dep.Identifier.Equals(plugin, StringComparison.InvariantCultureIgnoreCase))))
{
return true;
}
}
return false;
}
2020-10-21 14:02:20 +02:00
}
2020-11-06 08:06:37 +01:00
<style>
2023-12-13 12:36:23 +01:00
.version-switch .nav-link { display: inline; }
.version-switch .nav-link.active { display: none; }
2020-11-06 08:06:37 +01:00
</style>
2021-12-31 08:36:38 +01:00
<partial name="_StatusMessage" />
2023-12-14 12:41:37 +01:00
<div class="alert alert-warning alert-dismissible mb-4" role="alert">
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
<vc:icon symbol="close" />
</button>
<h5 class="alert-heading">Important notice about plugins</h5>
<p class="mb-0">
Plugins are developed by third parties. They need to be updated and maintained regularly in addition to BTCPay Server. Use plugins at your own risk.
<a href="#warning-details" data-bs-toggle="collapse" class="alert-link">Read more</a>
</p>
<div class="collapse" id="warning-details">
<p class="my-3"><strong>Use at Your Own Risk:</strong> Plugins in this store are developed by independent third parties. These plugins have not undergone review by the BTCPay Server team.</p>
<p class="mb-3"><strong>Disclaimer of Responsibility:</strong> BTCPay Server contributors or Foundation are not liable for any harm, loss, or damage resulting from the installation or use of the plugins. Users assume full responsibility for their installation, use, familiarity with licensing and terms of service and maintenance.</p>
<p class="mb-3"><strong>No Official Endorsement:</strong> Inclusion in the list of BTCPay Server plugins does not constitute an endorsement or guarantee of quality, safety, or compatibility.</p>
<p class="mb-3"><strong>Due Diligence Advised:</strong> We recommend users exercise caution and conduct their own research or consult the community before installing any plugin.</p>
<p class="mb-0"><strong>Feedback and Reporting:</strong> Should you experience issues with a plugin, please provide feedback or report concerns directly to the respective plugin developers.</p>
</div>
</div>
2021-04-01 05:27:22 +02:00
@if (Model.Disabled.Any())
{
2022-01-25 22:01:49 -08:00
<div class="alert alert-danger mb-4 d-flex align-items-center justify-content-between">
2021-04-01 05:27:22 +02:00
Some plugins were disabled due to fatal errors. They may be incompatible with this version of BTCPay Server.
2023-11-28 15:19:47 +01:00
</div>
<div class="mb-5">
<h3 class="mb-4">Disabled Plugins</h3>
<ul class="list-group list-group-flush d-inline-block">
@foreach (var d in Model.Disabled)
{
<li class="list-group-item px-0">
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
<span>@d</span>
<form asp-action="UnInstallPlugin" asp-route-plugin="@d">
<button type="submit" class="btn btn-sm btn-outline-danger">Uninstall</button>
</form>
</div>
</li>
}
</ul>
2021-04-01 05:27:22 +02:00
</div>
}
2023-11-28 15:19:47 +01:00
2020-10-21 14:02:20 +02:00
@if (Model.Commands.Any())
{
2022-01-25 22:01:49 -08:00
<div class="alert alert-info mb-4 d-flex align-items-center justify-content-between">
2020-10-21 14:02:20 +02:00
You need to restart BTCPay Server in order to update your active plugins.
@if (Model.CanShowRestart)
{
2020-10-22 10:58:22 +02:00
<form method="post" asp-action="Maintenance" class="mt-2">
2023-01-19 14:27:33 +09:00
<button type="submit" name="command" value="soft-restart" class="btn btn-info" asp-action="Maintenance">Restart now</button>
2020-10-21 14:02:20 +02:00
</form>
}
</div>
}
@if (Model.Installed.Any())
{
2022-01-17 17:19:27 -08:00
<h3 class="mb-4">Installed Plugins</h3>
2020-10-22 10:58:22 +02:00
<div class="row mb-4">
2022-12-13 18:54:41 +09:00
@foreach (var plugin in Model.Installed.Where(i => !i.SystemPlugin))
2020-10-21 14:02:20 +02:00
{
2023-01-16 20:12:51 +09:00
Model.DownloadedPluginsByIdentifier.TryGetValue(plugin.Identifier, out var downloadInfo);
2022-01-25 11:15:15 +01:00
var matchedAvailable = Model.Available.Where(availablePlugin => availablePlugin.Identifier == plugin.Identifier && availablePlugin.Version > plugin.Version).OrderByDescending(availablePlugin => availablePlugin.Version).ToArray();
2023-12-13 12:36:23 +01:00
var x = matchedAvailable.FirstOrDefault(availablePlugin => PluginManager.DependenciesMet(availablePlugin.Dependencies, installed)) ?? matchedAvailable.FirstOrDefault();
2022-12-13 18:54:41 +09:00
var updateAvailable = matchedAvailable.Any();
2020-11-06 08:06:37 +01:00
var tabId = plugin.Identifier.ToLowerInvariant().Replace(".", "_");
2022-01-27 03:56:46 +01:00
<div class="col col-12 col-md-6 col-lg-12 col-xl-6 col-xxl-4 mb-4">
2022-02-02 04:47:22 +01:00
<div class="card h-100" id="@plugin.Identifier">
2020-10-22 10:58:22 +02:00
<div class="card-body">
2023-01-19 10:08:34 +01:00
<div class="d-flex flex-wrap align-items-baseline justify-content-between gap-2 mb-3">
<h4 class="card-title mb-0" data-bs-toggle="tooltip" title="@plugin.Identifier">@plugin.Name</h4>
2023-01-18 13:47:08 +01:00
@if (!string.IsNullOrEmpty(downloadInfo?.Author))
2023-01-16 20:12:51 +09:00
{
2023-01-19 10:08:34 +01:00
<span class="text-muted text-nowrap">
2023-01-16 20:12:51 +09:00
by
<a href="@downloadInfo.AuthorLink" rel="noreferrer noopener" target="_blank">
2023-01-19 10:08:34 +01:00
@downloadInfo.Author
2023-01-16 20:12:51 +09:00
</a>
</span>
}
</div>
2023-01-19 10:08:34 +01:00
<div class="d-flex flex-wrap align-items-center mb-2 gap-3">
2022-11-22 19:06:23 +09:00
<h5 class="text-muted d-flex align-items-center mt-1 gap-3">
2020-11-06 08:06:37 +01:00
@plugin.Version
2022-12-13 18:54:41 +09:00
@if (updateAvailable && x != null)
2020-11-06 08:06:37 +01:00
{
2022-11-22 19:06:23 +09:00
<div class="badge bg-info">
2022-01-25 11:15:15 +01:00
@x.Version available
2020-11-06 08:06:37 +01:00
</div>
}
</h5>
2020-11-05 15:43:14 +01:00
@if (updateAvailable)
2020-10-22 10:58:22 +02:00
{
2020-11-06 08:06:37 +01:00
<span class="nav version-switch mt-n1" role="tablist">
2023-01-19 10:08:34 +01:00
<a data-bs-toggle="tab" href="#@tabId-current" class="nav-link text-info p-0 show active">Show current info</a>
<a data-bs-toggle="tab" href="#@tabId-update" class="nav-link text-info p-0">Show update info</a>
2020-11-06 08:06:37 +01:00
</span>
2020-10-22 10:58:22 +02:00
}
2020-11-05 15:43:14 +01:00
</div>
<div class="tab-content">
2020-11-06 08:06:37 +01:00
<div class="tab-pane active" id="@tabId-current">
2020-11-05 15:43:14 +01:00
<p class="card-text">@plugin.Description</p>
@if (plugin.Dependencies.Any())
{
2023-01-19 10:08:34 +01:00
<h6 class="text-muted fw-semibold">Dependencies</h6>
2020-11-05 15:43:14 +01:00
<ul class="list-group list-group-flush">
@foreach (var dependency in plugin.Dependencies)
{
2023-01-19 10:08:34 +01:00
<li class="list-group-item p-2 d-inline-flex align-items-center gap-2">
2020-11-05 15:43:14 +01:00
@dependency
2023-12-13 12:36:23 +01:00
@if (!PluginManager.DependencyMet(dependency, installed))
2020-11-05 15:43:14 +01:00
{
2023-01-19 10:08:34 +01:00
<span title="Dependency not met." data-bs-toggle="tooltip" class="text-danger">
<vc:icon symbol="warning" />
</span>
2020-11-05 15:43:14 +01:00
}
</li>
}
</ul>
}
</div>
2022-11-22 19:06:23 +09:00
@if (updateAvailable && x != null)
2020-10-22 10:58:22 +02:00
{
2020-11-06 08:06:37 +01:00
<div class="tab-pane" id="@tabId-update">
2022-01-25 11:15:15 +01:00
<p class="card-text">@x.Description</p>
@if (x.Dependencies.Any())
2020-11-05 15:43:14 +01:00
{
2023-01-19 10:08:34 +01:00
<h6 class="text-muted fw-semibold">Dependencies</h6>
2020-11-05 15:43:14 +01:00
<ul class="list-group list-group-flush">
2022-01-25 11:15:15 +01:00
@foreach (var dependency in x.Dependencies)
2020-11-05 15:43:14 +01:00
{
2023-01-19 10:08:34 +01:00
<li class="list-group-item p-2 d-inline-flex align-items-center gap-2">
2020-11-05 15:43:14 +01:00
@dependency
2023-12-13 12:36:23 +01:00
@if (!PluginManager.DependencyMet(dependency, installed))
2020-11-05 15:43:14 +01:00
{
2023-01-19 10:08:34 +01:00
<span title="Dependency not met." data-bs-toggle="tooltip" class="text-danger">
<vc:icon symbol="warning" />
</span>
2020-11-05 15:43:14 +01:00
}
</li>
}
</ul>
}
</div>
2020-10-22 10:58:22 +02:00
}
2023-01-16 20:12:51 +09:00
@if (plugin != null)
{
2023-01-19 10:08:34 +01:00
<h6 class="text-muted fw-semibold mt-4">Resources</h6>
2023-01-16 20:12:51 +09:00
<ul class="list-group list-group-flush list-unstyled">
2023-01-19 14:22:57 +09:00
@if (downloadInfo?.Source is not null)
2023-01-16 20:12:51 +09:00
{
<li>
<a href="@downloadInfo.Source" rel="noreferrer noopener" class="d-flex align-items-center" target="_blank">
2023-10-13 02:06:22 +02:00
<vc:icon symbol="social-github" />
2023-01-16 20:12:51 +09:00
<span style="margin-left:.4rem">Sources</span>
</a>
</li>
}
2023-01-19 14:22:57 +09:00
@if (!string.IsNullOrEmpty(downloadInfo?.Documentation))
2023-01-16 20:12:51 +09:00
{
<li>
<a href="@downloadInfo.Documentation" rel="noreferrer noopener" class="d-flex align-items-center gap-2" target="_blank">
<vc:icon symbol="docs" />
<span>Documentation</span>
</a>
</li>
}
else
{
<li>
<span rel="noreferrer noopener" class="d-flex align-items-center gap-2 text-danger" target="_blank">
<vc:icon symbol="docs" />
<span>No documentation</span>
</span>
</li>
}
</ul>
}
2020-11-05 15:43:14 +01:00
</div>
2020-10-22 10:58:22 +02:00
</div>
2020-11-05 15:43:14 +01:00
@{
var pendingAction = Model.Commands.Any(tuple => tuple.plugin.Equals(plugin.Identifier, StringComparison.InvariantCultureIgnoreCase));
2023-12-13 12:36:23 +01:00
var exclusivePendingAction = true;
2023-12-22 02:49:40 +01:00
}
<div class="card-footer border-0 pb-3 d-flex gap-2">
@if (pendingAction && updateAvailable)
{
var isUpdateAction = Model.Commands.Last(tuple => tuple.plugin.Equals(plugin.Identifier, StringComparison.InvariantCultureIgnoreCase)).command == "update";
if (isUpdateAction)
2020-10-22 10:58:22 +02:00
{
2023-12-22 02:49:40 +01:00
var version = PluginService.GetVersionOfPendingInstall(plugin.Identifier);
exclusivePendingAction = version == x.Version;
2020-10-22 10:58:22 +02:00
}
2023-12-22 02:49:40 +01:00
}
@if (pendingAction)
{
<form asp-action="CancelPluginCommands" asp-route-plugin="@plugin.Identifier">
<button type="submit" class="btn btn-outline-secondary">Cancel pending action</button>
</form>
}
@if (!pendingAction || !exclusivePendingAction)
{
@if (updateAvailable && x != null)
2020-10-21 14:02:20 +02:00
{
2023-12-22 02:49:40 +01:00
if (PluginManager.DependenciesMet(x.Dependencies, installed))
2020-10-22 10:58:22 +02:00
{
2023-12-22 02:49:40 +01:00
<form asp-action="InstallPlugin" asp-route-plugin="@plugin.Identifier" asp-route-version="@x.Version" asp-route-update="true" class="me-3">
<button type="submit" class="btn btn-secondary">Update</button>
</form>
2020-11-05 15:43:14 +01:00
}
else
{
2023-12-22 02:49:40 +01:00
<form asp-action="InstallPlugin" asp-route-plugin="@plugin.Identifier" asp-route-version="@x.Version" asp-route-update="true" class="me-3">
<button title="Schedule upgrade for when the dependencies have been met to ensure a smooth update" data-bs-toggle="tooltip" type="submit" class="btn btn-secondary">Schedule update</button>
2020-11-05 15:43:14 +01:00
</form>
}
2020-10-21 14:02:20 +02:00
}
2023-12-22 02:49:40 +01:00
@if (DependentOn(plugin.Identifier))
{
<button type="button" class="btn btn-outline-danger" data-bs-toggle="tooltip" title="This plugin cannot be uninstalled as it is depended on by other plugins.">Uninstall <span class="fa fa-exclamation"></span></button>
}
else
{
<form asp-action="UnInstallPlugin" asp-route-plugin="@plugin.Identifier">
<button type="submit" class="btn btn-outline-danger">Uninstall</button>
</form>
}
}
</div>
2020-10-22 10:58:22 +02:00
</div>
2020-10-21 14:02:20 +02:00
</div>
}
</div>
}
2021-04-08 15:32:42 +02:00
2020-10-21 14:02:20 +02:00
@if (availableAndNotInstalled.Any())
{
2022-01-17 17:19:27 -08:00
<h3 class="mb-4">Available Plugins</h3>
2020-10-22 10:58:22 +02:00
<div class="row mb-4">
2021-09-09 13:11:59 +02:00
@foreach (var plugin in availableAndNotInstalled)
2020-10-21 14:02:20 +02:00
{
2023-12-13 12:36:23 +01:00
var recommended = BTCPayServerOptions.RecommendedPlugins.Any(id => string.Equals(id, plugin.Identifier, StringComparison.InvariantCultureIgnoreCase));
2021-12-07 20:47:35 -08:00
var disabled = Model.Disabled?.Contains(plugin.Identifier) ?? false;
2023-01-16 20:12:51 +09:00
2022-01-27 03:56:46 +01:00
<div class="col col-12 col-md-6 col-lg-12 col-xl-6 col-xxl-4 mb-4">
2022-02-02 04:47:22 +01:00
<div class="card h-100" id="@plugin.Identifier">
2020-10-22 10:58:22 +02:00
<div class="card-body">
2023-01-19 10:08:34 +01:00
<div class="d-flex flex-wrap align-items-baseline justify-content-between gap-2 mb-3">
<h4 class="card-title mb-0" data-bs-toggle="tooltip" title="@plugin.Identifier">@plugin.Name</h4>
2023-01-16 20:12:51 +09:00
@if (!string.IsNullOrEmpty(plugin.Author))
{
2023-01-19 10:08:34 +01:00
<span class="text-muted text-nowrap">
2023-01-16 20:12:51 +09:00
by
<a href="@plugin.AuthorLink" rel="noreferrer noopener" target="_blank">
2023-01-19 10:08:34 +01:00
@plugin.Author
2023-01-16 20:12:51 +09:00
</a>
</span>
}
</div>
2022-11-22 19:06:23 +09:00
<h5 class="text-muted d-flex align-items-center mt-1 gap-2">
2020-11-06 08:06:37 +01:00
@plugin.Version
2023-01-16 20:12:51 +09:00
@if (disabled)
2021-12-07 20:47:35 -08:00
{
2022-11-22 19:06:23 +09:00
<div class="badge bg-light">Disabled</div>
2021-12-07 20:47:35 -08:00
}
else if (recommended)
2020-11-05 10:21:09 +01:00
{
2023-02-13 00:25:24 -08:00
<div class="badge bg-light text-nowrap" data-bs-toggle="tooltip" title="This plugin has been recommended to be installed by your deployment method.">Recommended <vc:icon symbol="info" /></div>
2020-11-05 10:21:09 +01:00
}
</h5>
2020-10-22 10:58:22 +02:00
<p class="card-text">@plugin.Description</p>
2020-11-05 15:43:14 +01:00
@if (plugin.Dependencies?.Any() is true)
{
2023-01-19 10:08:34 +01:00
<h6 class="text-muted fw-semibold">Dependencies</h6>
2020-11-05 15:43:14 +01:00
<ul class="list-group list-group-flush">
@foreach (var dependency in plugin.Dependencies)
{
2023-01-19 10:08:34 +01:00
<li class="list-group-item p-2 d-inline-flex align-items-center gap-2">
2020-11-05 15:43:14 +01:00
@dependency
2023-12-13 12:36:23 +01:00
@if (!PluginManager.DependencyMet(dependency, installed))
2020-11-05 15:43:14 +01:00
{
2023-01-19 10:08:34 +01:00
<span title="Dependency not met." data-bs-toggle="tooltip" class="text-danger">
<vc:icon symbol="warning" />
</span>
2020-11-05 15:43:14 +01:00
}
</li>
}
</ul>
2023-12-13 12:36:23 +01:00
if(!PluginManager.DependenciesMet(plugin.Dependencies, installed))
{
<div class="text-warning py-2 ">
Dependencies not met.
</div>
}
2020-11-05 15:43:14 +01:00
}
2023-01-16 20:12:51 +09:00
@if (plugin != null)
{
2023-01-19 10:08:34 +01:00
<h6 class="text-muted fw-semibold mt-4">Resources</h6>
2023-01-16 20:12:51 +09:00
<ul class="list-group list-group-flush list-unstyled">
@if (plugin.Source is not null)
{
<li>
<a href="@plugin.Source" rel="noreferrer noopener" class="d-flex align-items-center" target="_blank">
2023-10-13 02:06:22 +02:00
<vc:icon symbol="social-github" />
2023-01-16 20:12:51 +09:00
<span style="margin-left:.4rem">Sources</span>
</a>
</li>
}
@if (!string.IsNullOrEmpty(plugin.Documentation))
{
<li>
<a href="@plugin.Documentation" rel="noreferrer noopener" class="d-flex align-items-center gap-2" target="_blank">
<vc:icon symbol="docs" />
<span>Documentation</span>
</a>
</li>
}
else
{
<li>
<span rel="noreferrer noopener" class="d-flex align-items-center gap-2 text-danger" target="_blank">
<vc:icon symbol="docs" />
<span>No documentation</span>
</span>
</li>
}
</ul>
}
2020-10-22 10:58:22 +02:00
</div>
2023-12-13 12:36:23 +01:00
<div class="card-footer border-0 pb-3 d-flex gap-2">
2023-01-16 20:12:51 +09:00
@{
2023-12-13 12:36:23 +01:00
var pendingAction = Model.Commands.LastOrDefault(tuple => tuple.plugin.Equals(plugin.Identifier, StringComparison.InvariantCultureIgnoreCase));
var version = PluginService.GetVersionOfPendingInstall(plugin.Identifier);
var exclusivePendingAction = version == plugin.Version;
2023-01-16 20:12:51 +09:00
}
2023-12-13 12:36:23 +01:00
@if (!pendingAction.Equals(default))
2020-10-22 10:58:22 +02:00
{
2022-06-28 10:38:47 +02:00
<form asp-action="CancelPluginCommands" asp-route-plugin="@plugin.Identifier">
2023-12-13 12:36:23 +01:00
<button type="submit" class="btn btn-outline-secondary">Cancel pending @pendingAction.command</button>
2022-06-28 10:38:47 +02:00
</form>
2020-10-22 10:58:22 +02:00
}
2023-12-13 12:36:23 +01:00
@if (pendingAction.Equals(default) || !exclusivePendingAction)
2020-10-22 10:58:22 +02:00
{
2023-12-13 12:36:23 +01:00
if (PluginManager.DependenciesMet(plugin.Dependencies, installed))
{
@* Don't show the "Install" button if plugin has been disabled *@
@if (!disabled)
{
<form asp-action="InstallPlugin" asp-route-plugin="@plugin.Identifier" asp-route-version="@plugin.Version">
<button type="submit" class="btn btn-primary">Install</button>
</form>
}
}
else
2021-12-07 20:47:35 -08:00
{
2022-11-21 10:23:25 +09:00
<form asp-action="InstallPlugin" asp-route-plugin="@plugin.Identifier" asp-route-version="@plugin.Version">
2023-12-13 12:36:23 +01:00
<button title="Schedule install for when the dependencies have been met to ensure a smooth update" data-bs-toggle="tooltip" type="submit" class="btn btn-primary">Schedule install</button>
2021-12-07 20:47:35 -08:00
</form>
}
2020-10-22 10:58:22 +02:00
}
2023-12-20 10:56:21 +01:00
@if (disabled)
{
<form asp-action="UnInstallPlugin" asp-route-plugin="@plugin.Identifier">
<button type="submit" class="btn btn-sm btn-outline-danger">Uninstall</button>
</form>
}
2023-01-16 20:12:51 +09:00
</div>
2020-10-21 14:02:20 +02:00
</div>
</div>
}
</div>
}
2020-10-22 10:58:22 +02:00
<div class="mb-4">
2022-01-25 22:01:49 -08:00
<h3 class="mb-4">Upload Plugin</h3>
<button class="btn btn-secondary mb-4" type="button" data-bs-toggle="collapse" data-bs-target="#manual-upload">
Upload Plugin
2020-10-22 10:58:22 +02:00
</button>
<div class="row collapse" id="manual-upload">
2022-01-27 03:56:46 +01:00
<div class="col col-xl-6 mb-4">
2020-10-22 10:58:22 +02:00
<div class="card">
<div class="card-body">
<h4 class="card-title">Add plugin manually</h4>
<div class="alert alert-warning my-3">
2021-05-19 04:39:27 +02:00
<h6 class="me-1">This is an extremely dangerous operation!</h6>
2020-10-22 10:58:22 +02:00
Only upload plugins from trusted sources.
2020-10-21 14:02:20 +02:00
</div>
2020-10-22 10:58:22 +02:00
<form method="post" enctype="multipart/form-data" asp-action="UploadPlugin">
2021-05-19 04:39:27 +02:00
<input type="file" class="form-control mb-3" required name="files" accept=".btcpay" id="files">
2020-10-22 10:58:22 +02:00
<button class="btn btn-primary" type="submit">Upload</button>
</form>
2020-10-21 14:02:20 +02:00
</div>
2020-10-22 10:58:22 +02:00
</div>
2020-10-21 14:02:20 +02:00
</div>
</div>
</div>
2020-10-22 10:58:22 +02:00
2020-10-21 14:02:20 +02:00
@if (Model.Commands.Any())
{
2023-01-16 20:12:51 +09:00
<div class="mb-4">
<h3 class="mb-4">Pending Action</h3>
<button class="btn btn-secondary mb-4" type="button" data-bs-toggle="collapse" data-bs-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 p-2">
<div class="d-flex flex-wrap align-items-center justify-content-between">
<span class="my-2 me-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>
2020-10-22 10:58:22 +02:00
</div>
2020-10-21 14:02:20 +02:00
</div>
</div>
</div>
}