Skip to content

Commit 0fef639

Browse files
Adds recent processed files endpoint (#84)
Exposes an endpoint to retrieve and display recently processed files from both Offloc and Delius contexts. This provides users with a quick overview of the latest file processing activity.
1 parent 48ddb36 commit 0fef639

File tree

7 files changed

+173
-3
lines changed

7 files changed

+173
-3
lines changed

src/API/Endpoints/VisualisationEndpoints.cs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,40 @@ public static IEndpointRouteBuilder RegisterVisualisationEndpoints(this IEndpoin
2424
.ProducesProblem(StatusCodes.Status500InternalServerError)
2525
.RequireAuthorization("visualisation-write");
2626

27+
28+
group.MapGet("/processedfiles", GetRecentProcessedFiles)
29+
.Produces<ProcessedFileDto[]>();
30+
2731
group.RequireAuthorization("visualisation-read");
2832

2933
return routes;
3034
}
3135

36+
private static async Task<IResult> GetRecentProcessedFiles([FromServices] OfflocContext offlocContext, [FromServices] DeliusContext deliusContext)
37+
{
38+
var offlocFiles = await offlocContext.ProcessedFiles
39+
.OrderByDescending(pf => pf.ValidFrom)
40+
.Take(5)
41+
.Select(c => new ProcessedFileDto()
42+
{
43+
FileName = c.FileName,
44+
Status = c.Status,
45+
ValidFrom = c.ValidFrom
46+
}).ToArrayAsync();
47+
48+
var deliusFiles = await deliusContext.ProcessedFiles
49+
.OrderByDescending(pf => pf.ValidFrom)
50+
.Take(5)
51+
.Select(c => new ProcessedFileDto()
52+
{
53+
FileName = c.FileName,
54+
Status = c.Status,
55+
ValidFrom = c.ValidFrom
56+
}).ToArrayAsync();
57+
58+
return Results.Ok(offlocFiles.Union(deliusFiles));
59+
}
60+
3261
public static async Task<IResult> GetDetailsByUpciAsync([FromServices] ApiServices services, string upci)
3362
{
3463
var cluster = await services.VisualisationRepository.GetDetailsByUpciAsync(upci);
@@ -41,7 +70,7 @@ public static async Task<IResult> GenerateClusterAsync([FromServices] ApiService
4170
{
4271
var cluster = await services.ClusteringRepository.GenerateClusterAsync();
4372

44-
if(cluster is null)
73+
if (cluster is null)
4574
{
4675
return Results.NotFound();
4776
}
@@ -53,7 +82,7 @@ public static async Task<IResult> SaveNetworkAsync([FromServices] ApiServices se
5382
{
5483
var success = await services.VisualisationRepository.SaveNetworkAsync(network);
5584

56-
return success is false
85+
return success is false
5786
? Results.InternalServerError()
5887
: Results.Ok();
5988

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace Infrastructure.DTOs;
7+
8+
public class ProcessedFileDto
9+
{
10+
public required string FileName {get;set;}
11+
public DateTime ValidFrom {get;set;}
12+
public required string Status {get;set;}
13+
}
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
namespace Infrastructure.Entities.Delius;
1+
using Microsoft.Identity.Client;
2+
3+
namespace Infrastructure.Entities.Delius;
24

35
public partial class ProcessedFile
46
{
57
public string FileName { get; set; } = null!;
68

79
public int FileId { get; set; }
10+
11+
public string Status {get; set;} = null!;
12+
13+
public DateTime ValidFrom { get;set; }
814
}

src/Libraries/Infrastructure/Entities/Offloc/ProcessedFile.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ public partial class ProcessedFile
55
public string FileName { get; set; } = null!;
66

77
public int FileId { get; set; }
8+
9+
public DateTime ValidFrom {get;set;}
10+
11+
public string Status{ get;set;} = null!;
812
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
@page "{handler?}"
2+
3+
@model ProcessedFilesModel
4+
5+
@{
6+
ViewData["Title"] = "Processed Files";
7+
}
8+
9+
<h1>Most recent processed files</h1>
10+
11+
12+
13+
@if (!Model.ModelState.IsValid)
14+
{
15+
<div class="alert alert-danger">
16+
@foreach (var error in ViewData.ModelState.Values.SelectMany(v => v.Errors))
17+
{
18+
<div>@error.ErrorMessage</div>
19+
}
20+
</div>
21+
}
22+
23+
@if(Model.ProcessedFiles is { Length: > 0 })
24+
{
25+
<table class="table table-striped table-bordered">
26+
<thead>
27+
<tr>
28+
<th>File name</th>
29+
<th>Date</th>
30+
<th>Status</th>
31+
</tr>
32+
</thead>
33+
<tbody>
34+
@foreach(var file in Model.ProcessedFiles)
35+
{
36+
<tr>
37+
<td>@file.FileName</td>
38+
<td>@file.ValidFrom</td>
39+
<td>@file.Status</td>
40+
</tr>
41+
}
42+
</tbody>
43+
</table>
44+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text.Json;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore.Mvc;
7+
using Microsoft.AspNetCore.Mvc.RazorPages;
8+
using Microsoft.Identity.Abstractions;
9+
using Microsoft.Identity.Client;
10+
11+
namespace Visualiser.Pages
12+
{
13+
public class ProcessedFilesModel(IDownstreamApi api) : PageModel
14+
{
15+
16+
// Bindable property for the view
17+
public ProcessedFileDto[] ProcessedFiles { get; private set; } = Array.Empty<ProcessedFileDto>();
18+
19+
public async Task<IActionResult> OnGetAsync()
20+
{
21+
HttpResponseMessage? response = null;
22+
try
23+
{
24+
response = await api.CallApiForUserAsync("DMS", opts => opts.RelativePath = "Visualisation/processedfiles");
25+
}
26+
catch (Exception ex) when (ex.InnerException is MsalUiRequiredException { ErrorCode: MsalError.UserNullError })
27+
{
28+
return Challenge();
29+
}
30+
31+
if (response is null)
32+
{
33+
ModelState.AddModelError(string.Empty, "No response");
34+
return Page();
35+
}
36+
37+
if (response.IsSuccessStatusCode)
38+
{
39+
40+
try
41+
{
42+
var options = new JsonSerializerOptions
43+
{
44+
PropertyNameCaseInsensitive = true
45+
};
46+
47+
48+
var json = await response.Content.ReadAsStringAsync();
49+
ProcessedFiles = JsonSerializer.Deserialize<ProcessedFileDto[]>(json, options)
50+
?? Array.Empty<ProcessedFileDto>();
51+
}
52+
catch(JsonException)
53+
{
54+
ModelState.AddModelError(string.Empty, $"Failed to parse API response");
55+
}
56+
57+
}
58+
59+
return Page();
60+
}
61+
}
62+
63+
public class ProcessedFileDto
64+
{
65+
public required string FileName { get; set; }
66+
public DateTime ValidFrom { get; set; }
67+
public required string Status { get; set; }
68+
}
69+
}

src/Visualiser/Pages/Shared/_Layout.cshtml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
3737
</li>
3838
</ul>
39+
<ul class="navbar-nav flex-grow-1">
40+
<li class="nav-item">
41+
<a class="nav-link text-dark" asp-area="" asp-page="/ProcessedFiles">Files</a>
42+
</li>
43+
</ul>
3944
<partial name="_LoginPartial" />
4045
</div>
4146
</div>

0 commit comments

Comments
 (0)