feat: normalize release-cardinal fields out of track into a Release entity (Phase 8 §8.0)
This commit is contained in:
@@ -63,7 +63,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await CmsTrackService.GetAlbumSummariesAsync();
|
||||
var result = await CmsTrackService.GetReleasesAsync();
|
||||
_albumCount = result.Success && result.Value is not null ? result.Value.Count : null;
|
||||
if (!result.Success)
|
||||
{
|
||||
|
||||
@@ -264,7 +264,7 @@
|
||||
|
||||
var confirmed = await DialogService.ShowMessageBox(
|
||||
"Delete track",
|
||||
$"Permanently delete \"{_track.TrackName}\" by {_track.Artist}? This cannot be undone.",
|
||||
$"Permanently delete \"{_track.TrackName}\" by {_track.Release?.Artist ?? "Unknown"}? This cannot be undone.",
|
||||
yesText: "Delete",
|
||||
cancelText: "Cancel");
|
||||
|
||||
@@ -310,14 +310,14 @@
|
||||
public static TrackEditForm From(TrackDto track) => new()
|
||||
{
|
||||
TrackName = track.TrackName,
|
||||
Artist = track.Artist,
|
||||
Album = track.Album,
|
||||
Genre = track.Genre,
|
||||
ImagePath = track.ImagePath,
|
||||
ReleaseDate = track.ReleaseDate is { } d
|
||||
Artist = track.Release?.Artist ?? string.Empty,
|
||||
Album = track.Release?.Title,
|
||||
Genre = track.Release?.Genre,
|
||||
ImagePath = track.Release?.ImagePath,
|
||||
ReleaseDate = track.Release?.ReleaseDate is { } d
|
||||
? d.ToDateTime(TimeOnly.MinValue)
|
||||
: null,
|
||||
ReleaseType = track.ReleaseType,
|
||||
ReleaseType = track.Release?.ReleaseType ?? ReleaseType.Single,
|
||||
TrackNumber = track.TrackNumber
|
||||
};
|
||||
}
|
||||
|
||||
@@ -52,10 +52,10 @@
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="Track Name">@context.TrackName</MudTd>
|
||||
<MudTd DataLabel="Artist">@context.Artist</MudTd>
|
||||
<MudTd DataLabel="Album">@(context.Album ?? "—")</MudTd>
|
||||
<MudTd DataLabel="Genre">@(context.Genre ?? "—")</MudTd>
|
||||
<MudTd DataLabel="Release Date">@(context.ReleaseDate?.ToString("yyyy-MM-dd") ?? "—")</MudTd>
|
||||
<MudTd DataLabel="Artist">@(context.Release?.Artist ?? "—")</MudTd>
|
||||
<MudTd DataLabel="Album">@(context.Release?.Title ?? "—")</MudTd>
|
||||
<MudTd DataLabel="Genre">@(context.Release?.Genre ?? "—")</MudTd>
|
||||
<MudTd DataLabel="Release Date">@(context.Release?.ReleaseDate?.ToString("yyyy-MM-dd") ?? "—")</MudTd>
|
||||
<MudTd DataLabel="Entry Key"><MudText Typo="Typo.caption" Style="font-family: monospace;">@context.EntryKey</MudText></MudTd>
|
||||
<MudTd DataLabel="File Name"><MudText Typo="Typo.caption" Style="font-family: monospace;">@(context.OriginalFileName ?? "—")</MudText></MudTd>
|
||||
<MudTd DataLabel="Actions">
|
||||
@@ -216,7 +216,7 @@
|
||||
{
|
||||
var confirmed = await DialogService.ShowMessageBox(
|
||||
title: "Delete track",
|
||||
markupMessage: new MarkupString($"Delete <strong>{WebUtility.HtmlEncode(track.TrackName)}</strong> by {WebUtility.HtmlEncode(track.Artist)}? This removes both the metadata row and the underlying audio entry."),
|
||||
markupMessage: new MarkupString($"Delete <strong>{WebUtility.HtmlEncode(track.TrackName)}</strong> by {WebUtility.HtmlEncode(track.Release?.Artist ?? "Unknown")}? This removes both the metadata row and the underlying audio entry."),
|
||||
yesText: "Delete",
|
||||
cancelText: "Cancel");
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@ public class CmsTrackService : ICmsTrackService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ResultContainer<List<AlbumSummaryDto>>> GetAlbumSummariesAsync(CancellationToken ct = default)
|
||||
public async Task<ResultContainer<List<ReleaseDto>>> GetReleasesAsync(CancellationToken ct = default)
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient(ContentCmsClientName);
|
||||
|
||||
@@ -461,36 +461,36 @@ public class CmsTrackService : ICmsTrackService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Content API call failed for album summaries");
|
||||
return ResultContainer<List<AlbumSummaryDto>>.CreateFailResult("Content API is unreachable.");
|
||||
_logger.LogError(ex, "Content API call failed for releases");
|
||||
return ResultContainer<List<ReleaseDto>>.CreateFailResult("Content API is unreachable.");
|
||||
}
|
||||
|
||||
using (response)
|
||||
{
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
_logger.LogError("Content API album summaries failed: {Status}", (int)response.StatusCode);
|
||||
return ResultContainer<List<AlbumSummaryDto>>.CreateFailResult("Failed to load albums.");
|
||||
_logger.LogError("Content API releases failed: {Status}", (int)response.StatusCode);
|
||||
return ResultContainer<List<ReleaseDto>>.CreateFailResult("Failed to load albums.");
|
||||
}
|
||||
|
||||
List<AlbumSummaryDto>? albums;
|
||||
List<ReleaseDto>? releases;
|
||||
try
|
||||
{
|
||||
albums = await response.Content.ReadFromJsonAsync<List<AlbumSummaryDto>>(ct);
|
||||
releases = await response.Content.ReadFromJsonAsync<List<ReleaseDto>>(ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to deserialize album summaries from Content API response");
|
||||
return ResultContainer<List<AlbumSummaryDto>>.CreateFailResult("Content API returned an unexpected response.");
|
||||
_logger.LogError(ex, "Failed to deserialize releases from Content API response");
|
||||
return ResultContainer<List<ReleaseDto>>.CreateFailResult("Content API returned an unexpected response.");
|
||||
}
|
||||
|
||||
if (albums is null)
|
||||
if (releases is null)
|
||||
{
|
||||
_logger.LogError("Content API returned a null album summaries list");
|
||||
return ResultContainer<List<AlbumSummaryDto>>.CreateFailResult("Content API returned an empty response.");
|
||||
_logger.LogError("Content API returned a null releases list");
|
||||
return ResultContainer<List<ReleaseDto>>.CreateFailResult("Content API returned an empty response.");
|
||||
}
|
||||
|
||||
return ResultContainer<List<AlbumSummaryDto>>.CreatePassResult(albums);
|
||||
return ResultContainer<List<ReleaseDto>>.CreatePassResult(releases);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,8 +88,8 @@ public interface ICmsTrackService
|
||||
/// </summary>
|
||||
Task<Result> GenerateWaveformProfileAsync(string entryKey, CancellationToken ct = default);
|
||||
|
||||
/// <summary>Returns all distinct albums with track counts from GET api/track/albums.</summary>
|
||||
Task<ResultContainer<List<AlbumSummaryDto>>> GetAlbumSummariesAsync(CancellationToken ct = default);
|
||||
/// <summary>Returns all releases with track counts from GET api/track/albums.</summary>
|
||||
Task<ResultContainer<List<ReleaseDto>>> GetReleasesAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>Returns all distinct genres with track counts from GET api/track/genres.</summary>
|
||||
Task<ResultContainer<List<GenreSummaryDto>>> GetGenreSummariesAsync(CancellationToken ct = default);
|
||||
|
||||
Reference in New Issue
Block a user