ResourcesListComponent.razor 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. @using RackPeek.Domain.Persistence
  2. @typeparam TResource where TResource : RackPeek.Domain.Resources.Resource
  3. @inject IResourceCollection Repo
  4. @inject NavigationManager Nav
  5. <PageTitle>@Title</PageTitle>
  6. <h1 class="text-lg text-zinc-100" data-testid="@($"{TestId}-page-title")">
  7. @Title
  8. </h1>
  9. <div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono p-6 space-y-6"
  10. data-testid="@($"{TestId}-page-root")">
  11. <!-- Add Resource Section -->
  12. <div data-testid="@($"{TestId}-add-section")">
  13. <AddResourceComponent TResource="TResource"
  14. Placeholder=@($"{@Title} name")
  15. OnCreated="OnCreated" />
  16. </div>
  17. @if (_resources is null)
  18. {
  19. <div class="text-zinc-500"
  20. data-testid="@($"{TestId}-loading")">
  21. loading @Title.ToLower()…
  22. </div>
  23. }
  24. else if (!_resources.Any())
  25. {
  26. <div class="text-zinc-500"
  27. data-testid="@($"{TestId}-empty")">
  28. no @Title.ToLower() found
  29. </div>
  30. }
  31. else
  32. {
  33. <div class="space-y-4"
  34. data-testid="@($"{TestId}-list")">
  35. @foreach (var group in GroupResources(_resources))
  36. {
  37. var groupKey = FormatGroupKey(group.Key);
  38. <div data-testid="@($"{TestId}-group-{groupKey}")">
  39. @if (ShouldGroup)
  40. {
  41. <div class="text-xs text-zinc-500 uppercase tracking-wider mb-2"
  42. data-testid="@($"{TestId}-group-title-{groupKey}")">
  43. @DisplayGroupKey(group.Key)
  44. </div>
  45. }
  46. <div class="space-y-4"
  47. data-testid="@($"{TestId}-group-list-{groupKey}")">
  48. @foreach (var item in group)
  49. {
  50. @ItemTemplate(item)
  51. }
  52. </div>
  53. </div>
  54. }
  55. </div>
  56. }
  57. </div>
  58. @code {
  59. [Parameter] public string Title { get; set; } = default!;
  60. [Parameter] public string TestId { get; set; } = default!;
  61. [Parameter] public RenderFragment AddSection { get; set; } = default!;
  62. [Parameter] public RenderFragment<TResource> ItemTemplate { get; set; } = default!;
  63. [Parameter] public bool ShouldGroup { get; set; } = false;
  64. [Parameter] public Func<TResource, string?> GroupBy { get; set; } = (s => (string?)null);
  65. [Parameter] public EventCallback<string> OnCreated { get; set; }
  66. private IReadOnlyList<TResource>? _resources;
  67. protected override async Task OnInitializedAsync()
  68. {
  69. _resources = await Repo.GetAllOfTypeAsync<TResource>();
  70. }
  71. private IEnumerable<IGrouping<string?, TResource>> GroupResources(
  72. IEnumerable<TResource> resources)
  73. => resources
  74. .GroupBy(GroupBy)
  75. .OrderByDescending(g => g.Count());
  76. private static string FormatGroupKey(string? key)
  77. => string.IsNullOrWhiteSpace(key)
  78. ? "unassigned"
  79. : key.Replace(" ", "-");
  80. private static string DisplayGroupKey(string? key)
  81. => string.IsNullOrWhiteSpace(key)
  82. ? "Unassigned"
  83. : key;
  84. }