Skip to content

fix: wire filter/search params to Issues API (#116)#136

Merged
mpaulosky merged 7 commits intomainfrom
squad/116-issues-page-filter-wiring
Apr 15, 2026
Merged

fix: wire filter/search params to Issues API (#116)#136
mpaulosky merged 7 commits intomainfrom
squad/116-issues-page-filter-wiring

Conversation

@mpaulosky
Copy link
Copy Markdown
Owner

Closes #116

Summary

Wires the filter/search parameters from the IssuesPage UI through all backend layers to the MongoDB repository, enabling users to actually filter issues by status and category.

Changes Made

  • ✅ Added StatusName and CategoryName properties to ListIssuesQuery
  • ✅ Added statusName and categoryName parameters to IIssueRepository.GetAllAsync
  • ✅ Implemented MongoDB filtering for Status.StatusName and Category.CategoryName
  • ✅ Updated ListIssuesHandler to pass filter parameters to repository
  • ✅ Added query parameters to IssueEndpoints MapGet handler
  • ✅ Updated IssueApiClient interface and implementation with new parameters
  • ✅ Wired _statusFilter and _categoryFilter from IssuesPage to API client
  • ✅ Updated all test signatures to match new repository method signature

Testing

  • ✅ All unit tests pass (Api.Tests.Unit, Shared.Tests.Unit)
  • Note: Web test failures are pre-existing npm/CSS build issues unrelated to this PR

Working as

🤖 Working as Sam (Backend Developer)

- Add StatusName and CategoryName properties to ListIssuesQuery
- Add statusName and categoryName parameters to IIssueRepository.GetAllAsync
- Add MongoDB filtering for Status.StatusName and Category.CategoryName in IssueRepository
- Pass StatusName and CategoryName from ListIssuesHandler to repository
- Add statusName and categoryName query params to IssueEndpoints MapGet
- Add statusName and categoryName to IssueApiClient interface and implementation
- Wire _statusFilter and _categoryFilter from IssuesPage to API client
- Update all test signatures to match new repository method signature

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 15, 2026 03:08
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 15, 2026

Test Results Summary

  6 files  ±0   33 suites  ±0   11s ⏱️ ±0s
842 tests ±0  842 ✅ ±0  0 💤 ±0  0 ❌ ±0 
853 runs  ±0  853 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 7d738fa. ± Comparison against base commit 4b0f9b6.

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Wires IssuesPage filter inputs (search/status/category) through the Web API client, API endpoint/handler, and MongoDB repository so list results can be filtered server-side (Closes #116).

Changes:

  • Added StatusName/CategoryName filters to ListIssuesQuery and threaded them through handler → repository.
  • Extended /api/v1/issues endpoint and Web IIssueApiClient to accept statusName/categoryName query parameters.
  • Implemented MongoDB filtering on Status.StatusName and Category.CategoryName and updated unit test mocks for the new repository signature.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/Api.Tests.Unit/Handlers/Issues/ListIssuesHandlerTests.cs Updates repository mock calls to new GetAllAsync signature.
tests/Api.Tests.Unit/Endpoints/IssueEndpointsTests.cs Updates endpoint test repository mock signature for list route.
src/Web/Components/Features/Issues/IssuesPage.razor Passes _searchTerm, _statusFilter, _categoryFilter into API client call.
src/Web/Components/Features/Issues/IssueApiClient.cs Adds statusName/categoryName to client contract and query-string construction.
src/Shared/Contracts/ListIssuesQuery.cs Adds StatusName and CategoryName properties to the shared query contract.
src/Api/Handlers/Issues/ListIssuesHandler.cs Forwards new query fields into repository call.
src/Api/Handlers/Issues/IssueEndpoints.cs Adds new query params to the list endpoint and maps them into ListIssuesQuery.
src/Api/Data/IssueRepository.cs Adds MongoDB filters for status/category name.
src/Api/Data/Interfaces/IIssueRepository.cs Extends repository interface signature to accept status/category filters.
Comments suppressed due to low confidence (1)

tests/Api.Tests.Unit/Endpoints/IssueEndpointsTests.cs:47

  • This endpoint test only verifies a 200 response and doesn’t cover the new query parameters. Add a test that calls /api/v1/issues?statusName=...&categoryName=... and asserts the repository substitute received GetAllAsync with the expected statusName/categoryName values, so the new binding/forwarding is covered.
	public async Task ListIssues_ReturnsOk()
	{
		// Arrange
		IReadOnlyList<IssueDto> items = [];
		_factory.IssueRepository
			.GetAllAsync(Arg.Any<int>(), Arg.Any<int>(), Arg.Any<string?>(), Arg.Any<string?>(), Arg.Any<string?>(), Arg.Any<string?>(), Arg.Any<CancellationToken>())
			.Returns(Result<(IReadOnlyList<IssueDto> Items, long Total)>.Ok((items, 0L)));

		// Act
		var response = await _client.GetAsync("/api/v1/issues").ConfigureAwait(false);

Comment on lines +36 to +44
/// <summary>
/// Gets or sets the status name for filtering by status.
/// </summary>
public string? StatusName { get; init; }

/// <summary>
/// Gets or sets the category name for filtering by category.
/// </summary>
public string? CategoryName { get; init; }
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ListIssuesQueryValidator currently enforces max lengths for SearchTerm and AuthorName, but the newly added StatusName/CategoryName aren’t validated. To keep request validation consistent and avoid overly long inputs reaching the repository, add similar maximum-length rules for these new properties.

Copilot uses AI. Check for mistakes.
try
{
var response = await IssueClient.GetAllAsync(page, 20);
var response = await IssueClient.GetAllAsync(page, 20, _searchTerm, null, _statusFilter, _categoryFilter);
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call is now relying on positional arguments with an in-the-middle null placeholder for authorName, which is brittle as the method signature grows. Use named arguments for the optional parameters (e.g., searchTerm: _searchTerm, statusName: _statusFilter, categoryName: _categoryFilter) to prevent accidental mis-ordering.

Suggested change
var response = await IssueClient.GetAllAsync(page, 20, _searchTerm, null, _statusFilter, _categoryFilter);
var response = await IssueClient.GetAllAsync(
page,
20,
searchTerm: _searchTerm,
authorName: null,
statusName: _statusFilter,
categoryName: _categoryFilter);

Copilot uses AI. Check for mistakes.
Comment on lines 33 to 38
var query = new ListIssuesQuery { Page = 1, PageSize = 20 };

var issues = GenerateIssueDtos(20);
_repository.GetAllAsync(1, 20, null, null, Arg.Any<CancellationToken>())
_repository.GetAllAsync(1, 20, null, null, null, null, Arg.Any<CancellationToken>())
.Returns(((IReadOnlyList<IssueDto>)issues, 42L));

Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handler tests were updated for the new repository signature, but there’s no test exercising the new StatusName/CategoryName forwarding behavior. Add a test that sets query.StatusName/query.CategoryName and asserts the repository is called with those values (and that the returned response uses the result).

Copilot uses AI. Check for mistakes.
Comment on lines +24 to 36
group.MapGet("", async (int? page, int? pageSize, string? searchTerm, string? authorName, string? statusName, string? categoryName, ListIssuesHandler handler) =>
{
var query = new ListIssuesQuery
{
Page = page ?? 1,
PageSize = pageSize ?? 20,
SearchTerm = searchTerm,
AuthorName = authorName
AuthorName = authorName,
StatusName = statusName,
CategoryName = categoryName
};
var result = await handler.Handle(query);
return Results.Ok(result);
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ListIssues endpoint doesn’t pass a CancellationToken into ListIssuesHandler.Handle, so request aborts/timeouts won’t cancel repository calls. Add a CancellationToken parameter to the delegate (e.g., CancellationToken ct) and pass it through to handler.Handle(query, ct).

Copilot uses AI. Check for mistakes.
Comment on lines +99 to +107
if (!string.IsNullOrWhiteSpace(statusName))
{
filters.Add(filterBuilder.Regex(x => x.Status.StatusName, new BsonRegularExpression(statusName, "i")));
}

if (!string.IsNullOrWhiteSpace(categoryName))
{
filters.Add(filterBuilder.Regex(x => x.Category.CategoryName, new BsonRegularExpression(categoryName, "i")));
}
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new filters build MongoDB regexes directly from user input. This can lead to unintended regex semantics and expensive patterns; it’s also less efficient than an equality/normalized match for status/category values. Consider using an exact match (e.g., Eq on a normalized field) or at least escaping/anchoring the pattern before constructing BsonRegularExpression.

Copilot uses AI. Check for mistakes.
Scribe and others added 2 commits April 15, 2026 08:19
AdminPageTests and IssuesPageTests mocked IIssueApiClient.GetAllAsync
with 5 params (missing statusName and categoryName). Update all call
sites to the correct 7-parameter signature.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mpaulosky mpaulosky enabled auto-merge (squash) April 15, 2026 15:30
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 55.39%. Comparing base (5c64f85) to head (376243e).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #136   +/-   ##
=======================================
  Coverage   55.39%   55.39%           
=======================================
  Files         128      128           
  Lines        2939     2939           
  Branches      332      332           
=======================================
  Hits         1628     1628           
  Misses       1068     1068           
  Partials      243      243           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added the squad Squad triage inbox — Lead will assign to a member label Apr 15, 2026
@github-actions
Copy link
Copy Markdown

🏗️ PR Added to Squad Triage Queue

This PR has been labeled with squad and added to the triage queue.

Next steps:

  • The squad Lead will review and assign to an appropriate team member
  • A squad:member label will be added after triage

If you know which squad member should handle this, you can add the appropriate squad:member label yourself.

@mpaulosky mpaulosky merged commit ced28d8 into main Apr 15, 2026
19 checks passed
@mpaulosky mpaulosky deleted the squad/116-issues-page-filter-wiring branch April 15, 2026 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

squad Squad triage inbox — Lead will assign to a member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] IssuesPage: Filter/search bar not wired to API

2 participants