Add dynamic operations change UI

This commit is contained in:
2025-11-05 16:59:39 +09:00
parent 05e24d4eae
commit 6e191f3676
5 changed files with 124 additions and 6 deletions

View File

@ -42,16 +42,23 @@ namespace Hcs.WebApp.BackgroundServices
{ {
var executor = executorFactory.CreateExecutor(scope, client, operation); var executor = executorFactory.CreateExecutor(scope, client, operation);
await headquartersService.SetOperationStartedAsync(operation.Id); await headquartersService.SetOperationStartedAsync(operation.Id);
state.InvokeOnOperationStarted(operation);
messageGuid = await executor.ExecuteAsync(stoppingToken); messageGuid = await executor.ExecuteAsync(stoppingToken);
} }
catch (Exception e) catch (Exception e)
{ {
await headquartersService.SetOperationEndedWithFailAsync(operation.Id, e.CombineMessages()); await headquartersService.SetOperationEndedWithFailAsync(operation.Id, e.CombineMessages());
state.InvokeOnOperationEnded(operation);
} }
if (!string.IsNullOrEmpty(messageGuid)) if (!string.IsNullOrEmpty(messageGuid))
{ {
await headquartersService.SetOperationMessageGuidAsync(operation.Id, messageGuid); await headquartersService.SetOperationMessageGuidAsync(operation.Id, messageGuid);
state.InvokeOnOperationExecuted(operation);
} }
state.UnsetProcessingOperation(operation); state.UnsetProcessingOperation(operation);

View File

@ -10,6 +10,10 @@ namespace Hcs.WebApp.BackgroundServices
public bool Ready { get; set; } public bool Ready { get; set; }
public event Action<Operation> OnOperationStarted;
public event Action<Operation> OnOperationExecuted;
public event Action<Operation> OnOperationEnded;
public void EnqueueOperation(Operation operation) public void EnqueueOperation(Operation operation)
{ {
operationsInQueue.Enqueue(operation); operationsInQueue.Enqueue(operation);
@ -34,5 +38,32 @@ namespace Hcs.WebApp.BackgroundServices
{ {
return operationsInQueue.Any(x => x.CampaignId == campaignId) || operationsInProcess.Any(x => x.CampaignId == campaignId); return operationsInQueue.Any(x => x.CampaignId == campaignId) || operationsInProcess.Any(x => x.CampaignId == campaignId);
} }
public void InvokeOnOperationStarted(Operation operation)
{
try
{
OnOperationStarted?.Invoke(operation);
}
catch { }
}
public void InvokeOnOperationExecuted(Operation operation)
{
try
{
OnOperationExecuted?.Invoke(operation);
}
catch { }
}
public void InvokeOnOperationEnded(Operation operation)
{
try
{
OnOperationEnded?.Invoke(operation);
}
catch { }
}
} }
} }

View File

@ -84,6 +84,8 @@ namespace Hcs.WebApp.BackgroundServices
await headquartersService.SetOperationEndedWithFailAsync(entry.operation.Id, e.CombineMessages()); await headquartersService.SetOperationEndedWithFailAsync(entry.operation.Id, e.CombineMessages());
entry.state.done = true; entry.state.done = true;
state.InvokeOnOperationEnded(entry.operation);
} }
entry.state.attempt++; entry.state.attempt++;
@ -93,6 +95,7 @@ namespace Hcs.WebApp.BackgroundServices
if (entry.state.done) if (entry.state.done)
{ {
state.UnsetProcessingOperation(entry.operation); state.UnsetProcessingOperation(entry.operation);
state.InvokeOnOperationEnded(entry.operation);
} }
} }

View File

@ -10,6 +10,8 @@ namespace Hcs.WebApp.BackgroundServices
public bool Ready { get; set; } public bool Ready { get; set; }
public event Action<Operation> OnOperationEnded;
public void EnqueueOperation(Operation operation) public void EnqueueOperation(Operation operation)
{ {
operationsInQueue.Enqueue(operation); operationsInQueue.Enqueue(operation);
@ -34,5 +36,14 @@ namespace Hcs.WebApp.BackgroundServices
{ {
return operationsInQueue.Any(x => x.CampaignId == campaignId) || operationsInProcess.Any(x => x.CampaignId == campaignId); return operationsInQueue.Any(x => x.CampaignId == campaignId) || operationsInProcess.Any(x => x.CampaignId == campaignId);
} }
public void InvokeOnOperationEnded(Operation operation)
{
try
{
OnOperationEnded?.Invoke(operation);
}
catch { }
}
} }
} }

View File

@ -11,6 +11,8 @@
@inject AuthenticationStateProvider AuthenticationStateProvider @inject AuthenticationStateProvider AuthenticationStateProvider
@inject HeadquartersService HeadquartersService @inject HeadquartersService HeadquartersService
@inject CampaignManagementState CampaignManagementState @inject CampaignManagementState CampaignManagementState
@inject OperationExecutionState OperationExecutionState
@inject ResultWaitState ResultWaitState
<PageTitle>Кампании</PageTitle> <PageTitle>Кампании</PageTitle>
@ -24,7 +26,7 @@
</RadzenRow> </RadzenRow>
<RadzenRow> <RadzenRow>
<RadzenColumn SizeMD="12"> <RadzenColumn SizeMD="12">
<RadzenDataGrid @ref="@dataGrid" TItem="Campaign" Data="@campaigns" RowExpand="@RowExpandAsync" IsLoading="@(state != CampaignsPageState.Idle)" AllowFiltering="true" AllowPaging="true" ShowPagingSummary="true" PageSizeOptions=@(new int[] { 5, 10, 20, 30 }) AllowSorting="true" AllowColumnResize="true" ExpandMode="DataGridExpandMode.Single"> <RadzenDataGrid @ref="@dataGrid" TItem="Campaign" Data="@campaigns" RowExpand="@RowExpandAsync" RowCollapse="@RowCollapse" IsLoading="@(state != CampaignsPageState.Idle)" AllowFiltering="true" AllowPaging="true" ShowPagingSummary="true" PageSizeOptions=@(new int[] { 5, 10, 20, 30 }) AllowSorting="true" AllowColumnResize="true" ExpandMode="DataGridExpandMode.Single">
<Template Context="campaign"> <Template Context="campaign">
<RadzenDataGrid Data="@campaign.Operations" AllowFiltering="true" AllowPaging="true" ShowPagingSummary="true" PageSizeOptions=@(new int[] { 5, 10, 20, 30 }) AllowSorting="true" AllowColumnResize="true"> <RadzenDataGrid Data="@campaign.Operations" AllowFiltering="true" AllowPaging="true" ShowPagingSummary="true" PageSizeOptions=@(new int[] { 5, 10, 20, 30 }) AllowSorting="true" AllowColumnResize="true">
<Columns> <Columns>
@ -41,7 +43,7 @@
<Columns> <Columns>
<RadzenDataGridColumn TItem="Campaign" Property="Id" Title="ID" SortOrder="SortOrder.Descending" Resizable="false" Width="100px" MaxWidth="100px" /> <RadzenDataGridColumn TItem="Campaign" Property="Id" Title="ID" SortOrder="SortOrder.Descending" Resizable="false" Width="100px" MaxWidth="100px" />
<RadzenDataGridColumn TItem="Campaign" Property="Type" Title="Тип кампании" /> <RadzenDataGridColumn TItem="Campaign" Property="Type" Title="Тип кампании" />
<RadzenDataGridColumn Title="Состояние" Filterable="false" Sortable="false" Resizable="false" Width="70px" MaxWidth="70px"> <RadzenDataGridColumn Title="Прогресс" Filterable="false" Sortable="false" Resizable="false" Width="70px" MaxWidth="70px">
<Template Context="campaign"> <Template Context="campaign">
<RadzenProgressBar ProgressBarStyle="@(campaign.EndedAt.HasValue ? (string.IsNullOrEmpty(campaign.FailureReason) ? ProgressBarStyle.Success : ProgressBarStyle.Danger) : ProgressBarStyle.Primary)" Value="@campaign.Progress" ShowValue="false" /> <RadzenProgressBar ProgressBarStyle="@(campaign.EndedAt.HasValue ? (string.IsNullOrEmpty(campaign.FailureReason) ? ProgressBarStyle.Success : ProgressBarStyle.Danger) : ProgressBarStyle.Primary)" Value="@campaign.Progress" ShowValue="false" />
</Template> </Template>
@ -88,6 +90,12 @@
CampaignManagementState.OnCampaignStarted += OnCampaignStarted; CampaignManagementState.OnCampaignStarted += OnCampaignStarted;
CampaignManagementState.OnCampaignProgressStep += OnCampaignProgressStep; CampaignManagementState.OnCampaignProgressStep += OnCampaignProgressStep;
CampaignManagementState.OnCampaignEnded += OnCampaignEnded; CampaignManagementState.OnCampaignEnded += OnCampaignEnded;
OperationExecutionState.OnOperationStarted += OnOperationStarted;
OperationExecutionState.OnOperationExecuted += OnOperationExecuted;
OperationExecutionState.OnOperationEnded += OnOperationEnded;
ResultWaitState.OnOperationEnded += OnOperationEnded;
} }
ChangeState(CampaignsPageState.Idle); ChangeState(CampaignsPageState.Idle);
@ -104,6 +112,16 @@
} }
} }
void RowCollapse(Campaign campaign)
{
if (expandedCampaign != null && expandedCampaign.Id == campaign.Id)
{
expandedCampaign = null;
}
campaign.Operations = null;
}
void ChangeState(CampaignsPageState state) void ChangeState(CampaignsPageState state)
{ {
if (this.state == state) return; if (this.state == state) return;
@ -131,8 +149,6 @@
if (expandedCampaign != null && expandedCampaign.Id == campaign.Id) if (expandedCampaign != null && expandedCampaign.Id == campaign.Id)
{ {
dataGrid.CollapseAll(); dataGrid.CollapseAll();
expandedCampaign.Operations = null;
} }
}); });
} }
@ -150,8 +166,6 @@
if (expandedCampaign != null && expandedCampaign.Id == campaign.Id) if (expandedCampaign != null && expandedCampaign.Id == campaign.Id)
{ {
dataGrid.CollapseAll(); dataGrid.CollapseAll();
expandedCampaign.Operations = null;
} }
} }
}); });
@ -162,6 +176,52 @@
Task.Run(RefreshCampaigns); Task.Run(RefreshCampaigns);
} }
void OnOperationStarted(Operation operation)
{
InvokeAsync(() =>
{
if (expandedCampaign != null && expandedCampaign.Id == operation.CampaignId)
{
var targetOperation = expandedCampaign.Operations?.FirstOrDefault(x => x.Id == operation.Id);
if (targetOperation != null)
{
targetOperation.StartedAt = operation.StartedAt;
}
}
});
}
void OnOperationExecuted(Operation operation)
{
InvokeAsync(() =>
{
if (expandedCampaign != null && expandedCampaign.Id == operation.CampaignId)
{
var targetOperation = expandedCampaign.Operations?.FirstOrDefault(x => x.Id == operation.Id);
if (targetOperation != null)
{
targetOperation.MessageGuid = operation.MessageGuid;
}
}
});
}
void OnOperationEnded(Operation operation)
{
InvokeAsync(() =>
{
if (expandedCampaign != null && expandedCampaign.Id == operation.CampaignId)
{
var targetOperation = expandedCampaign.Operations?.FirstOrDefault(x => x.Id == operation.Id);
if (targetOperation != null)
{
targetOperation.EndedAt = operation.EndedAt;
targetOperation.FailureReason = operation.FailureReason;
}
}
});
}
async Task RefreshCampaigns() async Task RefreshCampaigns()
{ {
await InvokeAsync(() => ChangeState(CampaignsPageState.Loading)); await InvokeAsync(() => ChangeState(CampaignsPageState.Loading));
@ -183,5 +243,11 @@
CampaignManagementState.OnCampaignStarted -= OnCampaignStarted; CampaignManagementState.OnCampaignStarted -= OnCampaignStarted;
CampaignManagementState.OnCampaignProgressStep -= OnCampaignProgressStep; CampaignManagementState.OnCampaignProgressStep -= OnCampaignProgressStep;
CampaignManagementState.OnCampaignEnded -= OnCampaignEnded; CampaignManagementState.OnCampaignEnded -= OnCampaignEnded;
OperationExecutionState.OnOperationStarted -= OnOperationStarted;
OperationExecutionState.OnOperationExecuted -= OnOperationExecuted;
OperationExecutionState.OnOperationEnded -= OnOperationEnded;
ResultWaitState.OnOperationEnded -= OnOperationEnded;
} }
} }