mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 05:54:26 +01:00
Refactor access to the ViewModel of the MainLayout (#6970)
This commit is contained in:
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using BTCPayServer.Abstractions.Models;
|
||||||
using Microsoft.AspNetCore.Html;
|
using Microsoft.AspNetCore.Html;
|
||||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||||
|
|
||||||
@@ -35,16 +36,28 @@ namespace BTCPayServer.Abstractions.Extensions
|
|||||||
SetActivePage(viewData, activePage.ToString(), activePage.GetType().ToString(), title, activeId);
|
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
|
// Page Title
|
||||||
viewData["Title"] = title ?? activePage;
|
viewData["Title"] = model.Title ?? model.MenuItemId;
|
||||||
// Navigation
|
// Navigation
|
||||||
viewData[ACTIVE_PAGE_KEY] = activePage;
|
viewData[ACTIVE_PAGE_KEY] = model.MenuItemId;
|
||||||
viewData[ACTIVE_ID_KEY] = activeId;
|
viewData[ACTIVE_ID_KEY] = model.SubMenuItemId;
|
||||||
SetActiveCategory(viewData, category);
|
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)
|
public static void SetActiveCategory<T>(this ViewDataDictionary viewData, T activeCategory)
|
||||||
{
|
{
|
||||||
SetActiveCategory(viewData, activeCategory.ToString());
|
SetActiveCategory(viewData, activeCategory.ToString());
|
||||||
@@ -55,6 +68,7 @@ namespace BTCPayServer.Abstractions.Extensions
|
|||||||
viewData[ACTIVE_CATEGORY_KEY] = activeCategory;
|
viewData[ACTIVE_CATEGORY_KEY] = activeCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use IsCategory instead")]
|
||||||
public static bool IsCategoryActive(this ViewDataDictionary viewData, string category, object id = null)
|
public static bool IsCategoryActive(this ViewDataDictionary viewData, string category, object id = null)
|
||||||
{
|
{
|
||||||
if (!viewData.ContainsKey(ACTIVE_CATEGORY_KEY)) return false;
|
if (!viewData.ContainsKey(ACTIVE_CATEGORY_KEY)) return false;
|
||||||
@@ -65,6 +79,7 @@ namespace BTCPayServer.Abstractions.Extensions
|
|||||||
return categoryMatch && idMatch;
|
return categoryMatch && idMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use IsCategory instead")]
|
||||||
public static bool IsCategoryActive<T>(this ViewDataDictionary viewData, T category, object id = null)
|
public static bool IsCategoryActive<T>(this ViewDataDictionary viewData, T category, object id = null)
|
||||||
{
|
{
|
||||||
return IsCategoryActive(viewData, category.ToString(), id);
|
return IsCategoryActive(viewData, category.ToString(), id);
|
||||||
@@ -81,7 +96,7 @@ namespace BTCPayServer.Abstractions.Extensions
|
|||||||
var idMatch = id == null || activeId == null || id.Equals(activeId);
|
var idMatch = id == null || activeId == null || id.Equals(activeId);
|
||||||
return categoryAndPageMatch && idMatch;
|
return categoryAndPageMatch && idMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsPageActive<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null)
|
public static bool IsPageActive<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null)
|
||||||
where T : IConvertible
|
where T : IConvertible
|
||||||
{
|
{
|
||||||
@@ -98,17 +113,20 @@ namespace BTCPayServer.Abstractions.Extensions
|
|||||||
return IsCategoryActive(viewData, category, id) ? ACTIVE_CLASS : null;
|
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)
|
public static string ActivePageClass<T>(this ViewDataDictionary viewData, T page, object id = null)
|
||||||
where T : IConvertible
|
where T : IConvertible
|
||||||
{
|
{
|
||||||
return ActivePageClass(viewData, page.ToString(), page.GetType().ToString(), id);
|
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)
|
public static string ActivePageClass(this ViewDataDictionary viewData, string page, string category, object id = null)
|
||||||
{
|
{
|
||||||
return IsPageActive(viewData, page, category, id) ? ACTIVE_CLASS : 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
|
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;
|
return IsPageActive(viewData, pages, id) ? ACTIVE_CLASS : null;
|
||||||
|
|||||||
36
BTCPayServer.Abstractions/Models/LayoutModel.cs
Normal file
36
BTCPayServer.Abstractions/Models/LayoutModel.cs
Normal file
@@ -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; }
|
||||||
|
}
|
||||||
@@ -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 : "")}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,7 +91,7 @@ public class MultisigTests : UnitTestBase
|
|||||||
s.TestLogs.LogInformation($"Multisig wallet setup: {multisigDerivationScheme}");
|
s.TestLogs.LogInformation($"Multisig wallet setup: {multisigDerivationScheme}");
|
||||||
|
|
||||||
// fetch address from receive page
|
// fetch address from receive page
|
||||||
await s.Page.ClickAsync("#WalletNav-Receive");
|
await s.GoToWallet(navPages: WalletsNavPages.Receive);
|
||||||
|
|
||||||
var addressElement = s.Page.Locator("#Address");
|
var addressElement = s.Page.Locator("#Address");
|
||||||
await addressElement.ClickAsync();
|
await addressElement.ClickAsync();
|
||||||
@@ -101,7 +101,7 @@ public class MultisigTests : UnitTestBase
|
|||||||
await s.Page.ClickAsync("#CancelWizard");
|
await s.Page.ClickAsync("#CancelWizard");
|
||||||
|
|
||||||
// we are creating a pending transaction
|
// 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);
|
await s.Page.FillAsync("#Outputs_0__DestinationAddress", address);
|
||||||
var amount = "0.1";
|
var amount = "0.1";
|
||||||
await s.Page.FillAsync("#Outputs_0__Amount", amount);
|
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());
|
Assert.False(await s.Page.Locator("//a[text()='Broadcast']").IsVisibleAsync());
|
||||||
|
|
||||||
// Abort pending transaction flow
|
// 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__DestinationAddress", address);
|
||||||
await s.Page.FillAsync("#Outputs_0__Amount", "0.2");
|
await s.Page.FillAsync("#Outputs_0__Amount", "0.2");
|
||||||
await s.Page.ClickAsync("#CreatePendingTransaction");
|
await s.Page.ClickAsync("#CreatePendingTransaction");
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ fruit tea:
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Integration", "Integration")]
|
[Trait("Playwright", "Playwright")]
|
||||||
public async Task CanExportInvoicesWithMetadata()
|
public async Task CanExportInvoicesWithMetadata()
|
||||||
{
|
{
|
||||||
await using var s = CreatePlaywrightTester();
|
await using var s = CreatePlaywrightTester();
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace BTCPayServer.Tests
|
|||||||
var psbt = await ExtractPSBT(s);
|
var psbt = await ExtractPSBT(s);
|
||||||
|
|
||||||
await s.GoToStore(hot.storeId);
|
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.Locator("[name='PSBT']").FillAsync(psbt);
|
||||||
await s.Page.ClickAsync("#Decode");
|
await s.Page.ClickAsync("#Decode");
|
||||||
await s.Page.ClickAsync("#SignTransaction");
|
await s.Page.ClickAsync("#SignTransaction");
|
||||||
@@ -72,7 +72,7 @@ namespace BTCPayServer.Tests
|
|||||||
var skeletonPSBT = psbtParsed;
|
var skeletonPSBT = psbtParsed;
|
||||||
|
|
||||||
await s.GoToStore(cold.storeId);
|
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.Locator("[name='PSBT']").FillAsync(skeletonPSBT.ToBase64());
|
||||||
await s.Page.ClickAsync("#Decode");
|
await s.Page.ClickAsync("#Decode");
|
||||||
await s.Page.ClickAsync("#SignTransaction");
|
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)
|
// 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)
|
// 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.Locator("[name='PSBT']").FillAsync(psbtParsed.ToBase64());
|
||||||
await s.Page.ClickAsync("#Decode");
|
await s.Page.ClickAsync("#Decode");
|
||||||
await s.Page.ClickAsync("#PSBTOptionsAdvancedHeader");
|
await s.Page.ClickAsync("#PSBTOptionsAdvancedHeader");
|
||||||
|
|||||||
@@ -7,21 +7,17 @@ using System.Text.RegularExpressions;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Extensions;
|
using BTCPayServer.Abstractions.Extensions;
|
||||||
using BTCPayServer.Abstractions.Models;
|
using BTCPayServer.Abstractions.Models;
|
||||||
using BTCPayServer.Blazor.VaultBridge.Elements;
|
|
||||||
using BTCPayServer.Client.Models;
|
using BTCPayServer.Client.Models;
|
||||||
using BTCPayServer.Data;
|
|
||||||
using BTCPayServer.Lightning;
|
using BTCPayServer.Lightning;
|
||||||
using BTCPayServer.Lightning.CLightning;
|
using BTCPayServer.Lightning.CLightning;
|
||||||
using BTCPayServer.Views.Manage;
|
using BTCPayServer.Views.Manage;
|
||||||
using BTCPayServer.Views.Server;
|
using BTCPayServer.Views.Server;
|
||||||
using BTCPayServer.Views.Stores;
|
using BTCPayServer.Views.Stores;
|
||||||
using BTCPayServer.Views.Wallets;
|
using BTCPayServer.Views.Wallets;
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Playwright;
|
using Microsoft.Playwright;
|
||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using NBitcoin.RPC;
|
using NBitcoin.RPC;
|
||||||
using OpenQA.Selenium;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace BTCPayServer.Tests
|
namespace BTCPayServer.Tests
|
||||||
@@ -52,7 +48,8 @@ namespace BTCPayServer.Tests
|
|||||||
Browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
|
Browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
|
||||||
{
|
{
|
||||||
Headless = Server.PayTester.InContainer,
|
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();
|
var context = await Browser.NewContextAsync();
|
||||||
Page = await context.NewPageAsync();
|
Page = await context.NewPageAsync();
|
||||||
@@ -67,7 +64,7 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
if (storeId is null)
|
if (storeId is null)
|
||||||
{
|
{
|
||||||
await Page.Locator("#StoreNav-Invoices").ClickAsync();
|
await Page.Locator("#menu-item-Invoices").ClickAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -117,21 +114,51 @@ namespace BTCPayServer.Tests
|
|||||||
await GoToUrl($"/i/{invoiceId}");
|
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;
|
var walletPage = GetWalletIdFromUrl();
|
||||||
await GoToUrl($"wallets/{walletId}");
|
// If null, we try to go to the wallet of the current page
|
||||||
if (navPages == WalletsNavPages.PSBT)
|
if (walletId is null)
|
||||||
{
|
{
|
||||||
await Page.Locator("#WalletNav-Send").ClickAsync();
|
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 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();
|
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)
|
public async Task<ILocator> FindAlertMessage(StatusMessageModel.StatusSeverity severity = StatusMessageModel.StatusSeverity.Success, string partialText = null)
|
||||||
{
|
{
|
||||||
var locator = await FindAlertMessage(new[] { severity });
|
var locator = await FindAlertMessage(new[] { severity });
|
||||||
@@ -219,7 +246,7 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.Equal("Recommendation (Kraken)", selectedOption?.Trim());
|
Assert.Equal("Recommendation (Kraken)", selectedOption?.Trim());
|
||||||
await Page.Locator("#PreferredExchange").SelectOptionAsync(new SelectOptionValue { Label = preferredExchange });
|
await Page.Locator("#PreferredExchange").SelectOptionAsync(new SelectOptionValue { Label = preferredExchange });
|
||||||
await Page.ClickAsync("#Create");
|
await Page.ClickAsync("#Create");
|
||||||
await Page.ClickAsync("#StoreNav-General");
|
await GoToStore(StoreNavPages.General);
|
||||||
var storeId = await Page.InputValueAsync("#Id");
|
var storeId = await Page.InputValueAsync("#Id");
|
||||||
if (keepId)
|
if (keepId)
|
||||||
StoreId = storeId;
|
StoreId = storeId;
|
||||||
@@ -232,7 +259,8 @@ namespace BTCPayServer.Tests
|
|||||||
var isImport = !string.IsNullOrEmpty(seed);
|
var isImport = !string.IsNullOrEmpty(seed);
|
||||||
await GoToWalletSettings(cryptoCode);
|
await GoToWalletSettings(cryptoCode);
|
||||||
// Replace previous wallet case
|
// Replace previous wallet case
|
||||||
if (await Page.Locator("#ActionsDropdownToggle").IsVisibleAsync())
|
var isSettings = Page.Url.EndsWith("/settings");
|
||||||
|
if (isSettings)
|
||||||
{
|
{
|
||||||
TestLogs.LogInformation($"Replacing the wallet");
|
TestLogs.LogInformation($"Replacing the wallet");
|
||||||
await Page.ClickAsync("#ActionsDropdownToggle");
|
await Page.ClickAsync("#ActionsDropdownToggle");
|
||||||
@@ -296,7 +324,7 @@ namespace BTCPayServer.Tests
|
|||||||
}
|
}
|
||||||
public async Task Logout()
|
public async Task Logout()
|
||||||
{
|
{
|
||||||
await Page.Locator("#Nav-Account").ClickAsync();
|
await Page.Locator("#menu-item-Account").ClickAsync();
|
||||||
await Page.Locator("#Nav-Logout").ClickAsync();
|
await Page.Locator("#Nav-Logout").ClickAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,24 +358,24 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
public async Task GoToProfile(ManageNavPages navPages = ManageNavPages.Index)
|
public async Task GoToProfile(ManageNavPages navPages = ManageNavPages.Index)
|
||||||
{
|
{
|
||||||
await Page.ClickAsync("#Nav-Account");
|
await Page.ClickAsync("#menu-item-Account");
|
||||||
await Page.ClickAsync("#Nav-ManageAccount");
|
await Page.ClickAsync("#Nav-ManageAccount");
|
||||||
if (navPages != ManageNavPages.Index)
|
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)
|
public async Task GoToServer(ServerNavPages navPages = ServerNavPages.Policies)
|
||||||
{
|
{
|
||||||
await Page.ClickAsync("#Nav-ServerSettings");
|
await Page.ClickAsync("#menu-item-Policies");
|
||||||
if (navPages != ServerNavPages.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 = [];
|
List<string> links = [];
|
||||||
foreach (var locator in await Page.Locator($"{sectionSelector} .nav-link").AllAsync())
|
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")
|
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 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")
|
public async Task GoToWalletSettings(string cryptoCode = "BTC")
|
||||||
{
|
{
|
||||||
await Page.ClickAsync($"#StoreNav-Wallet{cryptoCode}");
|
await Page.GetByTestId("Wallet-" + cryptoCode).Locator("a").ClickAsync();
|
||||||
var walletNavSettings = Page.Locator("#WalletNav-Settings");
|
var walletNavSettings = Page.Locator($"#menu-item-Settings-{cryptoCode}");
|
||||||
if (await walletNavSettings.CountAsync() > 0)
|
if (await walletNavSettings.CountAsync() > 0)
|
||||||
await walletNavSettings.ClickAsync();
|
await walletNavSettings.ClickAsync();
|
||||||
}
|
}
|
||||||
@@ -476,9 +504,9 @@ namespace BTCPayServer.Tests
|
|||||||
if (WalletId != null)
|
if (WalletId != null)
|
||||||
WalletId = new WalletId(storeId, WalletId.CryptoCode);
|
WalletId = new WalletId(storeId, WalletId.CryptoCode);
|
||||||
if (storeNavPage != StoreNavPages.General)
|
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()
|
public async Task ClickCancel()
|
||||||
{
|
{
|
||||||
@@ -561,7 +589,7 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
name = $"{type}-{Guid.NewGuid().ToString()[..14]}";
|
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 Page.Locator("[name='AppName']").FillAsync(name);
|
||||||
await ClickPagePrimary();
|
await ClickPagePrimary();
|
||||||
await FindAlertMessage(partialText: "App successfully created");
|
await FindAlertMessage(partialText: "App successfully created");
|
||||||
|
|||||||
@@ -71,10 +71,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.InitializeBTCPayServer();
|
await s.InitializeBTCPayServer();
|
||||||
// Point Of Sale
|
// Point Of Sale
|
||||||
var appName = $"PoS-{Guid.NewGuid().ToString()[..21]}";
|
var appName = $"PoS-{Guid.NewGuid().ToString()[..21]}";
|
||||||
await s.Page.ClickAsync("#StoreNav-CreatePointOfSale");
|
await s.CreateApp("PointOfSale", appName);
|
||||||
await s.Page.FillAsync("#AppName", appName);
|
|
||||||
await s.ClickPagePrimary();
|
|
||||||
await s.FindAlertMessage(partialText: "App successfully created");
|
|
||||||
await s.Page.SelectOptionAsync("#FormId", "Email");
|
await s.Page.SelectOptionAsync("#FormId", "Email");
|
||||||
await s.ClickPagePrimary();
|
await s.ClickPagePrimary();
|
||||||
await s.FindAlertMessage(partialText: "App updated");
|
await s.FindAlertMessage(partialText: "App updated");
|
||||||
@@ -94,7 +91,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.GoToUrl($"/invoices/{invoiceId}/");
|
await s.GoToUrl($"/invoices/{invoiceId}/");
|
||||||
Assert.Contains("aa@aa.com", await s.Page.ContentAsync());
|
Assert.Contains("aa@aa.com", await s.Page.ContentAsync());
|
||||||
// Payment Request
|
// Payment Request
|
||||||
await s.Page.ClickAsync("#StoreNav-PaymentRequests");
|
await s.Page.ClickAsync("#menu-item-PaymentRequests");
|
||||||
await s.ClickPagePrimary();
|
await s.ClickPagePrimary();
|
||||||
await s.Page.FillAsync("#Title", "Pay123");
|
await s.Page.FillAsync("#Title", "Pay123");
|
||||||
await s.Page.FillAsync("#Amount", "700");
|
await s.Page.FillAsync("#Amount", "700");
|
||||||
@@ -142,9 +139,11 @@ namespace BTCPayServer.Tests
|
|||||||
await s.GoToHome();
|
await s.GoToHome();
|
||||||
await s.GoToStore();
|
await s.GoToStore();
|
||||||
await s.GoToStore(StoreNavPages.Forms);
|
await s.GoToStore(StoreNavPages.Forms);
|
||||||
|
await s.Page.WaitForLoadStateAsync();
|
||||||
Assert.Contains("Custom Form 1", await s.Page.ContentAsync());
|
Assert.Contains("Custom Form 1", await s.Page.ContentAsync());
|
||||||
await s.Page.GetByRole(AriaRole.Link, new() { Name = "Remove" }).ClickAsync();
|
await s.Page.GetByRole(AriaRole.Link, new() { Name = "Remove" }).ClickAsync();
|
||||||
await s.ConfirmDeleteModal();
|
await s.ConfirmDeleteModal();
|
||||||
|
await s.Page.WaitForLoadStateAsync();
|
||||||
Assert.DoesNotContain("Custom Form 1", await s.Page.ContentAsync());
|
Assert.DoesNotContain("Custom Form 1", await s.Page.ContentAsync());
|
||||||
await s.ClickPagePrimary();
|
await s.ClickPagePrimary();
|
||||||
await s.Page.FillAsync("[name='Name']", "Custom Form 2");
|
await s.Page.FillAsync("[name='Name']", "Custom Form 2");
|
||||||
@@ -169,7 +168,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.ClickPagePrimary();
|
await s.ClickPagePrimary();
|
||||||
await s.GoToStore(StoreNavPages.Forms);
|
await s.GoToStore(StoreNavPages.Forms);
|
||||||
Assert.Contains("Custom Form 3", await s.Page.ContentAsync());
|
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();
|
await s.ClickPagePrimary();
|
||||||
var selectOptions = await s.Page.Locator("#FormId >> option").CountAsync();
|
var selectOptions = await s.Page.Locator("#FormId >> option").CountAsync();
|
||||||
Assert.Equal(4, selectOptions);
|
Assert.Equal(4, selectOptions);
|
||||||
@@ -584,7 +583,7 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.Equal("Can Use Store?" ,await s.Page.InputValueAsync("#Name"));
|
Assert.Equal("Can Use Store?" ,await s.Page.InputValueAsync("#Name"));
|
||||||
await s.Page.FillAsync("#Name", "Just changed it!");
|
await s.Page.FillAsync("#Name", "Just changed it!");
|
||||||
await s.Page.ClickAsync("#Create");
|
await s.Page.ClickAsync("#Create");
|
||||||
await s.Page.ClickAsync("#StoreNav-General");
|
await s.GoToStore();
|
||||||
var newStoreId = await s.Page.InputValueAsync("#Id");
|
var newStoreId = await s.Page.InputValueAsync("#Id");
|
||||||
Assert.NotEqual(newStoreId, s.StoreId);
|
Assert.NotEqual(newStoreId, s.StoreId);
|
||||||
|
|
||||||
@@ -875,8 +874,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.GenerateWallet(cryptoCode, "", true);
|
await s.GenerateWallet(cryptoCode, "", true);
|
||||||
|
|
||||||
//let's test quickly the wallet send page
|
//let's test quickly the wallet send page
|
||||||
await s.Page.ClickAsync($"#StoreNav-Wallet{cryptoCode}");
|
await s.GoToWallet(navPages: WalletsNavPages.Send);
|
||||||
await s.Page.ClickAsync("#WalletNav-Send");
|
|
||||||
//you cannot use the Sign with NBX option without saving private keys when generating the wallet.
|
//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.DoesNotContain("nbx-seed", await s.Page.ContentAsync());
|
||||||
Assert.Equal(0, await s.Page.Locator("#GoBack").CountAsync());
|
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");
|
await s.Page.WaitForSelectorAsync("text=Destination Address field is required");
|
||||||
Assert.Equal(0, await s.Page.Locator("#GoBack").CountAsync());
|
Assert.Equal(0, await s.Page.Locator("#GoBack").CountAsync());
|
||||||
await s.Page.ClickAsync("#CancelWizard");
|
await s.Page.ClickAsync("#CancelWizard");
|
||||||
await s.Page.ClickAsync("#WalletNav-Receive");
|
await s.GoToWallet(navPages: WalletsNavPages.Receive);
|
||||||
|
|
||||||
//generate a receiving address
|
//generate a receiving address
|
||||||
await s.Page.WaitForSelectorAsync("#address-tab .qr-container");
|
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
|
// Assert that the added label is associated with the transaction
|
||||||
await wt.AssertHasLabels("tx-label");
|
await wt.AssertHasLabels("tx-label");
|
||||||
|
|
||||||
await s.Page.ClickAsync($"#StoreNav-Wallet{cryptoCode}");
|
await s.GoToWallet(navPages: WalletsNavPages.Send);
|
||||||
await s.Page.ClickAsync("#WalletNav-Send");
|
|
||||||
|
|
||||||
var jack = new Key().PubKey.Hash.GetAddress(Network.RegTest);
|
var jack = new Key().PubKey.Hash.GetAddress(Network.RegTest);
|
||||||
await ws.FillAddress(jack);
|
await ws.FillAddress(jack);
|
||||||
@@ -1090,7 +1087,7 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.Equal(settingsUri.ToString(), s.Page.Url);
|
Assert.Equal(settingsUri.ToString(), s.Page.Url);
|
||||||
|
|
||||||
// Once more, test the cancel link of the wallet send page leads back to the previous page
|
// 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");
|
cancelUrl = await s.Page.Locator("#CancelWizard").GetAttributeAsync("href");
|
||||||
Assert.EndsWith(settingsUri.AbsolutePath, cancelUrl);
|
Assert.EndsWith(settingsUri.AbsolutePath, cancelUrl);
|
||||||
// no previous page in the wizard, hence no back button
|
// no previous page in the wizard, hence no back button
|
||||||
@@ -1230,7 +1227,7 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
// Create a payment request
|
// Create a payment request
|
||||||
await s.GoToStore();
|
await s.GoToStore();
|
||||||
await s.Page.ClickAsync("#StoreNav-PaymentRequests");
|
await s.Page.ClickAsync("#menu-item-PaymentRequests");
|
||||||
await s.ClickPagePrimary();
|
await s.ClickPagePrimary();
|
||||||
await s.Page.FillAsync("#Title", "Test Payment Request");
|
await s.Page.FillAsync("#Title", "Test Payment Request");
|
||||||
await s.Page.FillAsync("#Amount", "0.1");
|
await s.Page.FillAsync("#Amount", "0.1");
|
||||||
@@ -1272,7 +1269,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.Page.WaitForLoadStateAsync();
|
await s.Page.WaitForLoadStateAsync();
|
||||||
|
|
||||||
await s.GoToStore();
|
await s.GoToStore();
|
||||||
await s.Page.ClickAsync("#StoreNav-PaymentRequests");
|
await s.Page.ClickAsync("#menu-item-PaymentRequests");
|
||||||
await s.Page.WaitForLoadStateAsync();
|
await s.Page.WaitForLoadStateAsync();
|
||||||
|
|
||||||
var opening2 = s.Page.Context.WaitForPageAsync();
|
var opening2 = s.Page.Context.WaitForPageAsync();
|
||||||
@@ -1288,7 +1285,7 @@ namespace BTCPayServer.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
await s.GoToStore();
|
await s.GoToStore();
|
||||||
await s.Page.ClickAsync("#StoreNav-PaymentRequests");
|
await s.Page.ClickAsync("#menu-item-PaymentRequests");
|
||||||
await s.Page.WaitForLoadStateAsync();
|
await s.Page.WaitForLoadStateAsync();
|
||||||
|
|
||||||
var listContent = await s.Page.ContentAsync();
|
var listContent = await s.Page.ContentAsync();
|
||||||
@@ -1349,14 +1346,14 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.Equal("1", await s.Page.Locator("#NotificationsBadge").TextContentAsync());
|
Assert.Equal("1", await s.Page.Locator("#NotificationsBadge").TextContentAsync());
|
||||||
});
|
});
|
||||||
|
|
||||||
await s.Page.Locator("#NotificationsHandle").ClickAsync();
|
await s.Page.ClickAsync("#NotificationsHandle");
|
||||||
Assert.Matches($"New user {unapproved.RegisterDetails.Email} requires approval", await s.Page.Locator("#NotificationsList .notification").TextContentAsync());
|
await s.Page.Locator($"#NotificationsList .notification:has-text('New user {unapproved.RegisterDetails.Email} requires approval')").WaitForAsync();
|
||||||
await s.Page.Locator("#NotificationsMarkAllAsSeen").ClickAsync();
|
await s.Page.ClickAsync("#NotificationsMarkAllAsSeen");
|
||||||
|
|
||||||
await s.GoToServer(ServerNavPages.Policies);
|
await s.GoToServer(ServerNavPages.Policies);
|
||||||
Assert.True(await s.Page.Locator("#EnableRegistration").IsCheckedAsync());
|
Assert.True(await s.Page.Locator("#EnableRegistration").IsCheckedAsync());
|
||||||
Assert.True(await s.Page.Locator("#RequiresUserApproval").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.ClickPagePrimary();
|
||||||
await s.FindAlertMessage(partialText: "Policies updated successfully");
|
await s.FindAlertMessage(partialText: "Policies updated successfully");
|
||||||
Assert.False(await s.Page.Locator("#RequiresUserApproval").IsCheckedAsync());
|
Assert.False(await s.Page.Locator("#RequiresUserApproval").IsCheckedAsync());
|
||||||
@@ -1702,7 +1699,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.Page.GetAttributeAsync("#AccountKeys_0__AccountKeyPath", "value"));
|
await s.Page.GetAttributeAsync("#AccountKeys_0__AccountKeyPath", "value"));
|
||||||
|
|
||||||
// Transactions list is empty
|
// Transactions list is empty
|
||||||
await s.Page.ClickAsync($"#StoreNav-Wallet{cryptoCode}");
|
await s.GoToWallet();
|
||||||
await s.Page.WaitForSelectorAsync("#WalletTransactions[data-loaded='true']");
|
await s.Page.WaitForSelectorAsync("#WalletTransactions[data-loaded='true']");
|
||||||
Assert.Contains("There are no transactions yet", await s.Page.Locator("#WalletTransactions").TextContentAsync());
|
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.Server.ExplorerNode.GenerateAsync(1);
|
||||||
await s.GoToWallet(walletId);
|
await s.GoToWallet(walletId, WalletsNavPages.Send);
|
||||||
await s.Page.ClickAsync("#toggleInputSelection");
|
await s.Page.ClickAsync("#toggleInputSelection");
|
||||||
|
|
||||||
var input = s.Page.Locator("input[placeholder^='Filter']");
|
var input = s.Page.Locator("input[placeholder^='Filter']");
|
||||||
@@ -1885,11 +1882,11 @@ namespace BTCPayServer.Tests
|
|||||||
(string storeName, _) = await s.CreateNewStore();
|
(string storeName, _) = await s.CreateNewStore();
|
||||||
|
|
||||||
// Check status in navigation
|
// 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
|
// Set up LN node
|
||||||
await s.AddLightningNode();
|
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
|
// Check public node info for availability
|
||||||
var opening = s.Page.Context.WaitForPageAsync();
|
var opening = s.Page.Context.WaitForPageAsync();
|
||||||
@@ -1915,7 +1912,7 @@ namespace BTCPayServer.Tests
|
|||||||
await s.FindAlertMessage(partialText: "BTC Lightning node updated.");
|
await s.FindAlertMessage(partialText: "BTC Lightning node updated.");
|
||||||
|
|
||||||
// Check offline state is communicated in nav item
|
// 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
|
// Check public node info for availability
|
||||||
opening = s.Page.Context.WaitForPageAsync();
|
opening = s.Page.Context.WaitForPageAsync();
|
||||||
@@ -2098,8 +2095,9 @@ namespace BTCPayServer.Tests
|
|||||||
await s.Page.SetCheckedAsync("#AutoApproveClaims", true);
|
await s.Page.SetCheckedAsync("#AutoApproveClaims", true);
|
||||||
await s.ClickPagePrimary();
|
await s.ClickPagePrimary();
|
||||||
|
|
||||||
|
var o = s.Page.Context.WaitForPageAsync();
|
||||||
await s.Page.ClickAsync("text=View");
|
await s.Page.ClickAsync("text=View");
|
||||||
var newPage = await s.Page.Context.WaitForPageAsync();
|
var newPage = await o;
|
||||||
|
|
||||||
var address = await s.Server.ExplorerNode.GetNewAddressAsync();
|
var address = await s.Server.ExplorerNode.GetNewAddressAsync();
|
||||||
await newPage.FillAsync("#Destination", address.ToString());
|
await newPage.FillAsync("#Destination", address.ToString());
|
||||||
@@ -2198,7 +2196,7 @@ namespace BTCPayServer.Tests
|
|||||||
// The delivery is done asynchronously, so small wait here
|
// The delivery is done asynchronously, so small wait here
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
await s.GoToStore();
|
await s.GoToStore();
|
||||||
await s.Page.ClickAsync("#StoreNav-Webhooks");
|
await s.GoToStore(StoreNavPages.Webhooks);
|
||||||
await s.Page.ClickAsync("text=Modify");
|
await s.Page.ClickAsync("text=Modify");
|
||||||
var redeliverElements = await s.Page.Locator("button.redeliver").AllAsync();
|
var redeliverElements = await s.Page.Locator("button.redeliver").AllAsync();
|
||||||
|
|
||||||
@@ -2235,8 +2233,9 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
private static async Task CanBrowseContentAsync(PlaywrightTester s)
|
private static async Task CanBrowseContentAsync(PlaywrightTester s)
|
||||||
{
|
{
|
||||||
|
var newPageDoing = s.Page.Context.WaitForPageAsync();
|
||||||
await s.Page.ClickAsync(".delivery-content");
|
await s.Page.ClickAsync(".delivery-content");
|
||||||
var newPage = await s.Page.Context.WaitForPageAsync();
|
var newPage = await newPageDoing;
|
||||||
var bodyText = await newPage.Locator("body").TextContentAsync();
|
var bodyText = await newPage.Locator("body").TextContentAsync();
|
||||||
JObject.Parse(bodyText);
|
JObject.Parse(bodyText);
|
||||||
await newPage.CloseAsync();
|
await newPage.CloseAsync();
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ retry:
|
|||||||
Assert.Equal("Recommendation (Kraken)", rateSource.SelectedOption.Text);
|
Assert.Equal("Recommendation (Kraken)", rateSource.SelectedOption.Text);
|
||||||
rateSource.SelectByText("CoinGecko");
|
rateSource.SelectByText("CoinGecko");
|
||||||
Driver.WaitForElement(By.Id("Create")).Click();
|
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");
|
var storeId = Driver.WaitForElement(By.Id("Id")).GetAttribute("value");
|
||||||
if (keepId)
|
if (keepId)
|
||||||
StoreId = storeId;
|
StoreId = storeId;
|
||||||
@@ -415,7 +415,7 @@ retry:
|
|||||||
{
|
{
|
||||||
if (!Driver.PageSource.Contains("id=\"Nav-Logout\""))
|
if (!Driver.PageSource.Contains("id=\"Nav-Logout\""))
|
||||||
GoToUrl("/account");
|
GoToUrl("/account");
|
||||||
Driver.FindElement(By.Id("Nav-Account")).Click();
|
Driver.FindElement(By.Id("menu-item-Account")).Click();
|
||||||
Driver.FindElement(By.Id("Nav-Logout")).Click();
|
Driver.FindElement(By.Id("Nav-Logout")).Click();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,27 +447,27 @@ retry:
|
|||||||
|
|
||||||
if (storeNavPage != StoreNavPages.General)
|
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")
|
public void GoToWalletSettings(string cryptoCode = "BTC")
|
||||||
{
|
{
|
||||||
Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
Driver.FindElement(By.CssSelector($"[data-testid=\"Wallet-{cryptoCode}\"] a")).Click();
|
||||||
if (Driver.PageSource.Contains("id=\"WalletNav-Settings\""))
|
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")
|
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 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)
|
public void GoToInvoiceCheckout(string invoiceId = null)
|
||||||
{
|
{
|
||||||
invoiceId ??= InvoiceId;
|
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();
|
Driver.FindElement(By.Id($"invoice-checkout-{invoiceId}")).Click();
|
||||||
CheckForJSErrors();
|
CheckForJSErrors();
|
||||||
Driver.WaitUntilAvailable(By.Id("Checkout"));
|
Driver.WaitUntilAvailable(By.Id("Checkout"));
|
||||||
@@ -495,7 +495,7 @@ retry:
|
|||||||
{
|
{
|
||||||
if (storeId is null)
|
if (storeId is null)
|
||||||
{
|
{
|
||||||
Driver.FindElement(By.Id("StoreNav-Invoices")).Click();
|
Driver.FindElement(By.Id("menu-item-Invoices")).Click();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -506,11 +506,11 @@ retry:
|
|||||||
|
|
||||||
public void GoToProfile(ManageNavPages navPages = ManageNavPages.Index)
|
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"));
|
Driver.WaitForAndClick(By.Id("Nav-ManageAccount"));
|
||||||
if (navPages != ManageNavPages.Index)
|
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}"));
|
Driver.Navigate().GoToUrl(new Uri(ServerUri, $"wallets/{walletId}"));
|
||||||
if (navPages == WalletsNavPages.PSBT)
|
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();
|
Driver.FindElement(By.Id("PSBT")).Click();
|
||||||
}
|
}
|
||||||
else if (navPages != WalletsNavPages.Transactions)
|
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)
|
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)
|
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))
|
if (string.IsNullOrEmpty(name))
|
||||||
name = $"{type}-{Guid.NewGuid().ToString()[..14]}";
|
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);
|
Driver.FindElement(By.Name("AppName")).SendKeys(name);
|
||||||
ClickPagePrimary();
|
ClickPagePrimary();
|
||||||
Assert.Contains("App successfully created", FindAlertMessage().Text);
|
Assert.Contains("App successfully created", FindAlertMessage().Text);
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.True(s.Driver.FindElement(By.Id("Dashboard")).Displayed);
|
Assert.True(s.Driver.FindElement(By.Id("Dashboard")).Displayed);
|
||||||
|
|
||||||
// setup offchain wallet
|
// setup offchain wallet
|
||||||
s.Driver.FindElement(By.Id("StoreNav-LightningBTC")).Click();
|
s.Driver.FindElement(By.CssSelector("[data-testid='Lightning-BTC']")).Click();
|
||||||
s.AddLightningNode();
|
s.AddLightningNode();
|
||||||
s.Driver.AssertNoError();
|
s.Driver.AssertNoError();
|
||||||
var successAlert = s.FindAlertMessage();
|
var successAlert = s.FindAlertMessage();
|
||||||
@@ -449,16 +449,16 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
// Archive
|
// Archive
|
||||||
s.Driver.SwitchTo().Window(windows[0]);
|
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();
|
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.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.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);
|
s.Driver.Navigate().GoToUrl(posBaseUrl);
|
||||||
Assert.Contains("Page not found", s.Driver.Title, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("Page not found", s.Driver.Title, StringComparison.OrdinalIgnoreCase);
|
||||||
s.Driver.Navigate().Back();
|
s.Driver.Navigate().Back();
|
||||||
s.Driver.FindElement(By.Id("Nav-ArchivedApps")).Click();
|
s.Driver.FindElement(By.Id("menu-item-AppsNavPages")).Click();
|
||||||
|
|
||||||
// Unarchive
|
// Unarchive
|
||||||
s.Driver.FindElement(By.Id($"App-{appId}")).Click();
|
s.Driver.FindElement(By.Id($"App-{appId}")).Click();
|
||||||
@@ -527,17 +527,17 @@ namespace BTCPayServer.Tests
|
|||||||
s.Driver.SwitchTo().Window(windows[0]);
|
s.Driver.SwitchTo().Window(windows[0]);
|
||||||
|
|
||||||
// Archive
|
// 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.SwitchTo().Window(windows[0]);
|
||||||
s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
|
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.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.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);
|
s.Driver.Navigate().GoToUrl(cfUrl);
|
||||||
Assert.Contains("Page not found", s.Driver.Title, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("Page not found", s.Driver.Title, StringComparison.OrdinalIgnoreCase);
|
||||||
s.Driver.Navigate().Back();
|
s.Driver.Navigate().Back();
|
||||||
s.Driver.FindElement(By.Id("Nav-ArchivedApps")).Click();
|
s.Driver.FindElement(By.Id("menu-item-AppsNavPages")).Click();
|
||||||
|
|
||||||
// Unarchive
|
// Unarchive
|
||||||
s.Driver.FindElement(By.Id($"App-{appId}")).Click();
|
s.Driver.FindElement(By.Id($"App-{appId}")).Click();
|
||||||
@@ -612,14 +612,14 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
s.RegisterNewUser();
|
s.RegisterNewUser();
|
||||||
s.CreateNewStore();
|
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
|
// Should give us an error message if we try to create a payment request before adding a wallet
|
||||||
s.ClickPagePrimary();
|
s.ClickPagePrimary();
|
||||||
Assert.Contains("To create a payment request, you need to", s.Driver.PageSource);
|
Assert.Contains("To create a payment request, you need to", s.Driver.PageSource);
|
||||||
|
|
||||||
s.AddDerivationScheme();
|
s.AddDerivationScheme();
|
||||||
s.Driver.FindElement(By.Id("StoreNav-PaymentRequests")).Click();
|
s.Driver.FindElement(By.Id("menu-item-PaymentRequests")).Click();
|
||||||
s.ClickPagePrimary();
|
s.ClickPagePrimary();
|
||||||
s.Driver.FindElement(By.Id("Title")).SendKeys("Pay123");
|
s.Driver.FindElement(By.Id("Title")).SendKeys("Pay123");
|
||||||
s.Driver.FindElement(By.Id("Amount")).Clear();
|
s.Driver.FindElement(By.Id("Amount")).Clear();
|
||||||
@@ -1483,11 +1483,11 @@ namespace BTCPayServer.Tests
|
|||||||
//ln address tests
|
//ln address tests
|
||||||
s.CreateNewStore();
|
s.CreateNewStore();
|
||||||
//ensure ln address is not available as Lightning is not enable
|
//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.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");
|
s.Driver.ToggleCollapse("AddAddress");
|
||||||
var lnaddress1 = Guid.NewGuid().ToString();
|
var lnaddress1 = Guid.NewGuid().ToString();
|
||||||
|
|||||||
@@ -226,7 +226,8 @@ public class SubscriptionTests(ITestOutputHelper testOutputHelper) : UnitTestBas
|
|||||||
{
|
{
|
||||||
await portal.Downgrade("Basic Plan");
|
await portal.Downgrade("Basic Plan");
|
||||||
unused = GetUnusedPeriodValue(usedDays: 7, planPrice: 99.0m, daysInPeriod: DaysInThisMonth());
|
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);
|
Assert.Equal(unused, credited.Amount);
|
||||||
@@ -241,7 +242,8 @@ public class SubscriptionTests(ITestOutputHelper testOutputHelper) : UnitTestBas
|
|||||||
await portal.GoTo7Days();
|
await portal.GoTo7Days();
|
||||||
await portal.Upgrade("Pro Plan");
|
await portal.Upgrade("Pro Plan");
|
||||||
unused = GetUnusedPeriodValue(usedDays: 7, planPrice: 29.0m, daysInPeriod: DaysInThisMonth());
|
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;
|
expectedBalance = totalRefunded - 29.0m - 99.0m - 99.0m;
|
||||||
await portal.AssertCredit(creditBalance: $"${expectedBalance:F2}");
|
await portal.AssertCredit(creditBalance: $"${expectedBalance:F2}");
|
||||||
|
|
||||||
@@ -253,14 +255,24 @@ public class SubscriptionTests(ITestOutputHelper testOutputHelper) : UnitTestBas
|
|||||||
await s.Server.WaitForEvent<SubscriptionEvent.PlanStarted>(async () =>
|
await s.Server.WaitForEvent<SubscriptionEvent.PlanStarted>(async () =>
|
||||||
{
|
{
|
||||||
await portal.Upgrade("Enterprise Plan");
|
await portal.Upgrade("Enterprise Plan");
|
||||||
await invoice.AssertContent(new()
|
|
||||||
{
|
|
||||||
TotalFiat = USD(299m - expectedBalance - unused)
|
|
||||||
});
|
|
||||||
await s.PayInvoice(mine: true);
|
await s.PayInvoice(mine: true);
|
||||||
});
|
});
|
||||||
await invoice.ClickRedirect();
|
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 match = Regex.Match(text!, @"\((.*?) USD has been refunded\)");
|
||||||
var v = decimal.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
|
var v = decimal.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
|
||||||
var diff = Math.Abs(refunded - v);
|
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;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,13 +784,16 @@ public class SubscriptionTests(ITestOutputHelper testOutputHelper) : UnitTestBas
|
|||||||
Assert.Equal(plan, name);
|
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++)
|
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);
|
Assert.StartsWith(creditLines[i], txt);
|
||||||
|
if (creditAmounts is not null)
|
||||||
|
Assert.Equal(creditAmounts[i], await credits[i].InnerTextAsync());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class WalletTests(ITestOutputHelper helper) : UnitTestBase(helper)
|
|||||||
var txs = (await client.ShowOnChainWalletTransactions(s.StoreId, "BTC")).Select(t => t.TransactionHash).ToArray();
|
var txs = (await client.ShowOnChainWalletTransactions(s.StoreId, "BTC")).Select(t => t.TransactionHash).ToArray();
|
||||||
Assert.Equal(3, txs.Length);
|
Assert.Equal(3, txs.Length);
|
||||||
|
|
||||||
var w = await s.GoToWalletTransactions();
|
var w = await s.GoToWalletTransactions(s.WalletId);
|
||||||
await w.BumpFee(txs[0]);
|
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)
|
// 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++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
var txs = await s.GoToWalletTransactions();
|
var txs = await s.GoToWalletTransactions(s.WalletId);
|
||||||
await txs.SelectAll();
|
await txs.SelectAll();
|
||||||
await txs.BumpFeeSelected();
|
await txs.BumpFeeSelected();
|
||||||
await s.ClickPagePrimary();
|
await s.ClickPagePrimary();
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
@using BTCPayServer.Views.Server
|
@using BTCPayServer.Views.Server
|
||||||
@using BTCPayServer.Views.Stores
|
@using BTCPayServer.Views.Stores
|
||||||
@using BTCPayServer.Views.Invoice
|
|
||||||
@using BTCPayServer.Views.Manage
|
@using BTCPayServer.Views.Manage
|
||||||
@using BTCPayServer.Views.PaymentRequest
|
|
||||||
@using BTCPayServer.Views.Wallets
|
@using BTCPayServer.Views.Wallets
|
||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@using BTCPayServer.Components.ThemeSwitch
|
|
||||||
@using BTCPayServer.Components.UIExtensionPoint
|
|
||||||
@using BTCPayServer.Plugins
|
@using BTCPayServer.Plugins
|
||||||
@using BTCPayServer.Services
|
@using BTCPayServer.Services
|
||||||
@using BTCPayServer.Views.Apps
|
@using BTCPayServer.Views.Apps
|
||||||
@@ -33,45 +29,45 @@
|
|||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
<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"/>
|
<vc:icon symbol="nav-dashboard"/>
|
||||||
<span text-translate="true">Dashboard</span>
|
<span text-translate="true">Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" permission="@Policies.CanViewStoreSettings">
|
<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"/>
|
<vc:icon symbol="nav-store-settings"/>
|
||||||
<span text-translate="true">Settings</span>
|
<span text-translate="true">Settings</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</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">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
</li>
|
||||||
}
|
}
|
||||||
<vc:ui-extension-point location="store-nav" model="@Model"/>
|
<vc:ui-extension-point location="store-nav" model="@Model"/>
|
||||||
@@ -88,39 +84,43 @@
|
|||||||
@foreach (var scheme in Model.DerivationSchemes.OrderBy(scheme => scheme.Collapsed))
|
@foreach (var scheme in Model.DerivationSchemes.OrderBy(scheme => scheme.Collapsed))
|
||||||
{
|
{
|
||||||
var isSetUp = !string.IsNullOrWhiteSpace(scheme.Value);
|
var isSetUp = !string.IsNullOrWhiteSpace(scheme.Value);
|
||||||
var categoryId = $"{Model.Store.Id}-{scheme.WalletId.CryptoCode}";
|
<li class="nav-item" data-testid="Wallet-@scheme.Crypto">
|
||||||
<li class="nav-item">
|
|
||||||
@if (isSetUp && scheme.WalletSupported)
|
@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 class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "pending")"></span>
|
||||||
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
|
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
else
|
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 class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "pending")"></span>
|
||||||
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
|
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
</li>
|
</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)
|
@if (!scheme.ReadonlyWallet)
|
||||||
{
|
{
|
||||||
<li class="nav-item nav-item-sub">
|
<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>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
<li class="nav-item nav-item-sub">
|
<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>
|
||||||
|
|
||||||
<li class="nav-item nav-item-sub">
|
<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>
|
</li>
|
||||||
<vc:ui-extension-point location="wallet-nav" model="@Model" />
|
<vc:ui-extension-point location="wallet-nav" model="@Model" />
|
||||||
}
|
}
|
||||||
@@ -134,23 +134,29 @@
|
|||||||
var status = scheme.Enabled
|
var status = scheme.Enabled
|
||||||
? scheme.Available ? "enabled" : "disabled"
|
? scheme.Available ? "enabled" : "disabled"
|
||||||
: "pending";
|
: "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 class="me-2 btcpay-status btcpay-status--@status"></span>
|
||||||
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
|
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
else
|
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 class="me-2 btcpay-status btcpay-status--@(scheme.Enabled ? "enabled" : "pending")"></span>
|
||||||
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
|
<span>@PrettyName.PrettyName(scheme.PaymentMethodId)</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
</li>
|
</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">
|
<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>
|
</li>
|
||||||
<vc:ui-extension-point location="lightning-nav" model="@Model"/>
|
<vc:ui-extension-point location="lightning-nav" model="@Model"/>
|
||||||
}
|
}
|
||||||
@@ -170,34 +176,36 @@
|
|||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item" permission="@Policies.CanViewInvoices">
|
<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"/>
|
<vc:icon symbol="nav-invoices"/>
|
||||||
<span text-translate="true">Invoices</span>
|
<span text-translate="true">Invoices</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" permission="@Policies.CanViewReports">
|
<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" />
|
<vc:icon symbol="nav-reporting" />
|
||||||
<span text-translate="true">Reporting</span>
|
<span text-translate="true">Reporting</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" permission="@Policies.CanViewPaymentRequests">
|
<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"/>
|
<vc:icon symbol="nav-payment-requests"/>
|
||||||
<span text-translate="true">Requests</span>
|
<span text-translate="true">Requests</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" permission="@Policies.CanViewPullPayments">
|
<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"/>
|
<vc:icon symbol="nav-pull-payments"/>
|
||||||
<span text-translate="true">Pull Payments</span>
|
<span text-translate="true">Pull Payments</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" permission="@Policies.CanViewPayouts">
|
<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-controller="UIStorePullPayments" asp-action="Payouts"
|
||||||
asp-route-pullPaymentId=""
|
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"/>
|
<vc:icon symbol="nav-payouts"/>
|
||||||
<span text-translate="true">Payouts</span>
|
<span text-translate="true">Payouts</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -226,7 +234,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
|
<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())
|
@if (PluginService.GetDisabledPlugins().Any())
|
||||||
{
|
{
|
||||||
<span class="me-2 btcpay-status btcpay-status--disabled"></span>
|
<span class="me-2 btcpay-status btcpay-status--disabled"></span>
|
||||||
@@ -241,7 +249,7 @@
|
|||||||
@if (Model.Store != null && Model.ArchivedAppsCount > 0)
|
@if (Model.Store != null && Model.ArchivedAppsCount > 0)
|
||||||
{
|
{
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
|
<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")
|
@Model.ArchivedAppsCount Archived App@(Model.ArchivedAppsCount == 1 ? "" : "s")
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -292,48 +300,48 @@
|
|||||||
{
|
{
|
||||||
<ul id="mainNavSettings" class="navbar-nav border-top p-3 px-lg-4">
|
<ul id="mainNavSettings" class="navbar-nav border-top p-3 px-lg-4">
|
||||||
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
|
<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"/>
|
<vc:icon symbol="nav-server-settings"/>
|
||||||
<span text-translate="true">Server Settings</span>
|
<span text-translate="true">Server Settings</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</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">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
<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>
|
</li>
|
||||||
@if (BtcPayServerOptions.DockerDeployment)
|
@if (BtcPayServerOptions.DockerDeployment)
|
||||||
{
|
{
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
<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>
|
||||||
}
|
}
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
<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>
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
<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>
|
</li>
|
||||||
|
|
||||||
<vc:ui-extension-point location="server-nav" model="@Model"/>
|
<vc:ui-extension-point location="server-nav" model="@Model"/>
|
||||||
}
|
}
|
||||||
<li class="nav-item dropup">
|
<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"/>
|
<vc:icon symbol="nav-account"/>
|
||||||
<span text-translate="true">Account</span>
|
<span text-translate="true">Account</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -347,11 +355,11 @@
|
|||||||
<strong class="d-block text-truncate" style="max-width:@(string.IsNullOrEmpty(Model.UserImageUrl) ? "195px" : "160px")">
|
<strong class="d-block text-truncate" style="max-width:@(string.IsNullOrEmpty(Model.UserImageUrl) ? "195px" : "160px")">
|
||||||
@if (string.IsNullOrEmpty(Model.UserName))
|
@if (string.IsNullOrEmpty(Model.UserName))
|
||||||
{
|
{
|
||||||
@(User.Identity.Name)
|
@(User.Identity?.Name)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@($"{Model.UserName} ({User.Identity.Name})")
|
@($"{Model.UserName} ({User.Identity?.Name})")
|
||||||
}
|
}
|
||||||
</strong>
|
</strong>
|
||||||
@if (User.IsInRole(Roles.ServerAdmin))
|
@if (User.IsInRole(Roles.ServerAdmin))
|
||||||
@@ -387,22 +395,22 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@if (ViewData.IsCategoryActive(typeof(ManageNavPages)) || ViewData.IsPageActive([ManageNavPages.ChangePassword]))
|
@if (ViewData.IsCategory(nameof(ManageNavPages)))
|
||||||
{
|
{
|
||||||
<li class="nav-item nav-item-sub">
|
<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>
|
||||||
<li class="nav-item nav-item-sub">
|
<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>
|
||||||
<li class="nav-item nav-item-sub">
|
<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>
|
||||||
<li class="nav-item nav-item-sub">
|
<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>
|
||||||
<li class="nav-item nav-item-sub">
|
<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>
|
</li>
|
||||||
<vc:ui-extension-point location="user-nav" model="@Model" />
|
<vc:ui-extension-point location="user-nav" model="@Model" />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,23 +51,19 @@ else
|
|||||||
@foreach (var option in Model.Options)
|
@foreach (var option in Model.Options)
|
||||||
{
|
{
|
||||||
<li>
|
<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>
|
</li>
|
||||||
}
|
}
|
||||||
@if (Model.Options.Any())
|
@if (Model.Options.Any())
|
||||||
{
|
{
|
||||||
<li><hr class="dropdown-divider"></li>
|
<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)
|
@if (Model.ArchivedCount > 0)
|
||||||
{
|
{
|
||||||
<li><hr class="dropdown-divider"></li>
|
<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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
@{
|
@{
|
||||||
var storeId = Context.GetStoreData().Id;
|
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">
|
<div class="sticky-header">
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
@{
|
@{
|
||||||
var storeId = Context.GetStoreData().Id;
|
var storeId = Context.GetStoreData().Id;
|
||||||
bool isEdit = Model.Trigger != null;
|
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 {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
@model BTCPayServer.Models.EmailsViewModel
|
@model BTCPayServer.Models.EmailsViewModel
|
||||||
@{
|
@{
|
||||||
var storeId = Context.GetStoreData().Id;
|
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">
|
<form method="post" autocomplete="off" permissioned="@Policies.CanModifyStoreSettings">
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ namespace BTCPayServer.Plugins.PointOfSale.Models
|
|||||||
[Display(Name = "Redirect invoice to redirect url automatically after paid")]
|
[Display(Name = "Redirect invoice to redirect url automatically after paid")]
|
||||||
public string RedirectAutomatically { get; set; } = string.Empty;
|
public string RedirectAutomatically { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string AppId { get; set; }
|
|
||||||
public string SearchTerm { get; set; }
|
public string SearchTerm { get; set; }
|
||||||
|
|
||||||
public SelectList RedirectAutomaticallySelectList =>
|
public SelectList RedirectAutomaticallySelectList =>
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ public partial class UIOfferingController(
|
|||||||
BTCPayServerEnvironment env,
|
BTCPayServerEnvironment env,
|
||||||
DisplayFormatter displayFormatter,
|
DisplayFormatter displayFormatter,
|
||||||
EmailSenderFactory emailSenderFactory,
|
EmailSenderFactory emailSenderFactory,
|
||||||
IHtmlHelper htmlHelper,
|
|
||||||
IEnumerable<EmailTriggerViewModel> emailTriggers
|
IEnumerable<EmailTriggerViewModel> emailTriggers
|
||||||
) : UISubscriptionControllerBase(dbContextFactory, linkGenerator, stringLocalizer, subsService)
|
) : UISubscriptionControllerBase(dbContextFactory, linkGenerator, stringLocalizer, subsService)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,14 +16,14 @@
|
|||||||
var appType = SubscriptionsAppType.AppType;
|
var appType = SubscriptionsAppType.AppType;
|
||||||
var apps = Model.Apps.Where(app => app.AppType == appType).ToList();
|
var apps = Model.Apps.Where(app => app.AppType == appType).ToList();
|
||||||
<li class="nav-item" permission="@Policies.CanModifyMembership">
|
<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" />
|
<vc:icon symbol="nav-reporting" />
|
||||||
<span text-translate="true">Subscriptions</span>
|
<span text-translate="true">Subscriptions</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@if (apps.Any())
|
@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">
|
<span class="nav-link">
|
||||||
<vc:icon symbol="nav-reporting" />
|
<vc:icon symbol="nav-reporting" />
|
||||||
<span text-translate="true">Subscriptions</span>
|
<span text-translate="true">Subscriptions</span>
|
||||||
@@ -35,12 +35,12 @@
|
|||||||
var offeringId = app.Data.GetSettings<SubscriptionsAppType.AppConfig>().OfferingId ?? "";
|
var offeringId = app.Data.GetSettings<SubscriptionsAppType.AppConfig>().OfferingId ?? "";
|
||||||
|
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewMembership">
|
<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>
|
<span>@app.AppName</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item nav-item-sub" not-permission="@Policies.CanViewMembership">
|
<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>
|
<span>@app.AppName</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
@model AddEditPlanViewModel
|
@using BTCPayServer.Plugins.Subscriptions
|
||||||
|
@model AddEditPlanViewModel
|
||||||
|
|
||||||
@{
|
@{
|
||||||
string storeId = (string)this.Context.GetRouteValue("storeId");
|
string storeId = (string)this.Context.GetRouteValue("storeId");
|
||||||
string offeringId = (string)this.Context.GetRouteValue("offeringId");
|
string offeringId = (string)this.Context.GetRouteValue("offeringId");
|
||||||
string submitLabel = "";
|
var title = Model.PlanId is null ? StringLocalizer["Add plan"] : StringLocalizer["Edit plan"];
|
||||||
if (Model.PlanId is null)
|
var submitLabel = Model.PlanId is null ? StringLocalizer["Create"] : StringLocalizer["Save"];
|
||||||
{
|
ViewData.SetLayoutModel(new LayoutModel($"{nameof(SubscriptionsPlugin)}-{offeringId}", title));
|
||||||
ViewData.SetActivePage(AppsNavPages.Update, StringLocalizer["Add plan"], offeringId);
|
|
||||||
submitLabel = StringLocalizer["Create"];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ViewData.SetActivePage(AppsNavPages.Update, StringLocalizer["Edit plan"], offeringId);
|
|
||||||
submitLabel = StringLocalizer["Save"];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
|
||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@using BTCPayServer.Controllers
|
@using BTCPayServer.Controllers
|
||||||
|
@using BTCPayServer.Plugins.Subscriptions
|
||||||
@model ConfigureOfferingViewModel
|
@model ConfigureOfferingViewModel
|
||||||
|
|
||||||
@{
|
@{
|
||||||
string offeringId = (string)this.Context.GetRouteValue("offeringId");
|
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");
|
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"])
|
var deleteModal = new ConfirmModel(StringLocalizer["Delete offering"], StringLocalizer["This offering will be removed from this store."], StringLocalizer["Delete"])
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
@using BTCPayServer.Services
|
@using BTCPayServer.Plugins.Subscriptions
|
||||||
|
@using BTCPayServer.Services
|
||||||
@model CreateOfferingViewModel
|
@model CreateOfferingViewModel
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(StoreNavPages.Subscriptions, StringLocalizer["New offering"]);
|
ViewData.SetLayoutModel(new LayoutModel(nameof(SubscriptionsPlugin), StringLocalizer["New offering"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@using BTCPayServer.Abstractions.Models
|
@using BTCPayServer.Client
|
||||||
@using BTCPayServer.Client
|
|
||||||
@using BTCPayServer.Controllers
|
|
||||||
@using BTCPayServer.Plugins.Emails
|
@using BTCPayServer.Plugins.Emails
|
||||||
|
@using BTCPayServer.Plugins.Subscriptions
|
||||||
@using BTCPayServer.Plugins.Subscriptions.Controllers
|
@using BTCPayServer.Plugins.Subscriptions.Controllers
|
||||||
@using BTCPayServer.Services
|
@using BTCPayServer.Services
|
||||||
@model SubscriptionsViewModel
|
@model SubscriptionsViewModel
|
||||||
@@ -11,7 +10,7 @@
|
|||||||
@{
|
@{
|
||||||
string storeId = (string)this.Context.GetRouteValue("storeId");
|
string storeId = (string)this.Context.GetRouteValue("storeId");
|
||||||
string offeringId = (string)this.Context.GetRouteValue("offeringId");
|
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();
|
Csp.UnsafeEval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@inject IEnumerable<AvailableWebhookViewModel> Webhooks
|
@inject IEnumerable<AvailableWebhookViewModel> Webhooks
|
||||||
@{
|
@{
|
||||||
var storeId = Context.GetStoreData().Id;
|
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 {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@model WebhooksViewModel
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -13,10 +13,8 @@
|
|||||||
|
|
||||||
var storeId = Context.GetRouteValue("storeId") as string;
|
var storeId = Context.GetRouteValue("storeId") as string;
|
||||||
var title = role is null ? StringLocalizer["Create role"] : StringLocalizer["Update Role"];
|
var title = role is null ? StringLocalizer["Create role"] : StringLocalizer["Update Role"];
|
||||||
if (storeId is null)
|
var category = storeId is null ? WellKnownCategories.Server : WellKnownCategories.Store;
|
||||||
ViewData.SetActivePage(ServerNavPages.Roles, title);
|
ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Roles), title).SetCategory(category));
|
||||||
else
|
|
||||||
ViewData.SetActivePage(StoreNavPages.Roles, title, storeId);
|
|
||||||
var storePolicies = Policies.AllPolicies.Where(Policies.IsStorePolicy).ToArray();
|
var storePolicies = Policies.AllPolicies.Where(Policies.IsStorePolicy).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +101,7 @@
|
|||||||
const { checked, value: policy } = element;
|
const { checked, value: policy } = element;
|
||||||
const policySelect = document.getElementById('Policies');
|
const policySelect = document.getElementById('Policies');
|
||||||
const subPolicies = element.parentElement.querySelectorAll(`.list-group .policy-cb:not([value="${policy}"])`);
|
const subPolicies = element.parentElement.querySelectorAll(`.list-group .policy-cb:not([value="${policy}"])`);
|
||||||
|
|
||||||
policySelect.querySelector(`option[value="${policy}"]`).selected = checked;
|
policySelect.querySelector(`option[value="${policy}"]`).selected = checked;
|
||||||
subPolicies.forEach(subPolicy => {
|
subPolicies.forEach(subPolicy => {
|
||||||
subPolicy.checked = checked? false : subPolicy.checked;
|
subPolicy.checked = checked? false : subPolicy.checked;
|
||||||
@@ -115,12 +113,12 @@
|
|||||||
policySelect.querySelector(`option[value="${subPolicy.value}"]`).selected = subPolicy.checked;
|
policySelect.querySelector(`option[value="${subPolicy.value}"]`).selected = subPolicy.checked;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
document.querySelectorAll(".policy-cb:checked").forEach(handleCheckboxChange);
|
document.querySelectorAll(".policy-cb:checked").forEach(handleCheckboxChange);
|
||||||
|
|
||||||
delegate('change', '.policy-cb', event => {
|
delegate('change', '.policy-cb', event => {
|
||||||
handleCheckboxChange(event.target);
|
handleCheckboxChange(event.target);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -14,14 +14,14 @@
|
|||||||
var appType = AppService.GetAppType(CrowdfundAppType.AppType)!;
|
var appType = AppService.GetAppType(CrowdfundAppType.AppType)!;
|
||||||
var apps = Model.Apps.Where(app => app.AppType == appType.Type).ToList();
|
var apps = Model.Apps.Where(app => app.AppType == appType.Type).ToList();
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
<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" />
|
<vc:icon symbol="nav-crowdfund" />
|
||||||
<span text-translate="true">Crowdfund</span>
|
<span text-translate="true">Crowdfund</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@if (apps.Any())
|
@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">
|
<span class="nav-link">
|
||||||
<vc:icon symbol="nav-crowdfund" />
|
<vc:icon symbol="nav-crowdfund" />
|
||||||
<span text-translate="true">Crowdfund</span>
|
<span text-translate="true">Crowdfund</span>
|
||||||
@@ -31,12 +31,12 @@
|
|||||||
@foreach (var app in apps)
|
@foreach (var app in apps)
|
||||||
{
|
{
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
<span>@app.AppName</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item nav-item-sub" not-permission="@Policies.CanViewStoreSettings">
|
<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>
|
<span>@app.AppName</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
@using System.Globalization
|
@using System.Globalization
|
||||||
@using BTCPayServer.Abstractions.Contracts
|
@using BTCPayServer.Abstractions.Contracts
|
||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@using BTCPayServer.TagHelpers
|
@using BTCPayServer.TagHelpers
|
||||||
@using BTCPayServer.Views.Apps
|
@using BTCPayServer.Views.Apps
|
||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@using BTCPayServer.Forms
|
@using BTCPayServer.Forms
|
||||||
|
@using BTCPayServer.Plugins.Crowdfund
|
||||||
@inject FormDataService FormDataService
|
@inject FormDataService FormDataService
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
||||||
@model BTCPayServer.Plugins.Crowdfund.Models.UpdateCrowdfundViewModel
|
@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();
|
Csp.UnsafeEval();
|
||||||
var canUpload = await FileService.IsAvailable();
|
var canUpload = await FileService.IsAvailable();
|
||||||
var checkoutFormOptions = await FormDataService.GetSelect(Model.StoreId, Model.FormId);
|
var checkoutFormOptions = await FormDataService.GetSelect(Model.StoreId, Model.FormId);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
@if (store.IsLightningEnabled(cryptoCode) && store.IsLNUrlEnabled(cryptoCode))
|
@if (store.IsLightningEnabled(cryptoCode) && store.IsLNUrlEnabled(cryptoCode))
|
||||||
{
|
{
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
<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 "/>
|
<vc:icon symbol="nav-lightning-address "/>
|
||||||
<span text-translate="true">Lightning Address</span>
|
<span text-translate="true">Lightning Address</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -6,10 +6,9 @@
|
|||||||
@{
|
@{
|
||||||
var storeId = Context.GetRouteValue("storeId") as string;
|
var storeId = Context.GetRouteValue("storeId") as string;
|
||||||
var controller = ViewContext.RouteData.Values["controller"].ToString().TrimEnd("Controller", StringComparison.InvariantCultureIgnoreCase);
|
var controller = ViewContext.RouteData.Values["controller"].ToString().TrimEnd("Controller", StringComparison.InvariantCultureIgnoreCase);
|
||||||
if (string.IsNullOrEmpty(storeId))
|
var category = string.IsNullOrEmpty(storeId) ? WellKnownCategories.Server : WellKnownCategories.Store;
|
||||||
ViewData.SetActivePage(ServerNavPages.Roles, StringLocalizer["Roles"]);
|
ViewData.SetLayoutModel(new LayoutModel(nameof(StoreNavPages.Roles), StringLocalizer["Roles"]).SetCategory(category));
|
||||||
else
|
|
||||||
ViewData.SetActivePage(StoreNavPages.Roles, StringLocalizer["Roles"], storeId);
|
|
||||||
var permission = string.IsNullOrEmpty(storeId) ? Policies.CanModifyServerSettings : Policies.CanModifyStoreSettings;
|
var permission = string.IsNullOrEmpty(storeId) ? Policies.CanModifyServerSettings : Policies.CanModifyStoreSettings;
|
||||||
var nextRoleSortOrder = (string) ViewData["NextRoleSortOrder"];
|
var nextRoleSortOrder = (string) ViewData["NextRoleSortOrder"];
|
||||||
var roleSortOrder = nextRoleSortOrder switch
|
var roleSortOrder = nextRoleSortOrder switch
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@using BTCPayServer.Views.Stores
|
@using BTCPayServer.Views.Stores
|
||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
@if (store != null)
|
@if (store != null)
|
||||||
{
|
{
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
<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"/>
|
<vc:icon symbol="nav-pay-button"/>
|
||||||
<span text-translate="true">Pay Button</span>
|
<span text-translate="true">Pay Button</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@inject BTCPayNetworkProvider NetworkProvider
|
@inject BTCPayNetworkProvider NetworkProvider
|
||||||
@model BTCPayServer.Plugins.PayButton.Models.PayButtonViewModel
|
@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();
|
Csp.UnsafeEval();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
const max = parseInt(event.target.getAttribute('max'));
|
const max = parseInt(event.target.getAttribute('max'));
|
||||||
if (event.target.value < min) {
|
if (event.target.value < min) {
|
||||||
event.target.value = min;
|
event.target.value = min;
|
||||||
} else if (event.target.value > max) {
|
} else if (event.target.value > max) {
|
||||||
event.target.value = max;
|
event.target.value = max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,11 +93,11 @@
|
|||||||
const price = parseInt(el.value);
|
const price = parseInt(el.value);
|
||||||
const min = parseInt(event.target.getAttribute('min')) || 1;
|
const min = parseInt(event.target.getAttribute('min')) || 1;
|
||||||
const max = parseInt(event.target.getAttribute('max'));
|
const max = parseInt(event.target.getAttribute('max'));
|
||||||
if (price < min) {
|
if (price < min) {
|
||||||
el.value = min;
|
el.value = min;
|
||||||
} else if (price > max) {
|
} else if (price > max) {
|
||||||
el.value = max;
|
el.value = max;
|
||||||
}
|
}
|
||||||
root.querySelector('.btcpay-input-range').value = el.value;
|
root.querySelector('.btcpay-input-range').value = el.value;
|
||||||
}
|
}
|
||||||
function handleSliderInput(event) {
|
function handleSliderInput(event) {
|
||||||
@@ -116,11 +116,11 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.lnurlEndpoint = @Safe.Json(Url.Action("GetLNUrlForStore", "UILNURL", new
|
window.lnurlEndpoint = @Safe.Json(Url.Action("GetLNUrlForStore", "UILNURL", new
|
||||||
{
|
{
|
||||||
storeId = Model.StoreId,
|
storeId = Model.StoreId,
|
||||||
cryptoCode = NetworkProvider.DefaultNetwork.CryptoCode
|
cryptoCode = NetworkProvider.DefaultNetwork.CryptoCode
|
||||||
}, "lnurlp", Context.Request.Host.ToString()));
|
}, "lnurlp", Context.Request.Host.ToString()));
|
||||||
const srvModel = @Safe.Json(Model);
|
const srvModel = @Safe.Json(Model);
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
light: '#f5f5f7'
|
light: '#f5f5f7'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
imageUrlRequired() {
|
imageUrlRequired() {
|
||||||
@@ -245,7 +245,7 @@
|
|||||||
<label for="buttonInlineTextMode" class="form-check-label" text-translate="true">Customize Pay Button Text</label>
|
<label for="buttonInlineTextMode" class="form-check-label" text-translate="true">Customize Pay Button Text</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group" v-show="buttonInlineTextMode">
|
<div class="form-group" v-show="buttonInlineTextMode">
|
||||||
<label class="form-label" for="pb-text" text-translate="true">Pay Button Text</label>
|
<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"
|
<input name="payButtonText" type="text" class="form-control" id="pb-text"
|
||||||
@@ -262,7 +262,7 @@
|
|||||||
<div class="form-group mb-4">
|
<div class="form-group mb-4">
|
||||||
<label class="form-label" text-translate="true">Image Size</label>
|
<label class="form-label" text-translate="true">Image Size</label>
|
||||||
<div class="btn-group d-flex" role="group">
|
<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>
|
v-on:click="inputChanges($event, 0)">146 x 40 px</button>
|
||||||
<button type="button" class="btn btn-outline-secondary"
|
<button type="button" class="btn btn-outline-secondary"
|
||||||
v-on:click="inputChanges($event, 1)">168 x 46 px</button>
|
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.
|
Please fix errors shown in order for code generation to successfully execute.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!srvModel.appIdEndpoint && (previewLink || lnurlLink)">
|
<div v-if="!srvModel.appIdEndpoint && (previewLink || lnurlLink)">
|
||||||
<h4 class="mt-5 mb-3" text-translate="true">Alternatives</h4>
|
<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>
|
<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;
|
line-height: 35px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btcpay-input-price::-webkit-outer-spin-button,
|
.btcpay-input-price::-webkit-outer-spin-button,
|
||||||
.btcpay-input-price::-webkit-inner-spin-button {
|
.btcpay-input-price::-webkit-inner-spin-button {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
|
|||||||
@@ -14,14 +14,14 @@
|
|||||||
var appType = AppService.GetAppType(PointOfSaleAppType.AppType)!;
|
var appType = AppService.GetAppType(PointOfSaleAppType.AppType)!;
|
||||||
var apps = Model.Apps.Where(app => app.AppType == appType.Type).ToList();
|
var apps = Model.Apps.Where(app => app.AppType == appType.Type).ToList();
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
<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" />
|
<vc:icon symbol="nav-pointofsale" />
|
||||||
<span text-translate="true">Point of Sale</span>
|
<span text-translate="true">Point of Sale</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@if (apps.Any())
|
@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">
|
<span class="nav-link">
|
||||||
<vc:icon symbol="nav-pointofsale" />
|
<vc:icon symbol="nav-pointofsale" />
|
||||||
<span text-translate="true">Point of Sale</span>
|
<span text-translate="true">Point of Sale</span>
|
||||||
@@ -31,12 +31,12 @@
|
|||||||
@foreach (var app in apps)
|
@foreach (var app in apps)
|
||||||
{
|
{
|
||||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
<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>
|
<span>@app.AppName</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item nav-item-sub" not-permission="@Policies.CanViewStoreSettings">
|
<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>
|
<span>@app.AppName</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@using BTCPayServer.Views.Apps
|
@using BTCPayServer.Views.Apps
|
||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@using BTCPayServer.Plugins.PointOfSale
|
@using BTCPayServer.Plugins.PointOfSale
|
||||||
@@ -9,7 +8,7 @@
|
|||||||
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
||||||
@model BTCPayServer.Plugins.PointOfSale.Models.UpdatePointOfSaleViewModel
|
@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();
|
Csp.UnsafeEval();
|
||||||
var checkoutFormOptions = await FormDataService.GetSelect(Model.StoreId, Model.FormId);
|
var checkoutFormOptions = await FormDataService.GetSelect(Model.StoreId, Model.FormId);
|
||||||
var posPath = Url.Action("ViewPointOfSale", "UIPointOfSale", new { appId = Model.Id });
|
var posPath = Url.Action("ViewPointOfSale", "UIPointOfSale", new { appId = Model.Id });
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
@if (store != null)
|
@if (store != null)
|
||||||
{
|
{
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
<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" />
|
<vc:icon symbol="logo-shopify" />
|
||||||
<span text-translate="true">Shopify</span>
|
<span text-translate="true">Shopify</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@model CreateAppViewModel
|
@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 {
|
@section PageFootContent {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
@using BTCPayServer.Services.Apps
|
@using BTCPayServer.Services.Apps
|
||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@model ListAppsViewModel
|
@model ListAppsViewModel
|
||||||
@inject AppService AppService
|
@inject AppService AppService
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(AppsNavPages.Index, "Apps");
|
ViewData.SetLayoutModel(new(nameof(AppsNavPages), "Apps"));
|
||||||
var nextAppNameSortOrder = (string)ViewData["AppNameNextSortOrder"];
|
var nextAppNameSortOrder = (string)ViewData["AppNameNextSortOrder"];
|
||||||
var nextAppTypeSortOrder = (string)ViewData["AppTypeNextSortOrder"];
|
var nextAppTypeSortOrder = (string)ViewData["AppTypeNextSortOrder"];
|
||||||
var nextStoreNameSortOrder = (string)ViewData["StoreNameNextSortOrder"];
|
var nextStoreNameSortOrder = (string)ViewData["StoreNameNextSortOrder"];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using Newtonsoft.Json.Linq
|
@using Newtonsoft.Json.Linq
|
||||||
@model Fido2NetLib.CredentialCreateOptions
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@model List<BTCPayServer.Data.FormData>
|
@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();
|
var storeId = Context.GetCurrentStoreId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@using BTCPayServer.Abstractions.TagHelpers
|
@using BTCPayServer.Abstractions.TagHelpers
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(InvoiceNavPages.Create, StringLocalizer["Create Invoice"]);
|
ViewData.SetLayoutModel(new("Invoices", StringLocalizer["Create Invoices"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageFootContent {
|
@section PageFootContent {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@model InvoiceDetailsModel
|
@model InvoiceDetailsModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = StringLocalizer["Invoice {0}", Model.Id];
|
ViewData.SetLayoutModel(new("Invoices", StringLocalizer["Invoice {0}", Model.Id]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace BTCPayServer.Views.Invoice
|
|
||||||
{
|
|
||||||
public enum InvoiceNavPages
|
|
||||||
{
|
|
||||||
Index, Create
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
@inject DisplayFormatter DisplayFormatter
|
@inject DisplayFormatter DisplayFormatter
|
||||||
@model InvoicesModel
|
@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 statusFilterCount = CountArrayFilter("status") + CountArrayFilter("exceptionstatus") + (HasBooleanFilter("includearchived") ? 1 : 0) + (HasBooleanFilter("unusual") ? 1 : 0);
|
||||||
var hasDateFilter = HasArrayFilter("startdate") || HasArrayFilter("enddate");
|
var hasDateFilter = HasArrayFilter("startdate") || HasArrayFilter("enddate");
|
||||||
var appFilterCount = Model.Apps.Count(app => HasArrayFilter("appid", app.Id));
|
var appFilterCount = Model.Apps.Count(app => HasArrayFilter("appid", app.Id));
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
@using BTCPayServer.Abstractions.Extensions
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
@using BTCPayServer.Services.Invoices
|
@using BTCPayServer.Services.Invoices
|
||||||
@using BTCPayServer.Views.Invoice
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
@using BTCPayServer.Abstractions.Extensions
|
|
||||||
@using BTCPayServer.Views
|
|
||||||
@using BTCPayServer.Views.Invoice
|
|
||||||
@{
|
|
||||||
ViewData.SetActiveCategory(typeof(InvoiceNavPages));
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
@using BTCPayServer.Views.Stores
|
@using BTCPayServer.Views.Stores
|
||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@model UILNURLController.EditLightningAddressVM
|
@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 {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using LNURL
|
@using LNURL
|
||||||
@model Uri
|
@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>
|
var formats = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "Bech32", LNURL.EncodeUri(Model, "login", true).ToString().ToUpperInvariant() },
|
{ "Bech32", LNURL.EncodeUri(Model, "login", true).ToString().ToUpperInvariant() },
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
@model BTCPayServer.PayoutProcessors.Lightning.UILightningAutomatedPayoutProcessorsController.LightningTransferViewModel
|
@model BTCPayServer.PayoutProcessors.Lightning.UILightningAutomatedPayoutProcessorsController.LightningTransferViewModel
|
||||||
@{
|
@{
|
||||||
var storeId = Context.GetStoreData().Id;
|
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">
|
<form method="post" permissioned="@Policies.CanModifyStoreSettings">
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
@namespace BTCPayServer.Client
|
@namespace BTCPayServer.Client
|
||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@using BTCPayServer.Abstractions.TagHelpers
|
@using BTCPayServer.Abstractions.TagHelpers
|
||||||
@using BTCPayServer.TagHelpers
|
@using BTCPayServer.TagHelpers
|
||||||
@using Microsoft.AspNetCore.Html
|
@using Microsoft.AspNetCore.Html
|
||||||
@@ -7,7 +6,8 @@
|
|||||||
@inject Security.ContentSecurityPolicies Csp
|
@inject Security.ContentSecurityPolicies Csp
|
||||||
@model BTCPayServer.Controllers.UIManageController.ApiKeysViewModel
|
@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();
|
Csp.UnsafeEval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
@model UIManageController.AddApiKeyViewModel
|
@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 {
|
@section PageHeadContent {
|
||||||
@@ -50,7 +51,7 @@
|
|||||||
<input asp-for="Label" class="form-control"/>
|
<input asp-for="Label" class="form-control"/>
|
||||||
<span asp-validation-for="Label" class="text-danger"></span>
|
<span asp-validation-for="Label" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h5 class="mt-4 mb-3">Permissions</h5>
|
<h5 class="mt-4 mb-3">Permissions</h5>
|
||||||
<div class="list-group mb-4">
|
<div class="list-group mb-4">
|
||||||
@for (int i = 0; i < Model.PermissionValues.Count; i++)
|
@for (int i = 0; i < Model.PermissionValues.Count; i++)
|
||||||
@@ -92,7 +93,7 @@
|
|||||||
</h5>
|
</h5>
|
||||||
<div class="text-muted">@Model.PermissionValues[i].Description</div>
|
<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>
|
<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())
|
@if (!Model.Stores.Any())
|
||||||
{
|
{
|
||||||
<p class="info-note text-warning mt-2 mb-0">
|
<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 asp-validation-for="PermissionValues[i].Value" class="text-danger"></span>
|
||||||
<span class="text-muted">@Model.PermissionValues[i].Description</span>
|
<span class="text-muted">@Model.PermissionValues[i].Description</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
var store = string.IsNullOrEmpty(Model.StoreId) ? null : Model.Stores.FirstOrDefault(s => s.Id == Model.StoreId);
|
var store = string.IsNullOrEmpty(Model.StoreId) ? null : Model.Stores.FirstOrDefault(s => s.Id == Model.StoreId);
|
||||||
var permissions = Model.Permissions?.Split(';') ?? Array.Empty<string>();
|
var permissions = Model.Permissions?.Split(';') ?? Array.Empty<string>();
|
||||||
var groupedPermissions = Permission.ToPermissions(permissions).GroupBy(permission => permission.Policy);
|
var groupedPermissions = Permission.ToPermissions(permissions).GroupBy(permission => permission.Policy);
|
||||||
ViewData["Title"] = $"Authorize {displayName ?? "Application"}";
|
ViewData.SetTitle($"Authorize {displayName ?? "Application"}");
|
||||||
Layout = "_LayoutWizard";
|
Layout = "_LayoutWizard";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,20 +73,20 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<input type="hidden" asp-for="StoreId" class="form-select"/>
|
<input type="hidden" asp-for="StoreId" class="form-select"/>
|
||||||
|
|
||||||
@if (Model.RedirectUrl != null)
|
@if (Model.RedirectUrl != null)
|
||||||
{
|
{
|
||||||
<p class="alert alert-info mb-4">
|
<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>
|
<span text-translate="true">If authorized, the generated API key will be provided to</span> <strong>@Model.RedirectUrl.AbsoluteUri</strong>
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="Label" class="form-label"></label>
|
<label asp-for="Label" class="form-label"></label>
|
||||||
<input asp-for="Label" class="form-control"/>
|
<input asp-for="Label" class="form-control"/>
|
||||||
<span asp-validation-for="Label" class="text-danger"></span>
|
<span asp-validation-for="Label" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 class="h5 fw-semibold mt-4" text-translate="true">Permissions</h2>
|
<h2 class="h5 fw-semibold mt-4" text-translate="true">Permissions</h2>
|
||||||
@if (!groupedPermissions.Any())
|
@if (!groupedPermissions.Any())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model ChangePasswordViewModel
|
@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">
|
<form method="post">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
@{
|
@{
|
||||||
var displayName = Model.ApplicationName ?? Model.ApplicationIdentifier;
|
var displayName = Model.ApplicationName ?? Model.ApplicationIdentifier;
|
||||||
ViewData["Title"] = $"Authorize {displayName ?? "Application"}";
|
ViewData.SetTitle($"Authorize {displayName ?? "Application"}");
|
||||||
Layout = "_LayoutWizard";
|
Layout = "_LayoutWizard";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@model EnableAuthenticatorViewModel
|
@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">
|
<div class="sticky-header">
|
||||||
<nav aria-label="breadcrumb">
|
<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>
|
<span text-translate="true">Your two-factor authenticator app will provide you with a unique code.</span>
|
||||||
<br/>
|
<br/>
|
||||||
<span text-translate="true">Enter the code in the confirmation box below.</span>
|
<span text-translate="true">Enter the code in the confirmation box below.</span>
|
||||||
</p>
|
</p>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input asp-for="AuthenticatorUri" type="hidden" />
|
<input asp-for="AuthenticatorUri" type="hidden" />
|
||||||
<input asp-for="SharedKey" type="hidden" />
|
<input asp-for="SharedKey" type="hidden" />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model GenerateRecoveryCodesViewModel
|
@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>
|
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
@using BTCPayServer.Abstractions.Contracts
|
@using BTCPayServer.Abstractions.Contracts
|
||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@model IndexViewModel
|
@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();
|
var canUpload = await FileService.IsAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@inject UserManager<ApplicationUser> UserManager;
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model BTCPayServer.Controllers.UIManageController.NotificationSettingsViewModel
|
@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">
|
<form method="post" asp-action="NotificationSettings">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model BTCPayServer.Models.ManageViewModels.SetPasswordViewModel
|
@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">
|
<form method="post">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@model TwoFactorAuthenticationViewModel
|
@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">
|
<div class="sticky-header">
|
||||||
<h2 class="my-1">@ViewData["Title"]</h2>
|
<h2 class="my-1">@ViewData["Title"]</h2>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
@{
|
@{
|
||||||
var storeId = Context.GetStoreData().Id;
|
var storeId = Context.GetStoreData().Id;
|
||||||
var cryptoCode = Context.GetRouteValue("cryptocode")?.ToString();
|
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">
|
<form method="post" permissioned="@Policies.CanModifyStoreSettings">
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
@model BTCPayServer.Models.PaymentRequestViewModels.UpdatePaymentRequestViewModel
|
@model BTCPayServer.Models.PaymentRequestViewModels.UpdatePaymentRequestViewModel
|
||||||
@{
|
@{
|
||||||
var checkoutFormOptions = await FormDataService.GetSelect(Model.StoreId, Model.FormId);
|
var checkoutFormOptions = await FormDataService.GetSelect(Model.StoreId, Model.FormId);
|
||||||
|
ViewData.SetLayoutModel(new LayoutModel("PaymentRequests", string.IsNullOrEmpty(Model.Id) ? StringLocalizer["Create Payment Request"] : StringLocalizer["Edit Payment Request"]));
|
||||||
ViewData.SetActivePage(PaymentRequestsNavPages.Create, string.IsNullOrEmpty(Model.Id) ? StringLocalizer["Create Payment Request"] : StringLocalizer["Edit Payment Request"], Model.Id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
@model BTCPayServer.Models.PaymentRequestViewModels.ListPaymentRequestsViewModel
|
@model BTCPayServer.Models.PaymentRequestViewModels.ListPaymentRequestsViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "_Layout";
|
Layout = "_Layout";
|
||||||
ViewData["Title"] = ViewLocalizer["Payment Requests"];
|
ViewData.SetLayoutModel(new("PaymentRequests", StringLocalizer["Payment Requests"]));
|
||||||
var storeId = Context.GetStoreData().Id;
|
var storeId = Context.GetStoreData().Id;
|
||||||
var statusFilterCount = CountArrayFilter("status") + (HasBooleanFilter("includearchived") ? 1 : 0);
|
var statusFilterCount = CountArrayFilter("status") + (HasBooleanFilter("includearchived") ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace BTCPayServer.Views.PaymentRequest
|
|
||||||
{
|
|
||||||
public enum PaymentRequestsNavPages
|
|
||||||
{
|
|
||||||
Index, Create
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +1 @@
|
|||||||
@using BTCPayServer.Abstractions.Extensions
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
@using BTCPayServer.Views.PaymentRequest
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
@using BTCPayServer.Abstractions.Extensions
|
|
||||||
@using BTCPayServer.Views
|
|
||||||
@using BTCPayServer.Views.PaymentRequest
|
|
||||||
@{
|
|
||||||
ViewData.SetActiveCategory(typeof(PaymentRequestsNavPages));
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
@using BTCPayServer.Views.Stores
|
@using BTCPayServer.Views.Stores
|
||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@model List<BTCPayServer.PayoutProcessors.UIPayoutProcessorsController.StorePayoutProcessorsView>
|
@model List<BTCPayServer.PayoutProcessors.UIPayoutProcessorsController.StorePayoutProcessorsView>
|
||||||
@{
|
@{
|
||||||
var storeId = Context.GetStoreData().Id;
|
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">
|
<div class="sticky-header">
|
||||||
<h2 class="my-1">@ViewData["Title"]</h2>
|
<h2 class="my-1">@ViewData["Title"]</h2>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@model BTCPayServer.Models.WalletViewModels.UpdatePullPaymentModel
|
@model BTCPayServer.Models.WalletViewModels.UpdatePullPaymentModel
|
||||||
@{
|
@{
|
||||||
var storeId = Context.GetStoreData().Id;
|
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 {
|
@section PageHeadContent {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
||||||
@model StoreReportsViewModel
|
@model StoreReportsViewModel
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(StoreNavPages.Reporting, StringLocalizer["Reporting"]);
|
ViewData.SetLayoutModel(new(nameof(StoreNavPages.Reporting), StringLocalizer["Reporting"]));
|
||||||
Csp.UnsafeEval();
|
Csp.UnsafeEval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
@model BrandingViewModel;
|
@model BrandingViewModel;
|
||||||
@inject IFileService FileService
|
@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 canUpload = await FileService.IsAvailable();
|
||||||
var themeExtension = ((ThemeExtension[])Enum.GetValues(typeof(ThemeExtension))).Select(t =>
|
var themeExtension = ((ThemeExtension[])Enum.GetValues(typeof(ThemeExtension))).Select(t =>
|
||||||
new SelectListItem(typeof(ThemeExtension).DisplayName(t.ToString()), t == ThemeExtension.Custom ? null : t.ToString()));
|
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>
|
<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>
|
<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">
|
<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" />
|
<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>
|
<div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model LndServicesViewModel
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@model LightningWalletServices
|
@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">
|
<div class="form-group">
|
||||||
<p text-translate="true">This page exposes information to use the configured BTCPay Server Configurator to modify this setup.</p>
|
<p text-translate="true">This page exposes information to use the configured BTCPay Server Configurator to modify this setup.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="@Model.ServiceLink" target="_blank" class="form-group" rel="noreferrer noopener">
|
<a href="@Model.ServiceLink" target="_blank" class="form-group" rel="noreferrer noopener">
|
||||||
<label asp-for="ServiceLink" class="form-label" text-translate="true">Service</label>
|
<label asp-for="ServiceLink" class="form-label" text-translate="true">Service</label>
|
||||||
<input asp-for="ServiceLink" class="form-control" readonly />
|
<input asp-for="ServiceLink" class="form-control" readonly />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model CreateDictionaryViewModel
|
@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">
|
<form method="post">
|
||||||
<div class="sticky-header">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
@using BTCPayServer.Controllers
|
@using BTCPayServer.Controllers
|
||||||
@model BTCPayServer.Controllers.UIServerController.CreateTemporaryFileUrlViewModel
|
@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">
|
<form method="post">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@model BTCPayServer.Controllers.RegisterFromAdminViewModel
|
@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;
|
var canSendEmail = ViewData["CanSendEmail"] is true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model BTCPayServer.Models.ServerViewModels.DynamicDnsViewModel
|
@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 {
|
@section PageFootContent {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@model BTCPayServer.Models.ServerViewModels.DynamicDnsViewModel[]
|
@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">
|
<div class="sticky-header">
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model BTCPayServer.Storage.Services.Providers.AmazonS3Storage.Configuration.AmazonS3StorageConfiguration
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model BTCPayServer.Storage.Services.Providers.AzureBlobStorage.Configuration.AzureBlobStorageConfiguration
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model EditDictionaryViewModel
|
@model EditDictionaryViewModel
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(ServerNavPages.Translations);
|
ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Translations), Context.GetRouteValue("dictionary") as string)
|
||||||
ViewData["Title"] = Context.GetRouteValue("dictionary");
|
.SetCategory(WellKnownCategories.Server));
|
||||||
}
|
}
|
||||||
|
|
||||||
<form method="post" class="d-flex flex-column">
|
<form method="post" class="d-flex flex-column">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model BTCPayServer.Storage.Services.Providers.FileSystemStorage.Configuration.FileSystemStorageConfiguration
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model BTCPayServer.Storage.Services.Providers.GoogleCloudStorage.Configuration.GoogleCloudStorageConfiguration
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@model ServerEmailsViewModel
|
@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">
|
<form method="post" autocomplete="off">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model ViewFilesViewModel
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model ChargeServiceViewModel
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model LightningWalletServices
|
@model LightningWalletServices
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(ServerNavPages.Services, Model.WalletName);
|
ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), Model.WalletName)
|
||||||
|
.SetCategory(WellKnownCategories.Server));
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@model ListDictionariesViewModel
|
@model ListDictionariesViewModel
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(ServerNavPages.Translations, StringLocalizer["Dictionaries"]);
|
ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Translations), StringLocalizer["Dictionaries"])
|
||||||
|
.SetCategory(WellKnownCategories.Server));
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
@inject PluginService PluginService
|
@inject PluginService PluginService
|
||||||
@{
|
@{
|
||||||
Layout = "_Layout";
|
Layout = "_Layout";
|
||||||
ViewData.SetActivePage(ServerNavPages.Plugins);
|
ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Plugins), StringLocalizer["Plugins"]));
|
||||||
var installed = Model.Installed;
|
var installed = Model.Installed;
|
||||||
var availableAndNotInstalled = new List<PluginService.AvailablePlugin>();
|
var availableAndNotInstalled = new List<PluginService.AvailablePlugin>();
|
||||||
var availableAndNotInstalledx = Model.Available
|
var availableAndNotInstalledx = Model.Available
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
@model BTCPayServer.Models.StoreViewModels.ListStoresViewModel
|
@model BTCPayServer.Models.StoreViewModels.ListStoresViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "_Layout";
|
Layout = "_Layout";
|
||||||
ViewData.SetActivePage(ServerNavPages.Stores, StringLocalizer["Store Overview"]);
|
ViewData.SetTitle(StringLocalizer["Store Overview"]);
|
||||||
|
ViewData["StoreList"] = true;
|
||||||
}
|
}
|
||||||
<div class="sticky-header">
|
<div class="sticky-header">
|
||||||
<h2 class="my-1">@ViewData["Title"]</h2>
|
<h2 class="my-1">@ViewData["Title"]</h2>
|
||||||
@@ -60,7 +61,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<span class="text-secondary" text-translate="true">No users</span>
|
<span class="text-secondary" text-translate="true">No users</span>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
||||||
@model UsersViewModel
|
@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 nextUserEmailSortOrder = (string)ViewData["NextUserEmailSortOrder"];
|
||||||
var userEmailSortOrder = nextUserEmailSortOrder switch
|
var userEmailSortOrder = nextUserEmailSortOrder switch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using BTCPayServer.Abstractions.Models
|
|
||||||
@model LndSeedBackupViewModel
|
@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">
|
<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>
|
<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>
|
</div>
|
||||||
<button class="btn btn-primary @(Model.Removed ? "collapse" : "")" id="details" type="button">See confidential seed information</button>
|
<button class="btn btn-primary @(Model.Removed ? "collapse" : "")" id="details" type="button">See confidential seed information</button>
|
||||||
|
|
||||||
@if (Model.Removed)
|
@if (Model.Removed)
|
||||||
{
|
{
|
||||||
<div class="alert alert-light d-flex align-items-center" role="alert">
|
<div class="alert alert-light d-flex align-items-center" role="alert">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model LndServicesViewModel
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model BTCPayServer.Models.ServerViewModels.LogsViewModel
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@model BTCPayServer.Models.ServerViewModels.MaintenanceViewModel
|
@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">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model LightningWalletServices
|
@model LightningWalletServices
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(ServerNavPages.Services, Model.WalletName);
|
ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), Model.WalletName)
|
||||||
|
.SetCategory(WellKnownCategories.Server));
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
@inject EmailSenderFactory EmailSenderFactory
|
@inject EmailSenderFactory EmailSenderFactory
|
||||||
@inject TransactionLinkProviders TransactionLinkProviders
|
@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();
|
var linkProviders = TransactionLinkProviders.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@model LightningWalletServices
|
@model LightningWalletServices
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(ServerNavPages.Services, Model.WalletName);
|
ViewData.SetLayoutModel(new LayoutModel(nameof(ServerNavPages.Services), Model.WalletName)
|
||||||
|
.SetCategory(WellKnownCategories.Server));
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header">
|
<div class="sticky-header">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@model BTCPayServer.Controllers.ResetUserPasswordFromAdmin
|
@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">
|
<form method="post" asp-action="ResetUserPassword">
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user