using DiunaBI.UI.Shared.Services; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using DiunaBI.Application.DTOModels.Common; using DiunaBI.Domain.Entities; using MudBlazor; using Microsoft.JSInterop; namespace DiunaBI.UI.Shared.Pages.Jobs; public partial class Index : ComponentBase, IDisposable { [Inject] private JobService JobService { get; set; } = default!; [Inject] private EntityChangeHubService HubService { get; set; } = default!; [Inject] private ISnackbar Snackbar { get; set; } = default!; [Inject] private NavigationManager NavigationManager { get; set; } = default!; [Inject] private IJSRuntime JSRuntime { get; set; } = default!; [Inject] private DateTimeHelper DateTimeHelper { get; set; } = default!; private PagedResult jobs = new(); private bool isLoading = false; private int currentPage = 1; private int pageSize = 50; private IEnumerable selectedStatuses = new HashSet(); private JobType? selectedJobType = null; protected override async Task OnInitializedAsync() { await DateTimeHelper.InitializeAsync(); await LoadJobs(); // Subscribe to SignalR entity changes HubService.EntityChanged += OnEntityChanged; } private async void OnEntityChanged(string module, string id, string operation) { Console.WriteLine($"🔔 JobListComponent.OnEntityChanged called: module={module}, id={id}, operation={operation}"); // Only react if it's a QueueJobs change if (module.Equals("QueueJobs", StringComparison.OrdinalIgnoreCase)) { Console.WriteLine($"📨 Job {id} changed, refreshing job list"); await InvokeAsync(async () => { Console.WriteLine($"🔄 LoadJobs starting..."); await LoadJobs(); Console.WriteLine($"🔄 StateHasChanged calling..."); StateHasChanged(); Console.WriteLine($"✅ Job list refresh complete"); }); } else { Console.WriteLine($"⏭️ Skipping - module '{module}' is not QueueJobs"); } } private async Task LoadJobs() { isLoading = true; try { var statusList = selectedStatuses?.ToList(); jobs = await JobService.GetJobsAsync(currentPage, pageSize, statusList, selectedJobType); } catch (Exception ex) { Console.WriteLine($"Loading jobs failed: {ex.Message}"); Snackbar.Add("Failed to load jobs", Severity.Error); } finally { isLoading = false; } } private async Task OnPageChanged(int page) { currentPage = page; await LoadJobs(); } private async Task ClearFilters() { selectedStatuses = new HashSet(); selectedJobType = null; currentPage = 1; await LoadJobs(); } private async Task OnStatusFilterChanged(IEnumerable values) { selectedStatuses = values; currentPage = 1; await LoadJobs(); } private async Task OnJobTypeFilterChanged(JobType? value) { selectedJobType = value; currentPage = 1; await LoadJobs(); } private async Task OnStatusClear() { selectedStatuses = new HashSet(); currentPage = 1; await LoadJobs(); } private async Task OnJobTypeClear() { selectedJobType = null; currentPage = 1; await LoadJobs(); } private void OnRowClick(QueueJob job) { NavigationManager.NavigateTo($"/jobs/{job.Id}"); } private async Task OnRowRightClick(MouseEventArgs e, QueueJob job) { var url = NavigationManager.ToAbsoluteUri($"/jobs/{job.Id}").ToString(); await JSRuntime.InvokeVoidAsync("open", url, "_blank"); } private async Task ScheduleJobs(string type) { isLoading = true; try { (bool success, int jobsCreated, string message) result = type switch { "all" => await JobService.ScheduleAllJobsAsync(), "imports" => await JobService.ScheduleImportJobsAsync(), "processes" => await JobService.ScheduleProcessJobsAsync(), _ => (false, 0, "Unknown job type") }; if (result.success) { Snackbar.Add($"{result.message} ({result.jobsCreated} jobs created)", Severity.Success); await LoadJobs(); } else { Snackbar.Add(result.message, Severity.Error); } } catch (Exception ex) { Console.WriteLine($"Scheduling jobs failed: {ex.Message}"); Snackbar.Add($"Failed to schedule jobs: {ex.Message}", Severity.Error); } finally { isLoading = false; } } private Color GetStatusColor(JobStatus status) { return status switch { JobStatus.Pending => Color.Default, JobStatus.Running => Color.Info, JobStatus.Completed => Color.Success, JobStatus.Failed => Color.Error, JobStatus.Retrying => Color.Warning, _ => Color.Default }; } private Color GetJobTypeColor(JobType jobType) { return jobType switch { JobType.Import => Color.Primary, JobType.Process => Color.Secondary, _ => Color.Default }; } public void Dispose() { HubService.EntityChanged -= OnEntityChanged; } }