Compare commits

...

5 Commits

Author SHA1 Message Date
7ea5ed506e Filter Layers by Type
All checks were successful
Build Docker Images / test (push) Successful in 1m37s
Build Docker Images / build-and-push (push) Successful in 1m35s
2025-12-01 13:21:45 +01:00
4d7df85df1 DataInbox Detail 2025-12-01 13:00:01 +01:00
3d654d972e DataInbox list 2025-12-01 12:55:47 +01:00
a71b6feefc Pagination style fix 2025-12-01 12:35:22 +01:00
cb0d050ad4 Imports for 2025.12 2025-11-30 16:09:32 +01:00
25 changed files with 526 additions and 198 deletions

View File

@@ -1,9 +1,9 @@
GET http://localhost:5400/tests/ping PUT https://pedrollopl.diunabi.com/api/DataInbox/Add/8kL2mN4pQ6rojshf8704i34p4eim1hs
Content-Type: application/json
Authorization: Basic cGVkcm9sbG9wbDo0MjU4dlc2eFk4TjRwUQ==
### {
"Source": "morska.import",
GET https://morska.diunabi.com/api/layers/autoImport/godojshf8704i357yhgdsahjdfh/K5- "Name": "morska.d3.importer",
"Data": "eyJrZXkiOiAidmFsdWUifQ=="
### }
GET http://localhost:5400/layers/autoImport/10763478CB738D4ecb2h76g803478CB738D4e/K5-

View File

@@ -2,7 +2,7 @@ DECLARE @JustForDebug TINYINT = 0;
-- SETUP VARIABLES -- SETUP VARIABLES
DECLARE @Type NVARCHAR(3) = 'D3'; DECLARE @Type NVARCHAR(3) = 'D3';
DECLARE @Month INT = 11; DECLARE @Month INT = 12;
DECLARE @Year INT = 2025; DECLARE @Year INT = 2025;
IF @Type NOT IN ('D3') IF @Type NOT IN ('D3')
@@ -14,7 +14,7 @@ END;
DECLARE @ImportType NVARCHAR(20) = 'Import-D3'; DECLARE @ImportType NVARCHAR(20) = 'Import-D3';
DECLARE @StartDate NVARCHAR(10) = FORMAT(DATEADD(DAY, 24, DATEADD(MONTH, @Month - 2, DATEFROMPARTS(YEAR(GETDATE()), 1, 1))), 'yyyy.MM.dd'); DECLARE @StartDate NVARCHAR(10) = FORMAT(DATEADD(DAY, 24, DATEADD(MONTH, @Month - 2, DATEFROMPARTS(YEAR(GETDATE()), 1, 1))), 'yyyy.MM.dd');
DECLARE @EndDate NVARCHAR(10) = FORMAT(DATEFROMPARTS(YEAR(GETDATE()), @Month + 1, 5), 'yyyy.MM.dd'); DECLARE @EndDate NVARCHAR(10) = FORMAT(DATEFROMPARTS(CASE WHEN @Month = 12 THEN @Year + 1 ELSE @Year END, CASE WHEN @Month = 12 THEN 1 ELSE @Month + 1 END, 5), 'yyyy.MM.dd');
DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]); DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]);
DECLARE @CurrentTimestamp NVARCHAR(14) = FORMAT(GETDATE(), 'yyyyMMddHHmm'); DECLARE @CurrentTimestamp NVARCHAR(14) = FORMAT(GETDATE(), 'yyyyMMddHHmm');
DECLARE @FormattedMonth NVARCHAR(2) = FORMAT(@Month, '00'); DECLARE @FormattedMonth NVARCHAR(2) = FORMAT(@Month, '00');

View File

@@ -2,9 +2,9 @@ DECLARE @JustForDebug TINYINT = 0;
-- SETUP VARIABLES -- SETUP VARIABLES
DECLARE @Type NVARCHAR(3) = 'D1'; DECLARE @Type NVARCHAR(3) = 'D1';
DECLARE @Month INT = 11; DECLARE @Month INT = 12;
DECLARE @Year INT = 2025; DECLARE @Year INT = 2025;
DECLARE @MonthName NVARCHAR(20) = 'Pazdziernik_2025'; DECLARE @MonthName NVARCHAR(20) = 'Grudzien_2025';
IF @Type NOT IN ('K5', 'PU', 'AK', 'FK', 'D1', 'FK2') IF @Type NOT IN ('K5', 'PU', 'AK', 'FK', 'D1', 'FK2')
BEGIN BEGIN
@@ -27,7 +27,7 @@ SET @ImportType =
ELSE 'Standard' ELSE 'Standard'
END; END;
DECLARE @StartDate NVARCHAR(10) = FORMAT(DATEADD(DAY, 24, DATEADD(MONTH, @Month - 2, DATEFROMPARTS(YEAR(GETDATE()), 1, 1))), 'yyyy.MM.dd'); DECLARE @StartDate NVARCHAR(10) = FORMAT(DATEADD(DAY, 24, DATEADD(MONTH, @Month - 2, DATEFROMPARTS(YEAR(GETDATE()), 1, 1))), 'yyyy.MM.dd');
DECLARE @EndDate NVARCHAR(10) = FORMAT(DATEFROMPARTS(YEAR(GETDATE()), @Month + 1, 5), 'yyyy.MM.dd'); DECLARE @EndDate NVARCHAR(10) = FORMAT(DATEFROMPARTS(CASE WHEN @Month = 12 THEN @Year + 1 ELSE @Year END, CASE WHEN @Month = 12 THEN 1 ELSE @Month + 1 END, 5), 'yyyy.MM.dd');
DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]); DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]);
DECLARE @CurrentTimestamp NVARCHAR(14) = FORMAT(GETDATE(), 'yyyyMMddHHmm'); DECLARE @CurrentTimestamp NVARCHAR(14) = FORMAT(GETDATE(), 'yyyyMMddHHmm');
DECLARE @FormattedMonth NVARCHAR(2) = FORMAT(@Month, '00'); DECLARE @FormattedMonth NVARCHAR(2) = FORMAT(@Month, '00');

View File

@@ -2,7 +2,7 @@
DECLARE @JustForDebug TINYINT = 0; DECLARE @JustForDebug TINYINT = 0;
-- SETUP VARIABLES -- SETUP VARIABLES
DECLARE @Month INT = 11; DECLARE @Month INT = 12;
DECLARE @Year INT = 2025; DECLARE @Year INT = 2025;
DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]); DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]);

View File

@@ -4,7 +4,7 @@ DECLARE @JustForDebug TINYINT = 0;
-- SETUP VARIABLES -- SETUP VARIABLES
DECLARE @Type NVARCHAR(3) = 'FK'; DECLARE @Type NVARCHAR(3) = 'FK';
DECLARE @Month INT = 11; DECLARE @Month INT = 12;
DECLARE @Year INT = 2025; DECLARE @Year INT = 2025;
IF @Type NOT IN ('K5', 'PU', 'AK', 'FK') IF @Type NOT IN ('K5', 'PU', 'AK', 'FK')

View File

@@ -4,7 +4,7 @@ DECLARE @JustForDebug TINYINT = 0;
-- SETUP VARIABLES -- SETUP VARIABLES
DECLARE @Type NVARCHAR(3) = 'FK2'; DECLARE @Type NVARCHAR(3) = 'FK2';
DECLARE @Month INT = 11; DECLARE @Month INT = 12;
DECLARE @Year INT = 2025; DECLARE @Year INT = 2025;
DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]); DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]);

View File

@@ -2,7 +2,7 @@
DECLARE @JustForDebug TINYINT = 0; DECLARE @JustForDebug TINYINT = 0;
-- SETUP VARIABLES -- SETUP VARIABLES
DECLARE @Month INT = 11; DECLARE @Month INT = 12;
DECLARE @Year INT = 2025; DECLARE @Year INT = 2025;
DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]); DECLARE @Number INT = (SELECT COUNT(id) + 1 FROM [diunabi-morska].[dbo].[Layers]);

View File

@@ -1,74 +0,0 @@
-- ADD IMPORT LAYER
-- DEPRECATED
RETURN;
DECLARE @LayerId UNIQUEIDENTIFIER;
SET @LayerId = NEWID();
INSERT INTO [diunabi-morska].[dbo].[Layers]
([Id], [Number], [Name], [CreatedAt], [ModifiedAt], [IsDeleted],
[CreatedById], [ModifiedById], [Type])
VALUES ((SELECT @LayerId), 5375, 'L5375-A-IW_D1-2025/01-202502182004',
GETDATE(), GETDATE(), 0, '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 2);
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'StartDate', '2025.02.10',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'EndDate', '2025.03.30',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'Source', 'GoogleSheet',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'SheetTabName', 'Styczen_2025',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'SheetId', '1wplF3CRHweDE8A3Dk9dYbhWAatj1kp0UBM7MiFE26hE',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'DataRange', 'A7:O200',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'ImportName', 'D1',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'ImportYear', '2025',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'ImportMonth', '01',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'Type', 'ImportWorker',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'IsEnabled', 'True',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'ImportType', 'D1',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));

View File

@@ -1,79 +0,0 @@
-- MORSKA:
-- FK: 1k_frcE49O-J_n5MaNiVLKq62-OTCJku1qutGb8YF9M0
-- ADD IMPORT LAYER
-- DEPRECATED
RETURN;
DECLARE @LayerId UNIQUEIDENTIFIER;
SET @LayerId = NEWID();
INSERT INTO [diunabi-morska].[dbo].[Layers]
([Id], [Number], [Name], [CreatedAt], [ModifiedAt], [IsDeleted],
[CreatedById], [ModifiedById], [Type])
VALUES ((SELECT @LayerId), 4907, 'L4907-A-IW_FK2-2025/02-202501301739',
GETDATE(), GETDATE(), 0, '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 2);
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'StartDate', '2025.01.29',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'EndDate', '2025.03.05',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'Source', 'GoogleSheet',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'SheetTabName', 'Luty_2025',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'SheetId', '1k_frcE49O-J_n5MaNiVLKq62-OTCJku1qutGb8YF9M0',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'DataRange', 'A8:I1652',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'ImportName', 'FK2',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'ImportMonth', '02',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'ImportYear', '2025',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'Type', 'ImportWorker',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'IsEnabled', 'True',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));
INSERT INTO [diunabi-morska].[dbo].[Records]
([Id], [Code], [Desc1], [CreatedAt], [ModifiedAt], [CreatedById], [ModifiedById], [IsDeleted], [LayerId])
VALUES ((SELECT NEWID()), 'ImportType', 'FK2',
GETDATE(), GETDATE(), '117be4f0-b5d1-41a1-a962-39dc30cce368', '117be4f0-b5d1-41a1-a962-39dc30cce368', 0, (SELECT @LayerId));

View File

@@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using DiunaBI.Infrastructure.Data; using DiunaBI.Infrastructure.Data;
using DiunaBI.Domain.Entities; using DiunaBI.Domain.Entities;
using DiunaBI.Application.DTOModels;
using DiunaBI.Application.DTOModels.Common;
namespace DiunaBI.API.Controllers; namespace DiunaBI.API.Controllers;
@@ -89,17 +91,86 @@ public class DataInboxController : Controller
} }
[HttpGet] [HttpGet]
public IActionResult GetAll() [Route("GetAll")]
public IActionResult GetAll([FromQuery] int start, [FromQuery] int limit, [FromQuery] string? search)
{ {
try try
{ {
var dataInbox = _db.DataInbox.AsNoTracking().ToList(); var query = _db.DataInbox.AsQueryable();
_logger.LogDebug("DataInbox: Retrieved {Count} records", dataInbox.Count);
return Ok(dataInbox); if (!string.IsNullOrEmpty(search))
{
query = query.Where(x => x.Name.Contains(search) || x.Source.Contains(search));
}
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<DataInboxDto>
{
Items = items,
TotalCount = totalCount,
Page = (start / limit) + 1,
PageSize = limit
};
_logger.LogDebug("GetAll: Retrieved {Count} of {TotalCount} data inbox items (page {Page}) with filter search={Search}",
items.Count, totalCount, pagedResult.Page, search);
return Ok(pagedResult);
} }
catch (Exception e) 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()); return BadRequest(e.ToString());
} }
} }

View File

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

View File

@@ -0,0 +1,78 @@
@using MudBlazor.Internal
<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.Info"
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>
<MudTd DataLabel="Name">@context.Name</MudTd>
<MudTd DataLabel="Source">@context.Source</MudTd>
<MudTd DataLabel="Created At">@context.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss")</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>
}

View File

@@ -0,0 +1,65 @@
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<DataInboxDto> 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();
}
private void OnRowClick(DataInboxDto dataInboxItem)
{
NavigationManager.NavigateTo($"/datainbox/{dataInboxItem.Id}");
}
}

View File

@@ -1,9 +1,10 @@
@using MudBlazor.Internal @using MudBlazor.Internal
@using DiunaBI.Application.DTOModels
<MudExpansionPanels Class="mb-4"> <MudExpansionPanels Class="mb-4">
<MudExpansionPanel Icon="@Icons.Material.Filled.FilterList" <MudExpansionPanel Icon="@Icons.Material.Filled.FilterList"
Text="Filters" Text="Filters"
Expanded="true"> Expanded="true">
<MudGrid> <MudGrid AlignItems="Center">
<MudItem xs="12" sm="6" md="4"> <MudItem xs="12" sm="6" md="4">
<MudTextField @bind-Value="filterRequest.Search" <MudTextField @bind-Value="filterRequest.Search"
Label="Search" Label="Search"
@@ -12,15 +13,29 @@
DebounceInterval="500" DebounceInterval="500"
OnDebounceIntervalElapsed="SearchLayers" OnDebounceIntervalElapsed="SearchLayers"
Clearable="true"/> Clearable="true"/>
</MudItem> </MudItem>
<MudItem xs="12" sm="6" md="4"> <MudItem xs="12" sm="6" md="4">
<MudButton Variant="Variant.Outlined" <MudSelect T="LayerType?"
OnClick="ClearFilters" Value="filterRequest.Type"
StartIcon="Icons.Material.Filled.Clear"> ValueChanged="OnTypeChanged"
Clear filters Label="Type"
</MudButton> 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> </MudItem>
</MudGrid> </MudGrid>
</MudExpansionPanel> </MudExpansionPanel>
@@ -66,7 +81,9 @@
Selected="layers.Page" Selected="layers.Page"
SelectedChanged="OnPageChanged" SelectedChanged="OnPageChanged"
ShowFirstButton="true" ShowFirstButton="true"
ShowLastButton="true"/> ShowLastButton="true"
Variant="Variant.Outlined"
/>
</MudItem> </MudItem>
</MudGrid> </MudGrid>
} }

View File

@@ -58,6 +58,20 @@ public partial class LayerListComponent : ComponentBase
await LoadLayers(); 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) private void OnRowClick(LayerDto layer)
{ {
NavigationManager.NavigateTo($"/layers/{layer.Id}"); NavigationManager.NavigateTo($"/layers/{layer.Id}");

View File

@@ -1,10 +0,0 @@
@using Microsoft.AspNetCore.Components.Routing
@using MudBlazor
<MudNavMenu>
<MudNavLink href="dashboard" Icon="@Icons.Material.Filled.Dashboard" Match="NavLinkMatch.All">
Dashboard
</MudNavLink>
<MudNavLink Href="layers" Icon="@Icons.Material.Filled.List" Match="NavLinkMatch.All">
Layers
</MudNavLink>
</MudNavMenu>

View File

@@ -36,6 +36,7 @@ public static class ServiceCollectionExtensions
// Services // Services
services.AddScoped<AuthService>(); services.AddScoped<AuthService>();
services.AddScoped<LayerService>(); services.AddScoped<LayerService>();
services.AddScoped<DataInboxService>();
return services; return services;
} }

View File

@@ -5,6 +5,7 @@
<AuthGuard> <AuthGuard>
<MudThemeProvider Theme="_theme"/> <MudThemeProvider Theme="_theme"/>
<MudPopoverProvider/>
<MudDialogProvider/> <MudDialogProvider/>
<MudSnackbarProvider/> <MudSnackbarProvider/>
@@ -35,6 +36,7 @@
<MudNavMenu> <MudNavMenu>
<MudNavLink Href="/dashboard" Icon="@Icons.Material.Filled.Dashboard">Dashboard</MudNavLink> <MudNavLink Href="/dashboard" Icon="@Icons.Material.Filled.Dashboard">Dashboard</MudNavLink>
<MudNavLink Href="/layers" Icon="@Icons.Material.Filled.Inventory">Layers</MudNavLink> <MudNavLink Href="/layers" Icon="@Icons.Material.Filled.Inventory">Layers</MudNavLink>
<MudNavLink Href="/datainbox" Icon="@Icons.Material.Filled.Inbox">Data Inbox</MudNavLink>
</MudNavMenu> </MudNavMenu>
</MudDrawer> </MudDrawer>

View File

@@ -0,0 +1,75 @@
@page "/datainbox/{id:guid}"
@using DiunaBI.UI.Shared.Services
@using DiunaBI.Application.DTOModels
@using MudBlazor
@inject DataInboxService DataInboxService
@inject NavigationManager NavigationManager
<MudCard>
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h5">Data Inbox Details</MudText>
</CardHeaderContent>
<CardHeaderActions>
<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 (dataInbox == null)
{
<MudAlert Severity="Severity.Error">Data Inbox item not found</MudAlert>
}
else
{
<MudGrid>
<MudItem xs="12" md="4">
<MudTextField @bind-Value="dataInbox.Name"
Label="Name"
Variant="Variant.Outlined"
ReadOnly="true"
FullWidth="true"/>
</MudItem>
<MudItem xs="12" md="4">
<MudTextField @bind-Value="dataInbox.Source"
Label="Source"
Variant="Variant.Outlined"
ReadOnly="true"
FullWidth="true"/>
</MudItem>
<MudItem xs="12" md="4">
<MudTextField Value="@dataInbox.CreatedAt.ToString("g")"
Label="Created At"
Variant="Variant.Outlined"
ReadOnly="true"
FullWidth="true"/>
</MudItem>
</MudGrid>
<MudDivider Class="my-4"/>
<MudText Typo="Typo.h6" Class="mb-2">Decoded Data</MudText>
@if (string.IsNullOrEmpty(decodedData))
{
<MudAlert Severity="Severity.Info">No data available</MudAlert>
}
else if (hasDecodingError)
{
<MudAlert Severity="Severity.Error">Error decoding Base64 data</MudAlert>
<MudPaper Class="pa-4 mt-2" Elevation="0">
<MudText Typo="Typo.body2" Style="font-family: monospace; white-space: pre-wrap; word-break: break-all;">@dataInbox.Data</MudText>
</MudPaper>
}
else
{
<MudPaper Class="pa-4" Elevation="0" Style="background-color: #f5f5f5; max-height: 600px; overflow-y: auto;">
<MudText Typo="Typo.body2" Style="font-family: monospace; white-space: pre-wrap; word-break: break-word;">@decodedData</MudText>
</MudPaper>
}
}
</MudCardContent>
</MudCard>

View File

@@ -0,0 +1,84 @@
using DiunaBI.Application.DTOModels;
using Microsoft.AspNetCore.Components;
using MudBlazor;
using System.Text;
namespace DiunaBI.UI.Shared.Pages;
public partial class DataInboxDetailPage : ComponentBase
{
[Parameter]
public Guid Id { get; set; }
[Inject]
private ISnackbar Snackbar { get; set; } = null!;
private DataInboxDto? dataInbox;
private string? decodedData;
private bool hasDecodingError = false;
private bool isLoading = false;
protected override async Task OnInitializedAsync()
{
await LoadDataInbox();
}
protected override async Task OnParametersSetAsync()
{
await LoadDataInbox();
}
private async Task LoadDataInbox()
{
isLoading = true;
StateHasChanged();
try
{
dataInbox = await DataInboxService.GetDataInboxByIdAsync(Id);
if (dataInbox != null)
{
DecodeData();
}
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error loading data inbox: {ex.Message}");
Snackbar.Add("Error loading data inbox item", Severity.Error);
}
finally
{
isLoading = false;
StateHasChanged();
}
}
private void DecodeData()
{
if (dataInbox == null || string.IsNullOrEmpty(dataInbox.Data))
{
decodedData = null;
hasDecodingError = false;
return;
}
try
{
var base64Bytes = Convert.FromBase64String(dataInbox.Data);
decodedData = Encoding.UTF8.GetString(base64Bytes);
hasDecodingError = false;
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error decoding Base64 data: {ex.Message}");
decodedData = null;
hasDecodingError = true;
}
}
private void GoBack()
{
NavigationManager.NavigateTo("/datainbox");
}
}

View File

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

View File

@@ -0,0 +1,51 @@
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<PagedResult<DataInboxDto>> 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 += $"&search={Uri.EscapeDataString(filterRequest.Search)}";
}
var response = await _httpClient.GetAsync(query);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<PagedResult<DataInboxDto>>(json, _jsonOptions);
return result ?? new PagedResult<DataInboxDto>();
}
public async Task<DataInboxDto?> GetDataInboxByIdAsync(Guid id)
{
var response = await _httpClient.GetAsync($"DataInbox/{id}");
if (!response.IsSuccessStatusCode)
return null;
return await response.Content.ReadFromJsonAsync<DataInboxDto>();
}
}

View File

@@ -28,10 +28,8 @@ public class LayerService
if (!string.IsNullOrEmpty(filterRequest.Search)) if (!string.IsNullOrEmpty(filterRequest.Search))
query += $"&name={Uri.EscapeDataString(filterRequest.Search)}"; query += $"&name={Uri.EscapeDataString(filterRequest.Search)}";
/* if (filterRequest.Type.HasValue)
if (type.HasValue) query += $"&type={(int)filterRequest.Type.Value}";
query += $"&type={type.Value}";
*/
var response = await _httpClient.GetAsync(query); var response = await _httpClient.GetAsync(query);
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();

View File

@@ -9,6 +9,7 @@
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" /> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" /> <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<link href="DiunaBI.UI.Web.styles.css" rel="stylesheet" /> <link href="DiunaBI.UI.Web.styles.css" rel="stylesheet" />
<link href="app.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" /> <link rel="icon" type="image/png" href="favicon.png" />
<script src="https://accounts.google.com/gsi/client" async defer></script> <script src="https://accounts.google.com/gsi/client" async defer></script>
<HeadOutlet /> <HeadOutlet />

View File

@@ -49,3 +49,12 @@ h1:focus {
.darker-border-checkbox.form-check-input { .darker-border-checkbox.form-check-input {
border-color: #929292; border-color: #929292;
} }
/* remove list markers for MudPagination */
.mud-pagination {
list-style: none;
padding-inline-start: 0;
}
.mud-pagination li::marker {
display: none;
}