ResourcesListComponent.razor 3.4 KB

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