Initial commit: JDE Scoping Tool migration project
Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
@page "/search/queue"
|
||||
@attribute [Authorize]
|
||||
@inject ISearchService SearchService
|
||||
@inject IHubConnectionService HubConnection
|
||||
@implements IDisposable
|
||||
|
||||
<PageTitle>Search Queue - JDE Scoping Tool</PageTitle>
|
||||
|
||||
<RadzenText TextStyle="TextStyle.H4" class="rz-mb-4">Search Queue</RadzenText>
|
||||
|
||||
<!-- Processor Status Panel -->
|
||||
<RadzenCard class="rz-mb-4">
|
||||
<RadzenText TextStyle="TextStyle.H6" class="rz-mb-3">Search Processor Status</RadzenText>
|
||||
|
||||
<RadzenRow Gap="1rem">
|
||||
<RadzenColumn Size="8">
|
||||
<RadzenFormField Text="Status Message" Style="width: 100%;">
|
||||
<RadzenTextBox Value="@_statusMessage" ReadOnly="true" Style="width: 100%;" />
|
||||
</RadzenFormField>
|
||||
</RadzenColumn>
|
||||
<RadzenColumn Size="4">
|
||||
<RadzenFormField Text="Last Update Timestamp" Style="width: 100%;">
|
||||
<RadzenTextBox Value="@_statusUpdateDt" ReadOnly="true" Style="width: 100%;" />
|
||||
</RadzenFormField>
|
||||
</RadzenColumn>
|
||||
</RadzenRow>
|
||||
</RadzenCard>
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<LoadingIndicator Message="Loading queue..." />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenDataGrid @ref="_grid" Data="@_searches" TItem="ClientSearchViewModel" AllowSorting="true" AllowPaging="true" PageSize="20"
|
||||
PagerHorizontalAlign="HorizontalAlign.Center" AllowColumnResize="true">
|
||||
<Columns>
|
||||
<RadzenDataGridColumn TItem="ClientSearchViewModel" Property="UserName" Title="Owner" Width="150px" />
|
||||
<RadzenDataGridColumn TItem="ClientSearchViewModel" Property="Name" Title="Name" />
|
||||
<RadzenDataGridColumn TItem="ClientSearchViewModel" Property="SubmitDT" Title="Submitted" Width="180px">
|
||||
<Template Context="search">
|
||||
@(search.SubmitDt?.ToString("MM/dd/yyyy hh:mm:ss tt") ?? "")
|
||||
</Template>
|
||||
</RadzenDataGridColumn>
|
||||
<RadzenDataGridColumn TItem="ClientSearchViewModel" Property="StartDT" Title="Started" Width="180px">
|
||||
<Template Context="search">
|
||||
@(search.StartDt?.ToString("MM/dd/yyyy hh:mm:ss tt") ?? "")
|
||||
</Template>
|
||||
</RadzenDataGridColumn>
|
||||
<RadzenDataGridColumn TItem="ClientSearchViewModel" Property="EndDT" Title="Ended" Width="180px">
|
||||
<Template Context="search">
|
||||
@(search.EndDt?.ToString("MM/dd/yyyy hh:mm:ss tt") ?? "")
|
||||
</Template>
|
||||
</RadzenDataGridColumn>
|
||||
<RadzenDataGridColumn TItem="ClientSearchViewModel" Property="Status" Title="Status" Width="100px">
|
||||
<Template Context="search">
|
||||
<RadzenBadge BadgeStyle="@GetBadgeStyle(search.Status)" Text="@search.Status" />
|
||||
</Template>
|
||||
</RadzenDataGridColumn>
|
||||
</Columns>
|
||||
</RadzenDataGrid>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<ClientSearchViewModel> _searches = [];
|
||||
private RadzenDataGrid<ClientSearchViewModel>? _grid;
|
||||
private bool _isLoading = true;
|
||||
|
||||
private string _statusMessage = "";
|
||||
private string _statusUpdateDt = "";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadQueueAsync();
|
||||
await SetupSignalRAsync();
|
||||
}
|
||||
|
||||
private async Task LoadQueueAsync()
|
||||
{
|
||||
_isLoading = true;
|
||||
try
|
||||
{
|
||||
_searches = await SearchService.GetQueueAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetupSignalRAsync()
|
||||
{
|
||||
HubConnection.OnSearchUpdate += HandleSearchUpdate;
|
||||
HubConnection.OnStatusUpdate += HandleStatusUpdate;
|
||||
await HubConnection.StartAsync();
|
||||
|
||||
// Get cached status
|
||||
var cachedStatus = await HubConnection.GetCachedStatusAsync();
|
||||
if (cachedStatus != null)
|
||||
{
|
||||
HandleStatusUpdate(cachedStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSearchUpdate(SearchUpdate update)
|
||||
{
|
||||
InvokeAsync(() =>
|
||||
{
|
||||
if (update.Status == "Ended" || update.Status == "Error")
|
||||
{
|
||||
// Remove completed/errored searches from queue
|
||||
var existing = _searches.FirstOrDefault(s => s.Id == update.Id);
|
||||
if (existing != null)
|
||||
{
|
||||
_searches.Remove(existing);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update or add the search
|
||||
var existing = _searches.FirstOrDefault(s => s.Id == update.Id);
|
||||
if (existing != null)
|
||||
{
|
||||
existing.Status = update.Status;
|
||||
existing.SubmitDt = update.SubmitDt;
|
||||
existing.StartDt = update.StartDt;
|
||||
existing.EndDt = update.EndDt;
|
||||
}
|
||||
else
|
||||
{
|
||||
_searches.Add(new ClientSearchViewModel
|
||||
{
|
||||
Id = update.Id,
|
||||
Name = update.Name,
|
||||
UserName = update.UserName,
|
||||
Status = update.Status,
|
||||
SubmitDt = update.SubmitDt,
|
||||
StartDt = update.StartDt,
|
||||
EndDt = update.EndDt
|
||||
});
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
private void HandleStatusUpdate(StatusUpdate update)
|
||||
{
|
||||
InvokeAsync(() =>
|
||||
{
|
||||
_statusMessage = update.Message;
|
||||
_statusUpdateDt = update.Timestamp?.ToString("MM/dd/yyyy hh:mm:ss tt") ?? "";
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
private static BadgeStyle GetBadgeStyle(string status) => status switch
|
||||
{
|
||||
"Error" => BadgeStyle.Danger,
|
||||
"Ended" => BadgeStyle.Success,
|
||||
"Running" => BadgeStyle.Info,
|
||||
"Queued" => BadgeStyle.Warning,
|
||||
_ => BadgeStyle.Light
|
||||
};
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
HubConnection.OnSearchUpdate -= HandleSearchUpdate;
|
||||
HubConnection.OnStatusUpdate -= HandleStatusUpdate;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user