From 52b2cf9a5befaba7a0f1d5b296abe80e7e99ec84 Mon Sep 17 00:00:00 2001 From: OlgunR Date: Thu, 5 Feb 2026 15:45:36 +0100 Subject: [PATCH] Add user-selectable page size to MassData grid Users can now choose how many records to display per page in the MassData grid (100, 1,000, 10,000, 100,000, or all). The backend and API client are updated to support nullable skip/take parameters, allowing "all" records to be fetched when desired. The pager and page count calculations are updated to reflect the selected page size, and the pager is hidden if only one page exists. Additional UI and CSS changes provide a combo box for page size selection. The API controller now treats take <= 0 as "no limit." --- DbFirst.API/Controllers/MassDataController.cs | 7 +- .../Components/MassDataGrid.razor | 71 ++++++++++++++++--- .../Services/MassDataApiClient.cs | 15 +++- .../Components/MassDataGrid.razor | 71 ++++++++++++++++--- .../Services/MassDataApiClient.cs | 15 +++- 5 files changed, 156 insertions(+), 23 deletions(-) diff --git a/DbFirst.API/Controllers/MassDataController.cs b/DbFirst.API/Controllers/MassDataController.cs index 2dbe55a..8d17209 100644 --- a/DbFirst.API/Controllers/MassDataController.cs +++ b/DbFirst.API/Controllers/MassDataController.cs @@ -27,7 +27,12 @@ public class MassDataController : ControllerBase [HttpGet] public async Task>> GetAll([FromQuery] int? skip, [FromQuery] int? take, CancellationToken cancellationToken) { - var resolvedTake = take is null or <= 0 ? 200 : take; + int? resolvedTake = take; + if (resolvedTake is <= 0) + { + resolvedTake = null; + } + var result = await _mediator.Send(new GetAllMassDataQuery(skip, resolvedTake), cancellationToken); return Ok(result); } diff --git a/DbFirst.BlazorWasm/Components/MassDataGrid.razor b/DbFirst.BlazorWasm/Components/MassDataGrid.razor index 8d6aa64..48240e4 100644 --- a/DbFirst.BlazorWasm/Components/MassDataGrid.razor +++ b/DbFirst.BlazorWasm/Components/MassDataGrid.razor @@ -10,6 +10,23 @@ margin-top: 12px; margin-bottom: 16px; } + .page-size-selector { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: nowrap; + } + .page-size-label { + white-space: nowrap; + } + .page-size-combo { + width: 13ch; + min-width: 13ch; + max-width: 13ch; + } + .page-size-combo input { + text-align: left; + } .massdata-grid .dxbl-grid-sort-asc, .massdata-grid .dxbl-grid-sort-desc { display: none; @@ -75,6 +92,18 @@ else if (items.Count == 0) } else { +
+ Datensätze je Seite: + +
+
-
- -
+ @if (pageCount > 1) + { +
+ +
+ }
} @code { - private const int PageSize = 100; private List items = new(); private bool isLoading; private string? errorMessage; private string? infoMessage; private int pageIndex; private int pageCount = 1; + private int? pageSize = 100; private string popupHeaderText = "Edit"; private EditContext? editContext; private ValidationMessageStore? validationMessageStore; + private readonly List pageSizeOptions = new() + { + new() { Value = 100, Text = "100" }, + new() { Value = 1000, Text = "1.000" }, + new() { Value = 10000, Text = "10.000" }, + new() { Value = 100000, Text = "100.000" }, + new() { Value = null, Text = "Alle" } + }; + private readonly List statusFilterOptions = new() { new() { Value = null, Text = "Alle" }, @@ -224,11 +264,12 @@ else try { var total = await Api.GetCountAsync(); - pageCount = Math.Max(1, (int)Math.Ceiling(total / (double)PageSize)); + var effectivePageSize = pageSize ?? (total == 0 ? 1 : total); + pageCount = Math.Max(1, (int)Math.Ceiling(total / (double)effectivePageSize)); pageIndex = Math.Clamp(page, 0, pageCount - 1); - var skip = pageIndex * PageSize; - items = await Api.GetAllAsync(skip, PageSize); + var skip = pageSize.HasValue ? pageIndex * pageSize.Value : 0; + items = await Api.GetAllAsync(skip, pageSize); } catch (Exception ex) { @@ -246,6 +287,12 @@ else await LoadPage(index); } + private async Task OnPageSizeChanged(int? size) + { + pageSize = size; + await LoadPage(0); + } + private void SetEditContext(EditContext context) { if (editContext == context) @@ -405,4 +452,10 @@ else public bool? Value { get; set; } public string Text { get; set; } = string.Empty; } + + private sealed class PageSizeOption + { + public int? Value { get; set; } + public string Text { get; set; } = string.Empty; + } } diff --git a/DbFirst.BlazorWasm/Services/MassDataApiClient.cs b/DbFirst.BlazorWasm/Services/MassDataApiClient.cs index 604451c..f20e048 100644 --- a/DbFirst.BlazorWasm/Services/MassDataApiClient.cs +++ b/DbFirst.BlazorWasm/Services/MassDataApiClient.cs @@ -19,9 +19,20 @@ public class MassDataApiClient return result ?? 0; } - public async Task> GetAllAsync(int skip, int take) + public async Task> GetAllAsync(int? skip, int? take) { - var result = await _httpClient.GetFromJsonAsync>($"{Endpoint}?skip={skip}&take={take}"); + var query = new List(); + if (skip.HasValue) + { + query.Add($"skip={skip.Value}"); + } + if (take.HasValue) + { + query.Add($"take={take.Value}"); + } + + var url = query.Count == 0 ? Endpoint : $"{Endpoint}?{string.Join("&", query)}"; + var result = await _httpClient.GetFromJsonAsync>(url); return result ?? new List(); } diff --git a/DbFirst.BlazorWebApp/Components/MassDataGrid.razor b/DbFirst.BlazorWebApp/Components/MassDataGrid.razor index 8a1b178..aaf3d0e 100644 --- a/DbFirst.BlazorWebApp/Components/MassDataGrid.razor +++ b/DbFirst.BlazorWebApp/Components/MassDataGrid.razor @@ -10,6 +10,23 @@ margin-top: 12px; margin-bottom: 16px; } + .page-size-selector { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: nowrap; + } + .page-size-label { + white-space: nowrap; + } + .page-size-combo { + width: 13ch; + min-width: 13ch; + max-width: 13ch; + } + .page-size-combo input { + text-align: left; + } .massdata-grid .dxbl-grid-sort-asc, .massdata-grid .dxbl-grid-sort-desc { display: none; @@ -75,6 +92,18 @@ else if (items.Count == 0) } else { +
+ Datensätze je Seite: + +
+
-
- -
+ @if (pageCount > 1) + { +
+ +
+ }
} @code { - private const int PageSize = 100; private List items = new(); private bool isLoading; private string? errorMessage; private string? infoMessage; private int pageIndex; private int pageCount = 1; + private int? pageSize = 100; private string popupHeaderText = "Edit"; private EditContext? editContext; private ValidationMessageStore? validationMessageStore; @@ -212,6 +243,15 @@ else new() { Value = 0, Text = "PRMassdata_UpsertByCustomerName" } }; + private readonly List pageSizeOptions = new() + { + new() { Value = 100, Text = "100" }, + new() { Value = 1000, Text = "1.000" }, + new() { Value = 10000, Text = "10.000" }, + new() { Value = 100000, Text = "100.000" }, + new() { Value = null, Text = "Alle" } + }; + protected override async Task OnInitializedAsync() { await LoadPage(0); @@ -224,11 +264,12 @@ else try { var total = await Api.GetCountAsync(); - pageCount = Math.Max(1, (int)Math.Ceiling(total / (double)PageSize)); + var effectivePageSize = pageSize ?? (total == 0 ? 1 : total); + pageCount = Math.Max(1, (int)Math.Ceiling(total / (double)effectivePageSize)); pageIndex = Math.Clamp(page, 0, pageCount - 1); - var skip = pageIndex * PageSize; - items = await Api.GetAllAsync(skip, PageSize); + var skip = pageSize.HasValue ? pageIndex * pageSize.Value : 0; + items = await Api.GetAllAsync(skip, pageSize); } catch (Exception ex) { @@ -246,6 +287,12 @@ else await LoadPage(index); } + private async Task OnPageSizeChanged(int? size) + { + pageSize = size; + await LoadPage(0); + } + private void SetEditContext(EditContext context) { if (editContext == context) @@ -405,4 +452,10 @@ else public bool? Value { get; set; } public string Text { get; set; } = string.Empty; } + + private sealed class PageSizeOption + { + public int? Value { get; set; } + public string Text { get; set; } = string.Empty; + } } diff --git a/DbFirst.BlazorWebApp/Services/MassDataApiClient.cs b/DbFirst.BlazorWebApp/Services/MassDataApiClient.cs index ce82d42..2ee4cbe 100644 --- a/DbFirst.BlazorWebApp/Services/MassDataApiClient.cs +++ b/DbFirst.BlazorWebApp/Services/MassDataApiClient.cs @@ -19,9 +19,20 @@ public class MassDataApiClient return result ?? 0; } - public async Task> GetAllAsync(int skip, int take) + public async Task> GetAllAsync(int? skip, int? take) { - var result = await _httpClient.GetFromJsonAsync>($"{Endpoint}?skip={skip}&take={take}"); + var query = new List(); + if (skip.HasValue) + { + query.Add($"skip={skip.Value}"); + } + if (take.HasValue) + { + query.Add($"take={take.Value}"); + } + + var url = query.Count == 0 ? Endpoint : $"{Endpoint}?{string.Join("&", query)}"; + var result = await _httpClient.GetFromJsonAsync>(url); return result ?? new List(); }