mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-10 09:19:24 +01:00
Unify list views (#5399)
This commit is contained in:
parent
6acc545b66
commit
27c22d5e33
40 changed files with 581 additions and 504 deletions
|
@ -1457,7 +1457,7 @@ namespace BTCPayServer.Tests
|
||||||
[Trait("Integration", "Integration")]
|
[Trait("Integration", "Integration")]
|
||||||
public async Task CanUseWebhooks()
|
public async Task CanUseWebhooks()
|
||||||
{
|
{
|
||||||
void AssertHook(FakeServer fakeServer, Client.Models.StoreWebhookData hook)
|
void AssertHook(FakeServer fakeServer, StoreWebhookData hook)
|
||||||
{
|
{
|
||||||
Assert.True(hook.Enabled);
|
Assert.True(hook.Enabled);
|
||||||
Assert.True(hook.AuthorizedEvents.Everything);
|
Assert.True(hook.AuthorizedEvents.Everything);
|
||||||
|
|
|
@ -196,7 +196,6 @@ namespace BTCPayServer.Tests
|
||||||
s.Driver.FindElement(By.Id("StoreNav-PaymentRequests")).Click();
|
s.Driver.FindElement(By.Id("StoreNav-PaymentRequests")).Click();
|
||||||
s.Driver.FindElement(By.Id("CreatePaymentRequest")).Click();
|
s.Driver.FindElement(By.Id("CreatePaymentRequest")).Click();
|
||||||
Assert.Equal(4, new SelectElement(s.Driver.FindElement(By.Id("FormId"))).Options.Count);
|
Assert.Equal(4, new SelectElement(s.Driver.FindElement(By.Id("FormId"))).Options.Count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact(Timeout = TestTimeout)]
|
[Fact(Timeout = TestTimeout)]
|
||||||
|
@ -216,8 +215,7 @@ namespace BTCPayServer.Tests
|
||||||
s.GoToInvoices(s.StoreId);
|
s.GoToInvoices(s.StoreId);
|
||||||
}
|
}
|
||||||
// Let's CPFP from the invoices page
|
// Let's CPFP from the invoices page
|
||||||
s.Driver.SetCheckbox(By.Id("selectAllCheckbox"), true);
|
s.Driver.SetCheckbox(By.CssSelector(".mass-action-select-all"), true);
|
||||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
|
||||||
s.Driver.FindElement(By.Id("BumpFee")).Click();
|
s.Driver.FindElement(By.Id("BumpFee")).Click();
|
||||||
s.Driver.FindElement(By.Id("BroadcastTransaction")).Click();
|
s.Driver.FindElement(By.Id("BroadcastTransaction")).Click();
|
||||||
s.FindAlertMessage();
|
s.FindAlertMessage();
|
||||||
|
@ -225,16 +223,14 @@ namespace BTCPayServer.Tests
|
||||||
|
|
||||||
// CPFP again should fail because all invoices got bumped
|
// CPFP again should fail because all invoices got bumped
|
||||||
s.GoToInvoices();
|
s.GoToInvoices();
|
||||||
s.Driver.SetCheckbox(By.Id("selectAllCheckbox"), true);
|
s.Driver.SetCheckbox(By.CssSelector(".mass-action-select-all"), true);
|
||||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
|
||||||
s.Driver.FindElement(By.Id("BumpFee")).Click();
|
s.Driver.FindElement(By.Id("BumpFee")).Click();
|
||||||
Assert.Contains($"/stores/{s.StoreId}/invoices", s.Driver.Url);
|
Assert.Contains($"/stores/{s.StoreId}/invoices", s.Driver.Url);
|
||||||
Assert.Contains("any UTXO available", s.FindAlertMessage(StatusMessageModel.StatusSeverity.Error).Text);
|
Assert.Contains("any UTXO available", s.FindAlertMessage(StatusMessageModel.StatusSeverity.Error).Text);
|
||||||
|
|
||||||
// But we should be able to bump from the wallet's page
|
// But we should be able to bump from the wallet's page
|
||||||
s.GoToWallet(navPages: WalletsNavPages.Transactions);
|
s.GoToWallet(navPages: WalletsNavPages.Transactions);
|
||||||
s.Driver.SetCheckbox(By.Id("selectAllCheckbox"), true);
|
s.Driver.SetCheckbox(By.CssSelector(".mass-action-select-all"), true);
|
||||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
|
||||||
s.Driver.FindElement(By.Id("BumpFee")).Click();
|
s.Driver.FindElement(By.Id("BumpFee")).Click();
|
||||||
s.Driver.FindElement(By.Id("BroadcastTransaction")).Click();
|
s.Driver.FindElement(By.Id("BroadcastTransaction")).Click();
|
||||||
Assert.Contains($"/wallets/{s.WalletId}", s.Driver.Url);
|
Assert.Contains($"/wallets/{s.WalletId}", s.Driver.Url);
|
||||||
|
@ -730,9 +726,8 @@ namespace BTCPayServer.Tests
|
||||||
Assert.Contains(invoiceId, s.Driver.PageSource);
|
Assert.Contains(invoiceId, s.Driver.PageSource);
|
||||||
|
|
||||||
// archive via list
|
// archive via list
|
||||||
s.Driver.FindElement(By.CssSelector($".selector[value=\"{invoiceId}\"]")).Click();
|
s.Driver.FindElement(By.CssSelector($".mass-action-select[value=\"{invoiceId}\"]")).Click();
|
||||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
s.Driver.FindElement(By.Id("ArchiveSelected")).Click();
|
||||||
s.Driver.FindElement(By.Id("ActionsDropdownArchive")).Click();
|
|
||||||
Assert.Contains("1 invoice archived", s.FindAlertMessage().Text);
|
Assert.Contains("1 invoice archived", s.FindAlertMessage().Text);
|
||||||
Assert.DoesNotContain(invoiceId, s.Driver.PageSource);
|
Assert.DoesNotContain(invoiceId, s.Driver.PageSource);
|
||||||
|
|
||||||
|
@ -740,9 +735,8 @@ namespace BTCPayServer.Tests
|
||||||
s.Driver.FindElement(By.Id("StatusOptionsToggle")).Click();
|
s.Driver.FindElement(By.Id("StatusOptionsToggle")).Click();
|
||||||
s.Driver.FindElement(By.Id("StatusOptionsIncludeArchived")).Click();
|
s.Driver.FindElement(By.Id("StatusOptionsIncludeArchived")).Click();
|
||||||
Assert.Contains(invoiceId, s.Driver.PageSource);
|
Assert.Contains(invoiceId, s.Driver.PageSource);
|
||||||
s.Driver.FindElement(By.CssSelector($".selector[value=\"{invoiceId}\"]")).Click();
|
s.Driver.FindElement(By.CssSelector($".mass-action-select[value=\"{invoiceId}\"]")).Click();
|
||||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
s.Driver.FindElement(By.Id("UnarchiveSelected")).Click();
|
||||||
s.Driver.FindElement(By.Id("ActionsDropdownUnarchive")).Click();
|
|
||||||
Assert.Contains("1 invoice unarchived", s.FindAlertMessage().Text);
|
Assert.Contains("1 invoice unarchived", s.FindAlertMessage().Text);
|
||||||
Assert.Contains(invoiceId, s.Driver.PageSource);
|
Assert.Contains(invoiceId, s.Driver.PageSource);
|
||||||
|
|
||||||
|
@ -1377,7 +1371,7 @@ namespace BTCPayServer.Tests
|
||||||
TestLogs.LogInformation("Let's try to update one of them");
|
TestLogs.LogInformation("Let's try to update one of them");
|
||||||
s.Driver.FindElement(By.LinkText("Modify")).Click();
|
s.Driver.FindElement(By.LinkText("Modify")).Click();
|
||||||
|
|
||||||
using FakeServer server = new FakeServer();
|
using var server = new FakeServer();
|
||||||
await server.Start();
|
await server.Start();
|
||||||
s.Driver.FindElement(By.Name("PayloadUrl")).Clear();
|
s.Driver.FindElement(By.Name("PayloadUrl")).Clear();
|
||||||
s.Driver.FindElement(By.Name("PayloadUrl")).SendKeys(server.ServerUri.AbsoluteUri);
|
s.Driver.FindElement(By.Name("PayloadUrl")).SendKeys(server.ServerUri.AbsoluteUri);
|
||||||
|
@ -1419,7 +1413,7 @@ namespace BTCPayServer.Tests
|
||||||
server.Done();
|
server.Done();
|
||||||
|
|
||||||
TestLogs.LogInformation("Let's make a failed event");
|
TestLogs.LogInformation("Let's make a failed event");
|
||||||
s.CreateInvoice();
|
var invoiceId = s.CreateInvoice();
|
||||||
request = await server.GetNextRequest();
|
request = await server.GetNextRequest();
|
||||||
request.Response.StatusCode = 404;
|
request.Response.StatusCode = 404;
|
||||||
server.Done();
|
server.Done();
|
||||||
|
@ -1444,7 +1438,7 @@ namespace BTCPayServer.Tests
|
||||||
CanBrowseContent(s);
|
CanBrowseContent(s);
|
||||||
|
|
||||||
s.GoToInvoices();
|
s.GoToInvoices();
|
||||||
s.Driver.FindElement(By.LinkText("Details")).Click();
|
s.Driver.FindElement(By.LinkText(invoiceId)).Click();
|
||||||
CanBrowseContent(s);
|
CanBrowseContent(s);
|
||||||
var element = s.Driver.FindElement(By.ClassName("redeliver"));
|
var element = s.Driver.FindElement(By.ClassName("redeliver"));
|
||||||
element.Click();
|
element.Click();
|
||||||
|
@ -1697,13 +1691,14 @@ namespace BTCPayServer.Tests
|
||||||
// no previous page in the wizard, hence no back button
|
// no previous page in the wizard, hence no back button
|
||||||
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
|
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
|
||||||
s.Driver.FindElement(By.Id("CancelWizard")).Click();
|
s.Driver.FindElement(By.Id("CancelWizard")).Click();
|
||||||
Assert.Equal(settingsUri.ToString(), s.Driver.Url);
|
Assert.Equal(settingsUri.ToString(), s.Driver.Url);
|
||||||
|
|
||||||
// Transactions list contains export and action, ensure functions are present.
|
// Transactions list contains export, ensure functions are present.
|
||||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
|
||||||
|
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
|
||||||
s.Driver.FindElement(By.Id("BumpFee"));
|
s.Driver.FindElement(By.Id("BumpFee"));
|
||||||
|
|
||||||
// JSON export
|
// JSON export
|
||||||
s.Driver.FindElement(By.Id("ExportDropdownToggle")).Click();
|
s.Driver.FindElement(By.Id("ExportDropdownToggle")).Click();
|
||||||
s.Driver.FindElement(By.Id("ExportJSON")).Click();
|
s.Driver.FindElement(By.Id("ExportJSON")).Click();
|
||||||
|
@ -1859,8 +1854,7 @@ namespace BTCPayServer.Tests
|
||||||
payouts[0].Click();
|
payouts[0].Click();
|
||||||
|
|
||||||
Assert.NotEmpty(s.Driver.FindElements(By.ClassName("payout")));
|
Assert.NotEmpty(s.Driver.FindElements(By.ClassName("payout")));
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-selectAllCheckbox")).Click();
|
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-actions")).Click();
|
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve-pay")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve-pay")).Click();
|
||||||
|
|
||||||
s.Driver.FindElement(By.Id("SignTransaction")).Click();
|
s.Driver.FindElement(By.Id("SignTransaction")).Click();
|
||||||
|
@ -1935,8 +1929,7 @@ namespace BTCPayServer.Tests
|
||||||
Assert.Contains(PayoutState.AwaitingApproval.GetStateString(), s.Driver.PageSource);
|
Assert.Contains(PayoutState.AwaitingApproval.GetStateString(), s.Driver.PageSource);
|
||||||
s.GoToStore(s.StoreId, StoreNavPages.Payouts);
|
s.GoToStore(s.StoreId, StoreNavPages.Payouts);
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-view")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-view")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-selectAllCheckbox")).Click();
|
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-actions")).Click();
|
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve")).Click();
|
||||||
s.FindAlertMessage();
|
s.FindAlertMessage();
|
||||||
var tx = await s.Server.ExplorerNode.SendToAddressAsync(address, Money.FromUnit(0.001m, MoneyUnit.BTC));
|
var tx = await s.Server.ExplorerNode.SendToAddressAsync(address, Money.FromUnit(0.001m, MoneyUnit.BTC));
|
||||||
|
@ -1945,8 +1938,7 @@ namespace BTCPayServer.Tests
|
||||||
|
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-view")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-view")).Click();
|
||||||
Assert.Contains(PayoutState.AwaitingPayment.GetStateString(), s.Driver.PageSource);
|
Assert.Contains(PayoutState.AwaitingPayment.GetStateString(), s.Driver.PageSource);
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-selectAllCheckbox")).Click();
|
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-actions")).Click();
|
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-mark-paid")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-mark-paid")).Click();
|
||||||
s.FindAlertMessage();
|
s.FindAlertMessage();
|
||||||
|
|
||||||
|
@ -2006,8 +1998,7 @@ namespace BTCPayServer.Tests
|
||||||
s.GoToStore(newStore.storeId, StoreNavPages.Payouts);
|
s.GoToStore(newStore.storeId, StoreNavPages.Payouts);
|
||||||
s.Driver.FindElement(By.Id($"{new PaymentMethodId("BTC", PaymentTypes.LightningLike)}-view")).Click();
|
s.Driver.FindElement(By.Id($"{new PaymentMethodId("BTC", PaymentTypes.LightningLike)}-view")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-view")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-view")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-selectAllCheckbox")).Click();
|
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-actions")).Click();
|
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve-pay")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve-pay")).Click();
|
||||||
Assert.Contains(bolt, s.Driver.PageSource);
|
Assert.Contains(bolt, s.Driver.PageSource);
|
||||||
Assert.Contains($"{payoutAmount.ToString()} BTC", s.Driver.PageSource);
|
Assert.Contains($"{payoutAmount.ToString()} BTC", s.Driver.PageSource);
|
||||||
|
@ -2023,8 +2014,7 @@ namespace BTCPayServer.Tests
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-view")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-view")).Click();
|
||||||
Assert.Contains(bolt, s.Driver.PageSource);
|
Assert.Contains(bolt, s.Driver.PageSource);
|
||||||
|
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-selectAllCheckbox")).Click();
|
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-actions")).Click();
|
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-mark-paid")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-mark-paid")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{new PaymentMethodId("BTC", PaymentTypes.LightningLike)}-view")).Click();
|
s.Driver.FindElement(By.Id($"{new PaymentMethodId("BTC", PaymentTypes.LightningLike)}-view")).Click();
|
||||||
|
|
||||||
|
@ -2553,8 +2543,7 @@ namespace BTCPayServer.Tests
|
||||||
payouts[0].Click();
|
payouts[0].Click();
|
||||||
s.Driver.FindElement(By.Id("BTC_LightningLike-view")).Click();
|
s.Driver.FindElement(By.Id("BTC_LightningLike-view")).Click();
|
||||||
Assert.NotEmpty(s.Driver.FindElements(By.ClassName("payout")));
|
Assert.NotEmpty(s.Driver.FindElements(By.ClassName("payout")));
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-selectAllCheckbox")).Click();
|
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-actions")).Click();
|
|
||||||
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve-pay")).Click();
|
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve-pay")).Click();
|
||||||
|
|
||||||
Assert.Contains(lnurl, s.Driver.PageSource);
|
Assert.Contains(lnurl, s.Driver.PageSource);
|
||||||
|
|
|
@ -634,58 +634,56 @@ namespace BTCPayServer.Controllers
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewInvoices)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanViewInvoices)]
|
||||||
public async Task<IActionResult> MassAction(string command, string[] selectedItems, string? storeId = null)
|
public async Task<IActionResult> MassAction(string command, string[] selectedItems, string? storeId = null)
|
||||||
{
|
{
|
||||||
if (selectedItems != null)
|
IActionResult NotSupported(string err)
|
||||||
{
|
{
|
||||||
switch (command)
|
TempData[WellKnownTempData.ErrorMessage] = err;
|
||||||
{
|
return RedirectToAction(nameof(ListInvoices), new { storeId });
|
||||||
case "archive":
|
}
|
||||||
await _InvoiceRepository.MassArchive(selectedItems);
|
if (selectedItems.Length == 0)
|
||||||
TempData[WellKnownTempData.SuccessMessage] = $"{selectedItems.Length} invoice{(selectedItems.Length == 1 ? "" : "s")} archived.";
|
return NotSupported("No invoice has been selected");
|
||||||
break;
|
|
||||||
|
|
||||||
case "unarchive":
|
switch (command)
|
||||||
await _InvoiceRepository.MassArchive(selectedItems, false);
|
{
|
||||||
TempData[WellKnownTempData.SuccessMessage] = $"{selectedItems.Length} invoice{(selectedItems.Length == 1 ? "" : "s")} unarchived.";
|
case "archive":
|
||||||
break;
|
await _InvoiceRepository.MassArchive(selectedItems);
|
||||||
case "cpfp":
|
TempData[WellKnownTempData.SuccessMessage] = $"{selectedItems.Length} invoice{(selectedItems.Length == 1 ? "" : "s")} archived.";
|
||||||
if (selectedItems.Length == 0)
|
break;
|
||||||
return NotSupported("No invoice has been selected");
|
|
||||||
var network = _NetworkProvider.DefaultNetwork;
|
|
||||||
var explorer = _ExplorerClients.GetExplorerClient(network);
|
|
||||||
IActionResult NotSupported(string err)
|
|
||||||
{
|
|
||||||
TempData[WellKnownTempData.ErrorMessage] = err;
|
|
||||||
return RedirectToAction(nameof(ListInvoices), new { storeId });
|
|
||||||
}
|
|
||||||
if (explorer is null)
|
|
||||||
return NotSupported("This feature is only available to BTC wallets");
|
|
||||||
if (!GetCurrentStore().HasPermission(GetUserId(), Policies.CanModifyStoreSettings))
|
|
||||||
return Forbid();
|
|
||||||
|
|
||||||
var derivationScheme = (this.GetCurrentStore().GetDerivationSchemeSettings(_NetworkProvider, network.CryptoCode))?.AccountDerivation;
|
case "unarchive":
|
||||||
if (derivationScheme is null)
|
await _InvoiceRepository.MassArchive(selectedItems, false);
|
||||||
return NotSupported("This feature is only available to BTC wallets");
|
TempData[WellKnownTempData.SuccessMessage] = $"{selectedItems.Length} invoice{(selectedItems.Length == 1 ? "" : "s")} unarchived.";
|
||||||
var bumpableAddresses = (await GetAddresses(selectedItems))
|
break;
|
||||||
.Where(p => p.GetPaymentMethodId().IsBTCOnChain)
|
case "cpfp":
|
||||||
.Select(p => p.GetAddress()).ToHashSet();
|
var network = _NetworkProvider.DefaultNetwork;
|
||||||
var utxos = await explorer.GetUTXOsAsync(derivationScheme);
|
var explorer = _ExplorerClients.GetExplorerClient(network);
|
||||||
var bumpableUTXOs = utxos.GetUnspentUTXOs().Where(u => u.Confirmations == 0 && bumpableAddresses.Contains(u.ScriptPubKey.Hash.ToString())).ToArray();
|
if (explorer is null)
|
||||||
var parameters = new MultiValueDictionary<string, string>();
|
return NotSupported("This feature is only available to BTC wallets");
|
||||||
foreach (var utxo in bumpableUTXOs)
|
if (!GetCurrentStore().HasPermission(GetUserId(), Policies.CanModifyStoreSettings))
|
||||||
{
|
return Forbid();
|
||||||
parameters.Add($"outpoints[]", utxo.Outpoint.ToString());
|
|
||||||
}
|
var derivationScheme = (this.GetCurrentStore().GetDerivationSchemeSettings(_NetworkProvider, network.CryptoCode))?.AccountDerivation;
|
||||||
return View("PostRedirect", new PostRedirectViewModel
|
if (derivationScheme is null)
|
||||||
{
|
return NotSupported("This feature is only available to BTC wallets");
|
||||||
AspController = "UIWallets",
|
var bumpableAddresses = (await GetAddresses(selectedItems))
|
||||||
AspAction = nameof(UIWalletsController.WalletCPFP),
|
.Where(p => p.GetPaymentMethodId().IsBTCOnChain)
|
||||||
RouteParameters = {
|
.Select(p => p.GetAddress()).ToHashSet();
|
||||||
{ "walletId", new WalletId(storeId, network.CryptoCode).ToString() },
|
var utxos = await explorer.GetUTXOsAsync(derivationScheme);
|
||||||
{ "returnUrl", Url.Action(nameof(ListInvoices), new { storeId }) }
|
var bumpableUTXOs = utxos.GetUnspentUTXOs().Where(u => u.Confirmations == 0 && bumpableAddresses.Contains(u.ScriptPubKey.Hash.ToString())).ToArray();
|
||||||
},
|
var parameters = new MultiValueDictionary<string, string>();
|
||||||
FormParameters = parameters,
|
foreach (var utxo in bumpableUTXOs)
|
||||||
});
|
{
|
||||||
}
|
parameters.Add($"outpoints[]", utxo.Outpoint.ToString());
|
||||||
|
}
|
||||||
|
return View("PostRedirect", new PostRedirectViewModel
|
||||||
|
{
|
||||||
|
AspController = "UIWallets",
|
||||||
|
AspAction = nameof(UIWalletsController.WalletCPFP),
|
||||||
|
RouteParameters = {
|
||||||
|
{ "walletId", new WalletId(storeId, network.CryptoCode).ToString() },
|
||||||
|
{ "returnUrl", Url.Action(nameof(ListInvoices), new { storeId }) }
|
||||||
|
},
|
||||||
|
FormParameters = parameters,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return RedirectToAction(nameof(ListInvoices), new { storeId });
|
return RedirectToAction(nameof(ListInvoices), new { storeId });
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||||
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||||
<a asp-action="CreateOrEditRole" asp-route-storeId="@storeId" class="btn btn-primary" role="button" id="CreateRole" asp-route-role="create"
|
<a asp-action="CreateOrEditRole" asp-route-storeId="@storeId" class="btn btn-primary" role="button" id="CreateRole" asp-route-role="create"
|
||||||
asp-controller="@controller">
|
asp-controller="@controller">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Add Role
|
Add Role
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||||
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</a>
|
</a>
|
||||||
</small>
|
</small>
|
||||||
</h2>
|
</h2>
|
||||||
<a asp-action="CreateApp" asp-route-storeId="@Context.GetStoreData().Id" class="btn btn-primary mt-3 mt-sm-0" role="button" id="CreateNewApp"><span class="fa fa-plus"></span> Create a new app</a>
|
<a asp-action="CreateApp" asp-route-storeId="@Context.GetStoreData().Id" class="btn btn-primary mt-3 mt-sm-0" role="button" id="CreateNewApp">Create a new app</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div id="custodianAccountView" v-cloak>
|
<div id="custodianAccountView" v-cloak>
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-flex flex-wrap gap-3 align-items-center justify-content-between">
|
<div class="sticky-header d-flex flex-wrap gap-3 align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">
|
<h2 class="mb-0">
|
||||||
@ViewData["Title"]
|
@ViewData["Title"]
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
</a>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
<a asp-action="Create" asp-route-storeId="@storeId" class="btn btn-primary mt-3 mt-sm-0" role="button" id="CreateForm">
|
<a asp-action="Create" asp-route-storeId="@storeId" class="btn btn-primary mt-3 mt-sm-0" role="button" id="CreateForm">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Create Form
|
Create Form
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<form asp-action="CreateInvoice" method="post" id="create-invoice-form">
|
<form asp-action="CreateInvoice" method="post" id="create-invoice-form">
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-flex align-items-center justify-content-between">
|
<div class="sticky-header d-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||||
<input type="submit" value="Create" class="btn btn-primary" id="Create" />
|
<input type="submit" value="Create" class="btn btn-primary" id="Create" />
|
||||||
|
|
|
@ -169,7 +169,6 @@
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-flex flex-wrap gap-3 align-items-center justify-content-between">
|
<div class="sticky-header d-flex flex-wrap gap-3 align-items-center justify-content-between">
|
||||||
<h2 class="mb-0 text-break">@ViewData["Title"]</h2>
|
<h2 class="mb-0 text-break">@ViewData["Title"]</h2>
|
||||||
<div class="d-flex flex-wrap gap-3 d-print-none">
|
<div class="d-flex flex-wrap gap-3 d-print-none">
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
@using BTCPayServer.Client
|
@using BTCPayServer.Client
|
||||||
@using BTCPayServer.Client.Models
|
@using BTCPayServer.Client.Models
|
||||||
@using BTCPayServer.Services
|
@using BTCPayServer.Services
|
||||||
|
@using SetPasswordViewModel = BTCPayServer.Models.ManageViewModels.SetPasswordViewModel
|
||||||
@inject DisplayFormatter DisplayFormatter
|
@inject DisplayFormatter DisplayFormatter
|
||||||
@inject ReportService ReportService
|
|
||||||
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
|
|
||||||
@model InvoicesModel
|
@model InvoicesModel
|
||||||
@{
|
@{
|
||||||
var reportNames = ReportService.ReportProviders.Select(p => p.Value.Name).OrderBy(c => c).ToArray();
|
|
||||||
ViewData.SetActivePage(InvoiceNavPages.Index, "Invoices");
|
ViewData.SetActivePage(InvoiceNavPages.Index, "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");
|
||||||
|
@ -32,8 +29,11 @@
|
||||||
@section PageHeadContent
|
@section PageHeadContent
|
||||||
{
|
{
|
||||||
<style>
|
<style>
|
||||||
|
.invoiceId-col {
|
||||||
|
min-width: 8rem;
|
||||||
|
}
|
||||||
.invoice-details-row > td {
|
.invoice-details-row > td {
|
||||||
padding: 1.5rem .5rem 0 2.65rem;
|
padding: 1.5rem 1rem 0 2.65rem;
|
||||||
}
|
}
|
||||||
.dropdown > .btn {
|
.dropdown > .btn {
|
||||||
min-width: 7rem;
|
min-width: 7rem;
|
||||||
|
@ -54,11 +54,7 @@
|
||||||
|
|
||||||
@* Custom Range Modal *@
|
@* Custom Range Modal *@
|
||||||
<script>
|
<script>
|
||||||
delegate('click', '#selectAllCheckbox', e => {
|
const timezoneOffset = new Date().getTimezoneOffset();
|
||||||
document.querySelectorAll(".selector").forEach(checkbox => {
|
|
||||||
checkbox.checked = e.target.checked;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
delegate('click', '.showInvoice', e => {
|
delegate('click', '.showInvoice', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -99,41 +95,11 @@
|
||||||
var str = newDate.toLocaleDateString() + " " + newDate.toLocaleTimeString();
|
var str = newDate.toLocaleDateString() + " " + newDate.toLocaleTimeString();
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
var timezoneOffset = new Date().getTimezoneOffset();
|
|
||||||
|
|
||||||
$("#invoices")
|
|
||||||
.on("click", ".invoice-row .invoice-details-toggle", function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation(true);
|
|
||||||
|
|
||||||
const $btnToggle = $(e.currentTarget);
|
|
||||||
const $invoiceRow = $btnToggle.parents(".invoice-row");
|
|
||||||
const $detailsRow = $invoiceRow.next(".invoice-details-row");
|
|
||||||
|
|
||||||
$detailsRow.toggle(0, function () {
|
|
||||||
const $icon = $btnToggle.children().first();
|
|
||||||
if ($(this).is(':visible')) {
|
|
||||||
$icon.removeClass('fa-angle-double-down').addClass('fa-angle-double-up');
|
|
||||||
} else {
|
|
||||||
$icon.removeClass('fa-angle-double-up').addClass('fa-angle-double-down');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.on("click", ".invoice-row", function (e) {
|
|
||||||
const $invoiceRow = $(e.currentTarget);
|
|
||||||
if ($(e.target).is("td")) {
|
|
||||||
$invoiceRow.find(".selector").trigger("click");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Html.HiddenFor(a => a.Count)
|
@Html.HiddenFor(a => a.Count)
|
||||||
|
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">
|
<h2 class="mb-0">
|
||||||
@ViewData["Title"]
|
@ViewData["Title"]
|
||||||
|
@ -142,7 +108,6 @@
|
||||||
</a>
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
<a id="CreateNewInvoice" asp-action="CreateInvoice" asp-route-storeId="@Model.StoreId" asp-route-searchTerm="@Model.SearchTerm" class="btn btn-primary mt-3 mt-sm-0">
|
<a id="CreateNewInvoice" asp-action="CreateInvoice" asp-route-storeId="@Model.StoreId" asp-route-searchTerm="@Model.SearchTerm" class="btn btn-primary mt-3 mt-sm-0">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Create Invoice
|
Create Invoice
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -169,7 +134,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<partial name="_StatusMessage" />
|
<partial name="_StatusMessage" />
|
||||||
|
|
||||||
<partial name="InvoiceStatusChangePartial" />
|
<partial name="InvoiceStatusChangePartial" />
|
||||||
|
|
||||||
@* Custom Range Modal *@
|
@* Custom Range Modal *@
|
||||||
|
@ -305,97 +269,100 @@
|
||||||
|
|
||||||
@if (Model.Invoices.Any())
|
@if (Model.Invoices.Any())
|
||||||
{
|
{
|
||||||
<form method="post" id="MassAction" asp-action="MassAction" class="">
|
<form method="post" asp-action="MassAction">
|
||||||
<div class="d-inline-flex align-items-center pb-2 float-xxl-end mb-2 gap-3">
|
<input type="hidden" name="storeId" value="@Model.StoreId" />
|
||||||
<input type="hidden" name="storeId" value="@Model.StoreId" />
|
|
||||||
<div class="dropdown order-xxl-1">
|
|
||||||
<button class="btn btn-secondary dropdown-toggle dropdown-toggle-custom-caret" type="button" id="ActionsDropdownToggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
Actions
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu dropdown-menu-xxl-end" aria-labelledby="ActionsDropdownToggle">
|
|
||||||
<button type="submit" class="dropdown-item" name="command" value="archive" id="ActionsDropdownArchive">Archive</button>
|
|
||||||
@if (HasBooleanFilter("includearchived"))
|
|
||||||
{
|
|
||||||
<button type="submit" asp-action="MassAction" class="dropdown-item" name="command" value="unarchive" id="ActionsDropdownUnarchive">Unarchive</button>
|
|
||||||
}
|
|
||||||
<button id="BumpFee" type="submit" permission="@Policies.CanModifyStoreSettings" class="dropdown-item" name="command" value="cpfp">Bump fee</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown d-inline-flex align-items-center gap-3">
|
|
||||||
<button class="btn btn-secondary dropdown-toggle dropdown-toggle-custom-caret order-xxl-1" type="button" id="ExportDropdownToggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
Reports
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu" aria-labelledby="ExportDropdownToggle">
|
|
||||||
@foreach (var report in reportNames)
|
|
||||||
{
|
|
||||||
<a asp-controller="UIReports" asp-action="StoreReports" asp-route-viewName="@report" asp-route-storeId="@Model.StoreId" class="dropdown-item export-link">@report</a>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<a href="https://docs.btcpayserver.org/Accounting/" target="_blank" rel="noreferrer noopener" title="More information...">
|
|
||||||
<vc:icon symbol="info" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style="clear:both"></div>
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table id="invoices" class="table table-hover">
|
<table id="invoices" class="table table-hover mass-action">
|
||||||
<thead>
|
<thead class="mass-action-head">
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:2rem;" class="only-for-js">
|
<th class="mass-action-select-col only-for-js">
|
||||||
<input id="selectAllCheckbox" type="checkbox" class="form-check-input" />
|
<input type="checkbox" class="form-check-input mass-action-select-all" />
|
||||||
<th class="w-150px">
|
</th>
|
||||||
|
<th class="date-col">
|
||||||
<div class="d-flex align-items-center gap-1">
|
<div class="d-flex align-items-center gap-1">
|
||||||
Date
|
Date
|
||||||
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format only-for-js" title="Switch date format"></button>
|
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format only-for-js" title="Switch date format"></button>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th class="text-nowrap">Order Id</th>
|
|
||||||
<th class="text-nowrap">Invoice Id</th>
|
<th class="text-nowrap">Invoice Id</th>
|
||||||
|
<th class="text-nowrap">Order Id</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th class="text-end">Amount</th>
|
<th class="amount-col">Amount</th>
|
||||||
<th class="text-end">Actions</th>
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<thead class="mass-action-actions">
|
||||||
|
<tr>
|
||||||
|
<th class="mass-action-select-col only-for-js">
|
||||||
|
<input type="checkbox" class="form-check-input mass-action-select-all" />
|
||||||
|
</th>
|
||||||
|
<th colspan="6">
|
||||||
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
|
||||||
|
<div>
|
||||||
|
<strong class="mass-action-selected-count">0</strong>
|
||||||
|
selected
|
||||||
|
</div>
|
||||||
|
<div class="d-inline-flex align-items-center gap-3">
|
||||||
|
<button type="submit" name="command" value="archive" id="ArchiveSelected" class="btn btn-link">
|
||||||
|
<vc:icon symbol="archive" />
|
||||||
|
Archive
|
||||||
|
</button>
|
||||||
|
@if (HasBooleanFilter("includearchived"))
|
||||||
|
{
|
||||||
|
<button type="submit" name="command" value="unarchive" id="UnarchiveSelected" class="btn btn-link">
|
||||||
|
<vc:icon symbol="archive" />
|
||||||
|
Unarchive
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
<button type="submit" name="command" value="cpfp" id="BumpFee" class="btn btn-link">
|
||||||
|
<vc:icon symbol="send" />
|
||||||
|
Bump fee
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (var invoice in Model.Invoices)
|
@foreach (var invoice in Model.Invoices)
|
||||||
{
|
{
|
||||||
<tr id="invoice_@invoice.InvoiceId" class="invoice-row">
|
var detailsId = $"invoice_details_{invoice.InvoiceId}";
|
||||||
<td class="only-for-js">
|
<tr id="invoice_@invoice.InvoiceId" class="mass-action-row">
|
||||||
<input name="selectedItems" type="checkbox" class="selector form-check-input" value="@invoice.InvoiceId" />
|
<td class="only-for-js align-middle">
|
||||||
|
<input name="selectedItems" type="checkbox" class="form-check-input mass-action-select" value="@invoice.InvoiceId" />
|
||||||
</td>
|
</td>
|
||||||
<td>@invoice.Date.ToBrowserDate()</td>
|
<td class="align-middle date-col">@invoice.Date.ToBrowserDate()</td>
|
||||||
<td>
|
<td class="text-break align-middle invoiceId-col">
|
||||||
|
<a asp-action="Invoice" class="invoice-details-link" asp-route-invoiceId="@invoice.InvoiceId">@invoice.InvoiceId</a>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle">
|
||||||
<vc:truncate-center text="@invoice.OrderId" link="@invoice.RedirectUrl" classes="truncate-center-id" />
|
<vc:truncate-center text="@invoice.OrderId" link="@invoice.RedirectUrl" classes="truncate-center-id" />
|
||||||
</td>
|
</td>
|
||||||
<td class="text-break">@invoice.InvoiceId</td>
|
<td class="align-middle">
|
||||||
<td>
|
<div class="d-inline-flex align-items-center gap-2">
|
||||||
<vc:invoice-status state="invoice.Status" payments="invoice.Details.Payments" invoice-id="@invoice.InvoiceId"
|
<vc:invoice-status state="invoice.Status" payments="invoice.Details.Payments" invoice-id="@invoice.InvoiceId"
|
||||||
is-archived="invoice.Details.Archived" has-refund="invoice.HasRefund" />
|
is-archived="invoice.Details.Archived" has-refund="invoice.HasRefund" />
|
||||||
</td>
|
@if (invoice.ShowCheckout)
|
||||||
<td class="text-end text-nowrap">
|
{
|
||||||
<span data-sensitive>@DisplayFormatter.Currency(invoice.Amount, invoice.Currency)</span>
|
<span> </span>
|
||||||
</td>
|
|
||||||
<td class="text-end text-nowrap">
|
|
||||||
@if (invoice.ShowCheckout)
|
|
||||||
{
|
|
||||||
<span>
|
|
||||||
<a asp-action="Checkout" asp-route-invoiceId="@invoice.InvoiceId" class="invoice-checkout-link" id="invoice-checkout-@invoice.InvoiceId">Checkout</a>
|
<a asp-action="Checkout" asp-route-invoiceId="@invoice.InvoiceId" class="invoice-checkout-link" id="invoice-checkout-@invoice.InvoiceId">Checkout</a>
|
||||||
<a asp-action="Checkout" asp-route-invoiceId="@invoice.InvoiceId" class="showInvoice only-for-js" data-invoice-id="@invoice.InvoiceId">[^]</a>
|
<a asp-action="Checkout" asp-route-invoiceId="@invoice.InvoiceId" class="showInvoice only-for-js" data-invoice-id="@invoice.InvoiceId">[^]</a>
|
||||||
@if (!invoice.CanMarkStatus)
|
}
|
||||||
{
|
</div>
|
||||||
<span>-</span>
|
</td>
|
||||||
}
|
<td class="align-middle amount-col">
|
||||||
</span>
|
<span data-sensitive>@DisplayFormatter.Currency(invoice.Amount, invoice.Currency)</span>
|
||||||
}
|
</td>
|
||||||
|
<td class="align-middle text-end">
|
||||||
<a asp-action="Invoice" class="invoice-details-link" asp-route-invoiceId="@invoice.InvoiceId">Details</a>
|
<div class="d-inline-flex align-items-center gap-2">
|
||||||
<a class="only-for-js invoice-details-toggle" href="#">
|
<button class="accordion-button collapsed only-for-js ms-0 d-inline-block" type="button" data-bs-toggle="collapse" data-bs-target="#@detailsId" aria-expanded="false" aria-controls="@detailsId">
|
||||||
<span title="Invoice Details Toggle" class="fa fa-1x fa-angle-double-down"></span>
|
<vc:icon symbol="caret-down" />
|
||||||
</a>
|
</button>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="invoice_details_@invoice.InvoiceId" class="invoice-details-row" style="display:none;">
|
<tr id="@detailsId" class="invoice-details-row collapse">
|
||||||
<td colspan="99" class="border-top-0">
|
<td colspan="7" class="border-top-0">
|
||||||
@* Leaving this as partial because it abstracts complexity of Invoice Payments *@
|
@* Leaving this as partial because it abstracts complexity of Invoice Payments *@
|
||||||
<partial name="ListInvoicesPaymentsPartial" model="(invoice.Details, true)" />
|
<partial name="ListInvoicesPaymentsPartial" model="(invoice.Details, true)" />
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
<div class="d-flex align-items-center justify-content-between mb-2">
|
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||||
<a data-bs-toggle="collapse" data-bs-target="#AddAddress" class="btn btn-primary" role="button">
|
<a data-bs-toggle="collapse" data-bs-target="#AddAddress" class="btn btn-primary" role="button">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Add Address
|
Add Address
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||||
<a class="btn btn-primary" asp-action="AddApiKey" id="AddApiKey">
|
<a class="btn btn-primary" asp-action="AddApiKey" id="AddApiKey">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Generate Key
|
Generate Key
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -135,7 +135,6 @@
|
||||||
<input type="text" class="form-control" name="Name" placeholder="Security device name"/>
|
<input type="text" class="form-control" name="Name" placeholder="Security device name"/>
|
||||||
<select asp-items="@Html.GetEnumSelectList<Fido2Credential.CredentialType>()" class="form-select w-auto" name="type"></select>
|
<select asp-items="@Html.GetEnumSelectList<Fido2Credential.CredentialType>()" class="form-select w-auto" name="type"></select>
|
||||||
<button id="btn-add" type="submit" class="btn btn-primary">
|
<button id="btn-add" type="submit" class="btn btn-primary">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Add
|
Add
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
@inject SignInManager<ApplicationUser> SignInManager
|
@inject SignInManager<ApplicationUser> SignInManager
|
||||||
|
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header mb-l">
|
<div class="sticky-header mb-l">
|
||||||
<h2 class="mt-1 mb-2 mb-lg-4">Account Settings</h2>
|
<h2 class="mt-1 mb-2 mb-lg-4">Account Settings</h2>
|
||||||
<nav id="SectionNav">
|
<nav id="SectionNav">
|
||||||
|
|
|
@ -14,61 +14,75 @@
|
||||||
@if (Model.Items.Count > 0)
|
@if (Model.Items.Count > 0)
|
||||||
{
|
{
|
||||||
<form method="post" asp-action="MassAction">
|
<form method="post" asp-action="MassAction">
|
||||||
<div class="row button-row">
|
@if (Model.Items.Any())
|
||||||
<div class="col-lg-6">
|
{
|
||||||
<span class="dropdown" style="display:none;" id="MassAction">
|
<div class="table-responsive-md">
|
||||||
<button class="btn btn-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<table class="table table-hover mass-action">
|
||||||
Actions
|
<thead class="mass-action-head">
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu">
|
|
||||||
<button type="submit" class="dropdown-item" name="command" value="mark-seen"><i class="fa fa-eye"></i> Mark seen</button>
|
|
||||||
<button type="submit" class="dropdown-item" name="command" value="mark-unseen"><i class="fa fa-eye-slash"></i> Mark unseen</button>
|
|
||||||
<button type="submit" class="dropdown-item" name="command" value="delete"><i class="fa fa-trash-o"></i> Delete</button>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<table class="table table-hover table-responsive-md">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:30px" class="only-for-js">
|
<th class="mass-action-select-col only-for-js">
|
||||||
@if (Model.Items.Count > 0)
|
<input name="selectedItems" type="checkbox" class="form-check-input mass-action-select-all" />
|
||||||
{
|
|
||||||
<input name="selectedItems" id="selectAllCheckbox" type="checkbox" class="form-check-input" />
|
|
||||||
}
|
|
||||||
</th>
|
</th>
|
||||||
<th class="w-150px">
|
<th class="date-col">
|
||||||
<div class="d-flex align-items-center gap-1">
|
<div class="d-flex align-items-center gap-1">
|
||||||
Date
|
Date
|
||||||
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format" title="Switch date format"></button>
|
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format" title="Switch date format"></button>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th>Message</th>
|
<th>Message</th>
|
||||||
<th class="text-end">Actions</th>
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<thead class="mass-action-actions">
|
||||||
|
<tr>
|
||||||
|
<th class="mass-action-select-col only-for-js">
|
||||||
|
<input type="checkbox" class="form-check-input mass-action-select-all" />
|
||||||
|
</th>
|
||||||
|
<th colspan="6">
|
||||||
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
|
||||||
|
<div>
|
||||||
|
<strong class="mass-action-selected-count">0</strong>
|
||||||
|
selected
|
||||||
|
</div>
|
||||||
|
<div class="d-inline-flex align-items-center gap-3">
|
||||||
|
<button type="submit" name="command" value="mark-seen" class="btn btn-link gap-1">
|
||||||
|
<i class="fa fa-eye"></i>
|
||||||
|
Mark seen
|
||||||
|
</button>
|
||||||
|
<button type="submit" name="command" value="mark-unseen" class="btn btn-link gap-1">
|
||||||
|
<i class="fa fa-eye-slash"></i>
|
||||||
|
Mark unseen
|
||||||
|
</button>
|
||||||
|
<button type="submit" name="command" value="delete" class="btn btn-link gap-1">
|
||||||
|
<i class="fa fa-trash-o"></i>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (var item in Model.Items)
|
@foreach (var item in Model.Items)
|
||||||
{
|
{
|
||||||
<tr data-guid="@item.Id" class="notification-row @(item.Seen ? "seen" : "")">
|
<tr data-guid="@item.Id" class="notification-row mass-action-row @(item.Seen ? "seen" : "")">
|
||||||
<td class="only-for-js">
|
<td class="only-for-js mass-action-select-col">
|
||||||
<input name="selectedItems" type="checkbox" class="selector form-check-input" value="@item.Id" />
|
<input name="selectedItems" type="checkbox" class="form-check-input mass-action-select" value="@item.Id" />
|
||||||
</td>
|
</td>
|
||||||
<td class="toggleRowCheckbox">@item.Created.ToBrowserDate()</td>
|
<td class="date-col">@item.Created.ToBrowserDate()</td>
|
||||||
<td class="toggleRowCheckbox">
|
<td>
|
||||||
@item.Body
|
@item.Body
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end fw-normal">
|
<td class="text-end">
|
||||||
@if (!String.IsNullOrEmpty(item.ActionLink))
|
<div class="d-inline-flex align-items-center gap-3">
|
||||||
{
|
<button class="btn btn-link p-0 btn-toggle-seen" type="submit" name="command" value="flip-individual:@(item.Id)">
|
||||||
<a href="@item.ActionLink" class="btn btn-link p-0" rel="noreferrer noopener">Details</a>
|
<span>Mark</span> <span class="seen-text"></span>
|
||||||
<span class="d-none d-md-inline-block"> - </span>
|
</button>
|
||||||
}
|
@if (!string.IsNullOrEmpty(item.ActionLink))
|
||||||
<button class="btn btn-link p-0 btn-toggle-seen" type="submit" name="command" value="flip-individual:@(item.Id)">
|
{
|
||||||
<span>Mark </span><span class="seen-text"></span>
|
<a href="@item.ActionLink" class="btn btn-link p-0" rel="noreferrer noopener">Details</a>
|
||||||
</button>
|
}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
@ -76,9 +90,8 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<vc:pager view-model="Model" />
|
<vc:pager view-model="Model" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -113,19 +126,6 @@ else
|
||||||
|
|
||||||
@section PageFootContent {
|
@section PageFootContent {
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
delegate('click', '#selectAllCheckbox', e => {
|
|
||||||
document.querySelectorAll('.notification-row .selector').forEach(checkbox => {
|
|
||||||
checkbox.checked = e.target.checked;
|
|
||||||
});
|
|
||||||
updateSelectors();
|
|
||||||
});
|
|
||||||
|
|
||||||
delegate('click', '.toggleRowCheckbox', e => {
|
|
||||||
const input = $(e.target).parents(".notification-row").find(".selector");
|
|
||||||
input.prop('checked', !input.prop("checked"));
|
|
||||||
updateSelectors();
|
|
||||||
})
|
|
||||||
|
|
||||||
delegate('click', '.btn-toggle-seen', e => {
|
delegate('click', '.btn-toggle-seen', e => {
|
||||||
const row = $(e.target).parents(".notification-row").toggleClass("loading");
|
const row = $(e.target).parents(".notification-row").toggleClass("loading");
|
||||||
const guid = row.data("guid");
|
const guid = row.data("guid");
|
||||||
|
@ -135,20 +135,5 @@ else
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
$(".selector").change(updateSelectors);
|
|
||||||
updateSelectors();
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateSelectors() {
|
|
||||||
var count = $(".selector:checked").length;
|
|
||||||
if (count > 0) {
|
|
||||||
$("#MassAction").children().eq(0).text("Batch Action (" + count + ")");
|
|
||||||
$("#MassAction").show();
|
|
||||||
} else {
|
|
||||||
$("#MassAction").hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<form method="post" action="@Url.Action("EditPaymentRequest", "UIPaymentRequest", new { storeId = Model.StoreId, payReqId = Model.Id }, Context.Request.Scheme)">
|
<form method="post" action="@Url.Action("EditPaymentRequest", "UIPaymentRequest", new { storeId = Model.StoreId, payReqId = Model.Id }, Context.Request.Scheme)">
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||||
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
Model.Search.ContainsFilter(key) && Model.Search.GetFilterBool(key) is true;
|
Model.Search.ContainsFilter(key) && Model.Search.GetFilterBool(key) is true;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">
|
<h2 class="mb-0">
|
||||||
@ViewData["Title"]
|
@ViewData["Title"]
|
||||||
|
@ -50,7 +49,7 @@
|
||||||
|
|
||||||
<partial name="_StatusMessage" />
|
<partial name="_StatusMessage" />
|
||||||
|
|
||||||
<form asp-action="GetPaymentRequests" method="get" class="d-flex flex-wrap flex-sm-nowrap align-items-center gap-3 mb-4 col-lg-9 col-xl-8 col-xxl-6">
|
<form asp-action="GetPaymentRequests" method="get" class="d-flex flex-wrap flex-sm-nowrap align-items-center gap-3 mb-4 col-xxl-8">
|
||||||
<input type="hidden" asp-for="Count" />
|
<input type="hidden" asp-for="Count" />
|
||||||
<input type="hidden" asp-for="TimezoneOffset" />
|
<input type="hidden" asp-for="TimezoneOffset" />
|
||||||
<input asp-for="SearchTerm" type="hidden" value="@Model.Search.WithoutSearchText()"/>
|
<input asp-for="SearchTerm" type="hidden" value="@Model.Search.WithoutSearchText()"/>
|
||||||
|
@ -78,57 +77,59 @@
|
||||||
|
|
||||||
@if (Model.Items.Any())
|
@if (Model.Items.Any())
|
||||||
{
|
{
|
||||||
<table class="table table-hover table-responsive-md" id="tableId">
|
<div class="table-responsive-md">
|
||||||
<thead>
|
<table class="table table-hover">
|
||||||
<tr>
|
<thead>
|
||||||
<th>Title</th>
|
|
||||||
<th class="w-150px">
|
|
||||||
<div class="d-flex align-items-center gap-1">
|
|
||||||
Expiry
|
|
||||||
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format only-for-js" title="Switch date format"></button>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th>Price</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th class="text-end">Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach (var item in Model.Items)
|
|
||||||
{
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<th>Title</th>
|
||||||
<a asp-action="ViewPaymentRequest" asp-route-payReqId="@item.Id" id="PaymentRequest-@item.Id">@item.Title</a>
|
<th class="date-col">
|
||||||
</td>
|
<div class="d-flex align-items-center gap-1">
|
||||||
<td>
|
Expiry
|
||||||
@(item.ExpiryDate?.ToBrowserDate() ?? new HtmlString("<span class=\"text-muted\">No Expiry</span>"))
|
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format only-for-js" title="Switch date format"></button>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span data-sensitive>@item.AmountFormatted</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span class="badge badge-@item.Status.ToLower() status-badge">@item.Status</span>
|
|
||||||
</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<div class="d-inline-flex align-items-center gap-3">
|
|
||||||
<a asp-action="EditPaymentRequest" asp-route-storeId="@item.StoreId" asp-route-payReqId="@item.Id" id="Edit-@item.Id">Edit</a>
|
|
||||||
<div class="dropdown">
|
|
||||||
<button class="btn btn-link dropdown-toggle p-0 dropdown-toggle-no-caret" type="button" data-bs-toggle="dropdown" aria-expanded="false" id="ToggleActions-@item.Id">
|
|
||||||
<i class="fa fa-ellipsis-h"></i>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="actionDropdown">
|
|
||||||
<li><a class="dropdown-item" asp-controller="UIInvoice" asp-action="ListInvoices" asp-route-storeId="@item.StoreId" asp-route-searchterm="@($"orderid:{PaymentRequestRepository.GetOrderIdForPaymentRequest(item.Id)}")">Invoices</a></li>
|
|
||||||
<li><a class="dropdown-item" asp-action="ClonePaymentRequest" asp-route-storeId="@item.StoreId" asp-route-payReqId="@item.Id" id="Clone-@item.Id">Clone</a></li>
|
|
||||||
<li class="dropdown-divider"></li>
|
|
||||||
<li><a class="dropdown-item" asp-action="TogglePaymentRequestArchival" asp-route-storeId="@item.StoreId" asp-route-payReqId="@item.Id" id="ToggleArchival-@item.Id">@(item.Archived ? "Unarchive" : "Archive")</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th class="amount-col">Amount</th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
@foreach (var item in Model.Items)
|
||||||
|
{
|
||||||
|
<tr class="mass-action-row">
|
||||||
|
<td>
|
||||||
|
<a asp-action="EditPaymentRequest" asp-route-storeId="@item.StoreId" asp-route-payReqId="@item.Id" id="Edit-@item.Id">@item.Title</a>
|
||||||
|
</td>
|
||||||
|
<td class="date-col">
|
||||||
|
@(item.ExpiryDate?.ToBrowserDate() ?? new HtmlString("<span class=\"text-muted\">No Expiry</span>"))
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge badge-@item.Status.ToLower() status-badge">@item.Status</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<span data-sensitive>@item.AmountFormatted</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<div class="d-inline-flex align-items-center gap-3">
|
||||||
|
<a asp-action="ViewPaymentRequest" asp-route-payReqId="@item.Id" id="PaymentRequest-@item.Id">View</a>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-link dropdown-toggle p-0 dropdown-toggle-no-caret text-body" type="button" data-bs-toggle="dropdown" aria-expanded="false" id="ToggleActions-@item.Id">
|
||||||
|
<vc:icon symbol="dots" />
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="actionDropdown">
|
||||||
|
<li><a class="dropdown-item" asp-controller="UIInvoice" asp-action="ListInvoices" asp-route-storeId="@item.StoreId" asp-route-searchterm="@($"orderid:{PaymentRequestRepository.GetOrderIdForPaymentRequest(item.Id)}")">Invoices</a></li>
|
||||||
|
<li><a class="dropdown-item" asp-action="ClonePaymentRequest" asp-route-storeId="@item.StoreId" asp-route-payReqId="@item.Id" id="Clone-@item.Id">Clone</a></li>
|
||||||
|
<li class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" asp-action="TogglePaymentRequestArchival" asp-route-storeId="@item.StoreId" asp-route-payReqId="@item.Id" id="ToggleArchival-@item.Id">@(item.Archived ? "Unarchive" : "Archive")</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<vc:pager view-model="Model" />
|
<vc:pager view-model="Model" />
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<form method="post" asp-action="EditPullPayment" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-pullPaymentId="@Model.Id">
|
<form method="post" asp-action="EditPullPayment" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-pullPaymentId="@Model.Id">
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||||
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||||
|
|
|
@ -20,8 +20,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header">
|
<div class="sticky-header">
|
||||||
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3 mb-3">
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
|
||||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
<h2 class="mb-0">
|
||||||
|
@ViewData["Title"]
|
||||||
|
<a href="https://docs.btcpayserver.org/Accounting/" target="_blank" rel="noreferrer noopener" title="More information...">
|
||||||
|
<vc:icon symbol="info" />
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
<div class="d-flex flex-wrap gap-3">
|
<div class="d-flex flex-wrap gap-3">
|
||||||
<a cheat-mode="true" class="btn btn-outline-info text-nowrap" asp-action="StoreReports" asp-route-fakeData="true" asp-route-viewName="@Model.Request?.ViewName">Create fake date</a>
|
<a cheat-mode="true" class="btn btn-outline-info text-nowrap" asp-action="StoreReports" asp-route-fakeData="true" asp-route-viewName="@Model.Request?.ViewName">Create fake date</a>
|
||||||
<button id="exportCSV" class="btn btn-primary text-nowrap" type="button">
|
<button id="exportCSV" class="btn btn-primary text-nowrap" type="button">
|
||||||
|
@ -29,32 +34,32 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex flex-column flex-sm-row align-items-sm-0center gap-3">
|
</div>
|
||||||
<div class="dropdown" v-pre>
|
<div class="d-flex flex-column flex-sm-row align-items-center gap-3 mb-l">
|
||||||
<button id="ViewNameToggle" class="btn btn-secondary dropdown-toggle dropdown-toggle-custom-caret" type="button" data-bs-toggle="dropdown" aria-expanded="false">@Model.Request.ViewName</button>
|
<div class="dropdown" v-pre>
|
||||||
<div class="dropdown-menu" aria-labelledby="ViewNameToggle">
|
<button id="ViewNameToggle" class="btn btn-secondary dropdown-toggle dropdown-toggle-custom-caret" type="button" data-bs-toggle="dropdown" aria-expanded="false">@Model.Request.ViewName</button>
|
||||||
@foreach (var v in Model.AvailableViews)
|
<div class="dropdown-menu" aria-labelledby="ViewNameToggle">
|
||||||
{
|
@foreach (var v in Model.AvailableViews)
|
||||||
<a href="#" data-view="@v" class="available-view dropdown-item @(Model.Request.ViewName == v ? "custom-active" : "")">@v</a>
|
{
|
||||||
}
|
<a href="#" data-view="@v" class="available-view dropdown-item @(Model.Request.ViewName == v ? "custom-active" : "")">@v</a>
|
||||||
</div>
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
</div>
|
||||||
<input id="fromDate" class="form-control flatdtpicker" type="datetime-local"
|
<div class="input-group">
|
||||||
data-fdtp='{ "enableTime": true, "enableSeconds": true, "dateFormat": "Y-m-d H:i:S", "time_24hr": true, "defaultHour": 0 }'
|
<input id="fromDate" class="form-control flatdtpicker" type="datetime-local"
|
||||||
placeholder="Start Date" />
|
data-fdtp='{ "enableTime": true, "enableSeconds": true, "dateFormat": "Y-m-d H:i:S", "time_24hr": true, "defaultHour": 0 }'
|
||||||
<button type="button" class="btn btn-primary input-group-clear" title="Clear">
|
placeholder="Start Date" />
|
||||||
<span class="fa fa-times"></span>
|
<button type="button" class="btn btn-primary input-group-clear" title="Clear">
|
||||||
</button>
|
<span class="fa fa-times"></span>
|
||||||
</div>
|
</button>
|
||||||
<div class="input-group">
|
</div>
|
||||||
<input id="toDate" class="form-control flatdtpicker" type="datetime-local"
|
<div class="input-group">
|
||||||
data-fdtp='{ "enableTime": true, "enableSeconds": true, "dateFormat": "Y-m-d H:i:S", "time_24hr": true, "defaultHour": 0 }'
|
<input id="toDate" class="form-control flatdtpicker" type="datetime-local"
|
||||||
placeholder="End Date" />
|
data-fdtp='{ "enableTime": true, "enableSeconds": true, "dateFormat": "Y-m-d H:i:S", "time_24hr": true, "defaultHour": 0 }'
|
||||||
<button type="button" class="btn btn-primary input-group-clear" title="Clear">
|
placeholder="End Date" />
|
||||||
<span class="fa fa-times"></span>
|
<button type="button" class="btn btn-primary input-group-clear" title="Clear">
|
||||||
</button>
|
<span class="fa fa-times"></span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -63,7 +68,7 @@
|
||||||
<h3>{{ chart.name }}</h3>
|
<h3>{{ chart.name }}</h3>
|
||||||
<div class="table-responsive" v-if="chart.rows.length || chart.hasGrandTotal">
|
<div class="table-responsive" v-if="chart.rows.length || chart.hasGrandTotal">
|
||||||
<table class="table table-hover w-auto">
|
<table class="table table-hover w-auto">
|
||||||
<thead class="sticky-top bg-body">
|
<thead class="bg-body">
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="group in chart.groups">{{ titleCase(group) }}</th>
|
<th v-for="group in chart.groups">{{ titleCase(group) }}</th>
|
||||||
<th v-for="agg in chart.aggregates" class="text-end">{{ titleCase(agg) }}</th>
|
<th v-for="agg in chart.aggregates" class="text-end">{{ titleCase(agg) }}</th>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</small>
|
</small>
|
||||||
</h3>
|
</h3>
|
||||||
<form method="post" asp-action="DynamicDnsService">
|
<form method="post" asp-action="DynamicDnsService">
|
||||||
<button id="AddDynamicDNS" class="btn btn-primary mt-2" type="submit"><span class="fa fa-plus"></span> Add service</button>
|
<button id="AddDynamicDNS" class="btn btn-primary mt-2" type="submit">Add service</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||||
<a asp-action="CreateUser" class="btn btn-primary" role="button" id="CreateUser">
|
<a asp-action="CreateUser" class="btn btn-primary" role="button" id="CreateUser">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Add User
|
Add User
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -154,7 +154,6 @@
|
||||||
<h5 class="d-flex align-items-center justify-content-between mt-5 gap-3">
|
<h5 class="d-flex align-items-center justify-content-between mt-5 gap-3">
|
||||||
Domain to app mapping
|
Domain to app mapping
|
||||||
<button id="AddDomainButton" type="submit" name="command" value="add-domain" class="d-inline-block btn text-primary btn-link p-0">
|
<button id="AddDomainButton" type="submit" name="command" value="add-domain" class="d-inline-block btn text-primary btn-link p-0">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Add domain mapping
|
Add domain mapping
|
||||||
</button>
|
</button>
|
||||||
</h5>
|
</h5>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
@using BTCPayServer.Configuration
|
@using BTCPayServer.Configuration
|
||||||
@inject BTCPayServerOptions _btcPayServerOptions
|
@inject BTCPayServerOptions _btcPayServerOptions
|
||||||
|
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header mb-l">
|
<div class="sticky-header mb-l">
|
||||||
<h2 class="mt-1 mb-2 mb-lg-4">Server Settings</h2>
|
<h2 class="mt-1 mb-2 mb-lg-4">Server Settings</h2>
|
||||||
<nav id="SectionNav">
|
<nav id="SectionNav">
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<form method="post" asp-route-walletId="@Context.GetRouteValue("walletId")" asp-action="NewPullPayment">
|
<form method="post" asp-route-walletId="@Context.GetRouteValue("walletId")" asp-action="NewPullPayment">
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-flex align-items-center justify-content-between">
|
<div class="sticky-header d-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||||
<input type="submit" value="Create" class="btn btn-primary" id="Create"/>
|
<input type="submit" value="Create" class="btn btn-primary" id="Create"/>
|
||||||
|
|
|
@ -27,14 +27,14 @@
|
||||||
switch (Model.PayoutState)
|
switch (Model.PayoutState)
|
||||||
{
|
{
|
||||||
case PayoutState.AwaitingApproval:
|
case PayoutState.AwaitingApproval:
|
||||||
stateActions.Add(("approve", "Approve selected payouts"));
|
stateActions.Add(("approve", "Approve"));
|
||||||
stateActions.Add(("approve-pay", "Approve & Send selected payouts"));
|
stateActions.Add(("approve-pay", "Approve & Send"));
|
||||||
stateActions.Add(("cancel", "Cancel selected payouts"));
|
stateActions.Add(("cancel", "Cancel"));
|
||||||
break;
|
break;
|
||||||
case PayoutState.AwaitingPayment:
|
case PayoutState.AwaitingPayment:
|
||||||
stateActions.Add(("pay", "Send selected payouts"));
|
stateActions.Add(("pay", "Send"));
|
||||||
stateActions.Add(("cancel", "Cancel selected payouts"));
|
stateActions.Add(("cancel", "Cancel"));
|
||||||
stateActions.Add(("mark-paid", "Mark selected payouts as already paid"));
|
stateActions.Add(("mark-paid", "Mark as already paid"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,6 @@
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-flex align-items-center justify-content-between">
|
<div class="sticky-header d-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">
|
<h2 class="mb-0">
|
||||||
@ViewData["Title"]
|
@ViewData["Title"]
|
||||||
|
@ -125,20 +124,7 @@
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
@if (Model.Payouts.Any() && stateActions.Any())
|
|
||||||
{
|
|
||||||
<div class="dropdown ms-xl-auto mt-xl-0" permission="@Policies.CanModifyStoreSettings">
|
|
||||||
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" id="@Model.PayoutState-actions">Actions</button>
|
|
||||||
<div class="dropdown-menu" aria-labelledby="@Model.PayoutState-actions">
|
|
||||||
@foreach (var action in stateActions)
|
|
||||||
{
|
|
||||||
<button type="submit" id="@Model.PayoutState-@action.Action" name="Command" class="dropdown-item" role="button" value="@Model.PayoutState-@action.Action">@action.Text</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav id="SectionNav" class="mb-3">
|
<nav id="SectionNav" class="mb-3">
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
@foreach (var state in Model.PayoutStateCount)
|
@foreach (var state in Model.PayoutStateCount)
|
||||||
|
@ -159,41 +145,71 @@
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@if (Model.Payouts.Any())
|
@if (Model.Payouts.Any())
|
||||||
{
|
{
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover">
|
<table class="table table-hover mass-action">
|
||||||
<thead>
|
<thead class="mass-action-head">
|
||||||
<tr>
|
<tr>
|
||||||
<th permission="@Policies.CanModifyStoreSettings">
|
@if (stateActions.Any())
|
||||||
<input id="@Model.PayoutState-selectAllCheckbox" type="checkbox" class="form-check-input selectAll" data-payout-state="@Model.PayoutState.ToString()" />
|
{
|
||||||
|
<th class="only-for-js mass-action-select-col" permission="@Policies.CanModifyStoreSettings">
|
||||||
|
<input type="checkbox" class="form-check-input mass-action-select-all" data-payout-state="@Model.PayoutState.ToString()" />
|
||||||
|
</th>
|
||||||
|
}
|
||||||
|
<th class="date-col">
|
||||||
|
<div class="d-flex align-items-center gap-1">
|
||||||
|
Date
|
||||||
|
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format only-for-js" title="Switch date format"></button>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th style="min-width: 90px;" class="col-md-auto">
|
<th>Source</th>
|
||||||
Date
|
<th>Destination</th>
|
||||||
</th>
|
<th class="amount-col">Amount</th>
|
||||||
<th class="text-start">Source</th>
|
|
||||||
<th class="text-start">Destination</th>
|
|
||||||
<th class="text-end">Amount</th>
|
|
||||||
@if (Model.PayoutState != PayoutState.AwaitingApproval)
|
@if (Model.PayoutState != PayoutState.AwaitingApproval)
|
||||||
{
|
{
|
||||||
<th class="text-end">Transaction</th>
|
<th class="text-end">Transaction</th>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@if (stateActions.Any())
|
||||||
|
{
|
||||||
|
<thead class="mass-action-actions" permission="@Policies.CanModifyStoreSettings">
|
||||||
|
<tr>
|
||||||
|
<th class="mass-action-select-col only-for-js">
|
||||||
|
<input type="checkbox" class="form-check-input mass-action-select-all" />
|
||||||
|
</th>
|
||||||
|
<th colspan="5">
|
||||||
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
|
||||||
|
<div>
|
||||||
|
<strong class="mass-action-selected-count">0</strong>
|
||||||
|
selected
|
||||||
|
</div>
|
||||||
|
<div class="d-inline-flex align-items-center gap-3">
|
||||||
|
@foreach (var action in stateActions)
|
||||||
|
{
|
||||||
|
<button type="submit" id="@Model.PayoutState-@action.Action" name="Command" class="btn btn-link" value="@Model.PayoutState-@action.Action">@action.Text</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
}
|
||||||
<tbody>
|
<tbody>
|
||||||
@for (int i = 0; i < Model.Payouts.Count; i++)
|
@for (var i = 0; i < Model.Payouts.Count; i++)
|
||||||
{
|
{
|
||||||
var pp = Model.Payouts[i];
|
var pp = Model.Payouts[i];
|
||||||
<tr class="payout">
|
<tr class="payout mass-action-row">
|
||||||
<td permission="@Policies.CanModifyStoreSettings">
|
@if (stateActions.Any())
|
||||||
<span>
|
{
|
||||||
<input type="checkbox" class="selection-item-@Model.PayoutState.ToString() form-check-input" asp-for="Payouts[i].Selected" />
|
<td class="only-for-js mass-action-select-col" permission="@Policies.CanModifyStoreSettings">
|
||||||
|
<input type="checkbox" class="selection-item-@Model.PayoutState.ToString() form-check-input mass-action-select" asp-for="Payouts[i].Selected" />
|
||||||
<input type="hidden" asp-for="Payouts[i].PayoutId" />
|
<input type="hidden" asp-for="Payouts[i].PayoutId" />
|
||||||
</span>
|
</td>
|
||||||
</td>
|
}
|
||||||
<td>
|
<td class="date-col">
|
||||||
<span>@pp.Date.ToBrowserDate()</span>
|
@pp.Date.ToBrowserDate()
|
||||||
</td>
|
</td>
|
||||||
<td class="mw-100">
|
<td class="mw-100">
|
||||||
@if (pp.SourceLink is not null && pp.Source is not null)
|
@if (pp.SourceLink is not null && pp.Source is not null)
|
||||||
|
@ -208,7 +224,7 @@
|
||||||
<td title="@pp.Destination">
|
<td title="@pp.Destination">
|
||||||
<span class="text-break">@pp.Destination</span>
|
<span class="text-break">@pp.Destination</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end text-nowrap">
|
<td class="amount-col">
|
||||||
<span data-sensitive>@pp.Amount</span>
|
<span data-sensitive>@pp.Amount</span>
|
||||||
</td>
|
</td>
|
||||||
@if (Model.PayoutState != PayoutState.AwaitingApproval)
|
@if (Model.PayoutState != PayoutState.AwaitingApproval)
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
</style>
|
</style>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header d-flex align-items-center justify-content-between">
|
<div class="sticky-header d-flex align-items-center justify-content-between">
|
||||||
<h2 class="mb-0">
|
<h2 class="mb-0">
|
||||||
@ViewData["Title"]
|
@ViewData["Title"]
|
||||||
|
@ -47,7 +46,7 @@
|
||||||
</a>
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
<a permission="@Policies.CanCreateNonApprovedPullPayments" asp-action="NewPullPayment" asp-route-storeId="@storeId" class="btn btn-primary" role="button" id="NewPullPayment">
|
<a permission="@Policies.CanCreateNonApprovedPullPayments" asp-action="NewPullPayment" asp-route-storeId="@storeId" class="btn btn-primary" role="button" id="NewPullPayment">
|
||||||
<span class="fa fa-plus"></span> Create Pull Payment
|
Create Pull Payment
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -104,27 +103,30 @@
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">
|
<th scope="col" class="date-col">
|
||||||
<a asp-action="PullPayments"
|
<div class="d-flex align-items-center gap-2">
|
||||||
asp-route-sortOrder="@(nextStartDateSortOrder ?? "asc")"
|
<a asp-action="PullPayments"
|
||||||
asp-route-pullPaymentState="@Model.ActiveState"
|
asp-route-sortOrder="@(nextStartDateSortOrder ?? "asc")"
|
||||||
class="text-nowrap"
|
asp-route-pullPaymentState="@Model.ActiveState"
|
||||||
title="@(nextStartDateSortOrder == "desc" ? sortByAsc : sortByDesc)">
|
class="text-nowrap"
|
||||||
Start
|
title="@(nextStartDateSortOrder == "desc" ? sortByAsc : sortByDesc)">
|
||||||
<span class="fa @(sortIconClass)"></span>
|
Start
|
||||||
</a>
|
<span class="fa @(sortIconClass)"></span>
|
||||||
|
</a>
|
||||||
|
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format only-for-js" title="Switch date format"></button>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">Name</th>
|
<th scope="col">Name</th>
|
||||||
<th scope="col">Automatically Approved</th>
|
<th scope="col">Automatically Approved</th>
|
||||||
<th scope="col">Refunded</th>
|
<th scope="col">Refunded</th>
|
||||||
<th scope="col" class="text-end">Actions</th>
|
<th scope="col"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (var pp in Model.PullPayments)
|
@foreach (var pp in Model.PullPayments)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr class="mass-action-row">
|
||||||
<td>@pp.StartDate.ToBrowserDate()</td>
|
<td class="date-col">@pp.StartDate.ToBrowserDate()</td>
|
||||||
<td>
|
<td>
|
||||||
<a asp-action="EditPullPayment"
|
<a asp-action="EditPullPayment"
|
||||||
asp-controller="UIPullPayment"
|
asp-controller="UIPullPayment"
|
||||||
|
@ -145,31 +147,31 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<a class="pp-payout"
|
<div class="d-inline-flex align-items-center gap-3">
|
||||||
asp-action="Payouts"
|
<a asp-action="ViewPullPayment"
|
||||||
asp-route-storeId="@storeId"
|
asp-controller="UIPullPayment"
|
||||||
asp-route-pullPaymentId="@pp.Id">
|
asp-route-pullPaymentId="@pp.Id">
|
||||||
Payouts
|
View
|
||||||
</a>
|
|
||||||
@if (!pp.Archived)
|
|
||||||
{
|
|
||||||
<span permission="@Policies.CanArchivePullPayments"> - </span>
|
|
||||||
<a asp-action="ArchivePullPayment"
|
|
||||||
permission="@Policies.CanArchivePullPayments"
|
|
||||||
asp-route-storeId="@storeId"
|
|
||||||
asp-route-pullPaymentId="@pp.Id"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#ConfirmModal"
|
|
||||||
data-description="Do you really want to archive the pull payment <strong>@Html.Encode(pp.Name)</strong>?">
|
|
||||||
Archive
|
|
||||||
</a>
|
</a>
|
||||||
}
|
<a class="pp-payout"
|
||||||
<span> - </span>
|
asp-action="Payouts"
|
||||||
<a asp-action="ViewPullPayment"
|
asp-route-storeId="@storeId"
|
||||||
asp-controller="UIPullPayment"
|
asp-route-pullPaymentId="@pp.Id">
|
||||||
asp-route-pullPaymentId="@pp.Id">
|
Payouts
|
||||||
View
|
</a>
|
||||||
</a>
|
@if (!pp.Archived)
|
||||||
|
{
|
||||||
|
<a asp-action="ArchivePullPayment"
|
||||||
|
permission="@Policies.CanArchivePullPayments"
|
||||||
|
asp-route-storeId="@storeId"
|
||||||
|
asp-route-pullPaymentId="@pp.Id"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#ConfirmModal"
|
||||||
|
data-description="Do you really want to archive the pull payment <strong>@Html.Encode(pp.Name)</strong>?">
|
||||||
|
Archive
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||||
<a id="CreateNewToken" asp-action="CreateToken" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")">
|
<a id="CreateNewToken" asp-action="CreateToken" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Create Token
|
Create Token
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
<button class="btn btn-primary" name="command" type="submit" value="add" id="CreateEmailRule">
|
<button class="btn btn-primary" name="command" type="submit" value="add" id="CreateEmailRule">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Create
|
Create
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-3">
|
<div class="ms-3">
|
||||||
<button type="submit" role="button" class="btn btn-primary"><span class="fa fa-plus"></span> Add User</button>
|
<button type="submit" role="button" class="btn btn-primary">Add User</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||||
<a id="CreateWebhook" asp-action="NewWebhook" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")">
|
<a id="CreateWebhook" asp-action="NewWebhook" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")">
|
||||||
<span class="fa fa-plus"></span>
|
|
||||||
Create Webhook
|
Create Webhook
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
var storeId = Context.GetStoreData()?.Id;
|
var storeId = Context.GetStoreData()?.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header mb-l">
|
<div class="sticky-header mb-l">
|
||||||
<h2 class="mt-1 mb-2 mb-lg-4">Store Settings</h2>
|
<h2 class="mt-1 mb-2 mb-lg-4">Store Settings</h2>
|
||||||
<nav id="SectionNav">
|
<nav id="SectionNav">
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
@using BTCPayServer.Client
|
||||||
|
@using BTCPayServer.Components
|
||||||
@model ListTransactionsViewModel
|
@model ListTransactionsViewModel
|
||||||
|
|
||||||
@{
|
@{
|
||||||
|
@ -55,12 +57,6 @@
|
||||||
const $dropdowns = document.getElementById('Dropdowns');
|
const $dropdowns = document.getElementById('Dropdowns');
|
||||||
const $indicator = document.getElementById('LoadingIndicator');
|
const $indicator = document.getElementById('LoadingIndicator');
|
||||||
|
|
||||||
delegate('click', '#selectAllCheckbox', e => {
|
|
||||||
document.querySelectorAll(".selector").forEach(checkbox => {
|
|
||||||
checkbox.checked = e.target.checked;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
delegate('click', '#GoToTop', () => {
|
delegate('click', '#GoToTop', () => {
|
||||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
});
|
});
|
||||||
|
@ -108,7 +104,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$indicator.classList.add('d-none');
|
$indicator.classList.add('d-none');
|
||||||
formatDateTimes(document.getElementById('switchTimeFormat').dataset.mode);
|
formatDateTimes(document.querySelector('#WalletTransactions .switch-time-format').dataset.mode);
|
||||||
initLabelManagers();
|
initLabelManagers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,16 +140,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="d-inline-flex align-items-center gap-3" id="Dropdowns">
|
<div class="d-inline-flex align-items-center gap-3" id="Dropdowns">
|
||||||
<div class="dropdown ms-auto" id="Actions">
|
|
||||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="ActionsDropdownToggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
Actions
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="ActionsDropdownToggle">
|
|
||||||
<form id="WalletActions" method="post" asp-action="WalletActions" asp-route-walletId="@walletId">
|
|
||||||
<button id="BumpFee" name="command" type="submit" class="dropdown-item" value="cpfp">Bump fee (CPFP)</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown d-inline-flex align-items-center gap-3" id="Export">
|
<div class="dropdown d-inline-flex align-items-center gap-3" id="Export">
|
||||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="ExportDropdownToggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button class="btn btn-secondary dropdown-toggle" type="button" id="ExportDropdownToggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
Export
|
Export
|
||||||
|
@ -168,23 +154,44 @@
|
||||||
<div style="clear:both"></div>
|
<div style="clear:both"></div>
|
||||||
|
|
||||||
<div id="WalletTransactions" class="table-responsive-md">
|
<div id="WalletTransactions" class="table-responsive-md">
|
||||||
<table class="table table-hover">
|
<table class="table table-hover mass-action">
|
||||||
<thead>
|
<thead class="mass-action-head">
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:2rem;" class="only-for-js">
|
<th class="only-for-js mass-action-select-col">
|
||||||
<input id="selectAllCheckbox" type="checkbox" class="form-check-input" />
|
<input type="checkbox" class="form-check-input mass-action-select-all" />
|
||||||
</th>
|
</th>
|
||||||
<th class="w-150px">
|
<th class="date-col">
|
||||||
<div class="d-flex align-items-center gap-1">
|
<div class="d-flex align-items-center gap-1">
|
||||||
Date
|
Date
|
||||||
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format" title="Switch date format" id="switchTimeFormat"></button>
|
<button type="button" class="btn btn-link p-0 fa fa-clock-o switch-time-format only-for-js" title="Switch date format"></button>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th class="text-start">Label</th>
|
<th class="text-start">Label</th>
|
||||||
<th>Transaction Id</th>
|
<th>Transaction Id</th>
|
||||||
<th class="text-end">Amount</th>
|
<th class="amount-col">Amount</th>
|
||||||
<th class="text-end" style="min-width:60px"></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<thead class="mass-action-actions">
|
||||||
|
<tr>
|
||||||
|
<th class="only-for-js mass-action-select-col">
|
||||||
|
<input type="checkbox" class="form-check-input mass-action-select-all" />
|
||||||
|
</th>
|
||||||
|
<th colspan="5">
|
||||||
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
|
||||||
|
<div>
|
||||||
|
<strong class="mass-action-selected-count">0</strong>
|
||||||
|
selected
|
||||||
|
</div>
|
||||||
|
<form id="WalletActions" method="post" asp-action="WalletActions" asp-route-walletId="@walletId" permission="@Policies.CanModifyStoreSettings" class="d-inline-flex align-items-center gap-3">
|
||||||
|
<button id="BumpFee" name="command" type="submit" value="cpfp" class="btn btn-link">
|
||||||
|
<vc:icon symbol="send" />
|
||||||
|
Bump fee
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="WalletTransactionsList">
|
<tbody id="WalletTransactionsList">
|
||||||
<partial name="_WalletTransactionsList" model="Model" />
|
<partial name="_WalletTransactionsList" model="Model" />
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
var wallet = walletId != null ? WalletId.Parse(walletId) : new WalletId(storeId, cryptoCode);
|
var wallet = walletId != null ? WalletId.Parse(walletId) : new WalletId(storeId, cryptoCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="sticky-header-setup"></div>
|
|
||||||
<div class="sticky-header">
|
<div class="sticky-header">
|
||||||
<vc:wallet-nav wallet-id="wallet"/>
|
<vc:wallet-nav wallet-id="wallet"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
@using BTCPayServer.Services
|
@using BTCPayServer.Services
|
||||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
|
||||||
@using BTCPayServer.Components.LabelManager
|
@using BTCPayServer.Components.LabelManager
|
||||||
@model ListTransactionsViewModel
|
@model ListTransactionsViewModel
|
||||||
@{
|
@{
|
||||||
|
@ -7,11 +6,11 @@
|
||||||
}
|
}
|
||||||
@foreach (var transaction in Model.Transactions)
|
@foreach (var transaction in Model.Transactions)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr class="mass-action-row">
|
||||||
<td class="only-for-js">
|
<td class="only-for-js mass-action-select-col">
|
||||||
<input name="selectedTransactions" type="checkbox" class="selector form-check-input" form="WalletActions" value="@transaction.Id" />
|
<input name="selectedTransactions" type="checkbox" class="form-check-input mass-action-select" form="WalletActions" value="@transaction.Id" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="date-col">
|
||||||
@transaction.Timestamp.ToBrowserDate()
|
@transaction.Timestamp.ToBrowserDate()
|
||||||
</td>
|
</td>
|
||||||
<td class="text-start">
|
<td class="text-start">
|
||||||
|
@ -27,18 +26,9 @@
|
||||||
@transaction.Id
|
@transaction.Id
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@if (transaction.Positive)
|
<td class="amount-col">
|
||||||
{
|
<span data-sensitive class="text-@(transaction.Positive ? "success" : "danger")">@transaction.Balance</span>
|
||||||
<td class="text-end text-success">
|
</td>
|
||||||
<span data-sensitive>@transaction.Balance</span>
|
|
||||||
</td>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<td class="text-end text-danger">
|
|
||||||
<span data-sensitive>@transaction.Balance</span>
|
|
||||||
</td>
|
|
||||||
}
|
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<div class="dropstart d-inline-block">
|
<div class="dropstart d-inline-block">
|
||||||
@if (string.IsNullOrEmpty(transaction.Comment))
|
@if (string.IsNullOrEmpty(transaction.Comment))
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
--mobile-header-height: 4rem;
|
--mobile-header-height: 4rem;
|
||||||
--desktop-header-height: 8rem;
|
--desktop-header-height: 8rem;
|
||||||
--sidebar-width: 280px;
|
--sidebar-width: 280px;
|
||||||
|
--sticky-header-height: 0; /* gets dynamically set via JavaScript */
|
||||||
|
|
||||||
|
scroll-padding-top: calc(var(--sticky-header-height) + var(--btcpay-space-m));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main Menu */
|
/* Main Menu */
|
||||||
|
|
|
@ -154,11 +154,7 @@ h2 svg.icon.icon-info {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
@media (min-width: 1400px) {
|
|
||||||
#MassAction {
|
|
||||||
margin-top: -4rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Prevent layout from breaking on hyperlinks with very long URLs as the visible text */
|
/* Prevent layout from breaking on hyperlinks with very long URLs as the visible text */
|
||||||
.invoice-details a {
|
.invoice-details a {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
@ -1060,3 +1056,90 @@ input.ts-wrapper.form-control:not(.ts-hidden-accessible,.ts-inline) {
|
||||||
height: .75rem;
|
height: .75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
.date-col {
|
||||||
|
min-width: 8rem;
|
||||||
|
}
|
||||||
|
.amount-col {
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mass Actions */
|
||||||
|
.mass-action-head,
|
||||||
|
.mass-action-actions {
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
top: var(--sticky-header-height);
|
||||||
|
z-index: 10;
|
||||||
|
background-color: var(--btcpay-body-bg);
|
||||||
|
}
|
||||||
|
.mass-action thead th::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -1px;
|
||||||
|
left: -1px;
|
||||||
|
right: -1px;
|
||||||
|
bottom: 0;
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
border-color: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.mass-action > .mass-action-actions,
|
||||||
|
.mass-action[data-selected] > .mass-action-head {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.mass-action[data-selected] > .mass-action-actions {
|
||||||
|
display: table-header-group;
|
||||||
|
border-top-width: 0;
|
||||||
|
}
|
||||||
|
.mass-action > .mass-action-actions button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 1.4rem;
|
||||||
|
padding: 0;
|
||||||
|
font-weight: var(--btcpay-font-weight-semibold);
|
||||||
|
}
|
||||||
|
.mass-action > .mass-action-actions button .icon {
|
||||||
|
--btn-icon-size: 1.75rem;
|
||||||
|
}
|
||||||
|
.mass-action .mass-action-select-col {
|
||||||
|
width: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Responsive table adjustments: Reset sticky header height,
|
||||||
|
because it doesn't work in containers with overflow auto.
|
||||||
|
*/
|
||||||
|
.table-responsive{
|
||||||
|
--sticky-header-height: 0;
|
||||||
|
}
|
||||||
|
@media (max-width: 575.98px) {
|
||||||
|
.table-responsive-sm {
|
||||||
|
--sticky-header-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.table-responsive-md {
|
||||||
|
--sticky-header-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.table-responsive-lg {
|
||||||
|
--sticky-header-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1199.98px) {
|
||||||
|
.table-responsive-xl {
|
||||||
|
--sticky-header-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1399.98px) {
|
||||||
|
.table-responsive-xxl {
|
||||||
|
--sticky-header-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -157,7 +157,14 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
// sticky header
|
// sticky header
|
||||||
const stickyHeader = document.querySelector('#mainContent > section > .sticky-header');
|
const stickyHeader = document.querySelector('#mainContent > section > .sticky-header');
|
||||||
if (stickyHeader) {
|
if (stickyHeader) {
|
||||||
document.documentElement.style.scrollPaddingTop = `calc(${stickyHeader.offsetHeight}px + var(--btcpay-space-m))`;
|
const setStickyHeaderHeight = () => {
|
||||||
|
document.documentElement.style.setProperty('--sticky-header-height', `${stickyHeader.offsetHeight}px`)
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', e => {
|
||||||
|
debounce('resize', setStickyHeaderHeight, 50)
|
||||||
|
});
|
||||||
|
setStickyHeaderHeight();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize timezone offset value if field is present in page
|
// initialize timezone offset value if field is present in page
|
||||||
|
@ -355,6 +362,46 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
window.localStorage.setItem(COLLAPSED_KEY, JSON.stringify(collapsed))
|
window.localStorage.setItem(COLLAPSED_KEY, JSON.stringify(collapsed))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mass Action Tables
|
||||||
|
const updateSelectedCount = ($table) => {
|
||||||
|
const selectedCount = document.querySelectorAll('.mass-action-select:checked').length;
|
||||||
|
const $selectedCount = $table.querySelector('.mass-action-selected-count');
|
||||||
|
if ($selectedCount) $selectedCount.innerText = selectedCount;
|
||||||
|
if (selectedCount === 0) {
|
||||||
|
$table.removeAttribute('data-selected');
|
||||||
|
} else {
|
||||||
|
$table.setAttribute('data-selected', selectedCount.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate('click', '.mass-action .mass-action-select-all', e => {
|
||||||
|
const $table = e.target.closest('.mass-action');
|
||||||
|
const { checked } = e.target;
|
||||||
|
$table.querySelectorAll('.mass-action-select,.mass-action-select-all').forEach($checkbox => {
|
||||||
|
$checkbox.checked = checked;
|
||||||
|
});
|
||||||
|
updateSelectedCount($table);
|
||||||
|
});
|
||||||
|
|
||||||
|
delegate('change', '.mass-action .mass-action-select', e => {
|
||||||
|
const $table = e.target.closest('.mass-action');
|
||||||
|
const selectedCount = $table.querySelectorAll('.mass-action-select:checked').length;
|
||||||
|
if (selectedCount === 0) {
|
||||||
|
$table.querySelectorAll('.mass-action-select-all').forEach(checkbox => {
|
||||||
|
checkbox.checked = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateSelectedCount($table);
|
||||||
|
});
|
||||||
|
|
||||||
|
delegate('click', '.mass-action .mass-action-row', e => {
|
||||||
|
const $target = e.target
|
||||||
|
if ($target.matches('td,time,span[data-sensitive]')) {
|
||||||
|
const $row = $target.closest('.mass-action-row');
|
||||||
|
$row.querySelector('.mass-action-select').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize Blazor
|
// Initialize Blazor
|
||||||
|
|
|
@ -9,3 +9,9 @@ function delegate(eventType, selector, handler, root) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEBOUNCE_TIMERS = {}
|
||||||
|
function debounce(key, fn, delay = 250) {
|
||||||
|
clearTimeout(DEBOUNCE_TIMERS[key])
|
||||||
|
DEBOUNCE_TIMERS[key] = setTimeout(fn, delay)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue