@* ReSharper disable once CSharpWarnings::CS8619 *@
@foreach (var group in FilteredItems)
{
}
@* Optional helper text *@
@if (!string.IsNullOrWhiteSpace(_model.Value) && _lookup.TryGetValue(_model.Value!, out var selected))
{
Selected: @selected.Type•@selected.Group
}
}
@code {
/* ---------- Parameters ---------- */
[Parameter] public bool IsOpen { get; set; }
[Parameter] public EventCallback IsOpenChanged { get; set; }
[Parameter] public string Title { get; set; } = "Select hardware or system";
[Parameter] public string? Value { get; set; }
[Parameter] public EventCallback OnAccept { get; set; }
private SelectionFormModel _model = new();
private string _search = string.Empty;
private List _items = new();
private Dictionary _lookup = new();
private bool CanAccept => !string.IsNullOrWhiteSpace(_model.Value);
/* ---------- Lifecycle ---------- */
protected override async Task OnParametersSetAsync()
{
if (!IsOpen) return;
// Load both sets
var hardware = (await Repo.GetAllOfTypeAsync())
.Select(h => SelectionItem.Hardware(h.Name, h.Kind))
.ToList();
var systems = (await Repo.GetAllOfTypeAsync())
.Select(s => SelectionItem.System(s.Name, string.IsNullOrWhiteSpace(s.Type) ? "System" : s.Type!))
.ToList();
_items = hardware
.Concat(systems)
.OrderBy(i => i.TypeSort)
.ThenBy(i => i.Group)
.ThenBy(i => i.Label)
.ToList();
_lookup = _items.ToDictionary(i => i.Value, i => i);
_model = new SelectionFormModel { Value = Value };
_search = string.Empty;
}
private IReadOnlyDictionary> FilteredItems =>
_items
.Where(i =>
string.IsNullOrWhiteSpace(_search) ||
i.Label.Contains(_search.Trim(), StringComparison.OrdinalIgnoreCase) ||
i.Group.Contains(_search.Trim(), StringComparison.OrdinalIgnoreCase))
.GroupBy(i => $"{i.Type} — {i.Group}")
.ToDictionary(
g => g.Key,
g => g.OrderBy(i => i.Label).ToList());
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);
}
private void OnSearchChanged(string? value)
{
_search = value ?? string.Empty;
}
private void OnSearchInput(ChangeEventArgs e)
{
_search = e.Value?.ToString() ?? string.Empty;
if (FilteredItems.SelectMany(g => g.Value).All(i => i.Value != _model.Value))
_model.Value = null;
}
private sealed class SelectionFormModel
{
[Required] public string? Value { get; set; }
}
private sealed record SelectionItem(
string Type,
string Group,
string Label,
string Value,
int TypeSort)
{
public static SelectionItem Hardware(string name, string kind)
{
return new SelectionItem("Hardware", kind, name, $"{name}", 0);
}
public static SelectionItem System(string name, string category)
{
return new SelectionItem("System", category, name, $"{name}", 1);
}
}
}