Refactor job sorting logic, reduce poll interval, and implement SignalR subscriptions for real-time updates in DataInbox and Layers pages
All checks were successful
Build Docker Images / test (map[name:Morska plugin_project:DiunaBI.Plugins.Morska]) (push) Successful in 1m28s
Build Docker Images / test (map[name:PedrolloPL plugin_project:DiunaBI.Plugins.PedrolloPL]) (push) Successful in 1m26s
Build Docker Images / build-and-push (map[image_suffix:morska name:Morska plugin_project:DiunaBI.Plugins.Morska]) (push) Successful in 1m38s
Build Docker Images / build-and-push (map[image_suffix:pedrollopl name:PedrolloPL plugin_project:DiunaBI.Plugins.PedrolloPL]) (push) Successful in 1m38s

This commit is contained in:
2025-12-08 23:08:46 +01:00
parent 151ecaa98f
commit dffbc31432
9 changed files with 95 additions and 13 deletions

View File

@@ -71,11 +71,10 @@ public class JobsController : Controller
var totalCount = await query.CountAsync();
// Sort by: Priority ASC (0=highest), JobType, then CreatedAt DESC
// Sort by: CreatedAt DESC (newest first), then Priority ASC (0=highest)
var items = await query
.OrderBy(j => j.Priority)
.ThenBy(j => j.JobType)
.ThenByDescending(j => j.CreatedAt)
.OrderByDescending(j => j.CreatedAt)
.ThenBy(j => j.Priority)
.Skip(start)
.Take(limit)
.AsNoTracking()

View File

@@ -11,7 +11,7 @@ public class JobWorkerService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<JobWorkerService> _logger;
private readonly TimeSpan _pollInterval = TimeSpan.FromSeconds(10);
private readonly TimeSpan _pollInterval = TimeSpan.FromSeconds(5);
private readonly TimeSpan _rateLimitDelay = TimeSpan.FromSeconds(5);
public JobWorkerService(IServiceProvider serviceProvider, ILogger<JobWorkerService> logger)

View File

@@ -1,6 +1,7 @@
@page "/datainbox"
@using MudBlazor.Internal
@using DiunaBI.Application.DTOModels
@implements IDisposable
<PageTitle>Data Inbox</PageTitle>

View File

@@ -8,9 +8,10 @@ using Microsoft.JSInterop;
namespace DiunaBI.UI.Shared.Pages.DataInbox;
public partial class Index : ComponentBase
public partial class Index : ComponentBase, IDisposable
{
[Inject] private DataInboxService DataInboxService { 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 DataInboxFilterStateService FilterStateService { get; set; } = default!;
@@ -27,6 +28,22 @@ public partial class Index : ComponentBase
await DateTimeHelper.InitializeAsync();
filterRequest = FilterStateService.FilterRequest;
await LoadDataInbox();
// Subscribe to SignalR entity changes
HubService.EntityChanged += OnEntityChanged;
}
private async void OnEntityChanged(string module, string id, string operation)
{
// Only react if it's a DataInbox change
if (module.Equals("DataInbox", StringComparison.OrdinalIgnoreCase))
{
await InvokeAsync(async () =>
{
await LoadDataInbox();
StateHasChanged();
});
}
}
private async Task LoadDataInbox()
@@ -77,4 +94,9 @@ public partial class Index : ComponentBase
var url = NavigationManager.ToAbsoluteUri($"/datainbox/{dataInboxItem.Id}").ToString();
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
}
public void Dispose()
{
HubService.EntityChanged -= OnEntityChanged;
}
}

View File

@@ -69,11 +69,6 @@
</MudMenuItem>
</MudMenu>
<MudIconButton Icon="@Icons.Material.Filled.Refresh"
OnClick="LoadJobs"
Color="Color.Primary"
Size="Size.Medium"
Title="Refresh"/>
<MudIconButton Icon="@Icons.Material.Filled.Clear"
OnClick="ClearFilters"
Color="Color.Default"

View File

@@ -2,6 +2,7 @@
@using DiunaBI.UI.Shared.Services
@using DiunaBI.Application.DTOModels
@using MudBlazor
@implements IDisposable
<MudCard>
<MudCardHeader>

View File

@@ -6,7 +6,7 @@ using System.Reflection;
namespace DiunaBI.UI.Shared.Pages.Layers;
public partial class Details : ComponentBase
public partial class Details : ComponentBase, IDisposable
{
[Parameter]
public Guid Id { get; set; }
@@ -20,6 +20,9 @@ public partial class Details : ComponentBase
[Inject]
private JobService JobService { get; set; } = null!;
[Inject]
private EntityChangeHubService HubService { get; set; } = null!;
[Inject]
private NavigationManager NavigationManager { get; set; } = null!;
@@ -57,6 +60,39 @@ public partial class Details : ComponentBase
{
await DateTimeHelper.InitializeAsync();
await LoadLayer();
// Subscribe to SignalR entity changes
HubService.EntityChanged += OnEntityChanged;
}
private async void OnEntityChanged(string module, string id, string operation)
{
// React to Layers or Records changes for this layer
if (module.Equals("Layers", StringComparison.OrdinalIgnoreCase) ||
module.Equals("Records", StringComparison.OrdinalIgnoreCase))
{
// Check if it's this layer or its records that changed
if (Guid.TryParse(id, out var changedId))
{
if (module.Equals("Layers", StringComparison.OrdinalIgnoreCase) && changedId == Id)
{
await InvokeAsync(async () =>
{
await LoadLayer();
StateHasChanged();
});
}
else if (module.Equals("Records", StringComparison.OrdinalIgnoreCase))
{
// For records, we reload to get the latest data
await InvokeAsync(async () =>
{
await LoadLayer();
StateHasChanged();
});
}
}
}
}
protected override async Task OnParametersSetAsync()
@@ -495,4 +531,9 @@ public partial class Details : ComponentBase
isRunningJob = false;
}
}
public void Dispose()
{
HubService.EntityChanged -= OnEntityChanged;
}
}

View File

@@ -1,6 +1,7 @@
@page "/layers"
@using MudBlazor.Internal
@using DiunaBI.Application.DTOModels
@implements IDisposable
<PageTitle>Layers</PageTitle>

View File

@@ -8,9 +8,10 @@ using Microsoft.JSInterop;
namespace DiunaBI.UI.Shared.Pages.Layers;
public partial class Index : ComponentBase
public partial class Index : ComponentBase, IDisposable
{
[Inject] private LayerService LayerService { 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 LayerFilterStateService FilterStateService { get; set; } = default!;
@@ -25,6 +26,22 @@ public partial class Index : ComponentBase
{
filterRequest = FilterStateService.FilterRequest;
await LoadLayers();
// Subscribe to SignalR entity changes
HubService.EntityChanged += OnEntityChanged;
}
private async void OnEntityChanged(string module, string id, string operation)
{
// Only react if it's a Layers change
if (module.Equals("Layers", StringComparison.OrdinalIgnoreCase))
{
await InvokeAsync(async () =>
{
await LoadLayers();
StateHasChanged();
});
}
}
private async Task LoadLayers()
@@ -89,4 +106,9 @@ public partial class Index : ComponentBase
var url = NavigationManager.ToAbsoluteUri($"/layers/{layer.Id}").ToString();
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
}
public void Dispose()
{
HubService.EntityChanged -= OnEntityChanged;
}
}