fix(cms): gate Session hero input to upload path; warn (not error) on missing hero

Edit forms (BatchEdit/TrackEdit/TrackNew) show the guidance alert instead of an
inert picker, via an AllowHeroUpload flag. Missing-hero nudge is Severity.Warning;
null-ReleaseId hero drop is now logged.
This commit is contained in:
daniel-c-harvey
2026-06-13 20:55:34 -04:00
parent 4701804594
commit 62dd9d5c03
4 changed files with 81 additions and 36 deletions
@@ -27,6 +27,7 @@
MediumChanged="OnMediumChanged"
@bind-SelectedImageFile="_selectedImageFile"
@bind-HeroImageFile="_heroImageFile"
AllowHeroUpload="true"
Disabled="_uploading" />
@if (_medium == ReleaseMedium.Cut)
@@ -72,6 +73,11 @@
<MudAlert Severity="Severity.Error" Class="mt-4">@_errorMessage</MudAlert>
}
@if (!string.IsNullOrEmpty(_warningMessage))
{
<MudAlert Severity="Severity.Warning" Class="mt-4">@_warningMessage</MudAlert>
}
<MudStack Row="true" Justify="Justify.FlexEnd" Spacing="2" Class="mt-4">
<MudButton Variant="Variant.Text"
OnClick="@(() => Navigation.NavigateTo("/tracks"))"
@@ -105,6 +111,8 @@
private bool _uploading;
private int _uploadedCount;
private string? _errorMessage;
// Separate from _errorMessage: a soft non-blocking nudge (Severity.Warning), not a hard failure.
private string? _warningMessage;
private IBrowserFile? _selectedImageFile;
private string? _imagePath;
@@ -205,6 +213,7 @@
private async Task SubmitAsync()
{
_errorMessage = null;
_warningMessage = null;
if (string.IsNullOrWhiteSpace(_albumName))
{
@@ -258,7 +267,7 @@
if (_medium == ReleaseMedium.Session && _heroImageFile is null && !_heroWarningAcknowledged)
{
_heroWarningAcknowledged = true;
_errorMessage = "No hero image selected. A Session usually needs one — you can add it now, "
_warningMessage = "No hero image selected. A Session usually needs one — you can add it now, "
+ "or submit again to create the Session without it (set the hero later from the Sessions browser).";
return;
}
@@ -382,6 +391,15 @@
Snackbar.Add("Session uploaded, but the hero image failed. Set it from the Sessions browser.", Severity.Warning);
}
}
else if (_medium == ReleaseMedium.Session && _heroImageFile is not null)
{
// ReleaseId was null on a Session track result — internal inconsistency.
// Hero file is held but cannot be uploaded without a release id; log and
// surface so the admin can set it from the Sessions browser.
Logger.LogWarning("Batch upload: Session track '{TrackName}' (id={Id}) has no ReleaseId — hero image dropped",
row.TrackName, result.Value.Id);
Snackbar.Add("Session uploaded, but the hero image could not be linked (no release id). Set it from the Sessions browser.", Severity.Warning);
}
// Mix uploads fire the server-side high-res waveform trigger (§3.4). The CMS
// computes nothing — the API derives the datum from the audio it just stored.