Refactor access to the ViewModel of the MainLayout (#6970)
What changed, and why it matters
This is a large internal refactoring of how BTCPay Server's web UI tracks which navigation menu item is active. It replaces scattered, string-based helpers with a single LayoutModel and a new Razor tag helper. There is no obvious security vulnerability in the change; it is primarily code cleanup and test updates to match the new HTML IDs.
No security action required. Treat as routine UI refactoring. If deploying, verify that navigation highlighting and automated UI tests pass due to changed element IDs.
Security signals we found
No security-relevant code paths modified
Refactoring only: navigation active-state helpers
No changes to authorization policies or permission checks
No input handling or output encoding changes
No CVE or advisory references present in commit or supplied references
Evidence from the diff
The commit introduces LayoutModel and LayoutMenuItemTagHelper to centralize navigation state (active page/category/title) in ViewData. It obsoletes older helpers like ActivePageClass/IsCategoryActive and updates ~150 Razor views and test files to use layout-menu-item attributes and SetLayoutModel calls. The diff also includes minor test harness tweaks (Playwright args, selector renames) and a couple of small subscription-test logic adjustments. No authentication, authorization, input validation, or cryptographic logic is changed.
Changed components
BTCPayServer.Abstractions/Extensions/ViewsRazor.csBTCPayServer.Abstractions/Models/LayoutModel.csBTCPayServer.Abstractions/TagHelpers/LayoutMenuItemTagHelper.csBTCPayServer/Components/MainNav/Default.cshtmlBTCPayServer/Components/StoreSelector/Default.cshtmlVarious Razor views and test filesInspect captured patch +554 / −442
diff --git a/BTCPayServer.Abstractions/Extensions/ViewsRazor.cs b/BTCPayServer.Abstractions/Extensions/ViewsRazor.cs
index 61813f9..68fc291 100644
--- a/BTCPayServer.Abstractions/Extensions/ViewsRazor.cs
+++ b/BTCPayServer.Abstractions/Extensions/ViewsRazor.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using BTCPayServer.Abstractions.Models;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
@@ -35,16 +36,28 @@ namespace BTCPayServer.Abstractions.Extensions
SetActivePage(viewData, activePage.ToString(), activePage.GetType().ToString(), title, activeId);
}
- public static void SetActivePage(this ViewDataDictionary viewData, string activePage, string category, string title = null, string activeId = null)
+ public static void SetTitle(this ViewDataDictionary viewData, string title) => viewData["Title"] = title;
+ public static string GetTitle(this ViewDataDictionary viewData) => viewData["Title"]?.ToString();
+
+ public static void SetLayoutModel(this ViewDataDictionary viewData, LayoutModel model)
{
// Page Title
- viewData["Title"] = title ?? activePage;
+ viewData["Title"] = model.Title ?? model.MenuItemId;
// Navigation
- viewData[ACTIVE_PAGE_KEY] = activePage;
- viewData[ACTIVE_ID_KEY] = activeId;
- SetActiveCategory(viewData, category);
+ viewData[ACTIVE_PAGE_KEY] = model.MenuItemId;
+ viewData[ACTIVE_ID_KEY] = model.SubMenuItemId;
+ SetActiveCategory(viewData, model.ActiveCategory);
}
+ public static bool IsCategory(this ViewDataDictionary viewData, string category) =>
+ viewData.TryGetValue(ACTIVE_CATEGORY_KEY, out var k) && category == k as string;
+
+ public static bool IsCategory(this ViewDataDictionary viewData, WellKnownCategories category) =>
+ IsCategory(viewData, LayoutModel.Map(category));
+
+ public static void SetActivePage(this ViewDataDictionary viewData, string activePage, string category, string title = null, string activeId = null)
+ => viewData.SetLayoutModel(new(activePage, title){ SubMenuItemId = activeId, ActiveCategory = category } );
+
public static void SetActiveCategory<T>(this ViewDataDictionary viewData, T activeCategory)
{
SetActiveCategory(viewData, activeCategory.ToString());
@@ -55,6 +68,7 @@ namespace BTCPayServer.Abstractions.Extensions
viewData[ACTIVE_CATEGORY_KEY] = activeCategory;
}
+ [Obsolete("Use IsCategory instead")]
public static bool IsCategoryActive(this ViewDataDictionary viewData, string category, object id = null)
{
if (!viewData.ContainsKey(ACTIVE_CATEGORY_KEY)) return false;
@@ -65,6 +79,7 @@ namespace BTCPayServer.Abstractions.Extensions
return categoryMatch && idMatch;
}
+ [Obsolete("Use IsCategory instead")]
public static bool IsCategoryActive<T>(this ViewDataDictionary viewData, T category, object id = null)
{
return IsCategoryActive(viewData, category.ToString(), id);
@@ -81,7 +96,7 @@ namespace BTCPayServer.Abstractions.Extensions
var idMatch = id == null || activeId == null || id.Equals(activeId);
return categoryAndPageMatch && idMatch;
}
-
+
public static bool IsPageActive<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null)
where T : IConvertible
{
@@ -98,17 +113,20 @@ namespace BTCPayServer.Abstractions.Extensions
return IsCategoryActive(viewData, category, id) ? ACTIVE_CLASS : null;
}
+ [Obsolete("Use the tagHelper layout-menu-item instead")]
public static string ActivePageClass<T>(this ViewDataDictionary viewData, T page, object id = null)
where T : IConvertible
{
return ActivePageClass(viewData, page.ToString(), page.GetType().ToString(), id);
}
+ [Obsolete("Use the tagHelper layout-menu-item instead")]
public static string ActivePageClass(this ViewDataDictionary viewData, string page, string category, object id = null)
{
return IsPageActive(viewData, page, category, id) ? ACTIVE_CLASS : null;
}
+ [Obsolete("Use the tagHelper layout-menu-item instead")]
public static string ActivePageClass<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null) where T : IConvertible
{
return IsPageActive(viewData, pages, id) ? ACTIVE_CLASS : null;
diff --git a/BTCPayServer.Abstractions/Models/LayoutModel.cs b/BTCPayServer.Abstractions/Models/LayoutModel.cs
new file mode 100644
index 0000000..7002f35
--- /dev/null
+++ b/BTCPayServer.Abstractions/Models/LayoutModel.cs
@@ -0,0 +1,36 @@
+#nullable enable
+using NBitcoin;
+
+namespace BTCPayServer.Abstractions.Models;
+
+public record WellKnownCategories(string CategoryId)
+{
+ public static readonly WellKnownCategories Server = new("BTCPayServer.Views.Server.ServerNavPages");
+ public static readonly WellKnownCategories Store = new("BTCPayServer.Views.Stores.StoreNavPages");
+ public static readonly WellKnownCategories Wallet = new("BTCPayServer.Views.Wallets.WalletsNavPages");
+ public static WellKnownCategories ForWallet(string cryptoCode) => new(
+ $"BTCPayServer.Views.Wallets.WalletsNavPages.{cryptoCode.ToUpperInvariant()}");
+ public static WellKnownCategories ForLightning(string cryptoCode) => new(
+ $"LightningPages.{cryptoCode.ToUpperInvariant()}");
+}
+
+public class LayoutModel(string menuItemId, string? title = null)
+{
+ public static string Map(WellKnownCategories c) => c.CategoryId;
+
+ public LayoutModel SetCategory(WellKnownCategories category)
+ {
+ ActiveCategory = Map(category);
+ return this;
+ }
+ public LayoutModel SetCategory(string category)
+ {
+ ActiveCategory = category;
+ return this;
+ }
+
+ public string? ActiveCategory { get; set; }
+ public string MenuItemId { get; set; } = menuItemId;
+ public string? Title { get; set; } = title;
+ public string? SubMenuItemId { get; set; }
+}
diff --git a/BTCPayServer.Abstractions/TagHelpers/LayoutMenuItemTagHelper.cs b/BTCPayServer.Abstractions/TagHelpers/LayoutMenuItemTagHelper.cs
new file mode 100644
index 0000000..c225c2e
--- /dev/null
+++ b/BTCPayServer.Abstractions/TagHelpers/LayoutMenuItemTagHelper.cs
@@ -0,0 +1,22 @@
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.AspNetCore.Razor.TagHelpers;
+
+namespace BTCPayServer.Abstractions.TagHelpers;
+
+[HtmlTargetElement(Attributes = "[layout-menu-item]")]
+public class LayoutMenuItemTagHelper : TagHelper
+{
+ private const string ActivePageKey = "ActivePage";
+ private const string ActiveClass = "active";
+ [ViewContext]
+ public ViewContext ViewContext { get; set; }
+ public string LayoutMenuItem { get; set; }
+ public override void Process(TagHelperContext context, TagHelperOutput output)
+ {
+ output.Attributes.Add("id", $"menu-item-{LayoutMenuItem}");
+ var viewData = ViewContext.ViewData;
+ var match = viewData.ContainsKey(ActivePageKey) && viewData[ActivePageKey]?.ToString() == LayoutMenuItem;
+ output.Attributes.Add("class", $"menu-item nav-link {(match ? ActiveClass : "")}");
+ }
+}
diff --git a/BTCPayServer.Tests/FeatureTests/MultisigTests.cs b/BTCPayServer.Tests/FeatureTests/MultisigTests.cs
index a70ce3a..6812874 100644
--- a/BTCPayServer.Tests/FeatureTests/MultisigTests.cs
+++ b/BTCPayServer.Tests/FeatureTests/MultisigTests.cs
@@ -91,7 +91,7 @@ public class MultisigTests : UnitTestBase
s.TestLogs.LogInformation($"Multisig wallet setup: {multisigDerivationScheme}");
// fetch address from receive page
- await s.Page.ClickAsync("#WalletNav-Receive");
+ await s.GoToWallet(navPages: WalletsNavPages.Receive);
var addressElement = s.Page.Locator("#Address");
await addressElement.ClickAsync();
@@ -101,7 +101,7 @@ public class MultisigTests : UnitTestBase
await s.Page.ClickAsync("#CancelWizard");
// we are creating a pending transaction
- await s.Page.ClickAsync("#WalletNav-Send");
+ await s.GoToWallet(navPages: WalletsNavPages.Send);
await s.Page.FillAsync("#Outputs_0__DestinationAddress", address);
var amount = "0.1";
await s.Page.FillAsync("#Outputs_0__Amount", amount);
@@ -127,7 +127,7 @@ public class MultisigTests : UnitTestBase
Assert.False(await s.Page.Locator("//a[text()='Broadcast']").IsVisibleAsync());
// Abort pending transaction flow
- await s.Page.ClickAsync("#WalletNav-Send");
+ await s.GoToWallet(navPages: WalletsNavPages.Send);
await s.Page.FillAsync("#Outputs_0__DestinationAddress", address);
await s.Page.FillAsync("#Outputs_0__Amount", "0.2");
await s.Page.ClickAsync("#CreatePendingTransaction");
diff --git a/BTCPayServer.Tests/POSTests.cs b/BTCPayServer.Tests/POSTests.cs
index 67f7e1b..a87f3e9 100644
--- a/BTCPayServer.Tests/POSTests.cs
+++ b/BTCPayServer.Tests/POSTests.cs
@@ -148,7 +148,7 @@ fruit tea:
}
[Fact]
- [Trait("Integration", "Integration")]
+ [Trait("Playwright", "Playwright")]
public async Task CanExportInvoicesWithMetadata()
{
await using var s = CreatePlaywrightTester();
diff --git a/BTCPayServer.Tests/PSBTTests.cs b/BTCPayServer.Tests/PSBTTests.cs
index 888dbf7..8284210 100644
--- a/BTCPayServer.Tests/PSBTTests.cs
+++ b/BTCPayServer.Tests/PSBTTests.cs
@@ -47,7 +47,7 @@ namespace BTCPayServer.Tests
var psbt = await ExtractPSBT(s);
await s.GoToStore(hot.storeId);
- await s.GoToWallet(navPages: Views.Wallets.WalletsNavPages.PSBT);
+ await s.GoToWallet(s.WalletId, navPages: Views.Wallets.WalletsNavPages.PSBT);
await s.Page.Locator("[name='PSBT']").FillAsync(psbt);
await s.Page.ClickAsync("#Decode");
await s.Page.ClickAsync("#SignTransaction");
@@ -72,7 +72,7 @@ namespace BTCPayServer.Tests
var skeletonPSBT = psbtParsed;
await s.GoToStore(cold.storeId);
- await s.GoToWallet(navPages: Views.Wallets.WalletsNavPages.PSBT);
+ await s.GoToWallet(s.WalletId, navPages: Views.Wallets.WalletsNavPages.PSBT);
await s.Page.Locator("[name='PSBT']").FillAsync(skeletonPSBT.ToBase64());
await s.Page.ClickAsync("#Decode");
await s.Page.ClickAsync("#SignTransaction");
@@ -96,7 +96,7 @@ namespace BTCPayServer.Tests
// Let's if we can combine the updated psbt (which has hdkeys, but no sig)
// with the signed psbt (which has sig, but no hdkeys)
- await s.GoToWallet(navPages: Views.Wallets.WalletsNavPages.PSBT);
+ await s.GoToWallet(s.WalletId, navPages: Views.Wallets.WalletsNavPages.PSBT);
await s.Page.Locator("[name='PSBT']").FillAsync(psbtParsed.ToBase64());
await s.Page.ClickAsync("#Decode");
await s.Page.ClickAsync("#PSBTOptionsAdvancedHeader");
diff --git a/BTCPayServer.Tests/PlaywrightTester.cs b/BTCPayServer.Tests/PlaywrightTester.cs
index bb027af..997c830 100644
--- a/BTCPayServer.Tests/PlaywrightTester.cs
+++ b/BTCPayServer.Tests/PlaywrightTester.cs
@@ -7,21 +7,17 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
-using BTCPayServer.Blazor.VaultBridge.Elements;
using BTCPayServer.Client.Models;
-using BTCPayServer.Data;
using BTCPayServer.Lightning;
using BTCPayServer.Lightning.CLightning;
using BTCPayServer.Views.Manage;
using BTCPayServer.Views.Server;
using BTCPayServer.Views.Stores;
using BTCPayServer.Views.Wallets;
-using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Playwright;
using NBitcoin;
using NBitcoin.RPC;
-using OpenQA.Selenium;
using Xunit;
namespace BTCPayServer.Tests
@@ -52,7 +48,8 @@ namespace BTCPayServer.Tests
Browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
Headless = Server.PayTester.InContainer,
- SlowMo = 0 // 50 if you want to slow down
+ SlowMo = 0, // 50 if you want to slow down
+ Args = ["--disable-frame-rate-limit"] // Fix slowness on linux (https://github.com/microsoft/playwright/issues/34625#issuecomment-2822015672)
});
var context = await Browser.NewContextAsync();
Page = await context.NewPageAsync();
@@ -67,7 +64,7 @@ namespace BTCPayServer.Tests
{
if (storeId is null)
{
- await Page.Locator("#StoreNav-Invoices").ClickAsync();
+ await Page.Locator("#menu-item-Invoices").ClickAsync();
}
else
{
@@ -117,21 +114,51 @@ namespace BTCPayServer.Tests
await GoToUrl($"/i/{invoiceId}");
}
- public async Task GoToWallet(WalletId walletId = null, WalletsNavPages navPages = WalletsNavPages.Send)
+ public async Task GoToWallet(WalletId walletId = null, WalletsNavPages? navPages = null)
{
- walletId ??= WalletId;
- await GoToUrl($"wallets/{walletId}");
- if (navPages == WalletsNavPages.PSBT)
+ var walletPage = GetWalletIdFromUrl();
+ // If null, we try to go to the wallet of the current page
+ if (walletId is null)
+ {
+ if (walletPage is not null)
+ walletId = WalletId.Parse(walletPage);
+ walletId ??= WalletId;
+ if (walletId is not null && walletId.ToString() != walletPage)
+ await GoToUrl($"wallets/{walletId}");
+ }
+ // If not, we browse to the wallet before going to subpages
+ else
{
- await Page.Locator("#WalletNav-Send").ClickAsync();
+ await GoToUrl($"wallets/{walletId}");
+ }
+ var cryptoCode = walletId?.CryptoCode ?? "BTC";
+ if (navPages is null)
+ {
+ await Page.GetByTestId("Wallet-" + cryptoCode).Locator("a").ClickAsync();
+ }
+ else if (navPages == WalletsNavPages.PSBT)
+ {
+ await Page.Locator($"#menu-item-Send-{cryptoCode}").ClickAsync();
await Page.Locator("#PSBT").ClickAsync();
}
- else if (navPages != WalletsNavPages.Transactions)
+ else
{
- await Page.Locator($"#WalletNav-{navPages}").ClickAsync();
+ await Page.Locator($"#menu-item-{navPages}-{cryptoCode}").ClickAsync();
}
}
+ private string GetWalletIdFromUrl()
+ {
+ var m = Regex.Match(Page.Url, "wallets/([^/]+)");
+ if (m.Success)
+ return m.Groups[1].Value;
+
+ m = Regex.Match(Page.Url, "([^/]+)/onchain/([^/]+)");
+ if (m.Success)
+ return new WalletId(m.Groups[1].Value, m.Groups[2].Value).ToString();
+ return null;
+ }
+
public async Task<ILocator> FindAlertMessage(StatusMessageModel.StatusSeverity severity = StatusMessageModel.StatusSeverity.Success, string partialText = null)
{
var locator = await FindAlertMessage(new[] { severity });
@@ -219,7 +246,7 @@ namespace BTCPayServer.Tests
Assert.Equal("Recommendation (Kraken)", selectedOption?.Trim());
await Page.Locator("#PreferredExchange").SelectOptionAsync(new SelectOptionValue { Label = preferredExchange });
await Page.ClickAsync("#Create");
- await Page.ClickAsync("#StoreNav-General");
+ await GoToStore(StoreNavPages.General);
var storeId = await Page.InputValueAsync("#Id");
if (keepId)
StoreId = storeId;
@@ -232,7 +259,8 @@ namespace BTCPayServer.Tests
var isImport = !string.IsNullOrEmpty(seed);
await GoToWalletSettings(cryptoCode);
// Replace previous wallet case
- if (await Page.Locator("#ActionsDropdownToggle").IsVisibleAsync())
+ var isSettings = Page.Url.EndsWith("/settings");
+ if (isSettings)
{
TestLogs.LogInformation($"Replacing the wallet");
await Page.ClickAsync("#ActionsDropdownToggle");
@@ -296,7 +324,7 @@ namespace BTCPayServer.Tests
}
public async Task Logout()
{
- await Page.Locator("#Nav-Account").ClickAsync();
+ await Page.Locator("#menu-item-Account").ClickAsync();
await Page.Locator("#Nav-Logout").ClickAsync();
}
@@ -330,24 +358,24 @@ namespace BTCPayServer.Tests
public async Task GoToProfile(ManageNavPages navPages = ManageNavPages.Index)
{
- await Page.ClickAsync("#Nav-Account");
+ await Page.ClickAsync("#menu-item-Account");
await Page.ClickAsync("#Nav-ManageAccount");
if (navPages != ManageNavPages.Index)
{
- await Page.ClickAsync($"#SectionNav-{navPages.ToString()}");
+ await Page.ClickAsync($"#menu-item-{navPages.ToString()}");
}
}
public async Task GoToServer(ServerNavPages navPages = ServerNavPages.Policies)
{
- await Page.ClickAsync("#Nav-ServerSettings");
+ await Page.ClickAsync("#menu-item-Policies");
if (navPages != ServerNavPages.Policies)
{
- await Page.ClickAsync($"#SectionNav-{navPages}");
+ await Page.ClickAsync($"#menu-item-{navPages}");
}
}
- public async Task ClickOnAllSectionLinks(string sectionSelector = "#SectionNav")
+ public async Task ClickOnAllSectionLinks(string sectionSelector = "#menu-item")
{
List<string> links = [];
foreach (var locator in await Page.Locator($"{sectionSelector} .nav-link").AllAsync())
@@ -441,11 +469,11 @@ namespace BTCPayServer.Tests
public async Task GoToLightningSettings(string cryptoCode = "BTC")
{
- await Page.ClickAsync($"#StoreNav-Lightning{cryptoCode}");
+ await Page.GetByTestId("Lightning-" + cryptoCode).ClickAsync();
// if Lightning is already set up we need to navigate to the settings
- if ((await Page.ContentAsync()).Contains("id=\"StoreNav-LightningSettings\""))
+ if ((await Page.ContentAsync()).Contains($"id=\"menu-item-LightningSettings-{cryptoCode}\""))
{
- await Page.ClickAsync("#StoreNav-LightningSettings");
+ await Page.ClickAsync($"#menu-item-LightningSettings-{cryptoCode}");
}
}
@@ -456,8 +484,8 @@ namespace BTCPayServer.Tests
public async Task GoToWalletSettings(string cryptoCode = "BTC")
{
- await Page.ClickAsync($"#StoreNav-Wallet{cryptoCode}");
- var walletNavSettings = Page.Locator("#WalletNav-Settings");
+ await Page.GetByTestId("Wallet-" + cryptoCode).Locator("a").ClickAsync();
+ var walletNavSettings = Page.Locator($"#menu-item-Settings-{cryptoCode}");
if (await walletNavSettings.CountAsync() > 0)
await walletNavSettings.ClickAsync();
}
@@ -476,9 +504,9 @@ namespace BTCPayServer.Tests
if (WalletId != null)
WalletId = new WalletId(storeId, WalletId.CryptoCode);
if (storeNavPage != StoreNavPages.General)
- await Page.Locator($"#StoreNav-{StoreNavPages.General}").ClickAsync();
+ await Page.Locator($"#menu-item-{StoreNavPages.General}").ClickAsync();
}
- await Page.Locator($"#StoreNav-{storeNavPage}").ClickAsync();
+ await Page.Locator($"#menu-item-{storeNavPage}").ClickAsync();
}
public async Task ClickCancel()
{
@@ -561,7 +589,7 @@ namespace BTCPayServer.Tests
{
if (string.IsNullOrEmpty(name))
name = $"{type}-{Guid.NewGuid().ToString()[..14]}";
- await Page.Locator($"#StoreNav-Create{type}").ClickAsync();
+ await Page.Locator($"#menu-item-CreateApp-{type}").ClickAsync();
await Page.Locator("[name='AppName']").FillAsync(name);
await ClickPagePrimary();
await FindAlertMessage(partialText: "App successfully created");
diff --git a/BTCPayServer.Tests/PlaywrightTests.cs b/BTCPayServer.Tests/PlaywrightTests.cs
index 8e95b4c..a0f52d5 100644
--- a/BTCPayServer.Tests/PlaywrightTests.cs
+++ b/BTCPayServer.Tests/PlaywrightTests.cs
@@ -71,10 +71,7 @@ namespace BTCPayServer.Tests
await s.InitializeBTCPayServer();
// Point Of Sale
var appName = $"PoS-{Guid.NewGuid().ToString()[..21]}";
- await s.Page.ClickAsync("#StoreNav-CreatePointOfSale");
- await s.Page.FillAsync("#AppName", appName);
- await s.ClickPagePrimary();
- await s.FindAlertMessage(partialText: "App successfully created");
+ await s.CreateApp("PointOfSale", appName);
await s.Page.SelectOptionAsync("#FormId", "Email");
await s.ClickPagePrimary();
await s.FindAlertMessage(partialText: "App updated");
@@ -94,7 +91,7 @@ namespace BTCPayServer.Tests
await s.GoToUrl($"/invoices/{invoiceId}/");
Assert.Contains("aa@aa.com", await s.Page.ContentAsync());
// Payment Request
- await s.Page.ClickAsync("#StoreNav-PaymentRequests");
+ await s.Page.ClickAsync("#menu-item-PaymentRequests");
await s.ClickPagePrimary();
await s.Page.FillAsync("#Title", "Pay123");
await s.Page.FillAsync("#Amount", "700");
@@ -142,9 +139,11 @@ namespace BTCPayServer.Tests
await s.GoToHome();
await s.GoToStore();
await s.GoToStore(StoreNavPages.Forms);
+ await s.Page.WaitForLoadStateAsync();
Assert.Contains("Custom Form 1", await s.Page.ContentAsync());
await s.Page.GetByRole(AriaRole.Link, new() { Name = "Remove" }).ClickAsync();
await s.ConfirmDeleteModal();
+ await s.Page.WaitForLoadStateAsync();
Assert.DoesNotContain("Custom Form 1", await s.Page.ContentAsync());
await s.ClickPagePrimary();
await s.Page.FillAsync("[name='Name']", "Custom Form 2");
@@ -169,7 +168,7 @@ namespace BTCPayServer.Tests
await s.ClickPagePrimary();
await s.GoToStore(StoreNavPages.Forms);
Assert.Contains("Custom Form 3", await s.Page.ContentAsync());
- await s.Page.ClickAsync("#StoreNav-PaymentRequests");
+ await s.Page.ClickAsync("#menu-item-PaymentRequests");
await s.ClickPagePrimary();
var selectOptions = await s.Page.Locator("#FormId >> option").CountAsync();
Assert.Equal(4, selectOptions);
@@ -584,7 +583,7 @@ namespace BTCPayServer.Tests
Assert.Equal("Can Use Store?" ,await s.Page.InputValueAsync("#Name"));
await s.Page.FillAsync("#Name", "Just changed it!");
await s.Page.ClickAsync("#Create");
- await s.Page.ClickAsync("#StoreNav-General");
+ await s.GoToStore();
var newStoreId = await s.Page.InputValueAsync("#Id");
Assert.NotEqual(newStoreId, s.StoreId);
@@ -875,8 +874,7 @@ namespace BTCPayServer.Tests
await s.GenerateWallet(cryptoCode, "", true);
//let's test quickly the wallet send page
- await s.Page.ClickAsync($"#StoreNav-Wallet{cryptoCode}");
- await s.Page.ClickAsync("#WalletNav-Send");
+ await s.GoToWallet(navPages: WalletsNavPages.Send);
//you cannot use the Sign with NBX option without saving private keys when generating the wallet.
Assert.DoesNotContain("nbx-seed", await s.Page.ContentAsync());
Assert.Equal(0, await s.Page.Locator("#GoBack").CountAsync());
@@ -884,7 +882,7 @@ namespace BTCPayServer.Tests
await s.Page.WaitForSelectorAsync("text=Destination Address field is required");
Assert.Equal(0, await s.Page.Locator("#GoBack").CountAsync());
await s.Page.ClickAsync("#CancelWizard");
- await s.Page.ClickAsync("#WalletNav-Receive");
+ await s.GoToWallet(navPages: WalletsNavPages.Receive);
//generate a receiving address
await s.Page.WaitForSelectorAsync("#address-tab .qr-container");
@@ -1038,8 +1036,7 @@ namespace BTCPayServer.Tests
// Assert that the added label is associated with the transaction
await wt.AssertHasLabels("tx-label");
- await s.Page.ClickAsync($"#StoreNav-Wallet{cryptoCode}");
- await s.Page.ClickAsync("#WalletNav-Send");
+ await s.GoToWallet(navPages: WalletsNavPages.Send);
var jack = new Key().PubKey.Hash.GetAddress(Network.RegTest);
await ws.FillAddress(jack);
@@ -1090,7 +1087,7 @@ namespace BTCPayServer.Tests
Assert.Equal(settingsUri.ToString(), s.Page.Url);
// Once more, test the cancel link of the wallet send page leads back to the previous page
- await s.Page.ClickAsync("#WalletNav-Send");
+ await s.GoToWallet(navPages: WalletsNavPages.Send);
cancelUrl = await s.Page.Locator("#CancelWizard").GetAttributeAsync("href");
Assert.EndsWith(settingsUri.AbsolutePath, cancelUrl);
// no previous page in the wizard, hence no back button
@@ -1230,7 +1227,7 @@ namespace BTCPayServer.Tests
// Create a payment request
await s.GoToStore();
- await s.Page.ClickAsync("#StoreNav-PaymentRequests");
+ await s.Page.ClickAsync("#menu-item-PaymentRequests");
await s.ClickPagePrimary();
await s.Page.FillAsync("#Title", "Test Payment Request");
await s.Page.FillAsync("#Amount", "0.1");
@@ -1272,7 +1269,7 @@ namespace BTCPayServer.Tests
await s.Page.WaitForLoadStateAsync();
await s.GoToStore();
- await s.Page.ClickAsync("#StoreNav-PaymentRequests");
+ await s.Page.ClickAsync("#menu-item-PaymentRequests");
await s.Page.WaitForLoadStateAsync();
var opening2 = s.Page.Context.WaitForPageAsync();
@@ -1288,7 +1285,7 @@ namespace BTCPayServer.Tests
}
await s.GoToStore();
- await s.Page.ClickAsync("#StoreNav-PaymentRequests");
+ await s.Page.ClickAsync("#menu-item-PaymentRequests");
await s.Page.WaitForLoadStateAsync();
var listContent = await s.Page.ContentAsync();
@@ -1349,14 +1346,14 @@ namespace BTCPayServer.Tests
Assert.Equal("1", await s.Page.Locator("#NotificationsBadge").TextContentAsync());
});
- await s.Page.Locator("#NotificationsHandle").ClickAsync();
- Assert.Matches($"New user {unapproved.RegisterDetails.Email} requires approval", await s.Page.Locator("#NotificationsList .notification").TextContentAsync());
- await s.Page.Locator("#NotificationsMarkAllAsSeen").ClickAsync();
+ await s.Page.ClickAsync("#NotificationsHandle");
+ await s.Page.Locator($"#NotificationsList .notification:has-text('New user {unapproved.RegisterDetails.Email} requires approval')").WaitForAsync();
+ await s.Page.ClickAsync("#NotificationsMarkAllAsSeen");
await s.GoToServer(ServerNavPages.Policies);
Assert.True(await s.Page.Locator("#EnableRegistration").IsCheckedAsync());
Assert.True(await s.Page.Locator("#RequiresUserApproval").IsCheckedAsync());
- await s.Page.Locator("#RequiresUserApproval").ClickAsync();
+ await s.Page.ClickAsync("#RequiresUserApproval");
await s.ClickPagePrimary();
await s.FindAlertMessage(partialText: "Policies updated successfully");
Assert.False(await s.Page.Locator("#RequiresUserApproval").IsCheckedAsync());
@@ -1702,7 +1699,7 @@ namespace BTCPayServer.Tests
await s.Page.GetAttributeAsync("#AccountKeys_0__AccountKeyPath", "value"));
// Transactions list is empty
- await s.Page.ClickAsync($"#StoreNav-Wallet{cryptoCode}");
+ await s.GoToWallet();
await s.Page.WaitForSelectorAsync("#WalletTransactions[data-loaded='true']");
Assert.Contains("There are no transactions yet", await s.Page.Locator("#WalletTransactions").TextContentAsync());
}
@@ -1829,7 +1826,7 @@ namespace BTCPayServer.Tests
];
await s.Server.ExplorerNode.GenerateAsync(1);
- await s.GoToWallet(walletId);
+ await s.GoToWallet(walletId, WalletsNavPages.Send);
await s.Page.ClickAsync("#toggleInputSelection");
var input = s.Page.Locator("input[placeholder^='Filter']");
@@ -1885,11 +1882,11 @@ namespace BTCPayServer.Tests
(string storeName, _) = await s.CreateNewStore();
// Check status in navigation
- await s.Page.Locator("#StoreNav-LightningBTC .btcpay-status--pending").WaitForAsync();
+ await s.Page.Locator("#menu-item-LightningSettings-BTC .btcpay-status--pending").WaitForAsync();
// Set up LN node
await s.AddLightningNode();
- await s.Page.Locator("#StoreNav-LightningBTC .btcpay-status--enabled").WaitForAsync();
+ await s.Page.Locator("#menu-item-Lightning-BTC .btcpay-status--enabled").WaitForAsync();
// Check public node info for availability
var opening = s.Page.Context.WaitForPageAsync();
@@ -1915,7 +1912,7 @@ namespace BTCPayServer.Tests
await s.FindAlertMessage(partialText: "BTC Lightning node updated.");
// Check offline state is communicated in nav item
- await s.Page.Locator("#StoreNav-LightningBTC .btcpay-status--disabled").WaitForAsync();
+ await s.Page.Locator("#menu-item-Lightning-BTC .btcpay-status--disabled").WaitForAsync();
// Check public node info for availability
opening = s.Page.Context.WaitForPageAsync();
@@ -2098,8 +2095,9 @@ namespace BTCPayServer.Tests
await s.Page.SetCheckedAsync("#AutoApproveClaims", true);
await s.ClickPagePrimary();
+ var o = s.Page.Context.WaitForPageAsync();
await s.Page.ClickAsync("text=View");
- var newPage = await s.Page.Context.WaitForPageAsync();
+ var newPage = await o;
var address = await s.Server.ExplorerNode.GetNewAddressAsync();
await newPage.FillAsync("#Destination", address.ToString());
@@ -2198,7 +2196,7 @@ namespace BTCPayServer.Tests
// The delivery is done asynchronously, so small wait here
await Task.Delay(500);
await s.GoToStore();
- await s.Page.ClickAsync("#StoreNav-Webhooks");
+ await s.GoToStore(StoreNavPages.Webhooks);
await s.Page.ClickAsync("text=Modify");
var redeliverElements = await s.Page.Locator("button.redeliver").AllAsync();
@@ -2235,8 +2233,9 @@ namespace BTCPayServer.Tests
private static async Task CanBrowseContentAsync(PlaywrightTester s)
{
+ var newPageDoing = s.Page.Context.WaitForPageAsync();
await s.Page.ClickAsync(".delivery-content");
- var newPage = await s.Page.Context.WaitForPageAsync();
+ var newPage = await newPageDoing;
var bodyText = await newPage.Locator("body").TextContentAsync();
JObject.Parse(bodyText);
await newPage.CloseAsync();
diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs
index 7efe667..4e649c7 100644
--- a/BTCPayServer.Tests/SeleniumTester.cs
+++ b/BTCPayServer.Tests/SeleniumTester.cs
@@ -222,7 +222,7 @@ retry:
Assert.Equal("Recommendation (Kraken)", rateSource.SelectedOption.Text);
rateSource.SelectByText("CoinGecko");
Driver.WaitForElement(By.Id("Create")).Click();
- Driver.FindElement(By.Id("StoreNav-General")).Click();
+ Driver.FindElement(By.Id("menu-item-General")).Click();
var storeId = Driver.WaitForElement(By.Id("Id")).GetAttribute("value");
if (keepId)
StoreId = storeId;
@@ -415,7 +415,7 @@ retry:
{
if (!Driver.PageSource.Contains("id=\"Nav-Logout\""))
GoToUrl("/account");
- Driver.FindElement(By.Id("Nav-Account")).Click();
+ Driver.FindElement(By.Id("menu-item-Account")).Click();
Driver.FindElement(By.Id("Nav-Logout")).Click();
}
@@ -447,27 +447,27 @@ retry:
if (storeNavPage != StoreNavPages.General)
{
- Driver.FindElement(By.Id($"StoreNav-{StoreNavPages.General}")).Click();
+ Driver.FindElement(By.Id($"menu-item-{StoreNavPages.General}")).Click();
}
- Driver.FindElement(By.Id($"StoreNav-{storeNavPage}")).Click();
+ Driver.FindElement(By.Id($"menu-item-{storeNavPage}")).Click();
}
public void GoToWalletSettings(string cryptoCode = "BTC")
{
- Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
- if (Driver.PageSource.Contains("id=\"WalletNav-Settings\""))
+ Driver.FindElement(By.CssSelector($"[data-testid=\"Wallet-{cryptoCode}\"] a")).Click();
+ if (Driver.PageSource.Contains($"id=\"menu-item-Settings-{cryptoCode}\""))
{
- Driver.FindElement(By.Id("WalletNav-Settings")).Click();
+ Driver.FindElement(By.Id($"menu-item-Settings-{cryptoCode}")).Click();
}
}
public void GoToLightningSettings(string cryptoCode = "BTC")
{
- Driver.FindElement(By.Id($"StoreNav-Lightning{cryptoCode}")).Click();
+ Driver.FindElement(By.CssSelector($"[data-testid=\"Lightning-{cryptoCode}\"]")).Click();
// if Lightning is already set up we need to navigate to the settings
- if (Driver.PageSource.Contains("id=\"StoreNav-LightningSettings\""))
+ if (Driver.PageSource.Contains($"id=\"menu-item-LightningSettings-{cryptoCode}\""))
{
- Driver.FindElement(By.Id("StoreNav-LightningSettings")).Click();
+ Driver.FindElement(By.Id($"menu-item-LightningSettings-{cryptoCode}")).Click();
}
}
@@ -480,7 +480,7 @@ retry:
public void GoToInvoiceCheckout(string invoiceId = null)
{
invoiceId ??= InvoiceId;
- Driver.FindElement(By.Id("StoreNav-Invoices")).Click();
+ Driver.FindElement(By.Id("menu-item-Invoices")).Click();
Driver.FindElement(By.Id($"invoice-checkout-{invoiceId}")).Click();
CheckForJSErrors();
Driver.WaitUntilAvailable(By.Id("Checkout"));
@@ -495,7 +495,7 @@ retry:
{
if (storeId is null)
{
- Driver.FindElement(By.Id("StoreNav-Invoices")).Click();
+ Driver.FindElement(By.Id("menu-item-Invoices")).Click();
}
else
{
@@ -506,11 +506,11 @@ retry:
public void GoToProfile(ManageNavPages navPages = ManageNavPages.Index)
{
- Driver.WaitForAndClick(By.Id("Nav-Account"));
+ Driver.WaitForAndClick(By.Id("menu-item-Account"));
Driver.WaitForAndClick(By.Id("Nav-ManageAccount"));
if (navPages != ManageNavPages.Index)
{
- Driver.WaitForAndClick(By.Id($"SectionNav-{navPages.ToString()}"));
+ Driver.WaitForAndClick(By.Id($"menu-item-{navPages.ToString()}"));
}
}
@@ -614,12 +614,12 @@ retry:
Driver.Navigate().GoToUrl(new Uri(ServerUri, $"wallets/{walletId}"));
if (navPages == WalletsNavPages.PSBT)
{
- Driver.FindElement(By.Id("WalletNav-Send")).Click();
+ Driver.FindElement(By.Id($"menu-item-Send-{walletId.CryptoCode}")).Click();
Driver.FindElement(By.Id("PSBT")).Click();
}
else if (navPages != WalletsNavPages.Transactions)
{
- Driver.FindElement(By.Id($"WalletNav-{navPages}")).Click();
+ Driver.FindElement(By.Id($"menu-item-{navPages}-{walletId.CryptoCode}")).Click();
}
}
@@ -630,10 +630,10 @@ retry:
public void GoToServer(ServerNavPages navPages = ServerNavPages.Policies)
{
- Driver.FindElement(By.Id("Nav-ServerSettings")).Click();
+ Driver.FindElement(By.Id("menu-item-Policies")).Click();
if (navPages != ServerNavPages.Policies)
{
- Driver.FindElement(By.Id($"SectionNav-{navPages}")).Click();
+ Driver.FindElement(By.Id($"menu-item-{navPages}")).Click();
}
}
@@ -671,7 +671,7 @@ retry:
{
if (string.IsNullOrEmpty(name))
name = $"{type}-{Guid.NewGuid().ToString()[..14]}";
- Driver.FindElement(By.Id($"StoreNav-Create{type}")).Click();
+ Driver.FindElement(By.Id($"menu-item-CreateApp-{type}")).Click();
Driver.FindElement(By.Name("AppName")).SendKeys(name);
ClickPagePrimary();
Assert.Contains("App successfully created", FindAlertMessage().Text);
diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs
index 77ab43b..edd7d47 100644
--- a/BTCPayServer.Tests/SeleniumTests.cs
+++ b/BTCPayServer.Tests/SeleniumTests.cs
@@ -165,7 +165,7 @@ namespace BTCPayServer.Tests
Assert.True(s.Driver.FindElement(By.Id("Dashboard")).Displayed);
// setup offchain wallet
- s.Driver.FindElement(By.Id("StoreNav-LightningBTC")).Click();
+ s.Driver.FindElement(By.CssSelector("[data-testid='Lightning-BTC']")).Click();
s.AddLightningNode();
s.Driver.AssertNoError();
var successAlert = s.FindAlertMessage();
@@ -449,16 +449,16 @@ namespace BTCPayServer.Tests
// Archive
s.Driver.SwitchTo().Window(windows[0]);
- Assert.True(s.Driver.ElementDoesNotExist(By.Id("Nav-ArchivedApps")));
+ Assert.True(s.Driver.ElementDoesNotExist(By.Id("menu-item-AppsNavPages")));
s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
Assert.Contains("The app has been archived and will no longer appear in the apps list by default.", s.FindAlertMessage().Text);
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ViewApp")));
- Assert.Contains("1 Archived App", s.Driver.FindElement(By.Id("Nav-ArchivedApps")).Text);
+ Assert.Contains("1 Archived App", s.Driver.FindElement(By.Id("menu-item-AppsNavPages")).Text);
s.Driver.Navigate().GoToUrl(posBaseUrl);
Assert.Contains("Page not found", s.Driver.Title, StringComparison.OrdinalIgnoreCase);
s.Driver.Navigate().Back();
- s.Driver.FindElement(By.Id("Nav-ArchivedApps")).Click();
+ s.Driver.FindElement(By.Id("menu-item-AppsNavPages")).Click();
// Unarchive
s.Driver.FindElement(By.Id($"App-{appId}")).Click();
@@ -527,17 +527,17 @@ namespace BTCPayServer.Tests
s.Driver.SwitchTo().Window(windows[0]);
// Archive
- Assert.True(s.Driver.ElementDoesNotExist(By.Id("Nav-ArchivedApps")));
+ Assert.True(s.Driver.ElementDoesNotExist(By.Id("menu-item-AppsNavPages")));
s.Driver.SwitchTo().Window(windows[0]);
s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
Assert.Contains("The app has been archived and will no longer appear in the apps list by default.", s.FindAlertMessage().Text);
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ViewApp")));
- Assert.Contains("1 Archived App", s.Driver.FindElement(By.Id("Nav-ArchivedApps")).Text);
+ Assert.Contains("1 Archived App", s.Driver.FindElement(By.Id("menu-item-AppsNavPages")).Text);
s.Driver.Navigate().GoToUrl(cfUrl);
Assert.Contains("Page not found", s.Driver.Title, StringComparison.OrdinalIgnoreCase);
s.Driver.Navigate().Back();
- s.Driver.FindElement(By.Id("Nav-ArchivedApps")).Click();
+ s.Driver.FindElement(By.Id("menu-item-AppsNavPages")).Click();
// Unarchive
s.Driver.FindElement(By.Id($"App-{appId}")).Click();
@@ -612,14 +612,14 @@ namespace BTCPayServer.Tests
await s.StartAsync();
s.RegisterNewUser();
s.CreateNewStore();
- s.Driver.FindElement(By.Id("StoreNav-PaymentRequests")).Click();
+ s.Driver.FindElement(By.Id("menu-item-PaymentRequests")).Click();
// Should give us an error message if we try to create a payment request before adding a wallet
s.ClickPagePrimary();
Assert.Contains("To create a payment request, you need to", s.Driver.PageSource);
s.AddDerivationScheme();
- s.Driver.FindElement(By.Id("StoreNav-PaymentRequests")).Click();
+ s.Driver.FindElement(By.Id("menu-item-PaymentRequests")).Click();
s.ClickPagePrimary();
s.Driver.FindElement(By.Id("Title")).SendKeys("Pay123");
s.Driver.FindElement(By.Id("Amount")).Clear();
@@ -1483,11 +1483,11 @@ namespace BTCPayServer.Tests
//ln address tests
s.CreateNewStore();
//ensure ln address is not available as Lightning is not enable
- s.Driver.AssertElementNotFound(By.Id("StoreNav-LightningAddress"));
+ s.Driver.AssertElementNotFound(By.Id("menu-item-LightningAddress"));
s.AddLightningNode(LightningConnectionType.LndREST, false);
- s.Driver.FindElement(By.Id("StoreNav-LightningAddress")).Click();
+ s.Driver.FindElement(By.Id("menu-item-LightningAddress")).Click();
s.Driver.ToggleCollapse("AddAddress");
var lnaddress1 = Guid.NewGuid().ToString();
diff --git a/BTCPayServer.Tests/SubscriptionTests.cs b/BTCPayServer.Tests/SubscriptionTests.cs
index 90a6c7f..3b8958b 100644
--- a/BTCPayServer.Tests/SubscriptionTests.cs
+++ b/BTCPayServer.Tests/SubscriptionTests.cs
@@ -226,7 +226,8 @@ public class SubscriptionTests(ITestOutputHelper testOutputHelper) : UnitTestBas
{
await portal.Downgrade("Basic Plan");
unused = GetUnusedPeriodValue(usedDays: 7, planPrice: 99.0m, daysInPeriod: DaysInThisMonth());
- totalRefunded += await portal.AssertRefunded(unused);
+ unused = await portal.AssertRefunded(unused);
+ totalRefunded += unused;
});
Assert.Equal(unused, credited.Amount);
@@ -241,7 +242,8 @@ public class SubscriptionTests(ITestOutputHelper testOutputHelper) : UnitTestBas
await portal.GoTo7Days();
await portal.Upgrade("Pro Plan");
unused = GetUnusedPeriodValue(usedDays: 7, planPrice: 29.0m, daysInPeriod: DaysInThisMonth());
- totalRefunded += await portal.AssertRefunded(unused);
+ unused = await portal.AssertRefunded(unused);
+ totalRefunded += unused;
expectedBalance = totalRefunded - 29.0m - 99.0m - 99.0m;
await portal.AssertCredit(creditBalance: $"${expectedBalance:F2}");
@@ -253,14 +255,24 @@ public class SubscriptionTests(ITestOutputHelper testOutputHelper) : UnitTestBas
await s.Server.WaitForEvent<SubscriptionEvent.PlanStarted>(async () =>
{
await portal.Upgrade("Enterprise Plan");
- await invoice.AssertContent(new()
- {
- TotalFiat = USD(299m - expectedBalance - unused)
- });
await s.PayInvoice(mine: true);
});
await invoice.ClickRedirect();
- totalRefunded += await portal.AssertRefunded(unused);
+ unused = await portal.AssertRefunded(unused);
+ totalRefunded += unused;
+ await s.Page.EvaluateAsync("window.scrollTo(0, document.body.scrollHeight)");
+ await s.TakeScreenshot("upgrade2.png");
+ await portal.AssertCreditHistory(
+ [
+ "Upgrade to new plan 'Enterprise Plan'",
+ "Credit purchase"
+ ],
+ [
+ "-$" + (299m - unused).ToString("F2", CultureInfo.InvariantCulture),
+ "$" + (299m - expectedBalance - unused).ToString("F2", CultureInfo.InvariantCulture)
+ ]);
+ expectedBalance = 0m;
+ await portal.AssertCredit(creditBalance: $"${expectedBalance:F2}");
}
}
@@ -759,7 +771,10 @@ public class SubscriptionTests(ITestOutputHelper testOutputHelper) : UnitTestBas
var match = Regex.Match(text!, @"\((.*?) USD has been refunded\)");
var v = decimal.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
var diff = Math.Abs(refunded - v);
- Assert.True(diff < 2.0m);
+ if (diff >= 3.0m)
+ {
+ Assert.Fail($"Expected {refunded} USD, but got {v} USD");
+ }
return v;
}
@@ -769,13 +784,16 @@ public class SubscriptionTests(ITestOutputHelper testOutputHelper) : UnitTestBas
Assert.Equal(plan, name);
}
- public async Task AssertCreditHistory(List<string> creditLines)
+ public async Task AssertCreditHistory(List<string> creditLines, List<string>? creditAmounts = null)
{
- var rows = await s.Page.QuerySelectorAllAsync(".credit-history tr td:nth-child(2)");
+ var descriptions = await s.Page.QuerySelectorAllAsync(".credit-history tr td:nth-child(2)");
+ var credits = await s.Page.QuerySelectorAllAsync(".credit-history tr td:nth-child(3)");
for (int i = 0; i < creditLines.Count; i++)
{
- var txt = await rows[i].InnerTextAsync();
+ var txt = await descriptions[i].InnerTextAsync();
Assert.StartsWith(creditLines[i], txt);
+ if (creditAmounts is not null)
+ Assert.Equal(creditAmounts[i], await credits[i].InnerTextAsync());
}
}
}
diff --git a/BTCPayServer.Tests/WalletTests.cs b/BTCPayServer.Tests/WalletTests.cs
index eaee1cc..4e7dcfd 100644
--- a/BTCPayServer.Tests/WalletTests.cs
+++ b/BTCPayServer.Tests/WalletTests.cs
@@ -25,7 +25,7 @@ public class WalletTests(ITestOutputHelper helper) : UnitTestBase(helper)
var txs = (await client.ShowOnChainWalletTransactions(s.StoreId, "BTC")).Select(t => t.TransactionHash).ToArray();
Assert.Equal(3, txs.Length);
- var w = await s.GoToWalletTransactions();
+ var w = await s.GoToWalletTransactions(s.WalletId);
await w.BumpFee(txs[0]);
// Because a single transaction is selected, we should be able to select CPFP only (Because no change are available, we can't do RBF)
@@ -145,7 +145,7 @@ public class WalletTests(ITestOutputHelper helper) : UnitTestBase(helper)
for (int i = 0; i < 5; i++)
{
- var txs = await s.GoToWalletTransactions();
+ var txs = await s.GoToWalletTransactions(s.WalletId);
await txs.SelectAll();
await txs.BumpFeeSelected();
await s.ClickPagePrimary();
diff --git a/BTCPayServer/Components/MainNav/Default.cshtml b/BTCPayServer/Components/MainNav/Default.cshtml
index f29113a..afae344 100644
--- a/BTCPayServer/Components/MainNav/Default.cshtml
+++ b/BTCPayServer/Components/MainNav/Default.cshtml
@@ -1,12 +1,8 @@
@using BTCPayServer.Views.Server
@using BTCPayServer.Views.Stores
-@using BTCPayServer.Views.Invoice
@using BTCPayServer.Views.Manage
-@using BTCPayServer.Views.PaymentRequest
@using BTCPayServer.Views.Wallets
@using BTCPayServer.Client
-@using BTCPayServer.Components.ThemeSwitch
-@using BTCPayServer.Components.UIExtensionPoint
@using BTCPayServer.Plugins
@using BTCPayServer.Services
@using BTCPayServer.Views.Apps
@@ -33,45 +29,45 @@
<div class="accordion-body">
<ul class="navbar-nav">
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.Dashboard))" asp-area="" asp-controller="UIStores" asp-action="Dashboard" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Dashboard)">
+ <a layout-menu-item="@nameof(StoreNavPages.Dashboard)" asp-area="" asp-controller="UIStores" asp-action="Dashboard" asp-route-storeId="@Model.Store.Id">
<vc:icon symbol="nav-dashboard"/>
<span text-translate="true">Dashboard</span>
</a>
</li>
<li class="nav-item" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.General))" asp-area="" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.General)">
+ <a layout-menu-item="General" asp-area="" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.Store.Id">
<vc:icon symbol="nav-store-settings"/>
<span text-translate="true">Settings</span>
</a>
</li>
- @if (ViewData.IsPageActive([StoreNavPages.General, StoreNavPages.Rates, StoreNavPages.CheckoutAppearance, StoreNavPages.Tokens, StoreNavPages.Users, StoreNavPages.Roles, StoreNavPages.Webhooks, StoreNavPages.PayoutProcessors, StoreNavPages.Emails, StoreNavPages.Forms]))
+ @if (ViewData.IsCategory(WellKnownCategories.Store))
{
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.Rates))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Rates)" asp-controller="UIStores" asp-action="Rates" asp-route-storeId="@Model.Store.Id" text-translate="true">Rates</a>
+ <a layout-menu-item="@(nameof(StoreNavPages.Rates))" asp-controller="UIStores" asp-action="Rates" asp-route-storeId="@Model.Store.Id" text-translate="true">Rates</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.CheckoutAppearance))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.CheckoutAppearance)" asp-controller="UIStores" asp-action="CheckoutAppearance" asp-route-storeId="@Model.Store.Id" text-translate="true">Checkout Appearance</a>
+ <a layout-menu-item="@(nameof(StoreNavPages.CheckoutAppearance))" asp-controller="UIStores" asp-action="CheckoutAppearance" asp-route-storeId="@Model.Store.Id" text-translate="true">Checkout Appearance</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.Tokens))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Tokens)" asp-controller="UIStores" asp-action="ListTokens" asp-route-storeId="@Model.Store.Id" text-translate="true">Access Tokens</a>
+ <a layout-menu-item="@nameof(StoreNavPages.Tokens)" asp-controller="UIStores" asp-action="ListTokens" asp-route-storeId="@Model.Store.Id" text-translate="true">Access Tokens</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.Users))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Users)" asp-controller="UIStores" asp-action="StoreUsers" asp-route-storeId="@Model.Store.Id" text-translate="true">Users</a>
+ <a layout-menu-item="@(nameof(StoreNavPages.Users))" asp-controller="UIStores" asp-action="StoreUsers" asp-route-storeId="@Model.Store.Id" text-translate="true">Users</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.Roles))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Roles)" asp-controller="UIStores" asp-action="ListRoles" asp-route-storeId="@Model.Store.Id" text-translate="true">Roles</a>
+ <a layout-menu-item="@(nameof(StoreNavPages.Roles))" asp-controller="UIStores" asp-action="ListRoles" asp-route-storeId="@Model.Store.Id" text-translate="true">Roles</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.Webhooks))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Webhooks)" asp-area="Webhooks" asp-controller="UIStoreWebhooks" asp-action="Webhooks" asp-route-storeId="@Model.Store.Id" text-translate="true">Webhooks</a>
+ <a layout-menu-item="@(nameof(StoreNavPages.Webhooks))" asp-area="Webhooks" asp-controller="UIStoreWebhooks" asp-action="Webhooks" asp-route-storeId="@Model.Store.Id" text-translate="true">Webhooks</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.PayoutProcessors))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.PayoutProcessors)" asp-controller="UIPayoutProcessors" asp-action="ConfigureStorePayoutProcessors" asp-route-storeId="@Model.Store.Id" text-translate="true">Payout Processors</a>
+ <a layout-menu-item="@(nameof(StoreNavPages.PayoutProcessors))" asp-controller="UIPayoutProcessors" asp-action="ConfigureStorePayoutProcessors" asp-route-storeId="@Model.Store.Id" text-translate="true">Payout Processors</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.Emails))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Emails)" asp-area="@EmailsPlugin.Area" asp-controller="UIStoresEmail" asp-action="StoreEmailSettings" asp-route-storeId="@Model.Store.Id" text-translate="true">Emails</a>
+ <a layout-menu-item="@(nameof(StoreNavPages.Emails))" asp-area="@EmailsPlugin.Area" asp-controller="UIStoresEmail" asp-action="StoreEmailSettings" asp-route-storeId="@Model.Store.Id" text-translate="true">Emails</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a id="StoreNav-@(nameof(StoreNavPages.Forms))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Forms)" asp-controller="UIForms" asp-action="FormsList" asp-route-storeId="@Model.Store.Id" text-translate="true">Forms</a>
+ <a layout-menu-item="@(nameof(StoreNavPages.Forms))" asp-controller="UIForms" asp-action="FormsList" asp-route-storeId="@Model.Store.Id" text-translate="true">Forms</a>
</li>
}
<vc:ui-extension-point location="store-nav" model="@Model"/>
@@ -88,39 +84,43 @@
@foreach (var scheme in Model.DerivationSchemes.OrderBy(scheme => scheme.Collapsed))
{
var isSetUp = !string.IsNullOrWhiteSpace(scheme.Value);
- var categoryId = $"{Model.Store.Id}-{scheme.WalletId.CryptoCode}";
- <li class="nav-item">
+ <li class="nav-item" data-testid="Wallet-@scheme.Crypto">
@if (isSetUp && scheme.WalletSupported)
{
- <a asp-area="" asp-controller="UIWallets" asp-action="WalletTransactions" asp-route-walletId="@scheme.WalletId" class="nav-link @ViewData.ActivePageClass([WalletsNavPages.Transactions], scheme.WalletId.ToString())" id="@($"StoreNav-Wallet{scheme.Crypto}")">
+ <a layout-menu-item="@nameof(WalletsNavPages.Transactions)-@scheme.Crypto" asp-area="" asp-controller="UIWallets" asp-action="WalletTransactions" asp-route-walletId="@scheme.WalletId">
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "pending")"></span>
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
</a>
}
else
{
- <a asp-area="" asp-controller="UIStores" asp-action="SetupWallet" asp-route-cryptoCode="@scheme.Crypto" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.OnchainSettings)" id="@($"StoreNav-Wallet{scheme.Crypto}")">
+ <a asp-area="" asp-controller="UIStores" asp-action="SetupWallet" asp-route-cryptoCode="@scheme.Crypto" asp-route-storeId="@Model.Store.Id">
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "pending")"></span>
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
</a>
}
</li>
- @if (ViewData.IsCategoryActive(typeof(WalletsNavPages), scheme.WalletId.ToString()) || ViewData.IsPageActive([WalletsNavPages.Settings], scheme.WalletId.ToString()) || ViewData.IsPageActive([StoreNavPages.OnchainSettings], categoryId))
+ @if (ViewData.IsCategory(WellKnownCategories.ForWallet(scheme.Crypto)))
{
@if (!scheme.ReadonlyWallet)
{
<li class="nav-item nav-item-sub">
- <a id="WalletNav-Send" class="nav-link @ViewData.ActivePageClass([WalletsNavPages.Send, WalletsNavPages.PSBT], scheme.WalletId.ToString())" asp-area="" asp-controller="UIWallets" asp-action="WalletSend" asp-route-walletId="@scheme.WalletId" text-translate="true">Send</a>
+ <a layout-menu-item="@nameof(WalletsNavPages.Send)-@scheme.Crypto"
+ asp-area="" asp-controller="UIWallets" asp-action="WalletSend" asp-route-walletId="@scheme.WalletId" text-translate="true">Send</a>
</li>
}
<li class="nav-item nav-item-sub">
- <a id="WalletNav-Receive" class="nav-link @ViewData.ActivePageClass(WalletsNavPages.Receive, scheme.WalletId.ToString())" asp-area="" asp-controller="UIWallets" asp-action="WalletReceive" asp-route-walletId="@scheme.WalletId" text-translate="true">Receive</a>
+ <a
+ layout-menu-item="@nameof(WalletsNavPages.Receive)-@scheme.Crypto"
+ asp-area="" asp-controller="UIWallets" asp-action="WalletReceive" asp-route-walletId="@scheme.WalletId" text-translate="true">Receive</a>
</li>
<li class="nav-item nav-item-sub">
- <a id="WalletNav-Settings" class="nav-link @ViewData.ActivePageClass(WalletsNavPages.Settings, scheme.WalletId.ToString()) @ViewData.ActivePageClass(StoreNavPages.OnchainSettings, categoryId)" asp-area="" asp-controller="UIStores" asp-action="WalletSettings" asp-route-cryptoCode="@scheme.WalletId.CryptoCode" asp-route-storeId="@scheme.WalletId.StoreId" text-translate="true">Settings</a>
+ <a
+ layout-menu-item="@nameof(WalletsNavPages.Settings)-@scheme.Crypto"
+ asp-area="" asp-controller="UIStores" asp-action="WalletSettings" asp-route-cryptoCode="@scheme.WalletId.CryptoCode" asp-route-storeId="@scheme.WalletId.StoreId" text-translate="true">Settings</a>
</li>
<vc:ui-extension-point location="wallet-nav" model="@Model" />
}
@@ -134,23 +134,29 @@
var status = scheme.Enabled
? scheme.Available ? "enabled" : "disabled"
: "pending";
- <a asp-area="" asp-controller="UIStores" asp-action="Lightning" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Lightning, $"{Model.Store.Id}-{scheme.CryptoCode}")" id="@($"StoreNav-Lightning{scheme.CryptoCode}")">
+ <a
+ data-testid="Lightning-@scheme.CryptoCode"
+ layout-menu-item="@nameof(StoreNavPages.Lightning)-@scheme.CryptoCode"
+ asp-area="" asp-controller="UIStores" asp-action="Lightning" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Store.Id">
<span class="me-2 btcpay-status btcpay-status--@status"></span>
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
</a>
}
else
{
- <a asp-area="" asp-controller="UIStores" asp-action="SetupLightningNode" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.LightningSettings, $"{Model.Store.Id}-{scheme.CryptoCode}")" id="@($"StoreNav-Lightning{scheme.CryptoCode}")">
+ <a
+ data-testid="Lightning-@scheme.CryptoCode"
+ layout-menu-item="@nameof(StoreNavPages.LightningSettings)-@scheme.CryptoCode"
+ asp-area="" asp-controller="UIStores" asp-action="SetupLightningNode" asp-route-cryptoCode="@scheme.CryptoCode" asp-route-storeId="@Model.Store.Id">
<span class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "pending")"></span>
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
</a>
}
</li>
- @if (ViewData.IsPageActive([StoreNavPages.Lightning, StoreNavPages.LightningSettings], $"{Model.Store.Id}-{scheme.CryptoCode}"))
+ @if (ViewData.IsCategory(WellKnownCategories.ForLightning(scheme.CryptoCode)))
{
<li class="nav-item nav-item-sub">
- <a id="StoreNav-@(nameof(StoreNavPages.LightningSettings))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.LightningSettings)" asp-controller="UIStores" asp-action="LightningSettings" asp-route-storeId="@Model.Store.Id" asp-route-cryptoCode="@scheme.CryptoCode" text-translate="true">Settings</a>
+ <a layout-menu-item="@(nameof(StoreNavPages.LightningSettings))-@scheme.CryptoCode" asp-controller="UIStores" asp-action="LightningSettings" asp-route-storeId="@Model.Store.Id" asp-route-cryptoCode="@scheme.CryptoCode" text-translate="true">Settings</a>
</li>
<vc:ui-extension-point location="lightning-nav" model="@Model"/>
}
@@ -170,34 +176,36 @@
<div class="accordion-body">
<ul class="navbar-nav">
<li class="nav-item" permission="@Policies.CanViewInvoices">
- <a asp-area="" asp-controller="UIInvoice" asp-action="ListInvoices" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActiveCategoryClass(typeof(InvoiceNavPages))" id="StoreNav-Invoices">
+ <a layout-menu-item="Invoices" asp-area="" asp-controller="UIInvoice" asp-action="ListInvoices" asp-route-storeId="@Model.Store.Id">
<vc:icon symbol="nav-invoices"/>
<span text-translate="true">Invoices</span>
</a>
</li>
<li class="nav-item" permission="@Policies.CanViewReports">
- <a asp-area="" asp-controller="UIReports" asp-action="StoreReports" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Reporting)" id="SectionNav-Reporting">
+ <a layout-menu-item="@nameof(StoreNavPages.Reporting)" asp-area="" asp-controller="UIReports" asp-action="StoreReports" asp-route-storeId="@Model.Store.Id">
<vc:icon symbol="nav-reporting" />
<span text-translate="true">Reporting</span>
</a>
</li>
<li class="nav-item" permission="@Policies.CanViewPaymentRequests">
- <a asp-area="" asp-controller="UIPaymentRequest" asp-action="GetPaymentRequests" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActiveCategoryClass(typeof(PaymentRequestsNavPages))" id="StoreNav-PaymentRequests">
+ <a layout-menu-item="PaymentRequests" asp-area="" asp-controller="UIPaymentRequest" asp-action="GetPaymentRequests" asp-route-storeId="@Model.Store.Id">
<vc:icon symbol="nav-payment-requests"/>
<span text-translate="true">Requests</span>
</a>
</li>
<li class="nav-item" permission="@Policies.CanViewPullPayments">
- <a asp-area="" asp-controller="UIStorePullPayments" asp-action="PullPayments" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.PullPayments)" id="StoreNav-PullPayments">
+ <a layout-menu-item="@nameof(StoreNavPages.PullPayments)" asp-area="" asp-controller="UIStorePullPayments" asp-action="PullPayments" asp-route-storeId="@Model.Store.Id">
<vc:icon symbol="nav-pull-payments"/>
<span text-translate="true">Pull Payments</span>
</a>
</li>
<li class="nav-item" permission="@Policies.CanViewPayouts">
- <a asp-area=""
+ <a
+ layout-menu-item="@nameof(StoreNavPages.Payouts)"
+ asp-area=""
asp-controller="UIStorePullPayments" asp-action="Payouts"
asp-route-pullPaymentId=""
- asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Payouts)" id="StoreNav-Payouts">
+ asp-route-storeId="@Model.Store.Id">
<vc:icon symbol="nav-payouts"/>
<span text-translate="true">Payouts</span>
</a>
@@ -226,7 +234,7 @@
</ul>
<ul class="navbar-nav">
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
- <a asp-area="" asp-controller="UIServer" asp-action="ListPlugins" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Plugins)" id="Nav-ManagePlugins">
+ <a layout-menu-item="@nameof(ServerNavPages.Plugins)" asp-area="" asp-controller="UIServer" asp-action="ListPlugins">
@if (PluginService.GetDisabledPlugins().Any())
{
<span class="me-2 btcpay-status btcpay-status--disabled"></span>
@@ -241,7 +249,7 @@
@if (Model.Store != null && Model.ArchivedAppsCount > 0)
{
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
- <a asp-area="" asp-controller="UIApps" asp-action="ListApps" asp-route-storeId="@Model.Store.Id" asp-route-archived="true" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Index)" id="Nav-ArchivedApps">
+ <a layout-menu-item="@nameof(AppsNavPages)" asp-area="" asp-controller="UIApps" asp-action="ListApps" asp-route-storeId="@Model.Store.Id" asp-route-archived="true">
@Model.ArchivedAppsCount Archived App@(Model.ArchivedAppsCount == 1 ? "" : "s")
</a>
</li>
@@ -292,48 +300,48 @@
{
<ul id="mainNavSettings" class="navbar-nav border-top p-3 px-lg-4">
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
- <a asp-area="" asp-controller="UIServer" asp-action="Policies" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Policies)" id="Nav-ServerSettings">
+ <a layout-menu-item="@nameof(ServerNavPages.Policies)" asp-area="" asp-controller="UIServer" asp-action="Policies">
<vc:icon symbol="nav-server-settings"/>
<span text-translate="true">Server Settings</span>
</a>
</li>
- @if (ViewData.IsCategoryActive(typeof(ServerNavPages)) && !ViewData.IsPageActive([ServerNavPages.Plugins]))
+ @if (ViewData.IsCategory(WellKnownCategories.Server))
{
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
- <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Users" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Users)" asp-action="ListUsers" text-translate="true">Users</a>
+ <a layout-menu-item="@nameof(ServerNavPages.Users)" asp-controller="UIServer" asp-action="ListUsers" text-translate="true">Users</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
- <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Roles" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Roles)" asp-action="ListRoles" text-translate="true">Roles</a>
+ <a layout-menu-item="@nameof(ServerNavPages.Roles)" asp-controller="UIServer" asp-action="ListRoles" text-translate="true">Roles</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
- <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Emails" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Emails)" asp-action="Emails" text-translate="true">Email</a>
+ <a layout-menu-item="Server-@nameof(ServerNavPages.Emails)" asp-controller="UIServer" asp-action="Emails" text-translate="true">Email</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
- <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Services" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Services)" asp-action="Services" text-translate="true">Services</a>
+ <a layout-menu-item="@nameof(ServerNavPages.Services)" asp-controller="UIServer" asp-action="Services" text-translate="true">Services</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
- <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Branding" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Branding)" asp-action="Branding" text-translate="true">Branding</a>
+ <a layout-menu-item="@nameof(ServerNavPages.Branding)" asp-controller="UIServer" asp-action="Branding" text-translate="true">Branding</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
- <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Translations" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Translations)" asp-action="ListDictionaries" text-translate="true">Translations</a>
+ <a layout-menu-item="@nameof(ServerNavPages.Translations)" asp-controller="UIServer" asp-action="ListDictionaries" text-translate="true">Translations</a>
</li>
@if (BtcPayServerOptions.DockerDeployment)
{
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
- <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Maintenance" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Maintenance)" asp-action="Maintenance" text-translate="true">Maintenance</a>
+ <a layout-menu-item="@nameof(ServerNavPages.Maintenance)" asp-controller="UIServer" asp-action="Maintenance" text-translate="true">Maintenance</a>
</li>
}
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
- <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Logs" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Logs)" asp-action="LogsView" text-translate="true">Logs</a>
+ <a layout-menu-item="@nameof(ServerNavPages.Logs)" asp-controller="UIServer" asp-action="LogsView" text-translate="true">Logs</a>
</li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
- <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Files" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Files)" asp-action="Files" text-translate="true">Files</a>
+ <a layout-menu-item="@nameof(ServerNavPages.Files)" asp-controller="UIServer" asp-action="Files" text-translate="true">Files</a>
</li>
<vc:ui-extension-point location="server-nav" model="@Model"/>
}
<li class="nav-item dropup">
- <a class="nav-link @ViewData.ActivePageClass(ManageNavPages.Index)" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false" id="Nav-Account">
+ <a layout-menu-item="Account" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
<vc:icon symbol="nav-account"/>
<span text-translate="true">Account</span>
</a>
@@ -347,11 +355,11 @@
<strong class="d-block text-truncate" style="max-width:@(string.IsNullOrEmpty(Model.UserImageUrl) ? "195px" : "160px")">
@if (string.IsNullOrEmpty(Model.UserName))
{
- @(User.Identity.Name)
+ @(User.Identity?.Name)
}
else
{
- @($"{Model.UserName} ({User.Identity.Name})")
+ @($"{Model.UserName} ({User.Identity?.Name})")
}
</strong>
@if (User.IsInRole(Roles.ServerAdmin))
@@ -387,22 +395,22 @@
</li>
</ul>
</li>
- @if (ViewData.IsCategoryActive(typeof(ManageNavPages)) || ViewData.IsPageActive([ManageNavPages.ChangePassword]))
+ @if (ViewData.IsCategory(nameof(ManageNavPages)))
{
<li class="nav-item nav-item-sub">
- <a id="SectionNav-@ManageNavPages.ChangePassword.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.ChangePassword)" asp-controller="UIManage" asp-action="ChangePassword" text-translate="true">Password</a>
+ <a layout-menu-item="@nameof(ManageNavPages.ChangePassword)" asp-controller="UIManage" asp-action="ChangePassword" text-translate="true">Password</a>
</li>
<li class="nav-item nav-item-sub">
- <a id="SectionNav-@ManageNavPages.TwoFactorAuthentication.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.TwoFactorAuthentication)" asp-controller="UIManage" asp-action="TwoFactorAuthentication" text-translate="true">Two-Factor Authentication</a>
+ <a layout-menu-item="@nameof(ManageNavPages.TwoFactorAuthentication)" asp-controller="UIManage" asp-action="TwoFactorAuthentication" text-translate="true">Two-Factor Authentication</a>
</li>
<li class="nav-item nav-item-sub">
- <a id="SectionNav-@ManageNavPages.APIKeys.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.APIKeys)" asp-controller="UIManage" asp-action="APIKeys" text-translate="true">API Keys</a>
+ <a layout-menu-item="@nameof(ManageNavPages.APIKeys)" asp-controller="UIManage" asp-action="APIKeys" text-translate="true">API Keys</a>
</li>
<li class="nav-item nav-item-sub">
- <a id="SectionNav-@ManageNavPages.Notifications.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.Notifications)" asp-controller="UIManage" asp-action="NotificationSettings" text-translate="true">Notifications</a>
+ <a layout-menu-item="@nameof(ManageNavPages.Notifications)" asp-controller="UIManage" asp-action="NotificationSettings" text-translate="true">Notifications</a>
</li>
<li class="nav-item nav-item-sub">
- <a id="SectionNav-@ManageNavPages.LoginCodes.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.LoginCodes)" asp-controller="UIManage" asp-action="LoginCodes" text-translate="true">Login Codes</a>
+ <a layout-menu-item="@nameof(ManageNavPages.LoginCodes)" asp-controller="UIManage" asp-action="LoginCodes" text-translate="true">Login Codes</a>
</li>
<vc:ui-extension-point location="user-nav" model="@Model" />
}
diff --git a/BTCPayServer/Components/StoreSelector/Default.cshtml b/BTCPayServer/Components/StoreSelector/Default.cshtml
index d10078d..0de642e 100644
--- a/BTCPayServer/Components/StoreSelector/Default.cshtml
+++ b/BTCPayServer/Components/StoreSelector/Default.cshtml
@@ -51,23 +51,19 @@ else
@foreach (var option in Model.Options)
{
<li>
- <a asp-controller="UIStores" asp-action="Index" asp-route-storeId="@option.Value" class="dropdown-item@(option.Selected && ViewData.ActivePageClass(ServerNavPages.Stores) != "active" ? " active" : "")" id="StoreSelectorMenuItem-@option.Value">@StoreName(option.Text)</a>
+ <a asp-controller="UIStores" asp-action="Index" asp-route-storeId="@option.Value" class="dropdown-item@(option.Selected && !ViewData.ContainsKey("StoreList"))" id="StoreSelectorMenuItem-@option.Value">@StoreName(option.Text)</a>
</li>
}
@if (Model.Options.Any())
{
<li><hr class="dropdown-divider"></li>
}
- <li><a asp-controller="UIUserStores" asp-action="CreateStore" class="dropdown-item @ViewData.ActivePageClass(StoreNavPages.Create)" id="StoreSelectorCreate" text-translate="true">Create Store</a></li>
+ <li><a asp-controller="UIUserStores" asp-action="CreateStore" class="dropdown-item @(ViewData.ContainsKey("CreateStore") ? "active" : "")" id="StoreSelectorCreate" text-translate="true">Create Store</a></li>
@if (Model.ArchivedCount > 0)
{
<li><hr class="dropdown-divider"></li>
- <li><a asp-controller="UIUserStores" asp-action="ListStores" asp-route-archived="true" class="dropdown-item @ViewData.ActivePageClass(StoreNavPages.Index)" id="StoreSelectorArchived">@(Model.ArchivedCount == 1 ? StringLocalizer["{0} Archived Store", Model.ArchivedCount] : StringLocalizer["{0} Archived Stores", Model.ArchivedCount])</a></li>
+ <li><a asp-controller="UIUserStores" asp-action="ListStores" asp-route-archived="true" class="dropdown-item @(ViewData.ContainsKey("ArchivedStores") ? "active" : "")" id="StoreSelectorArchived">@(Model.ArchivedCount == 1 ? StringLocalizer["{0} Archived Store", Model.ArchivedCount] : StringLocalizer["{0} Archived Stores", Model.ArchivedCount])</a></li>
}
- @*
- <li permission="@Policies.CanModifyServerSettings"><hr class="dropdown-divider"></li>
- <li permission="@Policies.CanModifyServerSettings"><a asp-controller="UIServer" asp-action="ListStores" class="dropdown-item @ViewData.ActivePageClass(ServerNavPages.Stores)" id="StoreSelectorAdminStores" text-translate="true">Admin Store Overview</a></li>
- *@
</ul>
</div>
</div>
diff --git a/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesList.cshtml b/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesList.cshtml
index 1f5ba7f..4b2a2e6 100644
--- a/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesList.cshtml
+++ b/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesList.cshtml
@@ -2,7 +2,8 @@
@{
var storeId = Context.GetStoreData().Id;
- ViewData.SetActivePage(StoreNavPages.Emails, StringLocalizer["Email Rules"], storeId);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Emails), StringLocalizer["Email Rules"])
+ .SetCategory(WellKnownCategories.Store));
}
<div class="sticky-header">
<nav aria-label="breadcrumb">
diff --git a/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesManage.cshtml b/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesManage.cshtml
index 7d8475a..a13088d 100644
--- a/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesManage.cshtml
+++ b/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesManage.cshtml
@@ -3,7 +3,8 @@
@{
var storeId = Context.GetStoreData().Id;
bool isEdit = Model.Trigger != null;
- ViewData.SetActivePage(StoreNavPages.Emails, StringLocalizer[isEdit ? "Edit Email Rule" : "Create Email Rule"], storeId);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Emails), StringLocalizer[isEdit ? "Edit Email Rule" : "Create Email Rule"])
+ .SetCategory(WellKnownCategories.Store));
}
@section PageHeadContent {
diff --git a/BTCPayServer/Plugins/Emails/Views/UIStoresEmail/StoreEmailSettings.cshtml b/BTCPayServer/Plugins/Emails/Views/UIStoresEmail/StoreEmailSettings.cshtml
index d798da4..c6411a9 100644
--- a/BTCPayServer/Plugins/Emails/Views/UIStoresEmail/StoreEmailSettings.cshtml
+++ b/BTCPayServer/Plugins/Emails/Views/UIStoresEmail/StoreEmailSettings.cshtml
@@ -4,7 +4,8 @@
@model BTCPayServer.Models.EmailsViewModel
@{
var storeId = Context.GetStoreData().Id;
- ViewData.SetActivePage(StoreNavPages.Emails, StringLocalizer["Email Rules"], storeId);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Emails), StringLocalizer["Email Rules"])
+ .SetCategory(WellKnownCategories.Store));
}
<form method="post" autocomplete="off" permissioned="@Policies.CanModifyStoreSettings">
diff --git a/BTCPayServer/Plugins/PointOfSale/Models/UpdatePointOfSaleViewModel.cs b/BTCPayServer/Plugins/PointOfSale/Models/UpdatePointOfSaleViewModel.cs
index 29b2e79..04d60c9 100644
--- a/BTCPayServer/Plugins/PointOfSale/Models/UpdatePointOfSaleViewModel.cs
+++ b/BTCPayServer/Plugins/PointOfSale/Models/UpdatePointOfSaleViewModel.cs
@@ -79,7 +79,6 @@ namespace BTCPayServer.Plugins.PointOfSale.Models
[Display(Name = "Redirect invoice to redirect url automatically after paid")]
public string RedirectAutomatically { get; set; } = string.Empty;
- public string AppId { get; set; }
public string SearchTerm { get; set; }
public SelectList RedirectAutomaticallySelectList =>
diff --git a/BTCPayServer/Plugins/Subscriptions/Controllers/UIOfferingController.cs b/BTCPayServer/Plugins/Subscriptions/Controllers/UIOfferingController.cs
index b714b4c..5b69ecb 100644
--- a/BTCPayServer/Plugins/Subscriptions/Controllers/UIOfferingController.cs
+++ b/BTCPayServer/Plugins/Subscriptions/Controllers/UIOfferingController.cs
@@ -45,7 +45,6 @@ public partial class UIOfferingController(
BTCPayServerEnvironment env,
DisplayFormatter displayFormatter,
EmailSenderFactory emailSenderFactory,
- IHtmlHelper htmlHelper,
IEnumerable<EmailTriggerViewModel> emailTriggers
) : UISubscriptionControllerBase(dbContextFactory, linkGenerator, stringLocalizer, subsService)
{
diff --git a/BTCPayServer/Plugins/Subscriptions/Views/NavExtension.cshtml b/BTCPayServer/Plugins/Subscriptions/Views/NavExtension.cshtml
index fd3ad27..0f98530 100644
--- a/BTCPayServer/Plugins/Subscriptions/Views/NavExtension.cshtml
+++ b/BTCPayServer/Plugins/Subscriptions/Views/NavExtension.cshtml
@@ -16,14 +16,14 @@
var appType = SubscriptionsAppType.AppType;
var apps = Model.Apps.Where(app => app.AppType == appType).ToList();
<li class="nav-item" permission="@Policies.CanModifyMembership">
- <a asp-area="Subscriptions" asp- asp-controller="UIOffering" asp-action="CreateOffering" asp-route-storeId="@store.Id" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Create, appType)" id="@($"StoreNav-Create{appType}")">
+ <a layout-menu-item="@nameof(SubscriptionsPlugin)" asp-area="Subscriptions" asp- asp-controller="UIOffering" asp-action="CreateOffering" asp-route-storeId="@store.Id">
<vc:icon symbol="nav-reporting" />
<span text-translate="true">Subscriptions</span>
</a>
</li>
@if (apps.Any())
{
- <li class="nav-item" not-permission="@Policies.CanModifyMembership" permission="@Policies.CanViewStoreSettings">
+ <li layout-menu-item="@nameof(SubscriptionsPlugin)" not-permission="@Policies.CanModifyMembership" permission="@Policies.CanViewStoreSettings">
<span class="nav-link">
<vc:icon symbol="nav-reporting" />
<span text-translate="true">Subscriptions</span>
@@ -35,12 +35,12 @@
var offeringId = app.Data.GetSettings<SubscriptionsAppType.AppConfig>().OfferingId ?? "";
<li class="nav-item nav-item-sub" permission="@Policies.CanViewMembership">
- <a asp-area="Subscriptions" asp-controller="UIOffering" asp-action="Offering" asp-route-storeId="@Model.Store.Id" asp-route-offeringId="@offeringId" asp-route-section="Plans" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Update, @offeringId)" id="@($"StoreNav-Offering-{offeringId}")">
+ <a layout-menu-item="@nameof(SubscriptionsPlugin)-@offeringId" asp-area="Subscriptions" asp-controller="UIOffering" asp-action="Offering" asp-route-storeId="@Model.Store.Id" asp-route-offeringId="@offeringId" asp-route-section="Plans">
<span>@app.AppName</span>
</a>
</li>
<li class="nav-item nav-item-sub" not-permission="@Policies.CanViewMembership">
- <a asp-area="Subscriptions" asp-controller="UIOffering" asp-action="Offering" asp-route-storeId="@Model.Store.Id" asp-route-offeringId="@offeringId" asp-route-section="Plans" class="nav-link">
+ <a layout-menu-item="@nameof(SubscriptionsPlugin)-@offeringId" asp-area="Subscriptions" asp-controller="UIOffering" asp-action="Offering" asp-route-storeId="@Model.Store.Id" asp-route-offeringId="@offeringId" asp-route-section="Plans" class="nav-link">
<span>@app.AppName</span>
</a>
</li>
diff --git a/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/AddPlan.cshtml b/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/AddPlan.cshtml
index 312927a..82fa7e6 100644
--- a/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/AddPlan.cshtml
+++ b/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/AddPlan.cshtml
@@ -1,19 +1,12 @@
-@model AddEditPlanViewModel
+@using BTCPayServer.Plugins.Subscriptions
+@model AddEditPlanViewModel
@{
string storeId = (string)this.Context.GetRouteValue("storeId");
string offeringId = (string)this.Context.GetRouteValue("offeringId");
- string submitLabel = "";
- if (Model.PlanId is null)
- {
- ViewData.SetActivePage(AppsNavPages.Update, StringLocalizer["Add plan"], offeringId);
- submitLabel = StringLocalizer["Create"];
- }
- else
- {
- ViewData.SetActivePage(AppsNavPages.Update, StringLocalizer["Edit plan"], offeringId);
- submitLabel = StringLocalizer["Save"];
- }
+ var title = Model.PlanId is null ? StringLocalizer["Add plan"] : StringLocalizer["Edit plan"];
+ var submitLabel = Model.PlanId is null ? StringLocalizer["Create"] : StringLocalizer["Save"];
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(SubscriptionsPlugin)}-{offeringId}", title));
}
<form method="post">
diff --git a/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/ConfigureOffering.cshtml b/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/ConfigureOffering.cshtml
index f129324..78b2a94 100644
--- a/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/ConfigureOffering.cshtml
+++ b/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/ConfigureOffering.cshtml
@@ -1,12 +1,12 @@
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Client
@using BTCPayServer.Controllers
+@using BTCPayServer.Plugins.Subscriptions
@model ConfigureOfferingViewModel
@{
string offeringId = (string)this.Context.GetRouteValue("offeringId");
- ViewData.SetActivePage(AppsNavPages.Update, StringLocalizer["Configure offering"], offeringId);
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(SubscriptionsPlugin)}-{offeringId}", StringLocalizer["Configure offering"]));
string storeId = (string)this.Context.GetRouteValue("storeId");
var deleteModal = new ConfirmModel(StringLocalizer["Delete offering"], StringLocalizer["This offering will be removed from this store."], StringLocalizer["Delete"])
{
diff --git a/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/CreateOffering.cshtml b/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/CreateOffering.cshtml
index 4cf6e14..a255ea2 100644
--- a/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/CreateOffering.cshtml
+++ b/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/CreateOffering.cshtml
@@ -1,8 +1,9 @@
-@using BTCPayServer.Services
+@using BTCPayServer.Plugins.Subscriptions
+@using BTCPayServer.Services
@model CreateOfferingViewModel
@{
- ViewData.SetActivePage(StoreNavPages.Subscriptions, StringLocalizer["New offering"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(SubscriptionsPlugin), StringLocalizer["New offering"]));
}
<form method="post">
diff --git a/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/Offering.cshtml b/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/Offering.cshtml
index 2ae002e..7950e1d 100644
--- a/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/Offering.cshtml
+++ b/BTCPayServer/Plugins/Subscriptions/Views/UIOffering/Offering.cshtml
@@ -1,7 +1,6 @@
-@using BTCPayServer.Abstractions.Models
-@using BTCPayServer.Client
-@using BTCPayServer.Controllers
+@using BTCPayServer.Client
@using BTCPayServer.Plugins.Emails
+@using BTCPayServer.Plugins.Subscriptions
@using BTCPayServer.Plugins.Subscriptions.Controllers
@using BTCPayServer.Services
@model SubscriptionsViewModel
@@ -11,7 +10,7 @@
@{
string storeId = (string)this.Context.GetRouteValue("storeId");
string offeringId = (string)this.Context.GetRouteValue("offeringId");
- ViewData.SetActivePage(AppsNavPages.Update, StringLocalizer["Subscriptions"], offeringId);
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(SubscriptionsPlugin)}-{offeringId}", StringLocalizer["Subscriptions"]));
Csp.UnsafeEval();
}
diff --git a/BTCPayServer/Plugins/Webhooks/Views/ModifyWebhook.cshtml b/BTCPayServer/Plugins/Webhooks/Views/ModifyWebhook.cshtml
index 9c385d8..3093b42 100644
--- a/BTCPayServer/Plugins/Webhooks/Views/ModifyWebhook.cshtml
+++ b/BTCPayServer/Plugins/Webhooks/Views/ModifyWebhook.cshtml
@@ -2,7 +2,7 @@
@inject IEnumerable<AvailableWebhookViewModel> Webhooks
@{
var storeId = Context.GetStoreData().Id;
- ViewData.SetActivePage(StoreNavPages.Webhooks, StringLocalizer["Webhook"], storeId);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Webhooks), StringLocalizer["Webhooks"]).SetCategory(WellKnownCategories.Store));
}
@section PageHeadContent {
diff --git a/BTCPayServer/Plugins/Webhooks/Views/Webhooks.cshtml b/BTCPayServer/Plugins/Webhooks/Views/Webhooks.cshtml
index 380b4b6..2f8c316 100644
--- a/BTCPayServer/Plugins/Webhooks/Views/Webhooks.cshtml
+++ b/BTCPayServer/Plugins/Webhooks/Views/Webhooks.cshtml
@@ -1,8 +1,7 @@
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Client
@model WebhooksViewModel
@{
- ViewData.SetActivePage(StoreNavPages.Webhooks, StringLocalizer["Webhooks"], Context.GetStoreData().Id);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Webhooks), StringLocalizer["Webhooks"]).SetCategory(WellKnownCategories.Store));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/Shared/CreateOrEditRole.cshtml b/BTCPayServer/Views/Shared/CreateOrEditRole.cshtml
index 5f248ba..4b9c16e 100644
--- a/BTCPayServer/Views/Shared/CreateOrEditRole.cshtml
+++ b/BTCPayServer/Views/Shared/CreateOrEditRole.cshtml
@@ -13,10 +13,8 @@
var storeId = Context.GetRouteValue("storeId") as string;
var title = role is null ? StringLocalizer["Create role"] : StringLocalizer["Update Role"];
- if (storeId is null)
- ViewData.SetActivePage(ServerNavPages.Roles, title);
- else
- ViewData.SetActivePage(StoreNavPages.Roles, title, storeId);
+ var category = storeId is null ? WellKnownCategories.Server : WellKnownCategories.Store;
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Roles), title).SetCategory(category));
var storePolicies = Policies.AllPolicies.Where(Policies.IsStorePolicy).ToArray();
}
@@ -103,7 +101,7 @@
const { checked, value: policy } = element;
const policySelect = document.getElementById('Policies');
const subPolicies = element.parentElement.querySelectorAll(`.list-group .policy-cb:not([value="${policy}"])`);
-
+
policySelect.querySelector(`option[value="${policy}"]`).selected = checked;
subPolicies.forEach(subPolicy => {
subPolicy.checked = checked? false : subPolicy.checked;
@@ -115,12 +113,12 @@
policySelect.querySelector(`option[value="${subPolicy.value}"]`).selected = subPolicy.checked;
});
}
-
+
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll(".policy-cb:checked").forEach(handleCheckboxChange);
-
+
delegate('change', '.policy-cb', event => {
handleCheckboxChange(event.target);
});
- });
+ });
</script>
diff --git a/BTCPayServer/Views/Shared/Crowdfund/NavExtension.cshtml b/BTCPayServer/Views/Shared/Crowdfund/NavExtension.cshtml
index 4f92c2c..3204cc1 100644
--- a/BTCPayServer/Views/Shared/Crowdfund/NavExtension.cshtml
+++ b/BTCPayServer/Views/Shared/Crowdfund/NavExtension.cshtml
@@ -14,14 +14,14 @@
var appType = AppService.GetAppType(CrowdfundAppType.AppType)!;
var apps = Model.Apps.Where(app => app.AppType == appType.Type).ToList();
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
- <a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")">
+ <a layout-menu-item="CreateApp-@appType.Type" asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type">
<vc:icon symbol="nav-crowdfund" />
<span text-translate="true">Crowdfund</span>
</a>
</li>
@if (apps.Any())
{
- <li class="nav-item" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings">
+ <li layout-menu-item="CreateApp-@appType.Type" class="nav-item" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings">
<span class="nav-link">
<vc:icon symbol="nav-crowdfund" />
<span text-translate="true">Crowdfund</span>
@@ -31,12 +31,12 @@
@foreach (var app in apps)
{
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a asp-area="" asp-controller="UICrowdfund" asp-action="UpdateCrowdfund" asp-route-appId="@app.Id" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Update, app.Id)" id="@($"StoreNav-App-{app.Id}")">
+ <a layout-menu-item="@nameof(CrowdfundPlugin)-@app.Id" asp-area="" asp-controller="UICrowdfund" asp-action="UpdateCrowdfund" asp-route-appId="@app.Id">
<span>@app.AppName</span>
</a>
</li>
<li class="nav-item nav-item-sub" not-permission="@Policies.CanViewStoreSettings">
- <a asp-area="" asp-controller="UICrowdfund" asp-action="ViewCrowdfund" asp-route-appId="@app.Id" class="nav-link">
+ <a layout-menu-item="@nameof(CrowdfundPlugin)-@app.Id" asp-area="" asp-controller="UICrowdfund" asp-action="ViewCrowdfund" asp-route-appId="@app.Id">
<span>@app.AppName</span>
</a>
</li>
diff --git a/BTCPayServer/Views/Shared/Crowdfund/UpdateCrowdfund.cshtml b/BTCPayServer/Views/Shared/Crowdfund/UpdateCrowdfund.cshtml
index 333ce17..462b890 100644
--- a/BTCPayServer/Views/Shared/Crowdfund/UpdateCrowdfund.cshtml
+++ b/BTCPayServer/Views/Shared/Crowdfund/UpdateCrowdfund.cshtml
@@ -1,17 +1,18 @@
@using System.Globalization
@using BTCPayServer.Abstractions.Contracts
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Client
@using BTCPayServer.TagHelpers
@using BTCPayServer.Views.Apps
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using BTCPayServer.Forms
+@using BTCPayServer.Plugins.Crowdfund
@inject FormDataService FormDataService
@inject IFileService FileService
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
@model BTCPayServer.Plugins.Crowdfund.Models.UpdateCrowdfundViewModel
@{
- ViewData.SetActivePage(AppsNavPages.Update, StringLocalizer["Update Crowdfund"], Model.AppId);
+ // layout-menu-item="@nameof(CrowdfundPlugin)-@app.Id"
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(CrowdfundPlugin)}-{Model.AppId}", StringLocalizer["Update Crowdfund"]));
Csp.UnsafeEval();
var canUpload = await FileService.IsAvailable();
var checkoutFormOptions = await FormDataService.GetSelect(Model.StoreId, Model.FormId);
diff --git a/BTCPayServer/Views/Shared/LNURL/LightningAddressNav.cshtml b/BTCPayServer/Views/Shared/LNURL/LightningAddressNav.cshtml
index 18320c8..b17fd03 100644
--- a/BTCPayServer/Views/Shared/LNURL/LightningAddressNav.cshtml
+++ b/BTCPayServer/Views/Shared/LNURL/LightningAddressNav.cshtml
@@ -8,7 +8,7 @@
@if (store.IsLightningEnabled(cryptoCode) && store.IsLNUrlEnabled(cryptoCode))
{
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
- <a asp-area="" asp-controller="UILNURL" asp-action="EditLightningAddress" asp-route-storeId="@store.Id" class="nav-link @ViewData.ActivePageClass("LightningAddress", nameof(StoreNavPages))" id="StoreNav-LightningAddress">
+ <a layout-menu-item="LightningAddress" asp-area="" asp-controller="UILNURL" asp-action="EditLightningAddress" asp-route-storeId="@store.Id">
<vc:icon symbol="nav-lightning-address "/>
<span text-translate="true">Lightning Address</span>
</a>
diff --git a/BTCPayServer/Views/Shared/ListRoles.cshtml b/BTCPayServer/Views/Shared/ListRoles.cshtml
index 5c04555..22926bc 100644
--- a/BTCPayServer/Views/Shared/ListRoles.cshtml
+++ b/BTCPayServer/Views/Shared/ListRoles.cshtml
@@ -6,10 +6,9 @@
@{
var storeId = Context.GetRouteValue("storeId") as string;
var controller = ViewContext.RouteData.Values["controller"].ToString().TrimEnd("Controller", StringComparison.InvariantCultureIgnoreCase);
- if (string.IsNullOrEmpty(storeId))
- ViewData.SetActivePage(ServerNavPages.Roles, StringLocalizer["Roles"]);
- else
- ViewData.SetActivePage(StoreNavPages.Roles, StringLocalizer["Roles"], storeId);
+ var category = string.IsNullOrEmpty(storeId) ? WellKnownCategories.Server : WellKnownCategories.Store;
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Roles), StringLocalizer["Roles"]).SetCategory(category));
+
var permission = string.IsNullOrEmpty(storeId) ? Policies.CanModifyServerSettings : Policies.CanModifyStoreSettings;
var nextRoleSortOrder = (string) ViewData["NextRoleSortOrder"];
var roleSortOrder = nextRoleSortOrder switch
diff --git a/BTCPayServer/Views/Shared/PayButton/Enable.cshtml b/BTCPayServer/Views/Shared/PayButton/Enable.cshtml
index 9dda162..7f5bed4 100644
--- a/BTCPayServer/Views/Shared/PayButton/Enable.cshtml
+++ b/BTCPayServer/Views/Shared/PayButton/Enable.cshtml
@@ -2,7 +2,7 @@
@using BTCPayServer.Views.Stores
@using Microsoft.AspNetCore.Mvc.TagHelpers
@{
- ViewData.SetActivePage(StoreNavPages.PayButton, StringLocalizer["Pay Button"], Context.GetStoreData().Id);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.PayButton), StringLocalizer["Pay Button"]));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/Shared/PayButton/NavExtension.cshtml b/BTCPayServer/Views/Shared/PayButton/NavExtension.cshtml
index 2e4e523..f7c6775 100644
--- a/BTCPayServer/Views/Shared/PayButton/NavExtension.cshtml
+++ b/BTCPayServer/Views/Shared/PayButton/NavExtension.cshtml
@@ -6,7 +6,7 @@
@if (store != null)
{
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
- <a asp-area="" asp-controller="UIPayButton" asp-action="PayButton" asp-route-storeId="@store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.PayButton)" id="StoreNav-PayButton">
+ <a layout-menu-item="PayButton" asp-area="" asp-controller="UIPayButton" asp-action="PayButton" asp-route-storeId="@store.Id">
<vc:icon symbol="nav-pay-button"/>
<span text-translate="true">Pay Button</span>
</a>
diff --git a/BTCPayServer/Views/Shared/PayButton/PayButton.cshtml b/BTCPayServer/Views/Shared/PayButton/PayButton.cshtml
index a65b761..17a34b5 100644
--- a/BTCPayServer/Views/Shared/PayButton/PayButton.cshtml
+++ b/BTCPayServer/Views/Shared/PayButton/PayButton.cshtml
@@ -3,7 +3,7 @@
@inject BTCPayNetworkProvider NetworkProvider
@model BTCPayServer.Plugins.PayButton.Models.PayButtonViewModel
@{
- ViewData.SetActivePage(StoreNavPages.PayButton, StringLocalizer["Pay Button"], Context.GetStoreData().Id);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.PayButton), StringLocalizer["Pay Button"]));
Csp.UnsafeEval();
}
@@ -74,7 +74,7 @@
const max = parseInt(event.target.getAttribute('max'));
if (event.target.value < min) {
event.target.value = min;
- } else if (event.target.value > max) {
+ } else if (event.target.value > max) {
event.target.value = max;
}
}
@@ -93,11 +93,11 @@
const price = parseInt(el.value);
const min = parseInt(event.target.getAttribute('min')) || 1;
const max = parseInt(event.target.getAttribute('max'));
- if (price < min) {
+ if (price < min) {
el.value = min;
} else if (price > max) {
el.value = max;
- }
+ }
root.querySelector('.btcpay-input-range').value = el.value;
}
function handleSliderInput(event) {
@@ -116,11 +116,11 @@
}
});
</template>
-
+
<script>
window.lnurlEndpoint = @Safe.Json(Url.Action("GetLNUrlForStore", "UILNURL", new
{
- storeId = Model.StoreId,
+ storeId = Model.StoreId,
cryptoCode = NetworkProvider.DefaultNetwork.CryptoCode
}, "lnurlp", Context.Request.Host.ToString()));
const srvModel = @Safe.Json(Model);
@@ -145,7 +145,7 @@
light: '#f5f5f7'
}
}
-
+
},
computed: {
imageUrlRequired() {
@@ -245,7 +245,7 @@
<label for="buttonInlineTextMode" class="form-check-label" text-translate="true">Customize Pay Button Text</label>
</div>
</div>
-
+
<div class="form-group" v-show="buttonInlineTextMode">
<label class="form-label" for="pb-text" text-translate="true">Pay Button Text</label>
<input name="payButtonText" type="text" class="form-control" id="pb-text"
@@ -262,7 +262,7 @@
<div class="form-group mb-4">
<label class="form-label" text-translate="true">Image Size</label>
<div class="btn-group d-flex" role="group">
- <button type="button" class="btn btn-outline-secondary"
+ <button type="button" class="btn btn-outline-secondary"
v-on:click="inputChanges($event, 0)">146 x 40 px</button>
<button type="button" class="btn btn-outline-secondary"
v-on:click="inputChanges($event, 1)">168 x 46 px</button>
@@ -419,7 +419,7 @@
Please fix errors shown in order for code generation to successfully execute.
</div>
</div>
-
+
<div v-if="!srvModel.appIdEndpoint && (previewLink || lnurlLink)">
<h4 class="mt-5 mb-3" text-translate="true">Alternatives</h4>
<p text-translate="true">You can also share the link/LNURL or encode it in a QR code.</p>
@@ -540,7 +540,7 @@
line-height: 35px;
background: #fff;
}
-
+
.btcpay-input-price::-webkit-outer-spin-button,
.btcpay-input-price::-webkit-inner-spin-button {
-webkit-appearance: none;
diff --git a/BTCPayServer/Views/Shared/PointOfSale/NavExtension.cshtml b/BTCPayServer/Views/Shared/PointOfSale/NavExtension.cshtml
index 784c3d7..9ba841c 100644
--- a/BTCPayServer/Views/Shared/PointOfSale/NavExtension.cshtml
+++ b/BTCPayServer/Views/Shared/PointOfSale/NavExtension.cshtml
@@ -14,14 +14,14 @@
var appType = AppService.GetAppType(PointOfSaleAppType.AppType)!;
var apps = Model.Apps.Where(app => app.AppType == appType.Type).ToList();
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
- <a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")">
+ <a layout-menu-item="CreateApp-@appType.Type" asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type">
<vc:icon symbol="nav-pointofsale" />
<span text-translate="true">Point of Sale</span>
</a>
</li>
@if (apps.Any())
{
- <li class="nav-item" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings">
+ <li layout-menu-item="CreateApp-@appType.Type" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings">
<span class="nav-link">
<vc:icon symbol="nav-pointofsale" />
<span text-translate="true">Point of Sale</span>
@@ -31,12 +31,12 @@
@foreach (var app in apps)
{
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
- <a asp-area="" asp-controller="UIPointOfSale" asp-action="UpdatePointOfSale" asp-route-appId="@app.Id" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Update, app.Id)" id="@($"StoreNav-App-{app.Id}")">
+ <a layout-menu-item="@nameof(PointOfSalePlugin)-@app.Id" asp-area="" asp-controller="UIPointOfSale" asp-action="UpdatePointOfSale" asp-route-appId="@app.Id">
<span>@app.AppName</span>
</a>
</li>
<li class="nav-item nav-item-sub" not-permission="@Policies.CanViewStoreSettings">
- <a asp-area="" asp-controller="UIPointOfSale" asp-action="ViewPointOfSale" asp-route-appId="@app.Id" class="nav-link">
+ <a layout-menu-item="@nameof(PointOfSalePlugin)-@app.Id" asp-area="" asp-controller="UIPointOfSale" asp-action="ViewPointOfSale" asp-route-appId="@app.Id">
<span>@app.AppName</span>
</a>
</li>
diff --git a/BTCPayServer/Views/Shared/PointOfSale/UpdatePointOfSale.cshtml b/BTCPayServer/Views/Shared/PointOfSale/UpdatePointOfSale.cshtml
index 7dfea09..dd60132 100644
--- a/BTCPayServer/Views/Shared/PointOfSale/UpdatePointOfSale.cshtml
+++ b/BTCPayServer/Views/Shared/PointOfSale/UpdatePointOfSale.cshtml
@@ -1,4 +1,3 @@
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Views.Apps
@using BTCPayServer.Client
@using BTCPayServer.Plugins.PointOfSale
@@ -9,7 +8,7 @@
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
@model BTCPayServer.Plugins.PointOfSale.Models.UpdatePointOfSaleViewModel
@{
- ViewData.SetActivePage(AppsNavPages.Update, StringLocalizer["Update Point of Sale"], Model.Id);
+ ViewData.SetLayoutModel(new($"{nameof(PointOfSalePlugin)}-{Model.Id}",StringLocalizer["Update Point of Sale"]));
Csp.UnsafeEval();
var checkoutFormOptions = await FormDataService.GetSelect(Model.StoreId, Model.FormId);
var posPath = Url.Action("ViewPointOfSale", "UIPointOfSale", new { appId = Model.Id });
diff --git a/BTCPayServer/Views/Shared/Shopify/NavExtension.cshtml b/BTCPayServer/Views/Shared/Shopify/NavExtension.cshtml
index fc473d4..007d527 100644
--- a/BTCPayServer/Views/Shared/Shopify/NavExtension.cshtml
+++ b/BTCPayServer/Views/Shared/Shopify/NavExtension.cshtml
@@ -8,7 +8,7 @@
@if (store != null)
{
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
- <a asp-area="" asp-controller="UIShopify" asp-action="EditShopify" asp-route-storeId="@store.Id" class="nav-link @ViewData.ActivePageClass("shopify", nameof(StoreNavPages))" id="StoreNav-Shopify">
+ <a layout-menu-item="Shopify" asp-area="" asp-controller="UIShopify" asp-action="EditShopify" asp-route-storeId="@store.Id">
<vc:icon symbol="logo-shopify" />
<span text-translate="true">Shopify</span>
</a>
diff --git a/BTCPayServer/Views/UIApps/CreateApp.cshtml b/BTCPayServer/Views/UIApps/CreateApp.cshtml
index 3529742..a0bcb4b 100644
--- a/BTCPayServer/Views/UIApps/CreateApp.cshtml
+++ b/BTCPayServer/Views/UIApps/CreateApp.cshtml
@@ -1,6 +1,6 @@
@model CreateAppViewModel
@{
- ViewData.SetActivePage(AppsNavPages.Create, StringLocalizer["Create a new {0}", Model.AppType]);
+ ViewData.SetLayoutModel(new($"CreateApp-{Model.AppType}", StringLocalizer["Create a new {0}", Model.AppType]));
}
@section PageFootContent {
diff --git a/BTCPayServer/Views/UIApps/ListApps.cshtml b/BTCPayServer/Views/UIApps/ListApps.cshtml
index 791ef34..711d74d 100644
--- a/BTCPayServer/Views/UIApps/ListApps.cshtml
+++ b/BTCPayServer/Views/UIApps/ListApps.cshtml
@@ -1,10 +1,9 @@
@using BTCPayServer.Services.Apps
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Client
@model ListAppsViewModel
@inject AppService AppService
@{
- ViewData.SetActivePage(AppsNavPages.Index, "Apps");
+ ViewData.SetLayoutModel(new(nameof(AppsNavPages), "Apps"));
var nextAppNameSortOrder = (string)ViewData["AppNameNextSortOrder"];
var nextAppTypeSortOrder = (string)ViewData["AppTypeNextSortOrder"];
var nextStoreNameSortOrder = (string)ViewData["StoreNameNextSortOrder"];
diff --git a/BTCPayServer/Views/UIFido2/Create.cshtml b/BTCPayServer/Views/UIFido2/Create.cshtml
index 45ce3ec..8f40747 100644
--- a/BTCPayServer/Views/UIFido2/Create.cshtml
+++ b/BTCPayServer/Views/UIFido2/Create.cshtml
@@ -1,7 +1,7 @@
@using Newtonsoft.Json.Linq
@model Fido2NetLib.CredentialCreateOptions
@{
- ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, StringLocalizer["Register your security device"]);
+ ViewData.SetLayoutModel(new(nameof(ManageNavPages.TwoFactorAuthentication), StringLocalizer["Register your security device"]));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIForms/FormsList.cshtml b/BTCPayServer/Views/UIForms/FormsList.cshtml
index fa06cac..50d1c3d 100644
--- a/BTCPayServer/Views/UIForms/FormsList.cshtml
+++ b/BTCPayServer/Views/UIForms/FormsList.cshtml
@@ -1,9 +1,8 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Client
@model List<BTCPayServer.Data.FormData>
@{
- ViewData.SetActivePage(StoreNavPages.Forms, StringLocalizer["Forms"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Forms), StringLocalizer["Forms"]).SetCategory(WellKnownCategories.Store));
var storeId = Context.GetCurrentStoreId();
}
diff --git a/BTCPayServer/Views/UIInvoice/CreateInvoice.cshtml b/BTCPayServer/Views/UIInvoice/CreateInvoice.cshtml
index 0305252..2604c96 100644
--- a/BTCPayServer/Views/UIInvoice/CreateInvoice.cshtml
+++ b/BTCPayServer/Views/UIInvoice/CreateInvoice.cshtml
@@ -3,7 +3,7 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using BTCPayServer.Abstractions.TagHelpers
@{
- ViewData.SetActivePage(InvoiceNavPages.Create, StringLocalizer["Create Invoice"]);
+ ViewData.SetLayoutModel(new("Invoices", StringLocalizer["Create Invoices"]));
}
@section PageFootContent {
diff --git a/BTCPayServer/Views/UIInvoice/Invoice.cshtml b/BTCPayServer/Views/UIInvoice/Invoice.cshtml
index 117928f..c62e551 100644
--- a/BTCPayServer/Views/UIInvoice/Invoice.cshtml
+++ b/BTCPayServer/Views/UIInvoice/Invoice.cshtml
@@ -1,7 +1,7 @@
@using BTCPayServer.Client
@model InvoiceDetailsModel
@{
- ViewData["Title"] = StringLocalizer["Invoice {0}", Model.Id];
+ ViewData.SetLayoutModel(new("Invoices", StringLocalizer["Invoice {0}", Model.Id]));
}
@section PageHeadContent {
diff --git a/BTCPayServer/Views/UIInvoice/InvoiceNavPages.cs b/BTCPayServer/Views/UIInvoice/InvoiceNavPages.cs
deleted file mode 100644
index 93a82cd..0000000
--- a/BTCPayServer/Views/UIInvoice/InvoiceNavPages.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace BTCPayServer.Views.Invoice
-{
- public enum InvoiceNavPages
- {
- Index, Create
- }
-}
diff --git a/BTCPayServer/Views/UIInvoice/ListInvoices.cshtml b/BTCPayServer/Views/UIInvoice/ListInvoices.cshtml
index a03a255..0feb767 100644
--- a/BTCPayServer/Views/UIInvoice/ListInvoices.cshtml
+++ b/BTCPayServer/Views/UIInvoice/ListInvoices.cshtml
@@ -5,7 +5,7 @@
@inject DisplayFormatter DisplayFormatter
@model InvoicesModel
@{
- ViewData.SetActivePage(InvoiceNavPages.Index, StringLocalizer["Invoices"]);
+ ViewData.SetLayoutModel(new("Invoices", StringLocalizer["Invoices"]));
var statusFilterCount = CountArrayFilter("status") + CountArrayFilter("exceptionstatus") + (HasBooleanFilter("includearchived") ? 1 : 0) + (HasBooleanFilter("unusual") ? 1 : 0);
var hasDateFilter = HasArrayFilter("startdate") || HasArrayFilter("enddate");
var appFilterCount = Model.Apps.Count(app => HasArrayFilter("appid", app.Id));
diff --git a/BTCPayServer/Views/UIInvoice/_ViewImports.cshtml b/BTCPayServer/Views/UIInvoice/_ViewImports.cshtml
index 7aca28a..8099a8a 100644
--- a/BTCPayServer/Views/UIInvoice/_ViewImports.cshtml
+++ b/BTCPayServer/Views/UIInvoice/_ViewImports.cshtml
@@ -1,3 +1,2 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Services.Invoices
-@using BTCPayServer.Views.Invoice
diff --git a/BTCPayServer/Views/UIInvoice/_ViewStart.cshtml b/BTCPayServer/Views/UIInvoice/_ViewStart.cshtml
deleted file mode 100644
index e48d5fe..0000000
--- a/BTCPayServer/Views/UIInvoice/_ViewStart.cshtml
+++ /dev/null
@@ -1,6 +0,0 @@
-@using BTCPayServer.Abstractions.Extensions
-@using BTCPayServer.Views
-@using BTCPayServer.Views.Invoice
-@{
- ViewData.SetActiveCategory(typeof(InvoiceNavPages));
-}
diff --git a/BTCPayServer/Views/UILNURL/EditLightningAddress.cshtml b/BTCPayServer/Views/UILNURL/EditLightningAddress.cshtml
index 3d0bf83..ba393b3 100644
--- a/BTCPayServer/Views/UILNURL/EditLightningAddress.cshtml
+++ b/BTCPayServer/Views/UILNURL/EditLightningAddress.cshtml
@@ -1,8 +1,7 @@
@using BTCPayServer.Views.Stores
-@using BTCPayServer.Abstractions.Models
@model UILNURLController.EditLightningAddressVM
@{
- ViewData.SetActivePage("LightningAddress", nameof(StoreNavPages), StringLocalizer["Lightning Address"], Context.GetStoreData().Id);
+ ViewData.SetLayoutModel(new LayoutModel("LightningAddress", StringLocalizer["Lightning Address"]).SetCategory(WellKnownCategories.Store));
}
@section PageHeadContent {
diff --git a/BTCPayServer/Views/UILNURLAuth/Create.cshtml b/BTCPayServer/Views/UILNURLAuth/Create.cshtml
index 67a114e..b346288 100644
--- a/BTCPayServer/Views/UILNURLAuth/Create.cshtml
+++ b/BTCPayServer/Views/UILNURLAuth/Create.cshtml
@@ -1,7 +1,7 @@
@using LNURL
@model Uri
@{
- ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, StringLocalizer["Register your Lightning node for LNURL Auth"]);
+ ViewData.SetLayoutModel(new(nameof(ManageNavPages.TwoFactorAuthentication), StringLocalizer["Register your Lightning node for LNURL Auth"]));
var formats = new Dictionary<string, string>
{
{ "Bech32", LNURL.EncodeUri(Model, "login", true).ToString().ToUpperInvariant() },
diff --git a/BTCPayServer/Views/UILightningAutomatedPayoutProcessors/Configure.cshtml b/BTCPayServer/Views/UILightningAutomatedPayoutProcessors/Configure.cshtml
index bca140b..42377bf 100644
--- a/BTCPayServer/Views/UILightningAutomatedPayoutProcessors/Configure.cshtml
+++ b/BTCPayServer/Views/UILightningAutomatedPayoutProcessors/Configure.cshtml
@@ -4,7 +4,7 @@
@model BTCPayServer.PayoutProcessors.Lightning.UILightningAutomatedPayoutProcessorsController.LightningTransferViewModel
@{
var storeId = Context.GetStoreData().Id;
- ViewData.SetActivePage(StoreNavPages.PayoutProcessors, StringLocalizer["Lightning Payout Processor"], storeId);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.PayoutProcessors), StringLocalizer["Lightning Payout Processor"]));
}
<form method="post" permissioned="@Policies.CanModifyStoreSettings">
diff --git a/BTCPayServer/Views/UIManage/APIKeys.cshtml b/BTCPayServer/Views/UIManage/APIKeys.cshtml
index c5e26e3..f608676 100644
--- a/BTCPayServer/Views/UIManage/APIKeys.cshtml
+++ b/BTCPayServer/Views/UIManage/APIKeys.cshtml
@@ -1,5 +1,4 @@
@namespace BTCPayServer.Client
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Abstractions.TagHelpers
@using BTCPayServer.TagHelpers
@using Microsoft.AspNetCore.Html
@@ -7,7 +6,8 @@
@inject Security.ContentSecurityPolicies Csp
@model BTCPayServer.Controllers.UIManageController.ApiKeysViewModel
@{
- ViewData.SetActivePage(ManageNavPages.APIKeys, StringLocalizer["API Keys"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.APIKeys), StringLocalizer["API Keys"])
+ .SetCategory(nameof(ManageNavPages)));
Csp.UnsafeEval();
}
diff --git a/BTCPayServer/Views/UIManage/AddApiKey.cshtml b/BTCPayServer/Views/UIManage/AddApiKey.cshtml
index d12abed..b4a6d7f 100644
--- a/BTCPayServer/Views/UIManage/AddApiKey.cshtml
+++ b/BTCPayServer/Views/UIManage/AddApiKey.cshtml
@@ -3,7 +3,8 @@
@model UIManageController.AddApiKeyViewModel
@{
- ViewData.SetActivePage(ManageNavPages.APIKeys, StringLocalizer["Generate API Key"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.APIKeys), StringLocalizer["Generate API Key"])
+ .SetCategory(nameof(ManageNavPages)));
}
@section PageHeadContent {
@@ -50,7 +51,7 @@
<input asp-for="Label" class="form-control"/>
<span asp-validation-for="Label" class="text-danger"></span>
</div>
-
+
<h5 class="mt-4 mb-3">Permissions</h5>
<div class="list-group mb-4">
@for (int i = 0; i < Model.PermissionValues.Count; i++)
@@ -92,7 +93,7 @@
</h5>
<div class="text-muted">@Model.PermissionValues[i].Description</div>
<button type="submit" class="btn btn-link p-0" name="command" value="@($"{Model.PermissionValues[i].Permission}:change-store-mode")">Give permission to all stores instead</button>
-
+
@if (!Model.Stores.Any())
{
<p class="info-note text-warning mt-2 mb-0">
@@ -138,7 +139,7 @@
<span asp-validation-for="PermissionValues[i].Value" class="text-danger"></span>
<span class="text-muted">@Model.PermissionValues[i].Description</span>
</div>
- </div>
+ </div>
}
</div>
}
diff --git a/BTCPayServer/Views/UIManage/AuthorizeAPIKey.cshtml b/BTCPayServer/Views/UIManage/AuthorizeAPIKey.cshtml
index 5408f55..22240d8 100644
--- a/BTCPayServer/Views/UIManage/AuthorizeAPIKey.cshtml
+++ b/BTCPayServer/Views/UIManage/AuthorizeAPIKey.cshtml
@@ -6,7 +6,7 @@
var store = string.IsNullOrEmpty(Model.StoreId) ? null : Model.Stores.FirstOrDefault(s => s.Id == Model.StoreId);
var permissions = Model.Permissions?.Split(';') ?? Array.Empty<string>();
var groupedPermissions = Permission.ToPermissions(permissions).GroupBy(permission => permission.Policy);
- ViewData["Title"] = $"Authorize {displayName ?? "Application"}";
+ ViewData.SetTitle($"Authorize {displayName ?? "Application"}");
Layout = "_LayoutWizard";
}
@@ -73,20 +73,20 @@
else
{
<input type="hidden" asp-for="StoreId" class="form-select"/>
-
+
@if (Model.RedirectUrl != null)
{
<p class="alert alert-info mb-4">
<span text-translate="true">If authorized, the generated API key will be provided to</span> <strong>@Model.RedirectUrl.AbsoluteUri</strong>
</p>
}
-
+
<div class="form-group">
<label asp-for="Label" class="form-label"></label>
<input asp-for="Label" class="form-control"/>
<span asp-validation-for="Label" class="text-danger"></span>
</div>
-
+
<h2 class="h5 fw-semibold mt-4" text-translate="true">Permissions</h2>
@if (!groupedPermissions.Any())
{
diff --git a/BTCPayServer/Views/UIManage/ChangePassword.cshtml b/BTCPayServer/Views/UIManage/ChangePassword.cshtml
index d3c6161..14153ab 100644
--- a/BTCPayServer/Views/UIManage/ChangePassword.cshtml
+++ b/BTCPayServer/Views/UIManage/ChangePassword.cshtml
@@ -1,6 +1,7 @@
@model ChangePasswordViewModel
@{
- ViewData.SetActivePage(ManageNavPages.ChangePassword, StringLocalizer["Change your password"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.ChangePassword), StringLocalizer["Change your password"])
+ .SetCategory(nameof(ManageNavPages)));
}
<form method="post">
diff --git a/BTCPayServer/Views/UIManage/ConfirmAPIKey.cshtml b/BTCPayServer/Views/UIManage/ConfirmAPIKey.cshtml
index 23bf420..92db043 100644
--- a/BTCPayServer/Views/UIManage/ConfirmAPIKey.cshtml
+++ b/BTCPayServer/Views/UIManage/ConfirmAPIKey.cshtml
@@ -2,7 +2,7 @@
@{
var displayName = Model.ApplicationName ?? Model.ApplicationIdentifier;
- ViewData["Title"] = $"Authorize {displayName ?? "Application"}";
+ ViewData.SetTitle($"Authorize {displayName ?? "Application"}");
Layout = "_LayoutWizard";
}
diff --git a/BTCPayServer/Views/UIManage/EnableAuthenticator.cshtml b/BTCPayServer/Views/UIManage/EnableAuthenticator.cshtml
index 49efb24..71c3b56 100644
--- a/BTCPayServer/Views/UIManage/EnableAuthenticator.cshtml
+++ b/BTCPayServer/Views/UIManage/EnableAuthenticator.cshtml
@@ -5,7 +5,8 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
@model EnableAuthenticatorViewModel
@{
- ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, StringLocalizer["Enable Authenticator App"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.TwoFactorAuthentication), StringLocalizer["Enable Authenticator App"])
+ .SetCategory(nameof(ManageNavPages)));
}
<div class="sticky-header">
<nav aria-label="breadcrumb">
@@ -59,7 +60,7 @@
<span text-translate="true">Your two-factor authenticator app will provide you with a unique code.</span>
<br/>
<span text-translate="true">Enter the code in the confirmation box below.</span>
- </p>
+ </p>
<form method="post">
<input asp-for="AuthenticatorUri" type="hidden" />
<input asp-for="SharedKey" type="hidden" />
diff --git a/BTCPayServer/Views/UIManage/GenerateRecoveryCodes.cshtml b/BTCPayServer/Views/UIManage/GenerateRecoveryCodes.cshtml
index c925601..5d63c8e 100644
--- a/BTCPayServer/Views/UIManage/GenerateRecoveryCodes.cshtml
+++ b/BTCPayServer/Views/UIManage/GenerateRecoveryCodes.cshtml
@@ -1,6 +1,7 @@
@model GenerateRecoveryCodesViewModel
@{
- ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, StringLocalizer["Recovery codes"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.TwoFactorAuthentication), StringLocalizer["Recovery codes"])
+ .SetCategory(nameof(ManageNavPages)));
}
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2>
diff --git a/BTCPayServer/Views/UIManage/Index.cshtml b/BTCPayServer/Views/UIManage/Index.cshtml
index b546ae0..2ddf2af 100644
--- a/BTCPayServer/Views/UIManage/Index.cshtml
+++ b/BTCPayServer/Views/UIManage/Index.cshtml
@@ -1,10 +1,10 @@
@using BTCPayServer.Abstractions.Contracts
-@using BTCPayServer.Abstractions.Models
@using Microsoft.AspNetCore.Mvc.TagHelpers
@inject IFileService FileService
@model IndexViewModel
@{
- ViewData.SetActivePage(ManageNavPages.Index, StringLocalizer["Update your account"]);
+ ViewData.SetLayoutModel(new LayoutModel("Account", StringLocalizer["Update your account"])
+ .SetCategory(nameof(ManageNavPages)));
var canUpload = await FileService.IsAvailable();
}
diff --git a/BTCPayServer/Views/UIManage/LoginCodes.cshtml b/BTCPayServer/Views/UIManage/LoginCodes.cshtml
index 6f7c1a9..40a88f6 100644
--- a/BTCPayServer/Views/UIManage/LoginCodes.cshtml
+++ b/BTCPayServer/Views/UIManage/LoginCodes.cshtml
@@ -1,6 +1,7 @@
@inject UserManager<ApplicationUser> UserManager;
@{
- ViewData.SetActivePage(ManageNavPages.LoginCodes, StringLocalizer["Login Codes"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.LoginCodes), StringLocalizer["Login Codes"])
+ .SetCategory(nameof(ManageNavPages)));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIManage/NotificationSettings.cshtml b/BTCPayServer/Views/UIManage/NotificationSettings.cshtml
index 010189e..530537c 100644
--- a/BTCPayServer/Views/UIManage/NotificationSettings.cshtml
+++ b/BTCPayServer/Views/UIManage/NotificationSettings.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Controllers.UIManageController.NotificationSettingsViewModel
@{
- ViewData.SetActivePage(ManageNavPages.Notifications, StringLocalizer["Notification Settings"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.Notifications), StringLocalizer["Notification Settings"])
+ .SetCategory(nameof(ManageNavPages)));
}
<form method="post" asp-action="NotificationSettings">
diff --git a/BTCPayServer/Views/UIManage/SetPassword.cshtml b/BTCPayServer/Views/UIManage/SetPassword.cshtml
index 03e9472..d0b5891 100644
--- a/BTCPayServer/Views/UIManage/SetPassword.cshtml
+++ b/BTCPayServer/Views/UIManage/SetPassword.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Models.ManageViewModels.SetPasswordViewModel
@{
- ViewData.SetActivePage(ManageNavPages.ChangePassword, StringLocalizer["Set your password"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.ChangePassword), StringLocalizer["Set your password"])
+ .SetCategory(nameof(ManageNavPages)));
}
<form method="post">
diff --git a/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml b/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml
index e6984e2..ddfa063 100644
--- a/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml
+++ b/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml
@@ -1,7 +1,7 @@
-@using BTCPayServer.Abstractions.Models
@model TwoFactorAuthenticationViewModel
@{
- ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, StringLocalizer["Two-Factor Authentication"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.TwoFactorAuthentication), StringLocalizer["Two-Factor Authentication"])
+ .SetCategory(nameof(ManageNavPages)));
}
<div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2>
diff --git a/BTCPayServer/Views/UIOnChainAutomatedPayoutProcessors/Configure.cshtml b/BTCPayServer/Views/UIOnChainAutomatedPayoutProcessors/Configure.cshtml
index 0ec84db..ea22639 100644
--- a/BTCPayServer/Views/UIOnChainAutomatedPayoutProcessors/Configure.cshtml
+++ b/BTCPayServer/Views/UIOnChainAutomatedPayoutProcessors/Configure.cshtml
@@ -5,7 +5,7 @@
@{
var storeId = Context.GetStoreData().Id;
var cryptoCode = Context.GetRouteValue("cryptocode")?.ToString();
- ViewData.SetActivePage(StoreNavPages.PayoutProcessors, StringLocalizer["On-Chain Payout Processor"], storeId);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.PayoutProcessors), StringLocalizer["On-Chain Payout Processor"]));
}
<form method="post" permissioned="@Policies.CanModifyStoreSettings">
diff --git a/BTCPayServer/Views/UIPaymentRequest/EditPaymentRequest.cshtml b/BTCPayServer/Views/UIPaymentRequest/EditPaymentRequest.cshtml
index 0ba212c..640d255 100644
--- a/BTCPayServer/Views/UIPaymentRequest/EditPaymentRequest.cshtml
+++ b/BTCPayServer/Views/UIPaymentRequest/EditPaymentRequest.cshtml
@@ -11,8 +11,7 @@
@model BTCPayServer.Models.PaymentRequestViewModels.UpdatePaymentRequestViewModel
@{
var checkoutFormOptions = await FormDataService.GetSelect(Model.StoreId, Model.FormId);
-
- ViewData.SetActivePage(PaymentRequestsNavPages.Create, string.IsNullOrEmpty(Model.Id) ? StringLocalizer["Create Payment Request"] : StringLocalizer["Edit Payment Request"], Model.Id);
+ ViewData.SetLayoutModel(new LayoutModel("PaymentRequests", string.IsNullOrEmpty(Model.Id) ? StringLocalizer["Create Payment Request"] : StringLocalizer["Edit Payment Request"]));
}
@section PageHeadContent {
diff --git a/BTCPayServer/Views/UIPaymentRequest/GetPaymentRequests.cshtml b/BTCPayServer/Views/UIPaymentRequest/GetPaymentRequests.cshtml
index 6ba32df..1795fa5 100644
--- a/BTCPayServer/Views/UIPaymentRequest/GetPaymentRequests.cshtml
+++ b/BTCPayServer/Views/UIPaymentRequest/GetPaymentRequests.cshtml
@@ -9,7 +9,7 @@
@model BTCPayServer.Models.PaymentRequestViewModels.ListPaymentRequestsViewModel
@{
Layout = "_Layout";
- ViewData["Title"] = ViewLocalizer["Payment Requests"];
+ ViewData.SetLayoutModel(new("PaymentRequests", StringLocalizer["Payment Requests"]));
var storeId = Context.GetStoreData().Id;
var statusFilterCount = CountArrayFilter("status") + (HasBooleanFilter("includearchived") ? 1 : 0);
}
diff --git a/BTCPayServer/Views/UIPaymentRequest/PaymentRequestsNavPages.cs b/BTCPayServer/Views/UIPaymentRequest/PaymentRequestsNavPages.cs
deleted file mode 100644
index 23c5995..0000000
--- a/BTCPayServer/Views/UIPaymentRequest/PaymentRequestsNavPages.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace BTCPayServer.Views.PaymentRequest
-{
- public enum PaymentRequestsNavPages
- {
- Index, Create
- }
-}
diff --git a/BTCPayServer/Views/UIPaymentRequest/_ViewImports.cshtml b/BTCPayServer/Views/UIPaymentRequest/_ViewImports.cshtml
index 76a727f..b1f16b1 100644
--- a/BTCPayServer/Views/UIPaymentRequest/_ViewImports.cshtml
+++ b/BTCPayServer/Views/UIPaymentRequest/_ViewImports.cshtml
@@ -1,2 +1 @@
@using BTCPayServer.Abstractions.Extensions
-@using BTCPayServer.Views.PaymentRequest
diff --git a/BTCPayServer/Views/UIPaymentRequest/_ViewStart.cshtml b/BTCPayServer/Views/UIPaymentRequest/_ViewStart.cshtml
deleted file mode 100644
index 8a17787..0000000
--- a/BTCPayServer/Views/UIPaymentRequest/_ViewStart.cshtml
+++ /dev/null
@@ -1,6 +0,0 @@
-@using BTCPayServer.Abstractions.Extensions
-@using BTCPayServer.Views
-@using BTCPayServer.Views.PaymentRequest
-@{
- ViewData.SetActiveCategory(typeof(PaymentRequestsNavPages));
-}
diff --git a/BTCPayServer/Views/UIPayoutProcessors/ConfigureStorePayoutProcessors.cshtml b/BTCPayServer/Views/UIPayoutProcessors/ConfigureStorePayoutProcessors.cshtml
index 4c96672..847a8fe 100644
--- a/BTCPayServer/Views/UIPayoutProcessors/ConfigureStorePayoutProcessors.cshtml
+++ b/BTCPayServer/Views/UIPayoutProcessors/ConfigureStorePayoutProcessors.cshtml
@@ -1,11 +1,10 @@
@using BTCPayServer.Views.Stores
@using Microsoft.AspNetCore.Mvc.TagHelpers
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Client
@model List<BTCPayServer.PayoutProcessors.UIPayoutProcessorsController.StorePayoutProcessorsView>
@{
var storeId = Context.GetStoreData().Id;
- ViewData.SetActivePage(StoreNavPages.PayoutProcessors, StringLocalizer["Payout Processors"], storeId);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.PayoutProcessors), StringLocalizer["Payout Processors"]).SetCategory(WellKnownCategories.Store));
}
<div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2>
diff --git a/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml b/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml
index 6bda478..fc8bb13 100644
--- a/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml
+++ b/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml
@@ -2,7 +2,7 @@
@model BTCPayServer.Models.WalletViewModels.UpdatePullPaymentModel
@{
var storeId = Context.GetStoreData().Id;
- ViewData.SetActivePage(StoreNavPages.Create, StringLocalizer["Edit Pull Payment"], Model.Id);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.Create), StringLocalizer["Edit Pull Payment"]));
}
@section PageHeadContent {
diff --git a/BTCPayServer/Views/UIReports/StoreReports.cshtml b/BTCPayServer/Views/UIReports/StoreReports.cshtml
index 304778c..ddb6a3b 100644
--- a/BTCPayServer/Views/UIReports/StoreReports.cshtml
+++ b/BTCPayServer/Views/UIReports/StoreReports.cshtml
@@ -4,7 +4,7 @@
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
@model StoreReportsViewModel
@{
- ViewData.SetActivePage(StoreNavPages.Reporting, StringLocalizer["Reporting"]);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.Reporting), StringLocalizer["Reporting"]));
Csp.UnsafeEval();
}
diff --git a/BTCPayServer/Views/UIServer/Branding.cshtml b/BTCPayServer/Views/UIServer/Branding.cshtml
index 64a2bc3..2e90433 100644
--- a/BTCPayServer/Views/UIServer/Branding.cshtml
+++ b/BTCPayServer/Views/UIServer/Branding.cshtml
@@ -3,7 +3,8 @@
@model BrandingViewModel;
@inject IFileService FileService
@{
- ViewData.SetActivePage(ServerNavPages.Branding, StringLocalizer["Branding"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Branding), StringLocalizer["Branding"])
+ .SetCategory(WellKnownCategories.Server));
var canUpload = await FileService.IsAvailable();
var themeExtension = ((ThemeExtension[])Enum.GetValues(typeof(ThemeExtension))).Select(t =>
new SelectListItem(typeof(ThemeExtension).DisplayName(t.ToString()), t == ThemeExtension.Custom ? null : t.ToString()));
@@ -65,7 +66,7 @@
<h3 class="mt-5 mb-3" text-translate="true">Theme</h3>
<p text-translate="true">Use the default Light or Dark Themes, or provide a custom CSS theme file below.</p>
-
+
<div class="d-flex align-items-center mb-3">
<input asp-for="CustomTheme" type="checkbox" class="btcpay-toggle me-3" data-bs-toggle="collapse" data-bs-target="#CustomThemeSettings" aria-expanded="@(Model.CustomTheme)" aria-controls="CustomThemeSettings" />
<div>
diff --git a/BTCPayServer/Views/UIServer/CLightningRestServices.cshtml b/BTCPayServer/Views/UIServer/CLightningRestServices.cshtml
index dce5185..e5ab085 100644
--- a/BTCPayServer/Views/UIServer/CLightningRestServices.cshtml
+++ b/BTCPayServer/Views/UIServer/CLightningRestServices.cshtml
@@ -1,6 +1,7 @@
@model LndServicesViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["Core Lightning {0}", Model.ConnectionType]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), StringLocalizer["Core Lightning {0}", Model.ConnectionType])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/ConfiguratorService.cshtml b/BTCPayServer/Views/UIServer/ConfiguratorService.cshtml
index e83b311..8694101 100644
--- a/BTCPayServer/Views/UIServer/ConfiguratorService.cshtml
+++ b/BTCPayServer/Views/UIServer/ConfiguratorService.cshtml
@@ -1,6 +1,6 @@
@model LightningWalletServices
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["BTCPay Server Configurator"]);
+ ViewData.SetLayoutModel(new(nameof(ServerNavPages.Services), StringLocalizer["BTCPay Server Configurator"]));
}
@@ -28,7 +28,7 @@
<div class="form-group">
<p text-translate="true">This page exposes information to use the configured BTCPay Server Configurator to modify this setup.</p>
</div>
-
+
<a href="@Model.ServiceLink" target="_blank" class="form-group" rel="noreferrer noopener">
<label asp-for="ServiceLink" class="form-label" text-translate="true">Service</label>
<input asp-for="ServiceLink" class="form-control" readonly />
diff --git a/BTCPayServer/Views/UIServer/CreateDictionary.cshtml b/BTCPayServer/Views/UIServer/CreateDictionary.cshtml
index 4133d2a..7633444 100644
--- a/BTCPayServer/Views/UIServer/CreateDictionary.cshtml
+++ b/BTCPayServer/Views/UIServer/CreateDictionary.cshtml
@@ -1,6 +1,7 @@
@model CreateDictionaryViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Translations, "Create a new dictionary");
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Translations), "Create a new dictionary")
+ .SetCategory(WellKnownCategories.Server));
}
<form method="post">
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/CreateTemporaryFileUrl.cshtml b/BTCPayServer/Views/UIServer/CreateTemporaryFileUrl.cshtml
index 0976c11..cdf0164 100644
--- a/BTCPayServer/Views/UIServer/CreateTemporaryFileUrl.cshtml
+++ b/BTCPayServer/Views/UIServer/CreateTemporaryFileUrl.cshtml
@@ -1,7 +1,8 @@
@using BTCPayServer.Controllers
@model BTCPayServer.Controllers.UIServerController.CreateTemporaryFileUrlViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["Create temporary file link"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), StringLocalizer["Create temporary file link"])
+ .SetCategory(WellKnownCategories.Server));
}
<form method="post">
diff --git a/BTCPayServer/Views/UIServer/CreateUser.cshtml b/BTCPayServer/Views/UIServer/CreateUser.cshtml
index b90452f..5ca9651 100644
--- a/BTCPayServer/Views/UIServer/CreateUser.cshtml
+++ b/BTCPayServer/Views/UIServer/CreateUser.cshtml
@@ -2,7 +2,7 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
@model BTCPayServer.Controllers.RegisterFromAdminViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Users, StringLocalizer["Create account"]);
+ ViewData.SetLayoutModel(new(nameof(ServerNavPages.Users), StringLocalizer["Create account"]));
var canSendEmail = ViewData["CanSendEmail"] is true;
}
diff --git a/BTCPayServer/Views/UIServer/DynamicDnsService.cshtml b/BTCPayServer/Views/UIServer/DynamicDnsService.cshtml
index 6b6be77..8a278d9 100644
--- a/BTCPayServer/Views/UIServer/DynamicDnsService.cshtml
+++ b/BTCPayServer/Views/UIServer/DynamicDnsService.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Models.ServerViewModels.DynamicDnsViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["Dynamic DNS Service"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), StringLocalizer["Dynamic DNS Service"])
+ .SetCategory(WellKnownCategories.Server));
}
@section PageFootContent {
diff --git a/BTCPayServer/Views/UIServer/DynamicDnsServices.cshtml b/BTCPayServer/Views/UIServer/DynamicDnsServices.cshtml
index b95cf9d..5aaa8f0 100644
--- a/BTCPayServer/Views/UIServer/DynamicDnsServices.cshtml
+++ b/BTCPayServer/Views/UIServer/DynamicDnsServices.cshtml
@@ -1,7 +1,7 @@
-@using BTCPayServer.Abstractions.Models
@model BTCPayServer.Models.ServerViewModels.DynamicDnsViewModel[]
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["Dynamic DNS Settings"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), StringLocalizer["Dynamic DNS Settings"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
<nav aria-label="breadcrumb">
diff --git a/BTCPayServer/Views/UIServer/EditAmazonS3StorageProvider.cshtml b/BTCPayServer/Views/UIServer/EditAmazonS3StorageProvider.cshtml
index bef2fe3..7de4624 100644
--- a/BTCPayServer/Views/UIServer/EditAmazonS3StorageProvider.cshtml
+++ b/BTCPayServer/Views/UIServer/EditAmazonS3StorageProvider.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Storage.Services.Providers.AmazonS3Storage.Configuration.AmazonS3StorageConfiguration
@{
- ViewData.SetActivePage(ServerNavPages.Files, StringLocalizer["Amazon S3 Storage"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Files), StringLocalizer["Amazon S3 Storage"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/EditAzureBlobStorageStorageProvider.cshtml b/BTCPayServer/Views/UIServer/EditAzureBlobStorageStorageProvider.cshtml
index 7deb05a..b182f3f 100644
--- a/BTCPayServer/Views/UIServer/EditAzureBlobStorageStorageProvider.cshtml
+++ b/BTCPayServer/Views/UIServer/EditAzureBlobStorageStorageProvider.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Storage.Services.Providers.AzureBlobStorage.Configuration.AzureBlobStorageConfiguration
@{
- ViewData.SetActivePage(ServerNavPages.Files, StringLocalizer["Azure Blob Storage"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Files), StringLocalizer["Azure Blob Storage"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/EditDictionary.cshtml b/BTCPayServer/Views/UIServer/EditDictionary.cshtml
index d556a16..4920499 100644
--- a/BTCPayServer/Views/UIServer/EditDictionary.cshtml
+++ b/BTCPayServer/Views/UIServer/EditDictionary.cshtml
@@ -1,7 +1,7 @@
@model EditDictionaryViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Translations);
- ViewData["Title"] = Context.GetRouteValue("dictionary");
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Translations), Context.GetRouteValue("dictionary") as string)
+ .SetCategory(WellKnownCategories.Server));
}
<form method="post" class="d-flex flex-column">
diff --git a/BTCPayServer/Views/UIServer/EditFileSystemStorageProvider.cshtml b/BTCPayServer/Views/UIServer/EditFileSystemStorageProvider.cshtml
index fb7e894..9191f84 100644
--- a/BTCPayServer/Views/UIServer/EditFileSystemStorageProvider.cshtml
+++ b/BTCPayServer/Views/UIServer/EditFileSystemStorageProvider.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Storage.Services.Providers.FileSystemStorage.Configuration.FileSystemStorageConfiguration
@{
- ViewData.SetActivePage(ServerNavPages.Files, StringLocalizer["Local Filesystem Storage"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Files), StringLocalizer["Local Filesystem Storage"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/EditGoogleCloudStorageStorageProvider.cshtml b/BTCPayServer/Views/UIServer/EditGoogleCloudStorageStorageProvider.cshtml
index 7a419be..82fbb15 100644
--- a/BTCPayServer/Views/UIServer/EditGoogleCloudStorageStorageProvider.cshtml
+++ b/BTCPayServer/Views/UIServer/EditGoogleCloudStorageStorageProvider.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Storage.Services.Providers.GoogleCloudStorage.Configuration.GoogleCloudStorageConfiguration
@{
- ViewData.SetActivePage(ServerNavPages.Files, StringLocalizer["Google Cloud Storage"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Files), StringLocalizer["Google Cloud Storage"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/Emails.cshtml b/BTCPayServer/Views/UIServer/Emails.cshtml
index 48b6377..f1b3d9c 100644
--- a/BTCPayServer/Views/UIServer/Emails.cshtml
+++ b/BTCPayServer/Views/UIServer/Emails.cshtml
@@ -1,6 +1,6 @@
@model ServerEmailsViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Emails, StringLocalizer["Emails"]);
+ ViewData.SetLayoutModel(new LayoutModel("Server-" + nameof(ServerNavPages.Emails), StringLocalizer["Emails"]).SetCategory(WellKnownCategories.Server));
}
<form method="post" autocomplete="off">
diff --git a/BTCPayServer/Views/UIServer/Files.cshtml b/BTCPayServer/Views/UIServer/Files.cshtml
index b7d7952..0f8290c 100644
--- a/BTCPayServer/Views/UIServer/Files.cshtml
+++ b/BTCPayServer/Views/UIServer/Files.cshtml
@@ -1,6 +1,7 @@
@model ViewFilesViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Files, StringLocalizer["File Storage"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Files), StringLocalizer["File Storage"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/LightningChargeServices.cshtml b/BTCPayServer/Views/UIServer/LightningChargeServices.cshtml
index 49944c8..a900e33 100644
--- a/BTCPayServer/Views/UIServer/LightningChargeServices.cshtml
+++ b/BTCPayServer/Views/UIServer/LightningChargeServices.cshtml
@@ -1,6 +1,7 @@
@model ChargeServiceViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["Lightning Charge Service"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), StringLocalizer["Lightning Charge Service"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/LightningWalletServices.cshtml b/BTCPayServer/Views/UIServer/LightningWalletServices.cshtml
index 8d12fb6..6b3371f 100644
--- a/BTCPayServer/Views/UIServer/LightningWalletServices.cshtml
+++ b/BTCPayServer/Views/UIServer/LightningWalletServices.cshtml
@@ -1,6 +1,7 @@
@model LightningWalletServices
@{
- ViewData.SetActivePage(ServerNavPages.Services, Model.WalletName);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), Model.WalletName)
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/ListDictionaries.cshtml b/BTCPayServer/Views/UIServer/ListDictionaries.cshtml
index 54f3695..3344993 100644
--- a/BTCPayServer/Views/UIServer/ListDictionaries.cshtml
+++ b/BTCPayServer/Views/UIServer/ListDictionaries.cshtml
@@ -1,7 +1,7 @@
-@using BTCPayServer.Abstractions.Models
@model ListDictionariesViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Translations, StringLocalizer["Dictionaries"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Translations), StringLocalizer["Dictionaries"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/ListPlugins.cshtml b/BTCPayServer/Views/UIServer/ListPlugins.cshtml
index 3da7565..2567471 100644
--- a/BTCPayServer/Views/UIServer/ListPlugins.cshtml
+++ b/BTCPayServer/Views/UIServer/ListPlugins.cshtml
@@ -5,7 +5,7 @@
@inject PluginService PluginService
@{
Layout = "_Layout";
- ViewData.SetActivePage(ServerNavPages.Plugins);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Plugins), StringLocalizer["Plugins"]));
var installed = Model.Installed;
var availableAndNotInstalled = new List<PluginService.AvailablePlugin>();
var availableAndNotInstalledx = Model.Available
diff --git a/BTCPayServer/Views/UIServer/ListStores.cshtml b/BTCPayServer/Views/UIServer/ListStores.cshtml
index 63a1a62..b8cdb89 100644
--- a/BTCPayServer/Views/UIServer/ListStores.cshtml
+++ b/BTCPayServer/Views/UIServer/ListStores.cshtml
@@ -1,7 +1,8 @@
@model BTCPayServer.Models.StoreViewModels.ListStoresViewModel
@{
Layout = "_Layout";
- ViewData.SetActivePage(ServerNavPages.Stores, StringLocalizer["Store Overview"]);
+ ViewData.SetTitle(StringLocalizer["Store Overview"]);
+ ViewData["StoreList"] = true;
}
<div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2>
@@ -60,7 +61,7 @@
}
else
{
- <span class="text-secondary" text-translate="true">No users</span>
+ <span class="text-secondary" text-translate="true">No users</span>
}
</td>
</tr>
diff --git a/BTCPayServer/Views/UIServer/ListUsers.cshtml b/BTCPayServer/Views/UIServer/ListUsers.cshtml
index 6acf97f..c96a773 100644
--- a/BTCPayServer/Views/UIServer/ListUsers.cshtml
+++ b/BTCPayServer/Views/UIServer/ListUsers.cshtml
@@ -1,8 +1,8 @@
-@using BTCPayServer.Abstractions.Models
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
@model UsersViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Users, StringLocalizer["Users"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Users), StringLocalizer["Users"])
+ .SetCategory(WellKnownCategories.Server));
var nextUserEmailSortOrder = (string)ViewData["NextUserEmailSortOrder"];
var userEmailSortOrder = nextUserEmailSortOrder switch
{
diff --git a/BTCPayServer/Views/UIServer/LndSeedBackup.cshtml b/BTCPayServer/Views/UIServer/LndSeedBackup.cshtml
index 2ffc562..95dfee5 100644
--- a/BTCPayServer/Views/UIServer/LndSeedBackup.cshtml
+++ b/BTCPayServer/Views/UIServer/LndSeedBackup.cshtml
@@ -1,7 +1,7 @@
-@using BTCPayServer.Abstractions.Models
@model LndSeedBackupViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["LND Seed Backup"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), StringLocalizer["LND Seed Backup"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
@@ -26,7 +26,7 @@
<p>The recovering process is documented by LND on <a href="https://github.com/lightningnetwork/lnd/blob/master/docs/recovery.md" rel="noreferrer noopener">this page</a>.</p>
</div>
<button class="btn btn-primary @(Model.Removed ? "collapse" : "")" id="details" type="button">See confidential seed information</button>
-
+
@if (Model.Removed)
{
<div class="alert alert-light d-flex align-items-center" role="alert">
diff --git a/BTCPayServer/Views/UIServer/LndServices.cshtml b/BTCPayServer/Views/UIServer/LndServices.cshtml
index d48ba29..b39307b 100644
--- a/BTCPayServer/Views/UIServer/LndServices.cshtml
+++ b/BTCPayServer/Views/UIServer/LndServices.cshtml
@@ -1,6 +1,7 @@
@model LndServicesViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["LND {0}", Model.ConnectionType]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), StringLocalizer["LND {0}", Model.ConnectionType])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/Logs.cshtml b/BTCPayServer/Views/UIServer/Logs.cshtml
index eafd044..56cf384 100644
--- a/BTCPayServer/Views/UIServer/Logs.cshtml
+++ b/BTCPayServer/Views/UIServer/Logs.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Models.ServerViewModels.LogsViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Logs, StringLocalizer["Logs"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Logs), StringLocalizer["Logs"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/Maintenance.cshtml b/BTCPayServer/Views/UIServer/Maintenance.cshtml
index 74a7007..9024610 100644
--- a/BTCPayServer/Views/UIServer/Maintenance.cshtml
+++ b/BTCPayServer/Views/UIServer/Maintenance.cshtml
@@ -3,7 +3,8 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
@model BTCPayServer.Models.ServerViewModels.MaintenanceViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Maintenance, StringLocalizer["Maintenance"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Maintenance), StringLocalizer["Maintenance"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/P2PService.cshtml b/BTCPayServer/Views/UIServer/P2PService.cshtml
index fdeaee6..801aa0f 100644
--- a/BTCPayServer/Views/UIServer/P2PService.cshtml
+++ b/BTCPayServer/Views/UIServer/P2PService.cshtml
@@ -1,6 +1,7 @@
@model LightningWalletServices
@{
- ViewData.SetActivePage(ServerNavPages.Services, Model.WalletName);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), Model.WalletName)
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/Policies.cshtml b/BTCPayServer/Views/UIServer/Policies.cshtml
index 36eaa15..c9cfd94 100644
--- a/BTCPayServer/Views/UIServer/Policies.cshtml
+++ b/BTCPayServer/Views/UIServer/Policies.cshtml
@@ -4,7 +4,8 @@
@inject EmailSenderFactory EmailSenderFactory
@inject TransactionLinkProviders TransactionLinkProviders
@{
- ViewData.SetActivePage(ServerNavPages.Policies, StringLocalizer["Policies"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Policies), StringLocalizer["Policies"])
+ .SetCategory(WellKnownCategories.Server));
var linkProviders = TransactionLinkProviders.ToArray();
}
diff --git a/BTCPayServer/Views/UIServer/RPCService.cshtml b/BTCPayServer/Views/UIServer/RPCService.cshtml
index b30f1f5..3817876 100644
--- a/BTCPayServer/Views/UIServer/RPCService.cshtml
+++ b/BTCPayServer/Views/UIServer/RPCService.cshtml
@@ -1,6 +1,7 @@
@model LightningWalletServices
@{
- ViewData.SetActivePage(ServerNavPages.Services, Model.WalletName);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), Model.WalletName)
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/ResetUserPassword.cshtml b/BTCPayServer/Views/UIServer/ResetUserPassword.cshtml
index 4f58ab8..ab247b2 100644
--- a/BTCPayServer/Views/UIServer/ResetUserPassword.cshtml
+++ b/BTCPayServer/Views/UIServer/ResetUserPassword.cshtml
@@ -1,6 +1,6 @@
@model BTCPayServer.Controllers.ResetUserPasswordFromAdmin
@{
- ViewData.SetActivePage(ServerNavPages.Users, StringLocalizer["Reset Password"]);
+ ViewData.SetLayoutModel(new(nameof(ServerNavPages.Users), StringLocalizer["Reset Password"]));
}
<form method="post" asp-action="ResetUserPassword">
diff --git a/BTCPayServer/Views/UIServer/SSHService.cshtml b/BTCPayServer/Views/UIServer/SSHService.cshtml
index 46f79b3..fc1fc06 100644
--- a/BTCPayServer/Views/UIServer/SSHService.cshtml
+++ b/BTCPayServer/Views/UIServer/SSHService.cshtml
@@ -1,7 +1,7 @@
-@using BTCPayServer.Abstractions.Models
@model BTCPayServer.Models.ServerViewModels.SSHServiceViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["SSH settings"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), StringLocalizer["SSH settings"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/Services.cshtml b/BTCPayServer/Views/UIServer/Services.cshtml
index 91a1c60..902c0af 100644
--- a/BTCPayServer/Views/UIServer/Services.cshtml
+++ b/BTCPayServer/Views/UIServer/Services.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Models.ServerViewModels.ServicesViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Services, StringLocalizer["Services"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), StringLocalizer["Services"])
+ .SetCategory(WellKnownCategories.Server));
}
<div class="sticky-header">
diff --git a/BTCPayServer/Views/UIServer/Storage.cshtml b/BTCPayServer/Views/UIServer/Storage.cshtml
index 0c58af7..b18396f 100644
--- a/BTCPayServer/Views/UIServer/Storage.cshtml
+++ b/BTCPayServer/Views/UIServer/Storage.cshtml
@@ -1,6 +1,7 @@
@model BTCPayServer.Storage.ViewModels.ChooseStorageViewModel
@{
- ViewData.SetActivePage(ServerNavPages.Files, StringLocalizer["Storage Provider"]);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Files), StringLocalizer["Storage Provider"])
+ .SetCategory(WellKnownCategories.Server));
}
<form method="post">
@@ -13,7 +14,7 @@
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol>
<h2>@ViewData["Title"]</h2>
- </nav>
+ </nav>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save" text-translate="true">Next</button>
</div>
<partial name="_StatusMessage" />
@@ -23,7 +24,7 @@
@if (Model.ShowChangeWarning)
{
<div class="alert alert-danger mb-4" text-translate="true">
- If you change your configured storage provider, your current files will become inaccessible.
+ If you change your configured storage provider, your current files will become inaccessible.
</div>
}
@if (!ViewContext.ModelState.IsValid)
diff --git a/BTCPayServer/Views/UIServer/User.cshtml b/BTCPayServer/Views/UIServer/User.cshtml
index d78ca8f..fe13b39 100644
--- a/BTCPayServer/Views/UIServer/User.cshtml
+++ b/BTCPayServer/Views/UIServer/User.cshtml
@@ -3,7 +3,7 @@
@model UsersViewModel.UserViewModel
@inject IFileService FileService
@{
- ViewData.SetActivePage(ServerNavPages.Users, Model.Email);
+ ViewData.SetLayoutModel(new(nameof(ServerNavPages.Users), Model.Email));
var canUpload = await FileService.IsAvailable();
}
@@ -36,7 +36,7 @@
</div>
</div>
}
-
+
<div class="form-group">
<label asp-for="Name" class="form-label"></label>
<input asp-for="Name" class="form-control" />
diff --git a/BTCPayServer/Views/UIShopify/EditShopify.cshtml b/BTCPayServer/Views/UIShopify/EditShopify.cshtml
index 4917645..8a5c223 100644
--- a/BTCPayServer/Views/UIShopify/EditShopify.cshtml
+++ b/BTCPayServer/Views/UIShopify/EditShopify.cshtml
@@ -1,8 +1,6 @@
-@using BTCPayServer.Views.Stores
@model BTCPayServer.Plugins.Shopify.Models.ShopifySettings
@{
- ViewData.SetActivePage("shopify", nameof(StoreNavPages), StringLocalizer["Shopify"], Context.GetStoreData().Id);
-
+ ViewData.SetLayoutModel(new LayoutModel("shopify", StringLocalizer["Shopify"]).SetCategory(WellKnownCategories.Store));
var shopifyCredsSet = Model?.IntegratedAt.HasValue is true;
var shopifyUrl = Model?.ShopifyUrl;
}
@@ -71,7 +69,7 @@
@if (shopifyCredsSet)
{
<div class="alert alert-warning">
- <h5 class="alert-heading" text-translate="true">In Shopify, please do the following …</h5>
+ <h5 class="alert-heading" text-translate="true">In Shopify, please do the following …</h5>
<ul>
<li>
Add a payment method at <a href="@shopifyUrl/admin/settings/payments" class="alert-link fw-bold" target="_blank" rel="noreferrer noopener">Settings > Payments > Manual Payment Methods</a> with the name <strong>Bitcoin with BTCPay Server</strong>
diff --git a/BTCPayServer/Views/UIStorePullPayments/NewPullPayment.cshtml b/BTCPayServer/Views/UIStorePullPayments/NewPullPayment.cshtml
index 18ea3aa..1f99427 100644
--- a/BTCPayServer/Views/UIStorePullPayments/NewPullPayment.cshtml
+++ b/BTCPayServer/Views/UIStorePullPayments/NewPullPayment.cshtml
@@ -3,7 +3,7 @@
@model BTCPayServer.Models.WalletViewModels.NewPullPaymentModel
@{
var storeId = Context.GetStoreData().Id;
- ViewData.SetActivePage(StoreNavPages.PullPayments, StringLocalizer["Create Pull Payment"], storeId);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.PullPayments), StringLocalizer["Create Pull Payment"]));
}
@section PageHeadContent {
diff --git a/BTCPayServer/Views/UIStorePullPayments/Payouts.cshtml b/BTCPayServer/Views/UIStorePullPayments/Payouts.cshtml
index fa28ca5..5e52456 100644
--- a/BTCPayServer/Views/UIStorePullPayments/Payouts.cshtml
+++ b/BTCPayServer/Views/UIStorePullPayments/Payouts.cshtml
@@ -7,7 +7,7 @@
@inject PayoutMethodHandlerDictionary PayoutHandlers;
@{
var storeId = Context.GetRouteValue("storeId") as string;
- ViewData.SetActivePage(StoreNavPages.Payouts, string.IsNullOrEmpty(Model.PullPaymentName) ? StringLocalizer["Payouts"] : StringLocalizer["Payouts for pull payment {0}", Model.PullPaymentName], Context.GetStoreData().Id);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.Payouts), string.IsNullOrEmpty(Model.PullPaymentName) ? StringLocalizer["Payouts"] : StringLocalizer["Payouts for pull payment {0}", Model.PullPaymentName]));
Model.PaginationQuery ??= new Dictionary<string, object>();
Model.PaginationQuery.Add("pullPaymentId", Model.PullPaymentId);
Model.PaginationQuery.Add("payoutMethodId", Model.PayoutMethodId);
diff --git a/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml b/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml
index 08567ec..678c0d7 100644
--- a/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml
+++ b/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml
@@ -1,5 +1,4 @@
@using BTCPayServer.Views.Stores
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Client
@using BTCPayServer.Client.Models
@using ExchangeSharp
@@ -15,7 +14,7 @@
"desc" => "asc",
_ => null
};
- ViewData.SetActivePage(StoreNavPages.PullPayments, StringLocalizer["Pull Payments"], storeId);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.PullPayments), StringLocalizer["Pull Payments"]));
}
@section PageHeadContent {
diff --git a/BTCPayServer/Views/UIStores/CheckoutAppearance.cshtml b/BTCPayServer/Views/UIStores/CheckoutAppearance.cshtml
index a3daa0b..10c2e91 100644
--- a/BTCPayServer/Views/UIStores/CheckoutAppearance.cshtml
+++ b/BTCPayServer/Views/UIStores/CheckoutAppearance.cshtml
@@ -7,8 +7,7 @@
@inject IFileService FileService
@model CheckoutAppearanceViewModel
@{
- ViewData.SetActivePage(StoreNavPages.CheckoutAppearance, StringLocalizer["Checkout Experience"], Context.GetStoreData().Id);
-
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.CheckoutAppearance), StringLocalizer["Checkout Experience"]).SetCategory(WellKnownCategories.Store));
var canUpload = await FileService.IsAvailable();
}
@functions {
@@ -44,7 +43,7 @@
$("#ShowPayInWalletButton").prop('checked', true);
$("#ShowStoreHeader").prop('checked', true);
});
-
+
delegate('click', '#CheckNFC button', async e => {
if ('NDEFReader' in window) {
const ndef = new NDEFReader();
diff --git a/BTCPayServer/Views/UIStores/CreateToken.cshtml b/BTCPayServer/Views/UIStores/CreateToken.cshtml
index fa4b26c..86213c2 100644
--- a/BTCPayServer/Views/UIStores/CreateToken.cshtml
+++ b/BTCPayServer/Views/UIStores/CreateToken.cshtml
@@ -1,7 +1,7 @@
@model CreateTokenViewModel
@{
var store = Context.GetStoreData();
- ViewData.SetActivePage(StoreNavPages.Tokens, StringLocalizer["Create New Token"], store?.Id);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.Tokens), StringLocalizer["Create New Token"]));
ViewBag.HidePublicKey ??= false;
ViewBag.ShowStores ??= false;
}
diff --git a/BTCPayServer/Views/UIStores/Dashboard.cshtml b/BTCPayServer/Views/UIStores/Dashboard.cshtml
index 78e350e..611b104 100644
--- a/BTCPayServer/Views/UIStores/Dashboard.cshtml
+++ b/BTCPayServer/Views/UIStores/Dashboard.cshtml
@@ -10,7 +10,7 @@
@model StoreDashboardViewModel
@{
BTCPayServer.Plugins.PluginExceptionHandler.SetDisablePluginIfCrash(Context);
- ViewData.SetActivePage(StoreNavPages.Dashboard, Model.StoreName, Model.StoreId);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.Dashboard), Model.StoreName));
var store = ViewContext.HttpContext.GetStoreData();
}
diff --git a/BTCPayServer/Views/UIStores/GeneralSettings.cshtml b/BTCPayServer/Views/UIStores/GeneralSettings.cshtml
index f5d86eb..7d217d0 100644
--- a/BTCPayServer/Views/UIStores/GeneralSettings.cshtml
+++ b/BTCPayServer/Views/UIStores/GeneralSettings.cshtml
@@ -1,4 +1,3 @@
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.TagHelpers
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using BTCPayServer.Abstractions.Contracts
@@ -6,7 +5,7 @@
@inject IFileService FileService;
@model GeneralSettingsViewModel
@{
- ViewData.SetActivePage(StoreNavPages.General, StringLocalizer["General"], Context.GetStoreData().Id);
+ ViewData.SetLayoutModel(new LayoutModel("General", StringLocalizer["General"]).SetCategory(WellKnownCategories.Store));
var canUpload = await FileService.IsAvailable();
}
<form method="post" enctype="multipart/form-data" permissioned="@Policies.CanModifyStoreSettings">
diff --git a/BTCPayServer/Views/UIStores/GenerateWallet.cshtml b/BTCPayServer/Views/UIStores/GenerateWallet.cshtml
index 885773d..eee0fd0 100644
--- a/BTCPayServer/Views/UIStores/GenerateWallet.cshtml
+++ b/BTCPayServer/Views/UIStores/GenerateWallet.cshtml
@@ -3,7 +3,7 @@
var isHotWallet = Model.Method == WalletSetupMethod.HotWallet;
var title = isHotWallet ? StringLocalizer["Create {0} Hot Wallet", Model.CryptoCode] : StringLocalizer["Create {0} Watch-Only Wallet", Model.CryptoCode];
Layout = "_LayoutWalletSetup";
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, title, $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(title);
Model.SetViewData(ViewData);
}
diff --git a/BTCPayServer/Views/UIStores/GenerateWalletOptions.cshtml b/BTCPayServer/Views/UIStores/GenerateWalletOptions.cshtml
index 6d17ce6..e4e17ea 100644
--- a/BTCPayServer/Views/UIStores/GenerateWalletOptions.cshtml
+++ b/BTCPayServer/Views/UIStores/GenerateWalletOptions.cshtml
@@ -3,8 +3,7 @@
@inject Microsoft.Extensions.Localization.IStringLocalizer StringLocalizer
@{
Layout = "_LayoutWalletSetup";
- var title = StringLocalizer["Generate {0} Wallet", Model.CryptoCode];
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, title, $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(StringLocalizer["Generate {0} Wallet", Model.CryptoCode]);
}
@section Navbar {
@@ -71,7 +70,7 @@
<h4 text-translate="true">Watch-only wallet</h4>
<p class="mb-0" text-translate="true">Please note that this instance does not support creating a new cold wallet for non-administrators. However, you can import one from other wallet software.</p>
</div>
- </div>
+ </div>
}
</div>
diff --git a/BTCPayServer/Views/UIStores/ImportWallet/ConfirmAddresses.cshtml b/BTCPayServer/Views/UIStores/ImportWallet/ConfirmAddresses.cshtml
index 9c67b27..0a2ac5d 100644
--- a/BTCPayServer/Views/UIStores/ImportWallet/ConfirmAddresses.cshtml
+++ b/BTCPayServer/Views/UIStores/ImportWallet/ConfirmAddresses.cshtml
@@ -1,7 +1,7 @@
@model WalletSetupViewModel
@{
Layout = "_LayoutWalletSetup";
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, StringLocalizer["Confirm addresses"], $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(StringLocalizer["Confirm addresses"]);
}
@section Navbar {
diff --git a/BTCPayServer/Views/UIStores/ImportWallet/File.cshtml b/BTCPayServer/Views/UIStores/ImportWallet/File.cshtml
index e33c6bd..521ac6a 100644
--- a/BTCPayServer/Views/UIStores/ImportWallet/File.cshtml
+++ b/BTCPayServer/Views/UIStores/ImportWallet/File.cshtml
@@ -1,7 +1,7 @@
@model WalletSetupViewModel
@{
Layout = "_LayoutWalletSetup";
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, StringLocalizer["Import your wallet file"], $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(StringLocalizer["Import your wallet file"]);
}
@section Navbar {
@@ -60,10 +60,10 @@
<tr>
<td>Passport</td>
<td>Wallet ❯ Connect Wallet ❯ BTCPay ❯ microSD ❯ Save wallet file</td>
- </tr>
+ </tr>
<tr>
<td>Nunchuk</td>
<td>... ❯ Export wallet configuration</td>
- </tr>
+ </tr>
</tbody>
</table>
diff --git a/BTCPayServer/Views/UIStores/ImportWallet/Hardware.cshtml b/BTCPayServer/Views/UIStores/ImportWallet/Hardware.cshtml
index 90d5b23..e1b6875 100644
--- a/BTCPayServer/Views/UIStores/ImportWallet/Hardware.cshtml
+++ b/BTCPayServer/Views/UIStores/ImportWallet/Hardware.cshtml
@@ -7,7 +7,7 @@
@{
Layout = "_LayoutWalletSetup";
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, StringLocalizer["Connect your hardware wallet"], $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(StringLocalizer["Connect your hardware wallet"]);
this.ViewData.SetBlazorAllowed(true);
}
diff --git a/BTCPayServer/Views/UIStores/ImportWallet/Scan.cshtml b/BTCPayServer/Views/UIStores/ImportWallet/Scan.cshtml
index f1019dc..407e883 100644
--- a/BTCPayServer/Views/UIStores/ImportWallet/Scan.cshtml
+++ b/BTCPayServer/Views/UIStores/ImportWallet/Scan.cshtml
@@ -2,7 +2,7 @@
@model WalletSetupViewModel
@{
Layout = "_LayoutWalletSetup";
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, StringLocalizer["Scan QR code"], $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(StringLocalizer["Scan QR code"]);
Csp.UnsafeEval();
}
diff --git a/BTCPayServer/Views/UIStores/ImportWallet/Seed.cshtml b/BTCPayServer/Views/UIStores/ImportWallet/Seed.cshtml
index 87401cd..cb43c40 100644
--- a/BTCPayServer/Views/UIStores/ImportWallet/Seed.cshtml
+++ b/BTCPayServer/Views/UIStores/ImportWallet/Seed.cshtml
@@ -1,7 +1,7 @@
@model WalletSetupViewModel
@{
Layout = "_LayoutWalletSetup";
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, StringLocalizer["Enter the wallet seed"], $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(StringLocalizer["Enter the wallet seed"]);
}
@section Navbar {
diff --git a/BTCPayServer/Views/UIStores/ImportWallet/Xpub.cshtml b/BTCPayServer/Views/UIStores/ImportWallet/Xpub.cshtml
index cd11901..a0b05a2 100644
--- a/BTCPayServer/Views/UIStores/ImportWallet/Xpub.cshtml
+++ b/BTCPayServer/Views/UIStores/ImportWallet/Xpub.cshtml
@@ -1,7 +1,7 @@
@model WalletSetupViewModel
@{
Layout = "_LayoutWalletSetup";
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, StringLocalizer["Enter your extended public key"], $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(StringLocalizer["Enter your extended public key"]);
}
@section Navbar {
diff --git a/BTCPayServer/Views/UIStores/ImportWalletOptions.cshtml b/BTCPayServer/Views/UIStores/ImportWalletOptions.cshtml
index 237032d..316dd91 100644
--- a/BTCPayServer/Views/UIStores/ImportWalletOptions.cshtml
+++ b/BTCPayServer/Views/UIStores/ImportWalletOptions.cshtml
@@ -5,8 +5,7 @@
@inject BTCPayNetworkProvider BTCPayNetworkProvider
@{
Layout = "_LayoutWalletSetup";
- var title = StringLocalizer["Import {0} Wallet", Model.CryptoCode];
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, title, $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(StringLocalizer["Import {0} Wallet", Model.CryptoCode]);
}
@section Navbar {
diff --git a/BTCPayServer/Views/UIStores/Lightning.cshtml b/BTCPayServer/Views/UIStores/Lightning.cshtml
index ca05e0b..ce138a0 100644
--- a/BTCPayServer/Views/UIStores/Lightning.cshtml
+++ b/BTCPayServer/Views/UIStores/Lightning.cshtml
@@ -4,7 +4,8 @@
@inject LightningClientFactoryService LightningClientFactoryService
@inject BTCPayNetworkProvider NetworkProvider
@{
- ViewData.SetActivePage(StoreNavPages.Lightning, StringLocalizer["{0} Lightning", Model.CryptoCode], $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(StoreNavPages.Lightning)}-{Model.CryptoCode}", StringLocalizer["{0} Lightning", Model.CryptoCode])
+ .SetCategory(WellKnownCategories.ForLightning(Model.CryptoCode)));
}
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2>
diff --git a/BTCPayServer/Views/UIStores/LightningSettings.cshtml b/BTCPayServer/Views/UIStores/LightningSettings.cshtml
index af546ff..da4d2e4 100644
--- a/BTCPayServer/Views/UIStores/LightningSettings.cshtml
+++ b/BTCPayServer/Views/UIStores/LightningSettings.cshtml
@@ -3,7 +3,8 @@
@inject LightningClientFactoryService LightningClientFactoryService
@inject BTCPayNetworkProvider NetworkProvider
@{
- ViewData.SetActivePage(StoreNavPages.LightningSettings, StringLocalizer["{0} Lightning Settings", Model.CryptoCode], $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(StoreNavPages.LightningSettings)}-{Model.CryptoCode}", StringLocalizer["{0} Lightning Settings", Model.CryptoCode])
+ .SetCategory(WellKnownCategories.ForLightning(Model.CryptoCode)));
}
<form method="post">
@@ -56,7 +57,7 @@
<input type="checkbox" asp-for="Enabled" class="btcpay-toggle me-3" id="@($"{Model.CryptoCode}LightningEnabled")" />
<label asp-for="Enabled" class="form-check-label"></label>
</div>
-
+
<div class="text-start">
<h3 class="mt-5 mb-3" text-translate="true">Payment</h3>
<div class="form-check my-3">
@@ -80,7 +81,7 @@
<span asp-validation-for="LightningDescriptionTemplate" class="text-danger"></span>
<div class="form-text" html-translate="true">Available placeholders: <code>{StoreName} {ItemDescription} {OrderId}</code></div>
</div>
-
+
<h3 class="mt-5 mb-3" id="ln-url" text-translate="true">LNURL</h3>
<div class="form-group d-flex align-items-center">
<input asp-for="LNURLEnabled" type="checkbox" class="btcpay-toggle me-3" data-bs-toggle="collapse" data-bs-target="#LNURLSettings" aria-expanded="@Model.LNURLEnabled" aria-controls="LNURLSettings"/>
diff --git a/BTCPayServer/Views/UIStores/ListTokens.cshtml b/BTCPayServer/Views/UIStores/ListTokens.cshtml
index bac083c..357d8fb 100644
--- a/BTCPayServer/Views/UIStores/ListTokens.cshtml
+++ b/BTCPayServer/Views/UIStores/ListTokens.cshtml
@@ -1,9 +1,8 @@
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Client
@using Microsoft.AspNetCore.Mvc.TagHelpers
@model TokensViewModel
@{
- ViewData.SetActivePage(StoreNavPages.Tokens, StringLocalizer["Access Tokens"], Context.GetStoreData().Id);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Tokens), StringLocalizer["Access Tokens"]).SetCategory(WellKnownCategories.Store));
}
@if (Model.StoreNotConfigured)
diff --git a/BTCPayServer/Views/UIStores/Rates.Source.cshtml b/BTCPayServer/Views/UIStores/Rates.Source.cshtml
index 6362f11..bab0aed 100644
--- a/BTCPayServer/Views/UIStores/Rates.Source.cshtml
+++ b/BTCPayServer/Views/UIStores/Rates.Source.cshtml
@@ -1,5 +1,4 @@
-@using BTCPayServer.Abstractions.Models
-@using BTCPayServer.Client
+@using BTCPayServer.Client
@model BTCPayServer.Models.StoreViewModels.RatesViewModel.Source
@if (Model.ShowScripting)
diff --git a/BTCPayServer/Views/UIStores/Rates.cshtml b/BTCPayServer/Views/UIStores/Rates.cshtml
index 15eafca..f098a74 100644
--- a/BTCPayServer/Views/UIStores/Rates.cshtml
+++ b/BTCPayServer/Views/UIStores/Rates.cshtml
@@ -1,12 +1,9 @@
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Client
@model BTCPayServer.Models.StoreViewModels.RatesViewModel
@{
- ViewData.SetActivePage(StoreNavPages.Rates, StringLocalizer["Rates"], Context.GetStoreData().Id);
+ ViewData.SetLayoutModel(new LayoutModel("Rates", StringLocalizer["Rates"]).SetCategory(WellKnownCategories.Store));
}
-
-
<form method="post" permissioned="@Policies.CanModifyStoreSettings">
<div class="sticky-header">
<h2>@ViewData["Title"]</h2>
diff --git a/BTCPayServer/Views/UIStores/RequestPairing.cshtml b/BTCPayServer/Views/UIStores/RequestPairing.cshtml
index 47c9791..24deb96 100644
--- a/BTCPayServer/Views/UIStores/RequestPairing.cshtml
+++ b/BTCPayServer/Views/UIStores/RequestPairing.cshtml
@@ -5,7 +5,7 @@
@{
var store = Context.GetStoreData();
Layout = store is null ? "_LayoutWizard" : "_Layout";
- ViewData.SetActivePage(StoreNavPages.Tokens, StringLocalizer["Pairing Permission"], store?.Id);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.Tokens), StringLocalizer["Pairing Permission"]));
}
@if (store is null)
diff --git a/BTCPayServer/Views/UIStores/SetupLightningNode.cshtml b/BTCPayServer/Views/UIStores/SetupLightningNode.cshtml
index dfa7b14..b0edaf0 100644
--- a/BTCPayServer/Views/UIStores/SetupLightningNode.cshtml
+++ b/BTCPayServer/Views/UIStores/SetupLightningNode.cshtml
@@ -1,7 +1,7 @@
@model LightningNodeViewModel
@{
Layout = "_LayoutWalletSetup.cshtml";
- ViewData.SetActivePage(StoreNavPages.LightningSettings, StringLocalizer["Connect to a Lightning node"], Model.StoreId);
+ ViewData.SetTitle(StringLocalizer["Connect to a Lightning node"]);
}
@section PageHeadContent {
diff --git a/BTCPayServer/Views/UIStores/SetupWallet.cshtml b/BTCPayServer/Views/UIStores/SetupWallet.cshtml
index 8eee262..78f17ce 100644
--- a/BTCPayServer/Views/UIStores/SetupWallet.cshtml
+++ b/BTCPayServer/Views/UIStores/SetupWallet.cshtml
@@ -4,8 +4,7 @@
@{
Layout = "_LayoutWalletSetup";
- var title = StringLocalizer["Setup {0} Wallet", Model.CryptoCode];
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, title, $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetTitle(StringLocalizer["Setup {0} Wallet", Model.CryptoCode]);
}
<h1 class="text-center" text-translate="true">Let's get started</h1>
diff --git a/BTCPayServer/Views/UIStores/ShowToken.cshtml b/BTCPayServer/Views/UIStores/ShowToken.cshtml
index 351a5ae..1af552c 100644
--- a/BTCPayServer/Views/UIStores/ShowToken.cshtml
+++ b/BTCPayServer/Views/UIStores/ShowToken.cshtml
@@ -1,6 +1,6 @@
@model BTCPayServer.Security.Bitpay.BitTokenEntity
@{
- ViewData.SetActivePage(StoreNavPages.Tokens, StringLocalizer["Access Tokens"], Context.GetStoreData().Id);
+ ViewData.SetLayoutModel(new(nameof(StoreNavPages.Tokens), StringLocalizer["Access Tokens"]));
}
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2>
<partial name="_StatusMessage" />
diff --git a/BTCPayServer/Views/UIStores/StoreUsers.cshtml b/BTCPayServer/Views/UIStores/StoreUsers.cshtml
index bedb708..aa7871a 100644
--- a/BTCPayServer/Views/UIStores/StoreUsers.cshtml
+++ b/BTCPayServer/Views/UIStores/StoreUsers.cshtml
@@ -1,4 +1,3 @@
-@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Services.Stores
@using BTCPayServer.Client
@using Microsoft.AspNetCore.Mvc.TagHelpers
@@ -10,7 +9,7 @@
await StoreRepository.GetStoreRoles(storeId),
nameof(StoreRepository.StoreRole.Id), nameof(StoreRepository.StoreRole.Role),
Model.Role);
- ViewData.SetActivePage(StoreNavPages.Users, StringLocalizer["Store Users"], storeId);
+ ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Users), StringLocalizer["Store Users"]).SetCategory(WellKnownCategories.Store));
}
@section PageHeadContent {
<style>
diff --git a/BTCPayServer/Views/UIStores/WalletSettings.cshtml b/BTCPayServer/Views/UIStores/WalletSettings.cshtml
index d1508c7..d779c47 100644
--- a/BTCPayServer/Views/UIStores/WalletSettings.cshtml
+++ b/BTCPayServer/Views/UIStores/WalletSettings.cshtml
@@ -1,11 +1,12 @@
@using NBitcoin.DataEncoders
@using Newtonsoft.Json
@using System.Text
-@using BTCPayServer.Abstractions.Models
+@using BTCPayServer.Views.Wallets
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
@model WalletSettingsViewModel
@{
- ViewData.SetActivePage(StoreNavPages.OnchainSettings, StringLocalizer["{0} Wallet Settings", Model.CryptoCode], $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(WalletsNavPages.Settings)}-{Model.CryptoCode}", StringLocalizer["{0} Wallet Settings", Model.CryptoCode])
+ .SetCategory(WellKnownCategories.ForWallet(Model.CryptoCode)));
Csp.UnsafeEval();
}
diff --git a/BTCPayServer/Views/UIUserStores/CreateStore.cshtml b/BTCPayServer/Views/UIUserStores/CreateStore.cshtml
index 9ecbcbe..f442df8 100644
--- a/BTCPayServer/Views/UIUserStores/CreateStore.cshtml
+++ b/BTCPayServer/Views/UIUserStores/CreateStore.cshtml
@@ -2,7 +2,9 @@
@inject DefaultRulesCollection DefaultRules
@{
Layout = Model.IsFirstStore ? "_LayoutWizard" : "_Layout";
- ViewData.SetActivePage(StoreNavPages.Create, Model.IsFirstStore ? StringLocalizer["Create your first store"] : StringLocalizer["Create a new store"]);
+ //ViewData.SetLayoutModel(new("CreateStore", Model.IsFirstStore ? StringLocalizer["Create your first store"] : StringLocalizer["Create a new store"]));
+ ViewData.SetTitle(Model.IsFirstStore ? StringLocalizer["Create your first store"] : StringLocalizer["Create a new store"]);
+ ViewData["CreateStore"] = true;
}
@section PageFootContent {
diff --git a/BTCPayServer/Views/UIUserStores/ListStores.cshtml b/BTCPayServer/Views/UIUserStores/ListStores.cshtml
index b7709d4..716381b 100644
--- a/BTCPayServer/Views/UIUserStores/ListStores.cshtml
+++ b/BTCPayServer/Views/UIUserStores/ListStores.cshtml
@@ -1,7 +1,11 @@
@using BTCPayServer.Client
@model BTCPayServer.Models.StoreViewModels.ListStoresViewModel
@{
- ViewData.SetActivePage(StoreNavPages.Index, Model.Archived ? StringLocalizer["Archived Stores"] : StringLocalizer["Stores"]);
+ if (Model.Archived)
+ {
+ ViewData["ArchivedStores"] = true;
+ }
+ ViewData.SetTitle(Model.Archived ? StringLocalizer["Archived Stores"] : StringLocalizer["Stores"]);
}
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2>
diff --git a/BTCPayServer/Views/UIWallets/ListWallets.cshtml b/BTCPayServer/Views/UIWallets/ListWallets.cshtml
index ee79c33..817dbc3 100644
--- a/BTCPayServer/Views/UIWallets/ListWallets.cshtml
+++ b/BTCPayServer/Views/UIWallets/ListWallets.cshtml
@@ -1,7 +1,7 @@
@using BTCPayServer.Client
@model BTCPayServer.Models.WalletViewModels.ListWalletsViewModel
@{
- ViewData.SetActivePage(WalletsNavPages.Index, StringLocalizer["Wallets"]);
+ ViewData.SetLayoutModel(new(nameof(WalletsNavPages.Index), StringLocalizer["Wallets"]));
}
<partial name="_StatusMessage" />
diff --git a/BTCPayServer/Views/UIWallets/ReservedAddresses.cshtml b/BTCPayServer/Views/UIWallets/ReservedAddresses.cshtml
index 9da9efc..50bc1b4 100644
--- a/BTCPayServer/Views/UIWallets/ReservedAddresses.cshtml
+++ b/BTCPayServer/Views/UIWallets/ReservedAddresses.cshtml
@@ -11,7 +11,8 @@
}
@{
- ViewData.SetActivePage(WalletsNavPages.Receive, "Reserved Addresses");
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(WalletsNavPages.Settings)}-{wallet.CryptoCode}", StringLocalizer["Reserved Addresses"])
+ .SetCategory(WellKnownCategories.ForWallet(wallet.CryptoCode)));
Csp.Add("worker-src", "blob:");
Csp.UnsafeEval();
}
diff --git a/BTCPayServer/Views/UIWallets/SignWithSeed.cshtml b/BTCPayServer/Views/UIWallets/SignWithSeed.cshtml
index 021c962..ec2c469 100644
--- a/BTCPayServer/Views/UIWallets/SignWithSeed.cshtml
+++ b/BTCPayServer/Views/UIWallets/SignWithSeed.cshtml
@@ -4,7 +4,7 @@
var walletId = Context.GetRouteValue("walletId").ToString();
Model.ReturnUrl ??= Url.WalletTransactions(walletId);
Layout = "_LayoutWizard";
- ViewData.SetActivePage(WalletsNavPages.Send, StringLocalizer["Sign PSBT"], walletId);
+ ViewData.SetTitle(StringLocalizer["Sign PSBT"]);
}
@section Navbar {
diff --git a/BTCPayServer/Views/UIWallets/WalletBumpFee.cshtml b/BTCPayServer/Views/UIWallets/WalletBumpFee.cshtml
index f1385b4..ed4ebc9 100644
--- a/BTCPayServer/Views/UIWallets/WalletBumpFee.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletBumpFee.cshtml
@@ -7,7 +7,7 @@
var walletId = Context.GetRouteValue("walletId").ToString();
var cancelUrl = this.Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId });
Layout = "_LayoutWizard";
- ViewData.SetActivePage(WalletsNavPages.Send, StringLocalizer["Bump fee"], walletId);
+ ViewData.SetTitle(StringLocalizer["Bump fee"]);
}
@section Navbar {
diff --git a/BTCPayServer/Views/UIWallets/WalletLabels.cshtml b/BTCPayServer/Views/UIWallets/WalletLabels.cshtml
index d8024da..88fa08f 100644
--- a/BTCPayServer/Views/UIWallets/WalletLabels.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletLabels.cshtml
@@ -1,8 +1,9 @@
-@using BTCPayServer.Abstractions.Models
@model WalletLabelsModel
@{
var walletId = Context.GetRouteValue("walletId").ToString();
- ViewData.SetActivePage(WalletsNavPages.Settings, StringLocalizer["{0} Wallet Labels", Model.WalletId.CryptoCode], walletId);
+ var cryptoCode = Model.WalletId.CryptoCode;
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(WalletsNavPages.Settings)}-{cryptoCode}", StringLocalizer["{0} Wallet Labels", Model.WalletId.CryptoCode])
+ .SetCategory(WellKnownCategories.ForWallet(cryptoCode)));
}
@section PageFootContent {
diff --git a/BTCPayServer/Views/UIWallets/WalletPSBT.cshtml b/BTCPayServer/Views/UIWallets/WalletPSBT.cshtml
index 062692e..1cdef74 100644
--- a/BTCPayServer/Views/UIWallets/WalletPSBT.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletPSBT.cshtml
@@ -5,7 +5,7 @@
var walletId = Context.GetRouteValue("walletId").ToString();
Model.ReturnUrl ??= Url.WalletTransactions(walletId);
Layout = "_LayoutWizard";
- ViewData.SetActivePage(WalletsNavPages.PSBT, StringLocalizer["Decode PSBT"], walletId);
+ ViewData.SetTitle(StringLocalizer["Decode PSBT"]);
Csp.UnsafeEval();
}
@@ -32,7 +32,7 @@
const cryptoPSBT = new window.URlib.CryptoPSBT(buffer);
const encoder = cryptoPSBT.toUREncoder();
const bbqrSplitResult = BBQr.splitQRs(buffer, 'P', { maxVersion: 10});
-
+
const modes = {
ur: { title: "UR", fragments: encoder.encodeWhole() },
static: { title: "Static", fragments: [psbtHex] },
@@ -94,7 +94,7 @@
<div class="d-flex">
@if (this.Model.SigningContext.PendingTransactionId is not null)
{
- <button type="submit" name="command" value="collect" class="btn btn-primary mt-2" id="Collect" text-translate="true">Collect signatures</button>
+ <button type="submit" name="command" value="collect" class="btn btn-primary mt-2" id="Collect" text-translate="true">Collect signatures</button>
}
else
{
diff --git a/BTCPayServer/Views/UIWallets/WalletPSBTCombine.cshtml b/BTCPayServer/Views/UIWallets/WalletPSBTCombine.cshtml
index fa23725..1b29fa6 100644
--- a/BTCPayServer/Views/UIWallets/WalletPSBTCombine.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletPSBTCombine.cshtml
@@ -4,7 +4,7 @@
var walletId = Context.GetRouteValue("walletId").ToString();
Model.ReturnUrl ??= Url.WalletTransactions(walletId);
Layout = "_LayoutWizard";
- ViewData.SetActivePage(WalletsNavPages.PSBT, StringLocalizer["Combine PSBT"], walletId);
+ ViewData.SetTitle(StringLocalizer["Combine PSBT"]);
}
@section Navbar {
diff --git a/BTCPayServer/Views/UIWallets/WalletPSBTDecoded.cshtml b/BTCPayServer/Views/UIWallets/WalletPSBTDecoded.cshtml
index 2738999..bfb3d5b 100644
--- a/BTCPayServer/Views/UIWallets/WalletPSBTDecoded.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletPSBTDecoded.cshtml
@@ -8,7 +8,7 @@
var isSignable = !isReady;
var needsExport = !isSignable && !isReady;
Layout = "_LayoutWizard";
- ViewData.SetActivePage(WalletsNavPages.PSBT, isReady ? StringLocalizer["Confirm broadcasting this transaction"] : StringLocalizer["Transaction Details"], walletId);
+ ViewData.SetTitle(StringLocalizer["Confirm broadcasting this transaction"]);
Csp.UnsafeEval();
}
@@ -33,7 +33,7 @@
<script>
hljs.initHighlightingOnLoad();
-
+
document.addEventListener("DOMContentLoaded", () => {
const psbtHex = @Json.Serialize(Model.PSBTHex);
const buffer = new window.URlib.Buffer.from(psbtHex, "hex");
@@ -49,14 +49,14 @@
document.querySelector("#PSBTOptionsImportHeader button").click()
document.getElementById("scanqrcode").click()
};
-
+
initQRShow({
title: "Scan the PSBT with your wallet",
modes,
continueTitle: "Continue with signed PSBT",
continueCallback
});
-
+
initCameraScanningApp("Scan the PSBT from your wallet", data => {
let hex = data;
if (typeof(data) === "object") {
@@ -95,18 +95,18 @@
<input type="hidden" asp-for="FileName" />
<input type="hidden" asp-for="ReturnUrl" />
<input type="hidden" asp-for="BackUrl" />
-
+
<partial name="SigningContext" for="SigningContext" />
<div class="d-flex flex-column flex-sm-row flex-wrap justify-content-center align-items-sm-center gap-2">
<button type="submit" id="SignTransaction" name="command" value="sign" class="btn btn-primary" text-translate="true">Sign transaction</button>
@if (Model.SigningContext.PendingTransactionId is null && !Model.NBXSeedAvailable)
{
- <button type="submit" id="CreatePendingTransaction" name="command" value="createpending"
+ <button type="submit" id="CreatePendingTransaction" name="command" value="createpending"
class="btn btn-primary">Create pending transaction</button>
}
else if (Model.SigningContext.PendingTransactionId is not null)
{
- <a asp-action="CancelPendingTransaction" asp-route-walletId="@walletId"
+ <a asp-action="CancelPendingTransaction" asp-route-walletId="@walletId"
asp-route-pendingTransactionId="@Model.SigningContext.PendingTransactionId" class="btn btn-danger">Cancel</a>
}
</div>
diff --git a/BTCPayServer/Views/UIWallets/WalletReceive.cshtml b/BTCPayServer/Views/UIWallets/WalletReceive.cshtml
index 2276a91..b2630f3 100644
--- a/BTCPayServer/Views/UIWallets/WalletReceive.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletReceive.cshtml
@@ -4,10 +4,10 @@
@using BTCPayServer.Services
@model BTCPayServer.Controllers.WalletReceiveViewModel
@{
- var walletId = Context.GetRouteValue("walletId").ToString();
+ var walletId = Context.GetRouteValue("walletId")!.ToString();
var returnUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId });
Layout = "_LayoutWizard";
- ViewData.SetActivePage(WalletsNavPages.Receive, StringLocalizer["Receive {0}", Model.CryptoCode], walletId);
+ ViewData.SetTitle(StringLocalizer["Receive {0}", Model!.CryptoCode]);
}
@section PageHeadContent
diff --git a/BTCPayServer/Views/UIWallets/WalletRescan.cshtml b/BTCPayServer/Views/UIWallets/WalletRescan.cshtml
index 4f8d215..a4ebd49 100644
--- a/BTCPayServer/Views/UIWallets/WalletRescan.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletRescan.cshtml
@@ -1,7 +1,9 @@
@model RescanWalletModel
@{
- var walletId = Context.GetRouteValue("walletId").ToString();
- ViewData.SetActivePage(WalletsNavPages.Settings, StringLocalizer["Rescan Wallet"], walletId);
+ var walletId = Context.GetRouteValue("walletId")!.ToString();
+ var w = WalletId.Parse(walletId!);
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(WalletsNavPages.Settings)}-{w.CryptoCode}", StringLocalizer["Rescan Wallet"])
+ .SetCategory(WellKnownCategories.ForWallet(w.CryptoCode)));
}
<h3 class="mb-3">@ViewData["Title"]</h3>
diff --git a/BTCPayServer/Views/UIWallets/WalletSend.cshtml b/BTCPayServer/Views/UIWallets/WalletSend.cshtml
index 922c4c2..20ea557 100644
--- a/BTCPayServer/Views/UIWallets/WalletSend.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletSend.cshtml
@@ -9,7 +9,8 @@
var walletId = Context.GetRouteValue("walletId").ToString();
Model.ReturnUrl ??= Url.WalletTransactions(walletId);
Layout = "_LayoutWizard";
- ViewData.SetActivePage(WalletsNavPages.Send, StringLocalizer["Send {0}", Model.CryptoCode], walletId);
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(WalletsNavPages.Send)}-{Model.CryptoCode}", StringLocalizer["Send {0}", Model.CryptoCode])
+ .SetCategory(WellKnownCategories.ForWallet(Model.CryptoCode)));
Csp.Add("worker-src", "blob:");
Csp.UnsafeEval();
}
diff --git a/BTCPayServer/Views/UIWallets/WalletSendVault.cshtml b/BTCPayServer/Views/UIWallets/WalletSendVault.cshtml
index ea42193..71a656c 100644
--- a/BTCPayServer/Views/UIWallets/WalletSendVault.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletSendVault.cshtml
@@ -5,7 +5,7 @@
var walletId = Context.GetRouteValue("walletId")?.ToString() ?? "";
Model.ReturnUrl ??= Url.WalletTransactions(walletId);
Layout = "_LayoutWizard";
- ViewData.SetActivePage(WalletsNavPages.Send, StringLocalizer["Sign the transaction"], walletId);
+ ViewData.SetTitle(StringLocalizer["Sign the transaction"]);
this.ViewData.SetBlazorAllowed(true);
// Calculate maximum PSBT size accounting for SignalR message overhead
@@ -20,7 +20,7 @@
}
<header class="text-center">
- <h1>@ViewData["Title"]</h1>
+ <h1>@ViewData.GetTitle()</h1>
<p class="lead text-secondary mt-3" text-translate="true">Using BTCPay Server Vault</p>
</header>
diff --git a/BTCPayServer/Views/UIWallets/WalletSigningOptions.cshtml b/BTCPayServer/Views/UIWallets/WalletSigningOptions.cshtml
index d211d67..32aefe5 100644
--- a/BTCPayServer/Views/UIWallets/WalletSigningOptions.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletSigningOptions.cshtml
@@ -5,7 +5,7 @@
var walletId = WalletId.Parse(Context.GetRouteValue("walletId").ToString());
Model.ReturnUrl ??= Url.WalletTransactions(walletId);
Layout = "_LayoutWizard";
- ViewData.SetActivePage(WalletsNavPages.Send, StringLocalizer["Sign the transaction"], walletId.ToString());
+ ViewData.SetTitle(StringLocalizer["Sign the transaction"]);
}
@section Navbar {
diff --git a/BTCPayServer/Views/UIWallets/WalletTransactions.cshtml b/BTCPayServer/Views/UIWallets/WalletTransactions.cshtml
index c57fc19..05a939d 100644
--- a/BTCPayServer/Views/UIWallets/WalletTransactions.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletTransactions.cshtml
@@ -15,7 +15,8 @@
var wallet = walletId != null ? WalletId.Parse(walletId) : new WalletId(storeId, cryptoCode);
storeId = wallet.StoreId;
- ViewData.SetActivePage(WalletsNavPages.Transactions, StringLocalizer["{0} Transactions", Model.CryptoCode], walletId);
+ ViewData.SetLayoutModel(new LayoutModel($"{nameof(WalletsNavPages.Transactions)}-{Model.CryptoCode}", StringLocalizer["{0} Transactions", Model.CryptoCode])
+ .SetCategory(WellKnownCategories.ForWallet(Model.CryptoCode)));
}
@section PageHeadContent {
diff --git a/BTCPayServer/_ViewImports.cshtml b/BTCPayServer/_ViewImports.cshtml
index f7629b2..febdc46 100644
--- a/BTCPayServer/_ViewImports.cshtml
+++ b/BTCPayServer/_ViewImports.cshtml
@@ -1,6 +1,7 @@
@using Microsoft.AspNetCore.Identity
@using BTCPayServer
@using BTCPayServer.Abstractions.Services
+@using BTCPayServer.Abstractions.Models
@using BTCPayServer.Views
@using BTCPayServer.Models
@using BTCPayServer.Models.AccountViewModels
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.