Consolidate CMS /tracks into standalone /releases page
Retire the Tracks list view; promote the Releases view to /releases with medium tabs (ALL/CUTS/SESSIONS/MIXES). Migrate bulk profile/high-res backfill and per-track waveform columns into the releases grids. Point catalogue cards at the three mediums. Remove dead BrowseMode/ViewModel.
This commit is contained in:
@@ -114,10 +114,48 @@ else
|
||||
<HeaderContent>
|
||||
<MudTh Style="width: 1%; white-space: nowrap;">#</MudTh>
|
||||
<MudTh>Track Name</MudTh>
|
||||
@* Per-track waveform-datum status + generate (migrated from the retired
|
||||
CmsTrackGrid). The expanded child row is the releases view's only
|
||||
per-track surface, so the unique per-track Profile / High-res columns
|
||||
live here. *@
|
||||
<MudTh Style="width: 1%; white-space: nowrap;">Profile</MudTh>
|
||||
<MudTh Style="width: 1%; white-space: nowrap;">High-res</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="#">@track.TrackNumber</MudTd>
|
||||
<MudTd DataLabel="Track Name">@track.TrackName</MudTd>
|
||||
<MudTd DataLabel="Profile">
|
||||
@if (HasProfile(track.EntryKey))
|
||||
{
|
||||
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" Size="Size.Small" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTooltip Text="Generate profile">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.GraphicEq"
|
||||
Size="Size.Small"
|
||||
Color="Color.Secondary"
|
||||
Disabled="@_generating.Contains(track.EntryKey)"
|
||||
OnClick="@(() => GenerateProfileAsync(track))" />
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd DataLabel="High-res">
|
||||
@if (HasHighRes(track.EntryKey))
|
||||
{
|
||||
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" Size="Size.Small" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTooltip Text="Generate high-res datum">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Waves"
|
||||
Size="Size.Small"
|
||||
Color="Color.Secondary"
|
||||
Disabled="@_generatingHighRes.Contains(track.EntryKey)"
|
||||
OnClick="@(() => GenerateHighResAsync(track))" />
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
}
|
||||
@@ -181,6 +219,101 @@ else
|
||||
[ReleaseMedium.Mix] = "DJ Mix",
|
||||
};
|
||||
|
||||
// EntryKey → HasProfile / HasHighRes for the expanded-row per-track waveform columns (migrated from
|
||||
// the retired CmsTrackGrid). Loaded once per grid instance on first row expand; a per-row generate
|
||||
// flips a single entry to true. Null until first loaded.
|
||||
private Dictionary<string, bool>? _profileStatus;
|
||||
private Dictionary<string, bool>? _highResStatus;
|
||||
private readonly HashSet<string> _generating = new();
|
||||
private readonly HashSet<string> _generatingHighRes = new();
|
||||
|
||||
private bool HasProfile(string entryKey) =>
|
||||
_profileStatus is not null && _profileStatus.TryGetValue(entryKey, out var has) && has;
|
||||
|
||||
private bool HasHighRes(string entryKey) =>
|
||||
_highResStatus is not null && _highResStatus.TryGetValue(entryKey, out var has) && has;
|
||||
|
||||
// Fetch the catalogue-wide waveform status once and cache it. The admin catalogue is small (one unpaged
|
||||
// call covers it), and per-track status only matters for rows the admin actually expands.
|
||||
private async Task EnsureWaveformStatusAsync()
|
||||
{
|
||||
if (_profileStatus is not null) return;
|
||||
|
||||
var result = await CmsTrackService.GetWaveformStatusAsync();
|
||||
if (result.Success && result.Value is not null)
|
||||
{
|
||||
_profileStatus = result.Value.ToDictionary(s => s.EntryKey, s => s.HasProfile);
|
||||
_highResStatus = result.Value.ToDictionary(s => s.EntryKey, s => s.HasHighRes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leave both empty (not null) so we do not re-fetch on every expand after a transient failure;
|
||||
// the next OnReleasesChanged refresh path will rebuild the grid and retry.
|
||||
_profileStatus = new Dictionary<string, bool>();
|
||||
_highResStatus = new Dictionary<string, bool>();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GenerateProfileAsync(TrackDto track)
|
||||
{
|
||||
_generating.Add(track.EntryKey);
|
||||
StateHasChanged();
|
||||
try
|
||||
{
|
||||
var result = await CmsTrackService.GenerateWaveformProfileAsync(track.EntryKey);
|
||||
if (result.Success)
|
||||
{
|
||||
(_profileStatus ??= new())[track.EntryKey] = true;
|
||||
Snackbar.Add($"Generated profile for '{track.TrackName}'.", Severity.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
|
||||
Snackbar.Add($"Generate failed for '{track.TrackName}': {error}", Severity.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Waveform generation failed for {EntryKey}", track.EntryKey);
|
||||
Snackbar.Add($"Generate failed for '{track.TrackName}' — please try again.", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_generating.Remove(track.EntryKey);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GenerateHighResAsync(TrackDto track)
|
||||
{
|
||||
_generatingHighRes.Add(track.EntryKey);
|
||||
StateHasChanged();
|
||||
try
|
||||
{
|
||||
var result = await CmsTrackService.GenerateHighResWaveformAsync(track.EntryKey);
|
||||
if (result.Success)
|
||||
{
|
||||
(_highResStatus ??= new())[track.EntryKey] = true;
|
||||
Snackbar.Add($"Generated high-res datum for '{track.TrackName}'.", Severity.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
|
||||
Snackbar.Add($"High-res generate failed for '{track.TrackName}': {error}", Severity.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "High-res waveform generation failed for {EntryKey}", track.EntryKey);
|
||||
Snackbar.Add($"High-res generate failed for '{track.TrackName}' — please try again.", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_generatingHighRes.Remove(track.EntryKey);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ToggleExpand(AlbumRow row)
|
||||
{
|
||||
row.IsExpanded = !row.IsExpanded;
|
||||
@@ -189,6 +322,9 @@ else
|
||||
row.IsLoading = true;
|
||||
StateHasChanged();
|
||||
row.Tracks = await LoadTracksAsync(row.Release.Title);
|
||||
// The per-track Profile / High-res columns need waveform status for the rows just loaded.
|
||||
// Loaded once for the catalogue on first expand and cached for this grid instance.
|
||||
await EnsureWaveformStatusAsync();
|
||||
row.IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user