@using System.ComponentModel.DataAnnotations @using RackPeek.Domain.Persistence @using RackPeek.Domain.Resources.Hardware @inject IResourceCollection Repo @if (IsOpen) {
@Title
@* ReSharper disable once CSharpWarnings::CS8619 *@
@foreach (var group in FilteredHardware) { @foreach (var hw in group.Value) { } }
} @code { /* ---------- Parameters ---------- */ [Parameter] public bool IsOpen { get; set; } [Parameter] public EventCallback IsOpenChanged { get; set; } [Parameter] [EditorRequired] public string Title { get; set; } = "Select hardware"; /// /// Default / pre-selected hardware name (may be null) /// [Parameter] public string? Value { get; set; } /// /// Called with the selected hardware name /// [Parameter] public EventCallback OnAccept { get; set; } /* ---------- State ---------- */ private SelectionFormModel _model = new(); private string _search = string.Empty; private List _hardware = new(); private bool CanAccept => !string.IsNullOrWhiteSpace(_model.Value); /* ---------- Lifecycle ---------- */ protected override async Task OnParametersSetAsync() { if (IsOpen) { _hardware = (await Repo.GetAllOfTypeAsync()) .OrderBy(h => h.Kind) .ThenBy(h => h.Name) .ToList(); _model = new SelectionFormModel { Value = Value }; _search = string.Empty; } } protected override void OnAfterRender(bool firstRender) { } /* ---------- Computed ---------- */ private IReadOnlyDictionary> FilteredHardware => _hardware .Where(h => string.IsNullOrWhiteSpace(_search) || h.Name.Contains(_search.Trim(), StringComparison.OrdinalIgnoreCase)) .GroupBy(h => h.Kind) .ToDictionary( g => g.Key, g => g.OrderBy(h => h.Name).ToList()); /* ---------- Actions ---------- */ private async Task HandleAccept() { await OnAccept.InvokeAsync(_model.Value); await Close(); } private async Task Cancel() { await Close(); } private async Task Close() { _model = new SelectionFormModel(); _search = string.Empty; await IsOpenChanged.InvokeAsync(false); } /* ---------- Model ---------- */ private sealed class SelectionFormModel { [Required] public string? Value { get; set; } } private void OnSearchChanged(string? value) { _search = value ?? string.Empty; } private void OnSearchInput(ChangeEventArgs e) { _search = e.Value?.ToString() ?? string.Empty; if (FilteredHardware.SelectMany(g => g.Value).All(h => h.Name != _model.Value)) { _model.Value = null; } } }