@page "/tracks/sessions" @using DeepDrftManager.Services @using DeepDrftModels.DTOs @using DeepDrftModels.Enums @using Microsoft.AspNetCore.Components.Forms @attribute [Authorize] @inject ICmsReleaseService CmsReleaseService @inject ISnackbar Snackbar @inject ILogger Logger @inject NavigationManager Navigation Sessions — DeepDrft CMS Back to Release Archive Sessions @if (_loading) { } else if (_rows.Count == 0) { No sessions found. } else { Cover Hero Session Artist Actions @if (!string.IsNullOrEmpty(context.Release.ImagePath)) {
} else {
}
@if (context.HeroImageEntryKey is { Length: > 0 } heroKey) {
} else {
}
@context.Release.Title @context.Release.Artist @if (context.IsUploading) { Uploading… } else { @(context.HeroImageEntryKey is { Length: > 0 } ? "Replace hero" : "Set hero") }
}
@code { private List _rows = new(); private bool _loading = true; protected override async Task OnInitializedAsync() => await LoadAsync(); private async Task LoadAsync() { _loading = true; // Sessions are single-track releases; a single generous page covers the CMS catalogue (same // small-catalogue assumption the album browser makes). var result = await CmsReleaseService.GetPagedAsync( ReleaseMedium.Session, page: 1, pageSize: 100, sortColumn: "Title", sortDescending: false); if (result.Success && result.Value is not null) { _rows = result.Value.Items .Select(r => new SessionRow { Release = r, HeroImageEntryKey = r.SessionMetadata?.HeroImageEntryKey }) .ToList(); } else { var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error"; Snackbar.Add($"Failed to load sessions: {error}", Severity.Error); _rows = new List(); } _loading = false; } // Relative path — resolves against the Manager's own origin, proxied by ImageProxyController. private static string ThumbUrl(string entryKey) => $"/api/image/{Uri.EscapeDataString(entryKey)}"; private async Task UploadHeroAsync(SessionRow row, IBrowserFile? file) { if (file is null) return; row.IsUploading = true; StateHasChanged(); try { await using var stream = file.OpenReadStream(maxAllowedSize: 50_000_000); var result = await CmsReleaseService.UploadSessionHeroImageAsync( row.Release.Id, stream, file.Name, file.ContentType); if (result.Success) { // The endpoint returns no payload; the entry key is server-generated. Re-fetch the // release so the hero thumbnail reflects the new key without guessing it. var refreshed = await CmsReleaseService.GetByIdAsync(row.Release.Id); if (refreshed.Success && refreshed.Value is { } release) { row.Release = release; row.HeroImageEntryKey = release.SessionMetadata?.HeroImageEntryKey; } Snackbar.Add($"Hero image set for '{row.Release.Title}'.", Severity.Success); } else { var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error"; Snackbar.Add($"Hero image upload failed: {error}", Severity.Error); } } catch (Exception ex) { Logger.LogError(ex, "Hero image upload failed for release {ReleaseId}", row.Release.Id); Snackbar.Add("Hero image upload failed — please try again.", Severity.Error); } finally { row.IsUploading = false; StateHasChanged(); } } private sealed class SessionRow { public required ReleaseDto Release { get; set; } public string? HeroImageEntryKey { get; set; } public bool IsUploading { get; set; } } }