Add Edit action to medium browsers; extract CmsMediumBrowserBase + CmsMediumTable
Session/Mix browsers share base (load/state/thumb) and a shared table shell carrying the per-row Edit link to BatchEdit; subclasses supply only their medium action.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
using DeepDrftManager.Services;
|
||||
using DeepDrftModels.DTOs;
|
||||
using DeepDrftModels.Enums;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
namespace DeepDrftManager.Components.Pages.Tracks;
|
||||
|
||||
/// <summary>
|
||||
/// Shared fetch + state logic for the single-track medium browsers (Sessions, Mixes). Analogous to the
|
||||
/// public-site <c>MediumBrowseBase</c>: subclasses supply the <see cref="Medium"/>, the noun used in
|
||||
/// error text, and a per-row projection from <see cref="ReleaseDto"/> to their own row model; this base
|
||||
/// owns the loading flag, the row list, the initial load, and the cover-thumbnail URL helper. The shared
|
||||
/// table structure lives in <c>CmsMediumTable</c>; subclasses render it and fill only the action column.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRow">The subclass's row model wrapping a <see cref="ReleaseDto"/>.</typeparam>
|
||||
public abstract class CmsMediumBrowserBase<TRow> : ComponentBase
|
||||
{
|
||||
[Inject] public required ICmsReleaseService CmsReleaseService { get; set; }
|
||||
[Inject] public required ISnackbar Snackbar { get; set; }
|
||||
|
||||
/// <summary>The medium this browser lists. Subclass-supplied constant.</summary>
|
||||
protected abstract ReleaseMedium Medium { get; }
|
||||
|
||||
/// <summary>Plural noun for this medium used in error text (e.g. "sessions", "mixes").</summary>
|
||||
protected abstract string MediumNoun { get; }
|
||||
|
||||
/// <summary>Projects a fetched release into the subclass's row model.</summary>
|
||||
protected abstract TRow ToRow(ReleaseDto release);
|
||||
|
||||
protected List<TRow> Rows { get; private set; } = new();
|
||||
protected bool Loading { get; private set; } = true;
|
||||
|
||||
protected override async Task OnInitializedAsync() => await LoadAsync();
|
||||
|
||||
private async Task LoadAsync()
|
||||
{
|
||||
Loading = true;
|
||||
// Single-track releases; a single generous page covers the CMS catalogue (same small-catalogue
|
||||
// assumption the album browser makes).
|
||||
var result = await CmsReleaseService.GetPagedAsync(
|
||||
Medium, page: 1, pageSize: 100,
|
||||
sortColumn: "Title", sortDescending: false);
|
||||
|
||||
if (result.Success && result.Value is not null)
|
||||
{
|
||||
Rows = result.Value.Items.Select(ToRow).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
|
||||
Snackbar.Add($"Failed to load {MediumNoun}: {error}", Severity.Error);
|
||||
Rows = new List<TRow>();
|
||||
}
|
||||
|
||||
Loading = false;
|
||||
}
|
||||
|
||||
// Relative path — resolves against the Manager's own origin, proxied by ImageProxyController.
|
||||
protected static string ThumbUrl(string entryKey) =>
|
||||
$"/api/image/{Uri.EscapeDataString(entryKey)}";
|
||||
}
|
||||
Reference in New Issue
Block a user