Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions PluginBuilder/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,8 @@ ORDER BY " + orderBy + @"
Contributors = pluginContributors,
RatingFilter = model.RatingFilter,
OwnerGithubUrl = ownerGithubUrl,
OwnerNostrUrl = ownerNostrUrl
OwnerNostrUrl = ownerNostrUrl,
EmbedMode = string.Equals(Request.Query["embed"], "1", StringComparison.Ordinal)
};
return View(vm);
}
Expand All @@ -518,7 +519,7 @@ ORDER BY " + orderBy + @"
[ValidateAntiForgeryToken]
public async Task<IActionResult> UpsertReview(
[ModelBinder(typeof(PluginSlugModelBinder))]
PluginSlug pluginSlug, int rating, string? body, string? pluginVersion)
PluginSlug pluginSlug, int rating, string? body, string? pluginVersion, string? embed = null)
{
if (rating is < 1 or > 5)
return BadRequest("Invalid rating");
Expand All @@ -533,7 +534,7 @@ public async Task<IActionResult> UpsertReview(
if (isOwner)
{
TempData[TempDataConstant.WarningMessage] = "You cannot review your own plugin.";
return RedirectToAction(nameof(GetPluginDetails), "Home", new { pluginSlug = pluginSlug.ToString() });
return RedirectToAction(nameof(GetPluginDetails), "Home", new { pluginSlug = pluginSlug.ToString(), embed = string.IsNullOrEmpty(embed) ? null : embed });
}

var reviewerAccountDetails = await conn.GetAccountDetailSettings(userId) ?? new AccountSettings();
Expand All @@ -558,7 +559,12 @@ public async Task<IActionResult> UpsertReview(
await conn.UpsertPluginReview(reviewViewModel);

var sort = Request.Query["sort"].ToString();
var url = Url.Action(nameof(GetPluginDetails), "Home", new { pluginSlug = pluginSlug.ToString(), sort = string.IsNullOrEmpty(sort) ? null : sort });
var url = Url.Action(nameof(GetPluginDetails), "Home", new
{
pluginSlug = pluginSlug.ToString(),
sort = string.IsNullOrEmpty(sort) ? null : sort,
embed = string.IsNullOrEmpty(embed) ? null : embed
});
return Redirect((url ?? "/") + "#reviews");
}

Expand Down Expand Up @@ -618,7 +624,8 @@ public async Task<IActionResult> VoteReview(
[ModelBinder(typeof(PluginSlugModelBinder))]
PluginSlug pluginSlug,
long id,
bool isHelpful)
bool isHelpful,
string? embed = null)
{
var userId = userManager.GetUserId(User);
if (string.IsNullOrEmpty(userId))
Expand All @@ -635,7 +642,11 @@ public async Task<IActionResult> VoteReview(
if (!ok)
TempData[TempDataConstant.WarningMessage] = "Error while updating review helpful vote";

var url = Url.Action(nameof(GetPluginDetails), new { pluginSlug = pluginSlug.ToString() });
var url = Url.Action(nameof(GetPluginDetails), new
{
pluginSlug = pluginSlug.ToString(),
embed = string.IsNullOrEmpty(embed) ? null : embed
});
return Redirect((url ?? "/") + "#reviews");
}

Expand All @@ -644,7 +655,8 @@ public async Task<IActionResult> VoteReview(
public async Task<IActionResult> DeleteReview(
[ModelBinder(typeof(PluginSlugModelBinder))]
PluginSlug pluginSlug,
long id)
long id,
string? embed = null)
{
var userId = userManager.GetUserId(User);
if (string.IsNullOrEmpty(userId))
Expand All @@ -659,7 +671,11 @@ public async Task<IActionResult> DeleteReview(
if (!ok)
TempData[TempDataConstant.WarningMessage] = "Error while deleting review";

var url = Url.Action(nameof(GetPluginDetails), new { pluginSlug = pluginSlug.ToString() });
var url = Url.Action(nameof(GetPluginDetails), new
{
pluginSlug = pluginSlug.ToString(),
embed = string.IsNullOrEmpty(embed) ? null : embed
});
return Redirect((url ?? "/") + "#reviews");
}

Expand Down
1 change: 1 addition & 0 deletions PluginBuilder/ViewModels/Home/PluginDetailsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public PluginDetailsViewModel()

public string? OwnerGithubUrl { get; set; }
public string? OwnerNostrUrl { get; set; }
public bool EmbedMode { get; set; }
}

public class Review
Expand Down
55 changes: 42 additions & 13 deletions PluginBuilder/Views/Home/AllPlugins.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
const string title = "BTCPay Server Plugin Directory";
const string desc = "Extend and customize your BTCPay Server with community and official plugins.";
ViewData["Title"] = title;
var embedMode = Context.Request.Query["embed"] == "1";
var embedRoute = embedMode ? "1" : null;

var currentSearch = Context.Request.Query["searchPluginName"].ToString();
var currentSort = (string?)Context.Request.Query["sort"] ?? "smart";
Expand Down Expand Up @@ -35,17 +37,24 @@

<partial name="_PublicHeader" />

<div class="container">
<div class="row mb-4">
<div class="col-12 text-center">
<h3 class="display-5 fw-bold">BTCPay Server Plugin Directory</h3>
<p class="text-muted">Extend and customize your BTCPay Server with community and official plugins.</p>
<div class="@(embedMode ? "container-fluid px-0" : "container")" data-embed-page="list">
@if (!embedMode)
{
<div class="row mb-4">
<div class="col-12 text-center">
<h3 class="display-5 fw-bold">BTCPay Server Plugin Directory</h3>
<p class="text-muted">Extend and customize your BTCPay Server with community and official plugins.</p>
</div>
</div>
</div>
<div class="row mb-4">
<div>
}
<div class="@(embedMode ? "mb-4" : "row mb-4")">
<div class="@(embedMode ? "" : "col-12")">
<form asp-action="AllPlugins" method="get" class="d-flex flex-wrap flex-sm-nowrap align-items-center gap-3">
<input type="hidden" name="sort" value="@currentSort" />
@if (embedMode)
{
<input type="hidden" name="embed" value="1" />
}

<input type="text"
name="searchPluginName"
Expand All @@ -66,24 +75,28 @@
<a class="dropdown-item @(currentSort == "smart" ? "active" : "")"
asp-action="AllPlugins"
asp-route-searchPluginName="@currentSearch"
asp-route-embed="@embedRoute"
asp-route-sort="smart">
Relevance
</a>
<a class="dropdown-item @(currentSort == "rating" ? "active" : "")"
asp-action="AllPlugins"
asp-route-searchPluginName="@currentSearch"
asp-route-embed="@embedRoute"
asp-route-sort="rating">
Highest rated
</a>
<a class="dropdown-item @(currentSort == "recent" ? "active" : "")"
asp-action="AllPlugins"
asp-route-searchPluginName="@currentSearch"
asp-route-embed="@embedRoute"
asp-route-sort="recent">
Most recent
</a>
<a class="dropdown-item @(currentSort == "alpha" ? "active" : "")"
asp-action="AllPlugins"
asp-route-searchPluginName="@currentSearch"
asp-route-embed="@embedRoute"
asp-route-sort="alpha">
Alphabetical
</a>
Expand All @@ -92,14 +105,16 @@
</form>
</div>
</div>
<div class="row">
<div class="@(embedMode ? "overflow-hidden" : "")">
<div class="@(embedMode ? "row row-cols-1 row-cols-md-2 g-4 mb-0" : "row")">
@if (Model != null && Model.Any())
{
@foreach (var plugin in Model)
{
var owner = plugin.GetOwnerName(GitHostingProviderFactory);
var ownerProfileUrl = plugin.GetOwnerProfileUrl(GitHostingProviderFactory);
<div class="col-md-6 mb-4">
var pluginIdentifier = plugin.ManifestInfo?["Identifier"]?.ToString();
<div class="@(embedMode ? "col" : "col-md-6 mb-4")" data-plugin-card data-plugin-identifier="@pluginIdentifier">
<div class="card h-100 plugin-card" data-type="community">
<div class="card-body">
@if (plugin.IsUnlisted)
Expand All @@ -116,6 +131,9 @@
<div>
<h3 style="margin-top: 0; margin-bottom: 5px;">
<a asp-action="GetPluginDetails"
asp-route-embed="@embedRoute"
data-plugin-slug="@plugin.ProjectSlug"
data-plugin-identifier="@plugin.ManifestInfo?["Identifier"]?.ToString()"
asp-route-pluginSlug="@plugin.ProjectSlug">@plugin.PluginTitle</a>
</h3>

Expand Down Expand Up @@ -159,10 +177,21 @@
{
<div class="col-12 text-center py-5">
<h4>No plugins available yet</h4>
<p class="text-muted">Check back later, or
<a asp-action="Login" asp-controller="Home" class="text-success text-decoration-none">login to upload one</a>
</p>
@if (!embedMode)
{
<p class="text-muted">Check back later, or
<a asp-action="Login" asp-controller="Home" class="text-success text-decoration-none">login to upload one</a>
</p>
}
</div>
}

@if (embedMode && Model != null && Model.Any())
{
<div class="col-12 text-center py-5" data-plugin-directory-empty-state hidden>
<h4>All compatible plugins from the public directory are already installed or disabled on this server.</h4>
</div>
}
</div>
</div>
</div>
Loading
Loading