mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 22:25:28 +01:00
* UI: Move section navigation to sidebar * Scroll active nav link into view * Move CTAs to top right * Server Settings: Make Policies first page * Responsive table fixes * Spacing fixes * Add breadcrumb samples * store settings fixes * payment request fixes * updates pull payment title * adds invoice detail fix * updates server settings breadcrumbs + copy fix * Don't open Server Settings on Plugins page * Add breadcrumbs to pull payment views * adds breadcrumbs to account * server and store breadcrumb fixes * fixes access tokens * Fix payment processor breadcrumbs * fixes webhook 404 * Final touches * Fix test * Add breadcrumb for email rules page * Design system updates --------- Co-authored-by: dstrukt <gfxdsign@gmail.com>
235 lines
10 KiB
Text
235 lines
10 KiB
Text
@using BTCPayServer.Client
|
|
@using BTCPayServer.Components
|
|
@model ListTransactionsViewModel
|
|
|
|
@{
|
|
var walletId = Context.GetRouteValue("walletId").ToString();
|
|
var storeId = Context.GetRouteValue("storeId")?.ToString();
|
|
var cryptoCode = Context.GetRouteValue("cryptoCode")?.ToString();
|
|
var labelFilter = Context.Request.Query["labelFilter"].ToString();
|
|
var wallet = walletId != null ? WalletId.Parse(walletId) : new WalletId(storeId, cryptoCode);
|
|
|
|
ViewData.SetActivePage(WalletsNavPages.Transactions, $"{Model.CryptoCode} Transactions", walletId);
|
|
}
|
|
|
|
@section PageHeadContent {
|
|
<script src="~/vendor/tom-select/tom-select.complete.min.js" asp-append-version="true"></script>
|
|
<link href="~/vendor/tom-select/tom-select.bootstrap5.min.css" asp-append-version="true" rel="stylesheet">
|
|
<style>
|
|
.smMaxWidth {
|
|
max-width: 125px;
|
|
}
|
|
|
|
@@media (min-width: 990px) {
|
|
.smMaxWidth {
|
|
max-width: 200px;
|
|
}
|
|
}
|
|
|
|
/* pull actions area, so that it is besides the search form */
|
|
@@media (min-width: 1200px) {
|
|
#Filter + #Dropdowns {
|
|
margin-top: -4rem;
|
|
float: right;
|
|
}
|
|
|
|
#Filter + #Dropdowns #Actions {
|
|
order: 1;
|
|
}
|
|
}
|
|
|
|
.unconf > * {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
#LoadingIndicator {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
</style>
|
|
}
|
|
|
|
@section PageFootContent {
|
|
@*Without async, somehow selenium do not manage to click on links in this page*@
|
|
<script src="~/modal/btcpay.js" asp-append-version="true" async></script>
|
|
@* Custom Range Modal *@
|
|
<script>
|
|
const $actions = document.getElementById('ListActions');
|
|
const $transactions = document.getElementById('WalletTransactions');
|
|
const $list = document.getElementById('WalletTransactionsList');
|
|
const $dropdowns = document.getElementById('Dropdowns');
|
|
const $indicator = document.getElementById('LoadingIndicator');
|
|
|
|
delegate('click', '#GoToTop', () => {
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
});
|
|
|
|
if ($actions && $actions.offsetTop - window.innerHeight > 0) {
|
|
document.getElementById('GoToTop').classList.remove('d-none');
|
|
}
|
|
|
|
const count = @Safe.Json(Model.Count);
|
|
const skipInitial = @Safe.Json(Model.Skip);
|
|
const loadMoreUrl = @Safe.Json(Url.Action("WalletTransactions", new { walletId, labelFilter, skip = Model.Skip, count = Model.Count, loadTransactions = true }));
|
|
// The next time we load transactions, skip will become 0
|
|
let skip = @Safe.Json(Model.Skip) - count;
|
|
|
|
async function loadMoreTransactions() {
|
|
$indicator.classList.remove('d-none');
|
|
|
|
const skipNext = skip + count;
|
|
const url = loadMoreUrl.replace(`skip=${skipInitial}`, `skip=${skipNext}`)
|
|
const response = await fetch(url, {
|
|
headers: {
|
|
'Accept': 'text/html',
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
const html = await response.text();
|
|
const responseEmpty = html.trim() === '';
|
|
$list.insertAdjacentHTML('beforeend', html);
|
|
skip = skipNext;
|
|
|
|
if (responseEmpty) {
|
|
// in case the response html was empty, remove the observer and stop loading
|
|
observer.unobserve($actions);
|
|
}
|
|
if (!$transactions.dataset.loaded) {
|
|
$transactions.dataset.loaded = 'true';
|
|
// replace table and dropdowns if initial response was empty
|
|
if (responseEmpty) {
|
|
$dropdowns.remove();
|
|
$transactions.innerHTML = '<div class="text-secondary" data-loaded="true">There are no transactions yet.</div>';
|
|
}
|
|
}
|
|
}
|
|
|
|
$indicator.classList.add('d-none');
|
|
formatDateTimes(document.querySelector('#WalletTransactions .switch-time-format').dataset.mode);
|
|
initLabelManagers();
|
|
}
|
|
|
|
const observer = new IntersectionObserver(async entries => {
|
|
const { isIntersecting } = entries[0];
|
|
if (isIntersecting) {
|
|
await loadMoreTransactions();
|
|
}
|
|
}, { rootMargin: '128px' });
|
|
|
|
// the actions div marks the end of the list table
|
|
observer.observe($actions);
|
|
</script>
|
|
}
|
|
|
|
<div class="sticky-header">
|
|
<vc:wallet-nav wallet-id="wallet"/>
|
|
</div>
|
|
<partial name="_StatusMessage" />
|
|
|
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3" id="Dropdowns">
|
|
@if (Model.Labels.Any())
|
|
{
|
|
<div class="btn-group" id="Filter">
|
|
<button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
|
@if (string.IsNullOrEmpty(labelFilter))
|
|
{
|
|
<span class="text-secondary">Filter by label</span>
|
|
}
|
|
else
|
|
{
|
|
<span class="text-secondary">Label:</span>
|
|
<span>@labelFilter</span>
|
|
}
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
@foreach (var label in Model.Labels)
|
|
{
|
|
<li><a asp-route-labelFilter="@label.Text" class="dropdown-item transaction-label-text@(labelFilter == label.Text ? " active" : string.Empty)" style="--btcpay-dropdown-link-active-bg:@label.Color;--btcpay-dropdown-link-active-color:@label.TextColor;">@label.Text</a></li>
|
|
}
|
|
@if (!string.IsNullOrEmpty(labelFilter))
|
|
{
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item" asp-route-labelFilter="">Clear filter</a></li>
|
|
}
|
|
</ul>
|
|
</div>
|
|
}
|
|
<div class="dropdown d-inline-flex align-items-center gap-3 ms-auto" id="Export">
|
|
<button class="btn btn-secondary dropdown-toggle" type="button" id="ExportDropdownToggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
Export
|
|
</button>
|
|
<div class="dropdown-menu" aria-labelledby="ExportDropdownToggle">
|
|
<a asp-action="Export" asp-route-walletId="@walletId" asp-route-format="csv" asp-route-labelFilter="@labelFilter" class="dropdown-item export-link" target="_blank" id="ExportCSV">CSV</a>
|
|
<a asp-action="Export" asp-route-walletId="@walletId" asp-route-format="json" asp-route-labelFilter="@labelFilter" class="dropdown-item export-link" target="_blank" id="ExportJSON">JSON</a>
|
|
<a asp-action="Export" asp-route-walletId="@walletId" asp-route-format="bip329" asp-route-labelFilter="@labelFilter" class="dropdown-item export-link" target="_blank" id="ExportBIP329">Wallet Labels (BIP-329)</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div style="clear:both"></div>
|
|
|
|
<div id="WalletTransactions" class="table-responsive-md">
|
|
<table class="table table-hover mass-action">
|
|
<thead class="mass-action-head">
|
|
<tr>
|
|
<th class="only-for-js mass-action-select-col">
|
|
<input type="checkbox" class="form-check-input mass-action-select-all" />
|
|
</th>
|
|
<th class="date-col">
|
|
<div class="d-flex align-items-center gap-1">
|
|
Date
|
|
<button type="button" class="btn btn-link p-0 switch-time-format only-for-js" title="Switch date format">
|
|
<vc:icon symbol="time" />
|
|
</button>
|
|
</div>
|
|
</th>
|
|
<th class="text-start">Label</th>
|
|
<th>Transaction Id</th>
|
|
<th class="amount-col">Amount</th>
|
|
<th></th>
|
|
</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="actions-send" />
|
|
Bump fee
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="WalletTransactionsList">
|
|
<partial name="_WalletTransactionsList" model="Model" />
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<noscript>
|
|
<vc:pager view-model="Model"/>
|
|
</noscript>
|
|
|
|
<div class="text-center only-for-js d-none" id="LoadingIndicator">
|
|
<div class="spinner-border spinner-border-sm text-secondary ms-2" role="status">
|
|
<span class="visually-hidden">Loading...</span>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex flex-wrap align-items-center justify-content-center gap-3 mb-5 only-for-js" id="ListActions">
|
|
<button type="button" class="btn btn-secondary d-none" id="GoToTop">Go to top</button>
|
|
</div>
|
|
|
|
<p class="mt-4 mb-0">
|
|
If BTCPay Server shows you an invalid balance, <a asp-action="WalletRescan" asp-route-walletId="@Context.GetRouteValue("walletId")">rescan your wallet</a>.
|
|
<br />
|
|
If some transactions appear in BTCPay Server, but are missing in another wallet, <a href="https://docs.btcpayserver.org/FAQ/Wallet/#missing-payments-in-my-software-or-hardware-wallet" rel="noreferrer noopener">follow these instructions</a>.
|
|
</p>
|