diff --git a/src/Web/Shared/Components/Form/DataTable.razor b/src/Web/Shared/Components/Form/DataTable.razor
index e88dbee316..88440ecc38 100644
--- a/src/Web/Shared/Components/Form/DataTable.razor
+++ b/src/Web/Shared/Components/Form/DataTable.razor
@@ -130,6 +130,7 @@
private async Task GetPageAsync(int page)
{
+ var restartFromFirstPage = false;
this._isLoading = true;
try
{
@@ -151,6 +152,10 @@
else
{
this._hasMoreEntries = false;
+
+ // A refresh of a page which does not exist anymore (for example after a filter reduced the results) would
+ // show an empty table without a way to notice why. Start over from the first page instead.
+ restartFromFirstPage = isRefresh && page > 1;
}
}
finally
@@ -158,5 +163,10 @@
this._isLoading = false;
await this.InvokeAsync(this.StateHasChanged).ConfigureAwait(false);
}
+
+ if (restartFromFirstPage)
+ {
+ await this.GetPageAsync(1);
+ }
}
}
diff --git a/tests/MUnique.OpenMU.Web.Tests/Components/DataTableTests.cs b/tests/MUnique.OpenMU.Web.Tests/Components/DataTableTests.cs
new file mode 100644
index 0000000000..37499f27c1
--- /dev/null
+++ b/tests/MUnique.OpenMU.Web.Tests/Components/DataTableTests.cs
@@ -0,0 +1,75 @@
+//
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace MUnique.OpenMU.Web.Tests.Components;
+
+using Bunit;
+using Microsoft.AspNetCore.Components;
+using Microsoft.Extensions.DependencyInjection;
+using MUnique.OpenMU.Web.Shared.Components.Form;
+using MUnique.OpenMU.Web.Shared.Services;
+
+///
+/// Tests for the component.
+///
+[TestFixture]
+public class DataTableTests
+{
+ ///
+ /// A refresh of a page which doesn't exist anymore, e.g. after a filter reduced the results,
+ /// starts over from the first page instead of showing an empty table.
+ ///
+ [Test]
+ public void RefreshOfEmptyPage_StartsOverFromFirstPage()
+ {
+ using var context = new BunitContext();
+ var dataService = new TestDataService(Enumerable.Range(1, 45).Select(i => new Item(i)));
+ context.Services.AddSingleton>(dataService);
+ var component = context.Render>(parameters => parameters
+ .Add(table => table.TableHeader, (RenderFragment)(_ => { }))
+ .Add(table => table.ItemTemplate, item => builder => builder.AddContent(0, item.Number)));
+
+ // The buttons are: previous page, page number, next page.
+ component.FindAll("button")[2].Click();
+ component.FindAll("button")[2].Click();
+ component.WaitForAssertion(() => Assert.That(component.Instance.Page, Is.EqualTo(3)));
+
+ dataService.SetItems(Enumerable.Range(1, 3).Select(i => new Item(i)));
+
+ component.WaitForAssertion(() =>
+ {
+ Assert.That(component.Instance.Page, Is.EqualTo(1));
+ Assert.That(component.FindAll("tbody tr"), Has.Count.EqualTo(3));
+ });
+ }
+
+ ///
+ /// An item of the table.
+ ///
+ /// The number of the item.
+ public sealed record Item(int Number);
+
+ private sealed class TestDataService : IDataService- , ISupportDataChangedNotification
+ {
+ private List
- _items;
+
+ public TestDataService(IEnumerable
- items)
+ {
+ this._items = items.ToList();
+ }
+
+ public event EventHandler? DataChanged;
+
+ public Task
> GetAsync(int offset, int count)
+ {
+ return Task.FromResult(this._items.Skip(offset).Take(count).ToList());
+ }
+
+ public void SetItems(IEnumerable- items)
+ {
+ this._items = items.ToList();
+ this.DataChanged?.Invoke(this, EventArgs.Empty);
+ }
+ }
+}