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

This commit is contained in:
2025-12-05 09:51:04 +01:00
parent 193127b86a
commit c7d9acead0
26 changed files with 746 additions and 44 deletions

View File

@@ -0,0 +1,42 @@
@page "/dashboard"
@using DiunaBI.UI.Shared.Services
@using MudBlazor
@inject AuthService AuthService
@inject NavigationManager NavigationManager
@if (AuthService.IsAuthenticated && AuthService.CurrentUser != null)
{
<MudCard Class="mt-4" Elevation="2">
<MudCardHeader>
<CardHeaderAvatar>
@if (!string.IsNullOrEmpty(AuthService.CurrentUser.AvatarUrl))
{
<MudAvatar Size="Size.Large" Style="background: transparent;">
<img src="@AuthService.CurrentUser.AvatarUrl" alt="Avatar" style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;" />
</MudAvatar>
}
else
{
<MudAvatar Color="Color.Primary" Size="Size.Large">
@(AuthService.CurrentUser.FullName.Length > 0 ? AuthService.CurrentUser.FullName.Substring(0, 1) : "?")
</MudAvatar>
}
</CardHeaderAvatar>
<CardHeaderContent>
<MudText Typo="Typo.h6">@AuthService.CurrentUser.FullName</MudText>
<MudText Typo="Typo.body2">@AuthService.CurrentUser.Email</MudText>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent>
<MudText Typo="Typo.body2">
✅ Signed in via Google
</MudText>
</MudCardContent>
</MudCard>
}
else
{
<MudAlert Severity="Severity.Warning" Class="mt-4">
You are not logged in
</MudAlert>
}

View File

@@ -2,8 +2,6 @@
@using DiunaBI.UI.Shared.Services
@using DiunaBI.Application.DTOModels
@using MudBlazor
@inject DataInboxService DataInboxService
@inject NavigationManager NavigationManager
<MudCard>
<MudCardHeader>

View File

@@ -1,15 +1,22 @@
using DiunaBI.Application.DTOModels;
using DiunaBI.UI.Shared.Services;
using Microsoft.AspNetCore.Components;
using MudBlazor;
using System.Text;
namespace DiunaBI.UI.Shared.Pages;
namespace DiunaBI.UI.Shared.Pages.DataInbox;
public partial class DataInboxDetailPage : ComponentBase
public partial class Details : ComponentBase
{
[Parameter]
public Guid Id { get; set; }
[Inject]
private DataInboxService DataInboxService { get; set; } = null!;
[Inject]
private NavigationManager NavigationManager { get; set; } = null!;
[Inject]
private ISnackbar Snackbar { get; set; } = null!;

View File

@@ -0,0 +1,85 @@
@page "/datainbox"
@using MudBlazor.Internal
@using DiunaBI.Application.DTOModels
<PageTitle>Data Inbox</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="4">
<MudTextField @bind-Value="filterRequest.Search"
Label="Search"
Placeholder="Name, source..."
Immediate="true"
DebounceInterval="500"
OnDebounceIntervalElapsed="SearchDataInbox"
Clearable="true"/>
</MudItem>
<MudItem xs="12" sm="6" md="4">
</MudItem>
<MudItem xs="12" sm="12" md="4" Class="d-flex justify-end">
<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="dataInbox.Items"
Dense="true"
Hover="true"
Loading="isLoading"
LoadingProgressColor="Color.Primary"
OnRowClick="@((TableRowClickEventArgs<DataInboxDto> args) => OnRowClick(args.Item))"
T="DataInboxDto"
Style="cursor: pointer;">
<HeaderContent>
<MudTh>Name</MudTh>
<MudTh>Source</MudTh>
<MudTh>Created At</MudTh>
</HeaderContent>
<RowTemplate Context="row">
<MudTd DataLabel="Name"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.Name</div></MudTd>
<MudTd DataLabel="Source"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.Source</div></MudTd>
<MudTd DataLabel="Created At"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss")</div></MudTd>
</RowTemplate>
<NoRecordsContent>
<MudText>No data inbox items to display</MudText>
</NoRecordsContent>
<LoadingContent>
Loading...
</LoadingContent>
</MudTable>
@if (dataInbox.TotalCount > 0)
{
<MudGrid Class="mt-4" AlignItems="Center.Center">
<MudItem xs="12" sm="6">
<MudText Typo="Typo.body2">
Results @((dataInbox.Page - 1) * dataInbox.PageSize + 1) - @Math.Min(dataInbox.Page * dataInbox.PageSize, dataInbox.TotalCount)
of @dataInbox.TotalCount
</MudText>
</MudItem>
<MudItem xs="12" sm="6" Class="d-flex justify-end">
<MudPagination Count="dataInbox.TotalPages"
Selected="dataInbox.Page"
SelectedChanged="OnPageChanged"
ShowFirstButton="true"
ShowLastButton="true"
Variant="Variant.Outlined"
/>
</MudItem>
</MudGrid>
}
</MudContainer>

View File

@@ -0,0 +1,78 @@
using DiunaBI.UI.Shared.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using DiunaBI.Application.DTOModels;
using DiunaBI.Application.DTOModels.Common;
using MudBlazor;
using Microsoft.JSInterop;
namespace DiunaBI.UI.Shared.Pages.DataInbox;
public partial class Index : ComponentBase
{
[Inject] private DataInboxService DataInboxService { get; set; } = default!;
[Inject] private ISnackbar Snackbar { get; set; } = default!;
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
[Inject] private DataInboxFilterStateService FilterStateService { get; set; } = default!;
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
private PagedResult<DataInboxDto> dataInbox = new();
private DataInboxFilterRequest filterRequest = new();
private bool isLoading = false;
protected override async Task OnInitializedAsync()
{
filterRequest = FilterStateService.FilterRequest;
await LoadDataInbox();
}
private async Task LoadDataInbox()
{
isLoading = true;
try
{
FilterStateService.UpdateFilter(filterRequest);
dataInbox = await DataInboxService.GetDataInboxAsync(filterRequest);
}
catch (Exception ex)
{
Console.WriteLine($"Loading data inbox failed: {ex.Message}");
}
finally
{
isLoading = false;
}
}
private async Task SearchDataInbox()
{
filterRequest.Page = 1;
await LoadDataInbox();
}
private async Task OnPageChanged(int page)
{
filterRequest.Page = page;
await LoadDataInbox();
}
private async Task ClearFilters()
{
filterRequest = new DataInboxFilterRequest();
FilterStateService.ClearFilter();
await LoadDataInbox();
}
private void OnRowClick(DataInboxDto dataInboxItem)
{
NavigationManager.NavigateTo($"/datainbox/{dataInboxItem.Id}");
}
private async Task OnRowRightClick(MouseEventArgs e, DataInboxDto dataInboxItem)
{
var url = NavigationManager.ToAbsoluteUri($"/datainbox/{dataInboxItem.Id}").ToString();
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
}
}

View File

@@ -1,8 +0,0 @@
@page "/datainbox"
@using DiunaBI.UI.Shared.Components
<PageTitle>Data Inbox</PageTitle>
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge">
<DataInboxListComponent />
</MudContainer>

View File

@@ -0,0 +1,15 @@
@page "/"
@inject NavigationManager Navigation
@code
{
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
Navigation.NavigateTo("/dashboard");
}
await base.OnAfterRenderAsync(firstRender);
}
}

View File

@@ -1,8 +0,0 @@
@page "/jobs"
@using DiunaBI.UI.Shared.Components
<PageTitle>Jobs</PageTitle>
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge">
<JobListComponent />
</MudContainer>

View 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>

View 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;
}
}

View File

@@ -1,8 +0,0 @@
@page "/layers"
@using DiunaBI.UI.Shared.Components
<PageTitle>Layers</PageTitle>
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge">
<LayerListComponent />
</MudContainer>

View File

@@ -2,10 +2,6 @@
@using DiunaBI.UI.Shared.Services
@using DiunaBI.Application.DTOModels
@using MudBlazor
@inject LayerService LayerService
@inject JobService JobService
@inject NavigationManager NavigationManager
@inject ISnackbar Snackbar
<MudCard>
<MudCardHeader>

View File

@@ -1,11 +1,12 @@
using DiunaBI.Application.DTOModels;
using DiunaBI.UI.Shared.Services;
using Microsoft.AspNetCore.Components;
using MudBlazor;
using System.Reflection;
namespace DiunaBI.UI.Shared.Pages;
namespace DiunaBI.UI.Shared.Pages.Layers;
public partial class LayerDetailPage : ComponentBase
public partial class Details : ComponentBase
{
[Parameter]
public Guid Id { get; set; }
@@ -13,6 +14,18 @@ public partial class LayerDetailPage : ComponentBase
[Inject]
private IDialogService DialogService { get; set; } = null!;
[Inject]
private LayerService LayerService { get; set; } = null!;
[Inject]
private JobService JobService { get; set; } = null!;
[Inject]
private NavigationManager NavigationManager { get; set; } = null!;
[Inject]
private ISnackbar Snackbar { get; set; } = null!;
private LayerDto? layer;
private List<RecordDto> records = new();
private List<string> displayedColumns = new();

View File

@@ -0,0 +1,95 @@
@page "/layers"
@using MudBlazor.Internal
@using DiunaBI.Application.DTOModels
<PageTitle>Layers</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="4">
<MudTextField @bind-Value="filterRequest.Search"
Label="Search"
Placeholder="Name, number..."
Immediate="true"
DebounceInterval="500"
OnDebounceIntervalElapsed="SearchLayers"
Clearable="true"/>
</MudItem>
<MudItem xs="12" sm="6" md="4">
<MudSelect T="LayerType?"
Value="filterRequest.Type"
ValueChanged="OnTypeChanged"
Label="Type"
Placeholder="All types"
Clearable="true"
OnClearButtonClick="OnTypeClear">
@foreach (LayerType type in Enum.GetValues(typeof(LayerType)))
{
<MudSelectItem T="LayerType?" Value="@type">@type.ToString()</MudSelectItem>
}
</MudSelect>
</MudItem>
<MudItem xs="12" sm="12" md="4" Class="d-flex justify-end">
<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="layers.Items"
Dense="true"
Hover="true"
Loading="isLoading"
LoadingProgressColor="Color.Primary"
OnRowClick="@((TableRowClickEventArgs<LayerDto> args) => OnRowClick(args.Item))"
T="LayerDto"
Style="cursor: pointer;">
<HeaderContent>
<MudTh>Name</MudTh>
<MudTh>Type</MudTh>
</HeaderContent>
<RowTemplate Context="row">
<MudTd DataLabel="Name"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.Name</div></MudTd>
<MudTd DataLabel="Type"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.Type</div></MudTd>
</RowTemplate>
<NoRecordsContent>
<MudText>No layers to display</MudText>
</NoRecordsContent>
<LoadingContent>
Loading...
</LoadingContent>
</MudTable>
@if (layers.TotalCount > 0)
{
<MudGrid Class="mt-4" AlignItems="Center.Center">
<MudItem xs="12" sm="6">
<MudText Typo="Typo.body2">
Results @((layers.Page - 1) * layers.PageSize + 1) - @Math.Min(layers.Page * layers.PageSize, layers.TotalCount)
of @layers.TotalCount
</MudText>
</MudItem>
<MudItem xs="12" sm="6" Class="d-flex justify-end">
<MudPagination Count="layers.TotalPages"
Selected="layers.Page"
SelectedChanged="OnPageChanged"
ShowFirstButton="true"
ShowLastButton="true"
Variant="Variant.Outlined"
/>
</MudItem>
</MudGrid>
}
</MudContainer>

View File

@@ -0,0 +1,92 @@
using DiunaBI.UI.Shared.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using DiunaBI.Application.DTOModels;
using DiunaBI.Application.DTOModels.Common;
using MudBlazor;
using Microsoft.JSInterop;
namespace DiunaBI.UI.Shared.Pages.Layers;
public partial class Index : ComponentBase
{
[Inject] private LayerService LayerService { get; set; } = default!;
[Inject] private ISnackbar Snackbar { get; set; } = default!;
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
[Inject] private LayerFilterStateService FilterStateService { get; set; } = default!;
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
private PagedResult<LayerDto> layers = new();
private LayerFilterRequest filterRequest = new();
private bool isLoading = false;
protected override async Task OnInitializedAsync()
{
filterRequest = FilterStateService.FilterRequest;
await LoadLayers();
}
private async Task LoadLayers()
{
isLoading = true;
try
{
FilterStateService.UpdateFilter(filterRequest);
layers = await LayerService.GetLayersAsync(filterRequest);
}
catch (Exception ex)
{
Console.WriteLine($"Loading layers failed: {ex.Message}");
}
finally
{
isLoading = false;
}
}
private async Task SearchLayers()
{
filterRequest.Page = 1;
await LoadLayers();
}
private async Task OnPageChanged(int page)
{
filterRequest.Page = page;
await LoadLayers();
}
private async Task ClearFilters()
{
filterRequest = new LayerFilterRequest();
FilterStateService.ClearFilter();
await LoadLayers();
}
private async Task OnTypeClear()
{
filterRequest.Type = null;
filterRequest.Page = 1;
await LoadLayers();
}
private async Task OnTypeChanged(LayerType? type)
{
filterRequest.Type = type;
filterRequest.Page = 1;
await LoadLayers();
}
private void OnRowClick(LayerDto layer)
{
NavigationManager.NavigateTo($"/layers/{layer.Id}");
}
private async Task OnRowRightClick(MouseEventArgs e, LayerDto layer)
{
var url = NavigationManager.ToAbsoluteUri($"/layers/{layer.Id}").ToString();
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
}
}