@page "/tracks/mixes" @inherits CmsMediumBrowserBase @using DeepDrftModels.DTOs @using DeepDrftModels.Enums @attribute [Authorize] @inject ILogger Logger Mixes — DeepDrft CMS Back to Release Archive Mixes @if (row.HasWaveform) { } else { } @if (row.IsGenerating) { Generating… } else { @(row.HasWaveform ? "Regenerate" : "Generate") } @code { protected override ReleaseMedium Medium => ReleaseMedium.Mix; protected override string MediumNoun => "mixes"; protected override MixRow ToRow(ReleaseDto release) => new() { Release = release, HasWaveform = !string.IsNullOrEmpty(release.MixMetadata?.WaveformEntryKey) }; private async Task GenerateWaveformAsync(MixRow row) { row.IsGenerating = true; StateHasChanged(); try { var result = await CmsReleaseService.GenerateMixWaveformAsync(row.Release.Id); if (result.Success) { // Optimistic update: the trigger succeeded, so the waveform is stored. Unlike SessionBrowser's // re-fetch (which retrieves the server-generated HeroImageEntryKey), there is nothing to reflect // back here — HasWaveform is derived from WaveformEntryKey being non-null, which we know is now set. row.HasWaveform = true; Snackbar.Add($"Generated waveform for '{row.Release.Title}'.", Severity.Success); } else { var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error"; Snackbar.Add($"Waveform generation failed for '{row.Release.Title}': {error}", Severity.Error); } } catch (Exception ex) { Logger.LogError(ex, "Waveform generation failed for release {ReleaseId}", row.Release.Id); Snackbar.Add($"Waveform generation failed for '{row.Release.Title}' — please try again.", Severity.Error); } finally { row.IsGenerating = false; StateHasChanged(); } } public sealed class MixRow { public required ReleaseDto Release { get; set; } public bool HasWaveform { get; set; } public bool IsGenerating { get; set; } } }