feat: add filtering by ServiceName and Key in email templates query and UI #11

Merged
agrynco merged 1 commits from development into main 2026-05-17 11:43:55 +03:00
7 changed files with 56 additions and 10 deletions
Showing only changes of commit 07f536938f - Show all commits
@@ -4,7 +4,7 @@ namespace HrynCo.NotificationService.DAL.Abstract.Repositories;
public interface IEmailTemplateRepository public interface IEmailTemplateRepository
{ {
Task<IReadOnlyList<EmailTemplate>> GetAllAsync(CancellationToken ct = default); Task<IReadOnlyList<EmailTemplate>> GetAllAsync(string? serviceName = null, string? key = null, CancellationToken ct = default);
Task<IReadOnlyList<EmailTemplate>> GetByServiceAsync(string serviceName, CancellationToken ct = default); Task<IReadOnlyList<EmailTemplate>> GetByServiceAsync(string serviceName, CancellationToken ct = default);
Task<EmailTemplate?> GetAsync(string serviceName, string key, string languageCode, CancellationToken ct = default); Task<EmailTemplate?> GetAsync(string serviceName, string key, string languageCode, CancellationToken ct = default);
Task AddAsync(EmailTemplate template, CancellationToken ct = default); Task AddAsync(EmailTemplate template, CancellationToken ct = default);
@@ -13,9 +13,21 @@ internal sealed class EmailTemplateRepository
{ {
} }
public async Task<IReadOnlyList<EmailTemplate>> GetAllAsync(CancellationToken ct = default) public async Task<IReadOnlyList<EmailTemplate>> GetAllAsync(string? serviceName = null, string? key = null, CancellationToken ct = default)
{ {
List<EmailTemplateEntity> entities = await EfRepository.Get() IQueryable<EmailTemplateEntity> query = EfRepository.Get();
if (!string.IsNullOrWhiteSpace(serviceName))
{
query = query.Where(x => x.ServiceName == serviceName);
}
if (!string.IsNullOrWhiteSpace(key))
{
query = query.Where(x => x.Key == key);
}
List<EmailTemplateEntity> entities = await query
.OrderBy(x => x.ServiceName).ThenBy(x => x.Key) .OrderBy(x => x.ServiceName).ThenBy(x => x.Key)
.AsNoTracking() .AsNoTracking()
.ToListAsync(ct); .ToListAsync(ct);
@@ -22,7 +22,7 @@ internal sealed class GetAllEmailTemplatesHandler
protected override async Task<ServiceResult<IReadOnlyList<EmailTemplate>>> DoOnHandle( protected override async Task<ServiceResult<IReadOnlyList<EmailTemplate>>> DoOnHandle(
GetAllEmailTemplatesQuery request, CancellationToken cancellationToken) GetAllEmailTemplatesQuery request, CancellationToken cancellationToken)
{ {
var templates = await _templates.GetAllAsync(cancellationToken); var templates = await _templates.GetAllAsync(request.ServiceName, request.Key, cancellationToken);
return Success(templates); return Success(templates);
} }
} }
@@ -4,4 +4,5 @@ using HrynCo.NotificationService.Services.Core;
namespace HrynCo.NotificationService.Services.EmailTemplates.GetAll; namespace HrynCo.NotificationService.Services.EmailTemplates.GetAll;
public sealed record GetAllEmailTemplatesQuery : IRequest<ServiceResult<IReadOnlyList<EmailTemplate>>>; public sealed record GetAllEmailTemplatesQuery(string? ServiceName = null, string? Key = null)
: IRequest<ServiceResult<IReadOnlyList<EmailTemplate>>>;
@@ -23,9 +23,12 @@ public class AdminTemplatesController : Controller
// GET /admin/templates // GET /admin/templates
[HttpGet("")] [HttpGet("")]
public async Task<IActionResult> Index(CancellationToken ct) public async Task<IActionResult> Index([FromQuery] string? serviceName, [FromQuery] string? key, CancellationToken ct)
{ {
var result = await _mediator.Send(new GetAllEmailTemplatesQuery(), ct); ViewData["ServiceNameFilter"] = serviceName;
ViewData["KeyFilter"] = key;
var result = await _mediator.Send(new GetAllEmailTemplatesQuery(serviceName, key), ct);
if (!result.IsSuccess) if (!result.IsSuccess)
{ {
ModelState.AddModelError("", result.Error?.Message ?? "Failed to load templates."); ModelState.AddModelError("", result.Error?.Message ?? "Failed to load templates.");
@@ -1,6 +1,7 @@
using HrynCo.NotificationService.Web.Infrastructure; using HrynCo.NotificationService.Web.Infrastructure;
using HrynCo.NotificationService.Services.EmailTemplates.Create; using HrynCo.NotificationService.Services.EmailTemplates.Create;
using HrynCo.NotificationService.Services.EmailTemplates.Delete; using HrynCo.NotificationService.Services.EmailTemplates.Delete;
using HrynCo.NotificationService.Services.EmailTemplates.GetAll;
using HrynCo.NotificationService.Services.EmailTemplates.Get; using HrynCo.NotificationService.Services.EmailTemplates.Get;
using HrynCo.NotificationService.Services.EmailTemplates.GetByService; using HrynCo.NotificationService.Services.EmailTemplates.GetByService;
using HrynCo.NotificationService.Services.EmailTemplates.Update; using HrynCo.NotificationService.Services.EmailTemplates.Update;
@@ -15,9 +16,9 @@ public sealed class EmailTemplatesController : ApiControllerBase
public EmailTemplatesController(IMediator mediator) : base(mediator) { } public EmailTemplatesController(IMediator mediator) : base(mediator) { }
[HttpGet] [HttpGet]
public async Task<IActionResult> GetAll([FromQuery] string serviceName, CancellationToken cancellationToken) public async Task<IActionResult> GetAll([FromQuery] string? serviceName, [FromQuery] string? key, CancellationToken cancellationToken)
{ {
var result = await Mediator.Send(new GetEmailTemplatesQuery(serviceName), cancellationToken); var result = await Mediator.Send(new GetAllEmailTemplatesQuery(serviceName, key), cancellationToken);
return FromServiceResult(result); return FromServiceResult(result);
} }
@@ -2,6 +2,8 @@
@model IReadOnlyList<EmailTemplate> @model IReadOnlyList<EmailTemplate>
@{ @{
ViewData["Title"] = "Email Templates"; ViewData["Title"] = "Email Templates";
var serviceNameFilter = ViewData["ServiceNameFilter"] as string ?? string.Empty;
var keyFilter = ViewData["KeyFilter"] as string ?? string.Empty;
} }
<div class="page-header"> <div class="page-header">
@@ -11,6 +13,33 @@
</a> </a>
</div> </div>
<div class="card shadow-sm mb-3">
<div class="card-body">
<form method="get" action="/admin/templates" class="row g-2 align-items-end">
<div class="col-12 col-md-5">
<label class="form-label fw-semibold" for="serviceName">Service Name</label>
<input id="serviceName"
name="serviceName"
value="@serviceNameFilter"
class="form-control"
placeholder="Filter by service name" />
</div>
<div class="col-12 col-md-5">
<label class="form-label fw-semibold" for="key">Key</label>
<input id="key"
name="key"
value="@keyFilter"
class="form-control"
placeholder="Filter by key" />
</div>
<div class="col-12 col-md-2 d-flex gap-2">
<button type="submit" class="btn btn-primary w-100">Filter</button>
<a href="/admin/templates" class="btn btn-outline-secondary w-100">Clear</a>
</div>
</form>
</div>
</div>
@if (!ViewData.ModelState.IsValid) @if (!ViewData.ModelState.IsValid)
{ {
<div class="alert alert-danger"> <div class="alert alert-danger">