ResourcesListComponent.razor 3.2 KB

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