@using Butter.Dtos.Jobs @using Butter.Types @using MilkStream.Client.Services @inject JobsService JobsService
@((MarkupString)Icon) @Job.Name @Elapsed @if (CanCancel) { }
@if (Expanded) {
Created: @Job.Created.ToLocalTime().ToString("g") @if (Job.Started.HasValue) { Started: @Job.Started.Value.ToLocalTime().ToString("g") } @if (Job.Finished.HasValue) { Finished: @Job.Finished.Value.ToLocalTime().ToString("g") } @if (Duration is not null) { Duration: @Duration.Value.ToString(@"h\:mm\:ss") }
@if (!string.IsNullOrEmpty(Job.Message)) {
@Job.Message
}
}
@code { [Parameter] public required JobStatusDto Job { get; set; } [Parameter] public int Level { get; set; } bool Expanded; string Icon => Job.JobType switch { EJobType.FileSystemScan => "", EJobType.ThumbnailGeneration => "", EJobType.PreviewGeneration => "", EJobType.MetadataExtraction => "", EJobType.IntegrityCheck => "", EJobType.PHashGeneration => "", _ => "" }; string RowClass => Job.Status switch { EJobStatus.Completed => "", EJobStatus.Failed => "border-start border-2 border-danger", EJobStatus.Canceled => "", _ => "" }; string DotColor => Job.Status switch { EJobStatus.Queued => "#6c757d", EJobStatus.Running => "#0d6efd", EJobStatus.Waiting => "#0dcaf0", EJobStatus.Completed => "#198754", EJobStatus.Failed => "#dc3545", EJobStatus.Canceled => "#6c757d", _ => "#6c757d" }; string StatusColor => Job.Status switch { EJobStatus.Queued => "secondary", EJobStatus.Running => "primary", EJobStatus.Waiting => "info", EJobStatus.Completed => "success", EJobStatus.Failed => "danger", EJobStatus.Canceled => "secondary", _ => "secondary" }; bool CanCancel => Job.Status is EJobStatus.Queued or EJobStatus.Running or EJobStatus.Waiting; string? Elapsed { get { var now = DateTime.Now; TimeSpan? ts = Job.Status switch { EJobStatus.Queued => now - Job.Created.ToLocalTime(), EJobStatus.Running or EJobStatus.Waiting when Job.Started.HasValue => now - Job.Started.Value.ToLocalTime(), EJobStatus.Completed or EJobStatus.Failed or EJobStatus.Canceled when Job.Finished.HasValue && Job.Started.HasValue => Job.Finished.Value.ToLocalTime() - Job.Started.Value.ToLocalTime(), EJobStatus.Completed or EJobStatus.Failed or EJobStatus.Canceled when Job.Finished.HasValue => Job.Finished.Value.ToLocalTime() - Job.Created.ToLocalTime(), _ => null }; return ts switch { null => null, { TotalMinutes: < 1 } => $"{(int)ts.Value.TotalSeconds}s", { TotalHours: < 1 } => $"{(int)ts.Value.TotalMinutes}m", _ => $"{(int)ts.Value.TotalHours}h {ts.Value.Minutes}m" }; } } TimeSpan? Duration { get { if (Job.Started is null) return null; var end = Job.Finished ?? DateTime.UtcNow; return end.ToLocalTime() - Job.Started.Value.ToLocalTime(); } } async Task Toggle() { Expanded = !Expanded; } async Task Cancel() { try { await JobsService.CancelJob(Job); } catch { // Silently handle — next poll will reflect actual state } } }