From d81b945754ae9e8ef6d7dd626244305715e56bbd Mon Sep 17 00:00:00 2001 From: Eduardo <6845999+eduardosmaniotto@users.noreply.github.com> Date: Sat, 30 May 2026 18:44:34 -0300 Subject: [PATCH 1/2] feature: add item search for large lists --- .../Shared/Components/Form/AutoForm.razor.css | 17 --------- .../Shared/Components/Form/ItemTable.razor | 16 +++++++- .../Shared/Components/Form/ItemTable.razor.cs | 38 ++++++++++++++++++- src/Web/Shared/Styles/Forms.scss | 17 +++++++++ src/Web/Shared/wwwroot/css/shared.css | 17 +++++++++ 5 files changed, 85 insertions(+), 20 deletions(-) diff --git a/src/Web/Shared/Components/Form/AutoForm.razor.css b/src/Web/Shared/Components/Form/AutoForm.razor.css index 73af722ac..f2dfd1a21 100644 --- a/src/Web/Shared/Components/Form/AutoForm.razor.css +++ b/src/Web/Shared/Components/Form/AutoForm.razor.css @@ -24,20 +24,3 @@ .form-actions .btn-secondary { margin-left: 1rem; } - -.auto-form-search-group { - position: relative; -} - -.auto-form-search-group .form-control { - padding-left: 2.25rem; -} - -.auto-form-search-group .search-icon { - position: absolute; - left: 0.75rem; - top: 50%; - transform: translateY(-50%); - color: #6c757d; - pointer-events: none; -} diff --git a/src/Web/Shared/Components/Form/ItemTable.razor b/src/Web/Shared/Components/Form/ItemTable.razor index bdd44ae8d..3aeae3791 100644 --- a/src/Web/Shared/Components/Form/ItemTable.razor +++ b/src/Web/Shared/Components/Form/ItemTable.razor @@ -25,9 +25,23 @@ @if (!this._isCollapsed) {
+ @if (this._showSearch) + { +
+
+ + +
+
+ } - @foreach (var item in (this.Value ?? Enumerable.Empty()) + @foreach (var item in this.FilteredItems .Select(i => (Name : i.GetName(), Id : i.GetId(), Item : i)) .OrderBy(i => i.Name)) { diff --git a/src/Web/Shared/Components/Form/ItemTable.razor.cs b/src/Web/Shared/Components/Form/ItemTable.razor.cs index dba95dcd9..1375a781d 100644 --- a/src/Web/Shared/Components/Form/ItemTable.razor.cs +++ b/src/Web/Shared/Components/Form/ItemTable.razor.cs @@ -16,12 +16,14 @@ namespace MUnique.OpenMU.Web.Shared.Components.Form; using MUnique.OpenMU.Web.Shared.Components.Form.Modal; /// -/// A component which shows a collection of in a table. +/// A component that shows a collection of in a table. /// /// The type of the item. public partial class ItemTable where TItem : class { + private readonly int _searchThreshold = 10; + private bool _isEditable; private bool _isInlineEditable; @@ -34,6 +36,10 @@ public partial class ItemTable private bool _isCollapsed; + private string? _searchTerm; + + private bool _showSearch; + /// /// Gets or sets the label. /// @@ -46,6 +52,23 @@ public partial class ItemTable [CascadingParameter] public IContext PersistenceContext { get; set; } = null!; + /// + /// Gets the filtered list of items based on the current search term. + /// + private IEnumerable FilteredItems + { + get + { + var items = this.Value ?? Enumerable.Empty(); + if (string.IsNullOrWhiteSpace(this._searchTerm)) + { + return items; + } + + return items.Where(i => i.GetName().Contains(this._searchTerm, StringComparison.OrdinalIgnoreCase)); + } + } + /// protected override void OnInitialized() { @@ -57,8 +80,19 @@ protected override void OnInitialized() this._isInlineEditable = this._isEditable && isMemberOfAggregate && this.ValueExpression!.ScaffoldColumn(); this._isAddingSupported = !isMemberOfAggregate; this._isCreatingSupported = isMemberOfAggregate; - this._isStartingCollapsed = this.Value is not null && this.Value.Count > 10; + this._isStartingCollapsed = this.Value is not null && this.Value.Count > this._searchThreshold; this._isCollapsed = this._isStartingCollapsed; + this._showSearch = this.Value is not null && this.Value.Count > this._searchThreshold; + } + + /// + protected override void OnParametersSet() + { + base.OnParametersSet(); + if (this.Value is not null && this.Value.Count > this._searchThreshold) + { + this._showSearch = true; + } } /// diff --git a/src/Web/Shared/Styles/Forms.scss b/src/Web/Shared/Styles/Forms.scss index beee1c141..71d2083c8 100644 --- a/src/Web/Shared/Styles/Forms.scss +++ b/src/Web/Shared/Styles/Forms.scss @@ -111,4 +111,21 @@ ul.socket > li > div { ul.socket > li > div:last-of-type { @extend .ml-3; +} + +.auto-form-search-group { + position: relative; +} + +.auto-form-search-group .form-control { + padding-left: 2.25rem; +} + +.auto-form-search-group .search-icon { + position: absolute; + left: 0.75rem; + top: 50%; + transform: translateY(-50%); + color: #6c757d; + pointer-events: none; } \ No newline at end of file diff --git a/src/Web/Shared/wwwroot/css/shared.css b/src/Web/Shared/wwwroot/css/shared.css index 0d407339c..4458fcb15 100644 --- a/src/Web/Shared/wwwroot/css/shared.css +++ b/src/Web/Shared/wwwroot/css/shared.css @@ -10064,6 +10064,23 @@ label > details[open] { z-index: 1; } +.auto-form-search-group { + position: relative; +} + +.auto-form-search-group .form-control, .auto-form-search-group th input, th .auto-form-search-group input, .auto-form-search-group select, .auto-form-search-group form input, form .auto-form-search-group input, .auto-form-search-group .invalid .valid, .invalid .auto-form-search-group .valid, .auto-form-search-group .valid.modified { + padding-left: 2.25rem; +} + +.auto-form-search-group .search-icon { + position: absolute; + left: 0.75rem; + top: 50%; + transform: translateY(-50%); + color: #6c757d; + pointer-events: none; +} + @keyframes FadeIn { 0% { opacity: 0; From b0215560b1c5ec601638bdf311e826a12bd37874 Mon Sep 17 00:00:00 2001 From: Eduardo <6845999+eduardosmaniotto@users.noreply.github.com> Date: Sun, 31 May 2026 11:11:14 -0300 Subject: [PATCH 2/2] ItemTable: add search input, handle null names, fix show/hide logic, remove duplicate id --- src/Web/Shared/Components/Form/ItemTable.razor | 5 ++--- src/Web/Shared/Components/Form/ItemTable.razor.cs | 8 ++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/Web/Shared/Components/Form/ItemTable.razor b/src/Web/Shared/Components/Form/ItemTable.razor index 3aeae3791..8eadb521e 100644 --- a/src/Web/Shared/Components/Form/ItemTable.razor +++ b/src/Web/Shared/Components/Form/ItemTable.razor @@ -29,9 +29,8 @@ {
- diff --git a/src/Web/Shared/Components/Form/ItemTable.razor.cs b/src/Web/Shared/Components/Form/ItemTable.razor.cs index 1375a781d..5c3269dd4 100644 --- a/src/Web/Shared/Components/Form/ItemTable.razor.cs +++ b/src/Web/Shared/Components/Form/ItemTable.razor.cs @@ -65,7 +65,7 @@ private IEnumerable FilteredItems return items; } - return items.Where(i => i.GetName().Contains(this._searchTerm, StringComparison.OrdinalIgnoreCase)); + return items.Where(i => (i.GetName()?.Contains(this._searchTerm, StringComparison.OrdinalIgnoreCase) ?? false)); } } @@ -82,17 +82,13 @@ protected override void OnInitialized() this._isCreatingSupported = isMemberOfAggregate; this._isStartingCollapsed = this.Value is not null && this.Value.Count > this._searchThreshold; this._isCollapsed = this._isStartingCollapsed; - this._showSearch = this.Value is not null && this.Value.Count > this._searchThreshold; } /// protected override void OnParametersSet() { base.OnParametersSet(); - if (this.Value is not null && this.Value.Count > this._searchThreshold) - { - this._showSearch = true; - } + this._showSearch = this.Value is not null && this.Value.Count > this._searchThreshold; } ///