diff --git a/DiunaBI.API/Controllers/DataInboxController.cs b/DiunaBI.API/Controllers/DataInboxController.cs index 2f6933b..2660a13 100644 --- a/DiunaBI.API/Controllers/DataInboxController.cs +++ b/DiunaBI.API/Controllers/DataInboxController.cs @@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using DiunaBI.Infrastructure.Data; using DiunaBI.Domain.Entities; +using DiunaBI.Application.DTOModels; +using DiunaBI.Application.DTOModels.Common; namespace DiunaBI.API.Controllers; @@ -89,17 +91,91 @@ public class DataInboxController : Controller } [HttpGet] - public IActionResult GetAll() + [Route("GetAll")] + public IActionResult GetAll([FromQuery] int start, [FromQuery] int limit, [FromQuery] string? name, [FromQuery] string? source) { try { - var dataInbox = _db.DataInbox.AsNoTracking().ToList(); - _logger.LogDebug("DataInbox: Retrieved {Count} records", dataInbox.Count); - return Ok(dataInbox); + var query = _db.DataInbox.AsQueryable(); + + if (name != null) + { + query = query.Where(x => x.Name.Contains(name)); + } + + if (source != null) + { + query = query.Where(x => x.Source.Contains(source)); + } + + var totalCount = query.Count(); + + var items = query + .OrderByDescending(x => x.CreatedAt) + .Skip(start) + .Take(limit) + .AsNoTracking() + .Select(x => new DataInboxDto + { + Id = x.Id, + Name = x.Name, + Source = x.Source, + Data = x.Data, + CreatedAt = x.CreatedAt + }) + .ToList(); + + var pagedResult = new PagedResult + { + Items = items, + TotalCount = totalCount, + Page = (start / limit) + 1, + PageSize = limit + }; + + _logger.LogDebug("GetAll: Retrieved {Count} of {TotalCount} data inbox items (page {Page}) with filter name={Name}, source={Source}", + items.Count, totalCount, pagedResult.Page, name, source); + + return Ok(pagedResult); } catch (Exception e) { - _logger.LogError(e, "DataInbox: Error retrieving records"); + _logger.LogError(e, "GetAll: Error retrieving data inbox items"); + return BadRequest(e.ToString()); + } + } + + [HttpGet] + [Route("{id:guid}")] + public IActionResult Get(Guid id) + { + try + { + var dataInbox = _db.DataInbox + .AsNoTracking() + .FirstOrDefault(x => x.Id == id); + + if (dataInbox == null) + { + _logger.LogWarning("Get: Data inbox item {Id} not found", id); + return NotFound(); + } + + var dto = new DataInboxDto + { + Id = dataInbox.Id, + Name = dataInbox.Name, + Source = dataInbox.Source, + Data = dataInbox.Data, + CreatedAt = dataInbox.CreatedAt + }; + + _logger.LogDebug("Get: Retrieved data inbox item {Id} {Name}", id, dataInbox.Name); + return Ok(dto); + } + catch (Exception e) + { + _logger.LogError(e, "Get: Error retrieving data inbox item {Id}", id); return BadRequest(e.ToString()); } } diff --git a/DiunaBI.Application/DTOModels/DataInboxDto.cs b/DiunaBI.Application/DTOModels/DataInboxDto.cs new file mode 100644 index 0000000..5c0117a --- /dev/null +++ b/DiunaBI.Application/DTOModels/DataInboxDto.cs @@ -0,0 +1,17 @@ +namespace DiunaBI.Application.DTOModels; + +public class DataInboxDto +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string Source { get; set; } = string.Empty; + public string Data { get; set; } = string.Empty; + public DateTime CreatedAt { get; set; } +} + +public class DataInboxFilterRequest +{ + public string? Search { get; set; } + public int Page { get; set; } = 1; + public int PageSize { get; set; } = 50; +} diff --git a/DiunaBI.UI.Shared/Components/DataInboxListComponent.razor b/DiunaBI.UI.Shared/Components/DataInboxListComponent.razor new file mode 100644 index 0000000..48df964 --- /dev/null +++ b/DiunaBI.UI.Shared/Components/DataInboxListComponent.razor @@ -0,0 +1,75 @@ +@using MudBlazor.Internal + + + + + + + + + + + Clear filters + + + + + + + + + + + Name + Source + Created At + + + @context.Name + @context.Source + @context.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss") + + + No data inbox items to display + + + Loading... + + + + @if (dataInbox.TotalCount > 0) + { + + + + Results @((dataInbox.Page - 1) * dataInbox.PageSize + 1) - @Math.Min(dataInbox.Page * dataInbox.PageSize, dataInbox.TotalCount) + of @dataInbox.TotalCount + + + + + + + } diff --git a/DiunaBI.UI.Shared/Components/DataInboxListComponent.razor.cs b/DiunaBI.UI.Shared/Components/DataInboxListComponent.razor.cs new file mode 100644 index 0000000..6984c72 --- /dev/null +++ b/DiunaBI.UI.Shared/Components/DataInboxListComponent.razor.cs @@ -0,0 +1,60 @@ +using DiunaBI.UI.Shared.Services; +using Microsoft.AspNetCore.Components; +using DiunaBI.Application.DTOModels; +using DiunaBI.Application.DTOModels.Common; +using MudBlazor; + +namespace DiunaBI.UI.Shared.Components; + +public partial class DataInboxListComponent : ComponentBase +{ + [Inject] private DataInboxService DataInboxService { get; set; } = default!; + [Inject] private ISnackbar Snackbar { get; set; } = default!; + [Inject] private NavigationManager NavigationManager { get; set; } = default!; + + + private PagedResult dataInbox = new(); + private DataInboxFilterRequest filterRequest = new(); + private bool isLoading = false; + + protected override async Task OnInitializedAsync() + { + await LoadDataInbox(); + } + + private async Task LoadDataInbox() + { + isLoading = true; + + try + { + 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(); + await LoadDataInbox(); + } +} diff --git a/DiunaBI.UI.Shared/Components/NavMenu.razor b/DiunaBI.UI.Shared/Components/NavMenu.razor deleted file mode 100644 index 8ae155a..0000000 --- a/DiunaBI.UI.Shared/Components/NavMenu.razor +++ /dev/null @@ -1,10 +0,0 @@ -@using Microsoft.AspNetCore.Components.Routing -@using MudBlazor - - - Dashboard - - - Layers - - \ No newline at end of file diff --git a/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs b/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs index 8b02713..b13ea13 100644 --- a/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs +++ b/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs @@ -36,6 +36,7 @@ public static class ServiceCollectionExtensions // Services services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } diff --git a/DiunaBI.UI.Shared/MainLayout.razor b/DiunaBI.UI.Shared/MainLayout.razor index 306f4cb..4200735 100644 --- a/DiunaBI.UI.Shared/MainLayout.razor +++ b/DiunaBI.UI.Shared/MainLayout.razor @@ -35,6 +35,7 @@ Dashboard Layers + Data Inbox diff --git a/DiunaBI.UI.Shared/Pages/DataInboxListPage.razor b/DiunaBI.UI.Shared/Pages/DataInboxListPage.razor new file mode 100644 index 0000000..e0629a4 --- /dev/null +++ b/DiunaBI.UI.Shared/Pages/DataInboxListPage.razor @@ -0,0 +1,8 @@ +@page "/datainbox" +@using DiunaBI.UI.Shared.Components + +Data Inbox + + + + diff --git a/DiunaBI.UI.Shared/Services/DataInboxService.cs b/DiunaBI.UI.Shared/Services/DataInboxService.cs new file mode 100644 index 0000000..a04ac84 --- /dev/null +++ b/DiunaBI.UI.Shared/Services/DataInboxService.cs @@ -0,0 +1,49 @@ +using System.Net.Http.Json; +using System.Text.Json; +using DiunaBI.Application.DTOModels; +using DiunaBI.Application.DTOModels.Common; + +namespace DiunaBI.UI.Shared.Services; + +public class DataInboxService +{ + private readonly HttpClient _httpClient; + + public DataInboxService(HttpClient httpClient) + { + _httpClient = httpClient; + } + + private readonly JsonSerializerOptions _jsonOptions = new() + { + PropertyNameCaseInsensitive = true + }; + + public async Task> GetDataInboxAsync(DataInboxFilterRequest filterRequest) + { + // Calculate start index from page number (page 1 = start 0, page 2 = start 50, etc.) + var start = (filterRequest.Page - 1) * filterRequest.PageSize; + var query = $"DataInbox/GetAll?start={start}&limit={filterRequest.PageSize}"; + + if (!string.IsNullOrEmpty(filterRequest.Search)) + query += $"&name={Uri.EscapeDataString(filterRequest.Search)}"; + + var response = await _httpClient.GetAsync(query); + response.EnsureSuccessStatusCode(); + + var json = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize>(json, _jsonOptions); + + return result ?? new PagedResult(); + } + + public async Task GetDataInboxByIdAsync(Guid id) + { + var response = await _httpClient.GetAsync($"DataInbox/{id}"); + + if (!response.IsSuccessStatusCode) + return null; + + return await response.Content.ReadFromJsonAsync(); + } +}