Added bootstrap paging buttons to the invoice list page and fixed paging buttons.

This commit is contained in:
Aaron Clauson
2019-01-16 21:33:04 +01:00
parent 686ae029e0
commit a4792f54a7
4 changed files with 126 additions and 94 deletions

View File

@@ -447,8 +447,11 @@ namespace BTCPayServer.Controllers
Count = count, Count = count,
StatusMessage = StatusMessage StatusMessage = StatusMessage
}; };
InvoiceQuery invoiceQuery = GetInvoiceQuery(searchTerm);
var list = await ListInvoicesProcess(searchTerm, skip, count); model.Total = await _InvoiceRepository.GetInvoicesTotal(invoiceQuery);
invoiceQuery.Count = count;
invoiceQuery.Skip = skip;
var list = await _InvoiceRepository.GetInvoices(invoiceQuery);
foreach (var invoice in list) foreach (var invoice in list)
{ {
var state = invoice.GetInvoiceState(); var state = invoice.GetInvoiceState();
@@ -468,14 +471,12 @@ namespace BTCPayServer.Controllers
return View(model); return View(model);
} }
private async Task<InvoiceEntity[]> ListInvoicesProcess(string searchTerm = null, int skip = 0, int count = 50) private InvoiceQuery GetInvoiceQuery(string searchTerm = null)
{ {
var filterString = new SearchString(searchTerm); var filterString = new SearchString(searchTerm);
var list = await _InvoiceRepository.GetInvoices(new InvoiceQuery() var invoiceQuery = new InvoiceQuery()
{ {
TextSearch = filterString.TextSearch, TextSearch = filterString.TextSearch,
Count = count,
Skip = skip,
UserId = GetUserId(), UserId = GetUserId(),
Unusual = !filterString.Filters.ContainsKey("unusual") ? null Unusual = !filterString.Filters.ContainsKey("unusual") ? null
: !bool.TryParse(filterString.Filters["unusual"].First(), out var r) ? (bool?)null : !bool.TryParse(filterString.Filters["unusual"].First(), out var r) ? (bool?)null
@@ -485,9 +486,8 @@ namespace BTCPayServer.Controllers
StoreId = filterString.Filters.ContainsKey("storeid") ? filterString.Filters["storeid"].ToArray() : null, StoreId = filterString.Filters.ContainsKey("storeid") ? filterString.Filters["storeid"].ToArray() : null,
ItemCode = filterString.Filters.ContainsKey("itemcode") ? filterString.Filters["itemcode"].ToArray() : null, ItemCode = filterString.Filters.ContainsKey("itemcode") ? filterString.Filters["itemcode"].ToArray() : null,
OrderId = filterString.Filters.ContainsKey("orderid") ? filterString.Filters["orderid"].ToArray() : null OrderId = filterString.Filters.ContainsKey("orderid") ? filterString.Filters["orderid"].ToArray() : null
}); };
return invoiceQuery;
return list;
} }
[HttpGet] [HttpGet]
@@ -497,7 +497,10 @@ namespace BTCPayServer.Controllers
{ {
var model = new InvoiceExport(_NetworkProvider, _CurrencyNameTable); var model = new InvoiceExport(_NetworkProvider, _CurrencyNameTable);
var invoices = await ListInvoicesProcess(searchTerm, 0, int.MaxValue); InvoiceQuery invoiceQuery = GetInvoiceQuery(searchTerm);
invoiceQuery.Count = int.MaxValue;
invoiceQuery.Skip = 0;
var invoices = await _InvoiceRepository.GetInvoices(invoiceQuery);
var res = model.Process(invoices, format); var res = model.Process(invoices, format);
var cd = new ContentDisposition var cd = new ContentDisposition

View File

@@ -15,6 +15,10 @@ namespace BTCPayServer.Models.InvoicingModels
{ {
get; set; get; set;
} }
public int Total
{
get; set;
}
public string SearchTerm public string SearchTerm
{ {
get; set; get; set;

View File

@@ -420,91 +420,108 @@ retry:
return entity; return entity;
} }
private IQueryable<Data.InvoiceData> GetInvoiceQuery(ApplicationDbContext context, InvoiceQuery queryObject)
{
IQueryable<Data.InvoiceData> query = context.Invoices;
if (!string.IsNullOrEmpty(queryObject.InvoiceId))
{
query = query.Where(i => i.Id == queryObject.InvoiceId);
}
if (queryObject.StoreId != null && queryObject.StoreId.Length > 0)
{
var stores = queryObject.StoreId.ToHashSet();
query = query.Where(i => stores.Contains(i.StoreDataId));
}
if (queryObject.UserId != null)
{
query = query.Where(i => i.StoreData.UserStores.Any(u => u.ApplicationUserId == queryObject.UserId));
}
if (!string.IsNullOrEmpty(queryObject.TextSearch))
{
var ids = new HashSet<string>(SearchInvoice(queryObject.TextSearch));
if (ids.Count == 0)
{
// Hacky way to return an empty query object. The nice way is much too elaborate:
// https://stackoverflow.com/questions/33305495/how-to-return-empty-iqueryable-in-an-async-repository-method
return query.Where(x => false);
}
query = query.Where(i => ids.Contains(i.Id));
}
if (queryObject.StartDate != null)
query = query.Where(i => queryObject.StartDate.Value <= i.Created);
if (queryObject.EndDate != null)
query = query.Where(i => i.Created <= queryObject.EndDate.Value);
if (queryObject.OrderId != null && queryObject.OrderId.Length > 0)
{
var statusSet = queryObject.OrderId.ToHashSet();
query = query.Where(i => statusSet.Contains(i.OrderId));
}
if (queryObject.ItemCode != null && queryObject.ItemCode.Length > 0)
{
var statusSet = queryObject.ItemCode.ToHashSet();
query = query.Where(i => statusSet.Contains(i.ItemCode));
}
if (queryObject.Status != null && queryObject.Status.Length > 0)
{
var statusSet = queryObject.Status.ToHashSet();
query = query.Where(i => statusSet.Contains(i.Status));
}
if (queryObject.Unusual != null)
{
var unused = queryObject.Unusual.Value;
query = query.Where(i => unused == (i.Status == "invalid" || i.ExceptionStatus != null));
}
if (queryObject.ExceptionStatus != null && queryObject.ExceptionStatus.Length > 0)
{
var exceptionStatusSet = queryObject.ExceptionStatus.Select(s => NormalizeExceptionStatus(s)).ToHashSet();
query = query.Where(i => exceptionStatusSet.Contains(i.ExceptionStatus));
}
query = query.OrderByDescending(q => q.Created);
if (queryObject.Skip != null)
query = query.Skip(queryObject.Skip.Value);
if (queryObject.Count != null)
query = query.Take(queryObject.Count.Value);
return query;
}
public async Task<int> GetInvoicesTotal(InvoiceQuery queryObject)
{
using (var context = _ContextFactory.CreateContext())
{
var query = GetInvoiceQuery(context, queryObject);
return await query.CountAsync();
}
}
public async Task<InvoiceEntity[]> GetInvoices(InvoiceQuery queryObject) public async Task<InvoiceEntity[]> GetInvoices(InvoiceQuery queryObject)
{ {
using (var context = _ContextFactory.CreateContext()) using (var context = _ContextFactory.CreateContext())
{ {
IQueryable<Data.InvoiceData> query = context var query = GetInvoiceQuery(context, queryObject);
.Invoices query = query.Include(o => o.Payments)
.Include(o => o.Payments)
.Include(o => o.RefundAddresses); .Include(o => o.RefundAddresses);
if (queryObject.IncludeAddresses) if (queryObject.IncludeAddresses)
query = query.Include(o => o.HistoricalAddressInvoices).Include(o => o.AddressInvoices); query = query.Include(o => o.HistoricalAddressInvoices).Include(o => o.AddressInvoices);
if (queryObject.IncludeEvents) if (queryObject.IncludeEvents)
query = query.Include(o => o.Events); query = query.Include(o => o.Events);
if (!string.IsNullOrEmpty(queryObject.InvoiceId))
{
query = query.Where(i => i.Id == queryObject.InvoiceId);
}
if (queryObject.StoreId != null && queryObject.StoreId.Length > 0)
{
var stores = queryObject.StoreId.ToHashSet();
query = query.Where(i => stores.Contains(i.StoreDataId));
}
if (queryObject.UserId != null)
{
query = query.Where(i => i.StoreData.UserStores.Any(u => u.ApplicationUserId == queryObject.UserId));
}
if (!string.IsNullOrEmpty(queryObject.TextSearch))
{
var ids = new HashSet<string>(SearchInvoice(queryObject.TextSearch));
if (ids.Count == 0)
return Array.Empty<InvoiceEntity>();
query = query.Where(i => ids.Contains(i.Id));
}
if (queryObject.StartDate != null)
query = query.Where(i => queryObject.StartDate.Value <= i.Created);
if (queryObject.EndDate != null)
query = query.Where(i => i.Created <= queryObject.EndDate.Value);
if (queryObject.OrderId != null && queryObject.OrderId.Length > 0)
{
var statusSet = queryObject.OrderId.ToHashSet();
query = query.Where(i => statusSet.Contains(i.OrderId));
}
if (queryObject.ItemCode != null && queryObject.ItemCode.Length > 0)
{
var statusSet = queryObject.ItemCode.ToHashSet();
query = query.Where(i => statusSet.Contains(i.ItemCode));
}
if (queryObject.Status != null && queryObject.Status.Length > 0)
{
var statusSet = queryObject.Status.ToHashSet();
query = query.Where(i => statusSet.Contains(i.Status));
}
if (queryObject.Unusual != null)
{
var unused = queryObject.Unusual.Value;
query = query.Where(i => unused == (i.Status == "invalid" || i.ExceptionStatus != null));
}
if (queryObject.ExceptionStatus != null && queryObject.ExceptionStatus.Length > 0)
{
var exceptionStatusSet = queryObject.ExceptionStatus.Select(s => NormalizeExceptionStatus(s)).ToHashSet();
query = query.Where(i => exceptionStatusSet.Contains(i.ExceptionStatus));
}
query = query.OrderByDescending(q => q.Created);
if (queryObject.Skip != null)
query = query.Skip(queryObject.Skip.Value);
if (queryObject.Count != null)
query = query.Take(queryObject.Count.Value);
var data = await query.ToArrayAsync().ConfigureAwait(false); var data = await query.ToArrayAsync().ConfigureAwait(false);
return data.Select(ToEntity).ToArray(); return data.Select(ToEntity).ToArray();
} }
} }
private string NormalizeExceptionStatus(string status) private string NormalizeExceptionStatus(string status)

View File

@@ -142,23 +142,31 @@
} }
</tbody> </tbody>
</table> </table>
<span>
@if (Model.Skip != 0) <nav aria-label="...">
{ <ul class="pagination">
<a href="@Url.Action("ListInvoices", new <li class="page-item @(Model.Skip == 0 ? "disabled" : null)">
<a class="page-link" tabindex="-1" href="@Url.Action("ListInvoices", new
{ {
searchTerm = Model.SearchTerm, searchTerm = Model.SearchTerm,
skip = Math.Max(0, Model.Skip - Model.Count), skip = Math.Max(0, Model.Skip - Model.Count),
count = Model.Count, count = Model.Count,
})"><<</a><span> - </span> })">Previous</a>
} </li>
<a href="@Url.Action("ListInvoices", new <li class="page-item disabled">
{ <span class="page-link">@(Model.Skip + 1) to @(Model.Skip + Model.Invoices.Count) of @Model.Total</span>
searchTerm = Model.SearchTerm, </li>
skip = Model.Skip + Model.Count, <li class="page-item @(Model.Total > (Model.Skip + Model.Invoices.Count) ? null : "disabled")">
count = Model.Count, <a class="page-link" href="@Url.Action("ListInvoices", new
})">>></a> {
</span> searchTerm = Model.SearchTerm,
skip = Model.Skip + Model.Count,
count = Model.Count,
})">Next</a>
</li>
</ul>
</nav>
</div> </div>
</div> </div>