UI refactor (structure cleanup)
Some checks failed
Build Docker Images / test (map[name:Morska plugin_project:DiunaBI.Plugins.Morska]) (push) Failing after 1m18s
Build Docker Images / test (map[name:PedrolloPL plugin_project:DiunaBI.Plugins.PedrolloPL]) (push) Failing after 1m18s
Build Docker Images / build-and-push (map[image_suffix:morska name:Morska plugin_project:DiunaBI.Plugins.Morska]) (push) Failing after 1m38s
Build Docker Images / build-and-push (map[image_suffix:pedrollopl name:PedrolloPL plugin_project:DiunaBI.Plugins.PedrolloPL]) (push) Failing after 1m37s
Some checks failed
Build Docker Images / test (map[name:Morska plugin_project:DiunaBI.Plugins.Morska]) (push) Failing after 1m18s
Build Docker Images / test (map[name:PedrolloPL plugin_project:DiunaBI.Plugins.PedrolloPL]) (push) Failing after 1m18s
Build Docker Images / build-and-push (map[image_suffix:morska name:Morska plugin_project:DiunaBI.Plugins.Morska]) (push) Failing after 1m38s
Build Docker Images / build-and-push (map[image_suffix:pedrollopl name:PedrolloPL plugin_project:DiunaBI.Plugins.PedrolloPL]) (push) Failing after 1m37s
This commit is contained in:
270
DiunaBI.UI.Shared/Pages/Jobs/Details.razor
Normal file
270
DiunaBI.UI.Shared/Pages/Jobs/Details.razor
Normal file
@@ -0,0 +1,270 @@
|
||||
@page "/jobs/{id:guid}"
|
||||
@using DiunaBI.UI.Shared.Services
|
||||
@using DiunaBI.Domain.Entities
|
||||
@using MudBlazor
|
||||
@inject JobService JobService
|
||||
@inject EntityChangeHubService HubService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ISnackbar Snackbar
|
||||
@implements IDisposable
|
||||
|
||||
<MudCard>
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h5">Job Details</MudText>
|
||||
</CardHeaderContent>
|
||||
<CardHeaderActions>
|
||||
@if (job != null && job.Status == JobStatus.Failed)
|
||||
{
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Warning"
|
||||
OnClick="RetryJob"
|
||||
StartIcon="@Icons.Material.Filled.Refresh">
|
||||
Retry
|
||||
</MudButton>
|
||||
}
|
||||
@if (job != null && (job.Status == JobStatus.Pending || job.Status == JobStatus.Retrying))
|
||||
{
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Error"
|
||||
OnClick="CancelJob"
|
||||
StartIcon="@Icons.Material.Filled.Cancel">
|
||||
Cancel
|
||||
</MudButton>
|
||||
}
|
||||
<MudButton Variant="Variant.Text"
|
||||
OnClick="GoBack"
|
||||
StartIcon="@Icons.Material.Filled.ArrowBack">
|
||||
Back to List
|
||||
</MudButton>
|
||||
</CardHeaderActions>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
@if (isLoading)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
|
||||
}
|
||||
else if (job == null)
|
||||
{
|
||||
<MudAlert Severity="Severity.Error">Job not found</MudAlert>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudGrid>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudTextField Value="@job.LayerName"
|
||||
Label="Layer Name"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"/>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudTextField Value="@job.PluginName"
|
||||
Label="Plugin Name"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"/>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="4">
|
||||
<MudTextField Value="@job.JobType.ToString()"
|
||||
Label="Job Type"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"/>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="4">
|
||||
<MudTextField Value="@job.Status.ToString()"
|
||||
Label="Status"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@GetStatusIcon(job.Status)"
|
||||
AdornmentColor="@GetStatusColor(job.Status)"/>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="4">
|
||||
<MudTextField Value="@job.Priority.ToString()"
|
||||
Label="Priority"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"/>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="6">
|
||||
<MudTextField Value="@job.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss")"
|
||||
Label="Created At"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"/>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudTextField Value="@(job.LastAttemptAt?.ToString("yyyy-MM-dd HH:mm:ss") ?? "-")"
|
||||
Label="Last Attempt At"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"/>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="6">
|
||||
<MudTextField Value="@(job.CompletedAt?.ToString("yyyy-MM-dd HH:mm:ss") ?? "-")"
|
||||
Label="Completed At"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"/>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudTextField Value="@($"{job.RetryCount} / {job.MaxRetries}")"
|
||||
Label="Retry Count / Max Retries"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"/>
|
||||
</MudItem>
|
||||
|
||||
@if (!string.IsNullOrEmpty(job.LastError))
|
||||
{
|
||||
<MudItem xs="12">
|
||||
<MudTextField Value="@job.LastError"
|
||||
Label="Last Error"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
FullWidth="true"
|
||||
Lines="5"
|
||||
AdornmentIcon="@Icons.Material.Filled.Error"
|
||||
AdornmentColor="Color.Error"/>
|
||||
</MudItem>
|
||||
}
|
||||
|
||||
<MudItem xs="12">
|
||||
<MudDivider Class="my-4"/>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12">
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
OnClick="@(() => NavigationManager.NavigateTo($"/layers/{job.LayerId}"))"
|
||||
StartIcon="@Icons.Material.Filled.Layers">
|
||||
View Layer Details
|
||||
</MudButton>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
}
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
private QueueJob? job;
|
||||
private bool isLoading = true;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadJob();
|
||||
|
||||
// Subscribe to SignalR entity changes
|
||||
HubService.EntityChanged += OnEntityChanged;
|
||||
}
|
||||
|
||||
private async void OnEntityChanged(string module, string id, string operation)
|
||||
{
|
||||
// Only react if it's a QueueJobs change for this specific job
|
||||
if (module.Equals("QueueJobs", StringComparison.OrdinalIgnoreCase) &&
|
||||
Guid.TryParse(id, out var jobId) && jobId == Id)
|
||||
{
|
||||
Console.WriteLine($"📨 Job {jobId} changed, refreshing detail page");
|
||||
await InvokeAsync(async () =>
|
||||
{
|
||||
await LoadJob();
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadJob()
|
||||
{
|
||||
isLoading = true;
|
||||
try
|
||||
{
|
||||
job = await JobService.GetJobByIdAsync(Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Loading job failed: {ex.Message}");
|
||||
Snackbar.Add("Failed to load job", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RetryJob()
|
||||
{
|
||||
if (job == null) return;
|
||||
|
||||
var success = await JobService.RetryJobAsync(job.Id);
|
||||
if (success)
|
||||
{
|
||||
Snackbar.Add("Job reset to Pending status", Severity.Success);
|
||||
await LoadJob();
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar.Add("Failed to retry job", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CancelJob()
|
||||
{
|
||||
if (job == null) return;
|
||||
|
||||
var success = await JobService.CancelJobAsync(job.Id);
|
||||
if (success)
|
||||
{
|
||||
Snackbar.Add("Job cancelled", Severity.Success);
|
||||
await LoadJob();
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar.Add("Failed to cancel job", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void GoBack()
|
||||
{
|
||||
NavigationManager.NavigateTo("/jobs");
|
||||
}
|
||||
|
||||
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 string GetStatusIcon(JobStatus status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
JobStatus.Pending => Icons.Material.Filled.HourglassEmpty,
|
||||
JobStatus.Running => Icons.Material.Filled.PlayArrow,
|
||||
JobStatus.Completed => Icons.Material.Filled.CheckCircle,
|
||||
JobStatus.Failed => Icons.Material.Filled.Error,
|
||||
JobStatus.Retrying => Icons.Material.Filled.Refresh,
|
||||
_ => Icons.Material.Filled.Help
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
HubService.EntityChanged -= OnEntityChanged;
|
||||
}
|
||||
}
|
||||
148
DiunaBI.UI.Shared/Pages/Jobs/Index.razor
Normal file
148
DiunaBI.UI.Shared/Pages/Jobs/Index.razor
Normal file
@@ -0,0 +1,148 @@
|
||||
@page "/jobs"
|
||||
@using MudBlazor.Internal
|
||||
@using DiunaBI.Domain.Entities
|
||||
@implements IDisposable
|
||||
|
||||
<PageTitle>Jobs</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge">
|
||||
<MudExpansionPanels Class="mb-4">
|
||||
<MudExpansionPanel Icon="@Icons.Material.Filled.FilterList"
|
||||
Text="Filters"
|
||||
Expanded="true">
|
||||
<MudGrid AlignItems="Center">
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudSelect T="JobStatus?"
|
||||
@bind-Value="selectedStatus"
|
||||
Label="Status"
|
||||
Placeholder="All statuses"
|
||||
Clearable="true"
|
||||
OnClearButtonClick="OnStatusClear">
|
||||
@foreach (JobStatus status in Enum.GetValues(typeof(JobStatus)))
|
||||
{
|
||||
<MudSelectItem T="JobStatus?" Value="@status">@status.ToString()</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudSelect T="JobType?"
|
||||
@bind-Value="selectedJobType"
|
||||
Label="Job Type"
|
||||
Placeholder="All types"
|
||||
Clearable="true"
|
||||
OnClearButtonClick="OnJobTypeClear">
|
||||
@foreach (JobType type in Enum.GetValues(typeof(JobType)))
|
||||
{
|
||||
<MudSelectItem T="JobType?" Value="@type">@type.ToString()</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="12" md="6" Class="d-flex justify-end align-center">
|
||||
<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"
|
||||
Size="Size.Medium"
|
||||
Title="Clear filters"/>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudExpansionPanel>
|
||||
</MudExpansionPanels>
|
||||
|
||||
<MudDivider Class="my-4"></MudDivider>
|
||||
|
||||
<MudTable Items="jobs.Items"
|
||||
Dense="true"
|
||||
Hover="true"
|
||||
Loading="isLoading"
|
||||
LoadingProgressColor="Color.Primary"
|
||||
OnRowClick="@((TableRowClickEventArgs<QueueJob> args) => OnRowClick(args.Item))"
|
||||
T="QueueJob"
|
||||
Style="cursor: pointer;">
|
||||
<HeaderContent>
|
||||
<MudTh>Layer Name</MudTh>
|
||||
<MudTh>Plugin</MudTh>
|
||||
<MudTh>Type</MudTh>
|
||||
<MudTh>Status</MudTh>
|
||||
<MudTh>Priority</MudTh>
|
||||
<MudTh>Retry</MudTh>
|
||||
<MudTh>Created</MudTh>
|
||||
<MudTh>Last Attempt</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate Context="row">
|
||||
<MudTd DataLabel="Layer Name">
|
||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||
@row.LayerName
|
||||
</div>
|
||||
</MudTd>
|
||||
<MudTd DataLabel="Plugin">
|
||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||
@row.PluginName
|
||||
</div>
|
||||
</MudTd>
|
||||
<MudTd DataLabel="Type">
|
||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||
<MudChip T="string" Size="Size.Small" Color="@GetJobTypeColor(row.JobType)">@row.JobType</MudChip>
|
||||
</div>
|
||||
</MudTd>
|
||||
<MudTd DataLabel="Status">
|
||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||
<MudChip T="string" Size="Size.Small" Color="@GetStatusColor(row.Status)">@row.Status</MudChip>
|
||||
</div>
|
||||
</MudTd>
|
||||
<MudTd DataLabel="Priority">
|
||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||
@row.Priority
|
||||
</div>
|
||||
</MudTd>
|
||||
<MudTd DataLabel="Retry">
|
||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||
@row.RetryCount / @row.MaxRetries
|
||||
</div>
|
||||
</MudTd>
|
||||
<MudTd DataLabel="Created">
|
||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||
@row.CreatedAt.ToString("yyyy-MM-dd HH:mm")
|
||||
</div>
|
||||
</MudTd>
|
||||
<MudTd DataLabel="Last Attempt">
|
||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||
@(row.LastAttemptAt?.ToString("yyyy-MM-dd HH:mm") ?? "-")
|
||||
</div>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
<NoRecordsContent>
|
||||
<MudText>No jobs to display</MudText>
|
||||
</NoRecordsContent>
|
||||
<LoadingContent>
|
||||
Loading...
|
||||
</LoadingContent>
|
||||
</MudTable>
|
||||
|
||||
@if (jobs.TotalCount > 0)
|
||||
{
|
||||
<MudGrid Class="mt-4" AlignItems="Center.Center">
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudText Typo="Typo.body2">
|
||||
Results @((jobs.Page - 1) * jobs.PageSize + 1) - @Math.Min(jobs.Page * jobs.PageSize, jobs.TotalCount)
|
||||
of @jobs.TotalCount
|
||||
</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" Class="d-flex justify-end">
|
||||
<MudPagination Count="jobs.TotalPages"
|
||||
Selected="jobs.Page"
|
||||
SelectedChanged="OnPageChanged"
|
||||
ShowFirstButton="true"
|
||||
ShowLastButton="true"
|
||||
Variant="Variant.Outlined"
|
||||
/>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
}
|
||||
</MudContainer>
|
||||
142
DiunaBI.UI.Shared/Pages/Jobs/Index.razor.cs
Normal file
142
DiunaBI.UI.Shared/Pages/Jobs/Index.razor.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
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!;
|
||||
|
||||
private PagedResult<QueueJob> jobs = new();
|
||||
private bool isLoading = false;
|
||||
private int currentPage = 1;
|
||||
private int pageSize = 50;
|
||||
private JobStatus? selectedStatus = null;
|
||||
private JobType? selectedJobType = null;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
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
|
||||
{
|
||||
jobs = await JobService.GetJobsAsync(currentPage, pageSize, selectedStatus, 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()
|
||||
{
|
||||
selectedStatus = null;
|
||||
selectedJobType = null;
|
||||
currentPage = 1;
|
||||
await LoadJobs();
|
||||
}
|
||||
|
||||
private async Task OnStatusClear()
|
||||
{
|
||||
selectedStatus = null;
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user