Skip to content

feat: Add archive action to CategoriesPage (admin-only)#138

Merged
mpaulosky merged 3 commits intomainfrom
squad/124-categories-page-archive-ui
Apr 15, 2026
Merged

feat: Add archive action to CategoriesPage (admin-only)#138
mpaulosky merged 3 commits intomainfrom
squad/124-categories-page-archive-ui

Conversation

@mpaulosky
Copy link
Copy Markdown
Owner

Summary

Adds admin-only Archive button with confirmation dialog to CategoriesPage.

Changes

  • Add ArchiveAsync method to ICategoryApiClient interface
  • Implement ArchiveAsync in CategoryApiClient (DELETE /api/v1/categories/{id})
  • Add Archive button to CategoriesPage visible only to admins
  • Add ConfirmDialog for archive confirmation
  • Implement optimistic UI update after successful archive

Testing

Tested locally (API endpoint may return 404 until PR #134 for #120 is merged).

Working as Legolas (Frontend Developer)

Closes #124
Depends on #120

Copilot AI review requested due to automatic review settings April 15, 2026 03:12
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 15, 2026

Test Results Summary

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

Results for commit e6f43d9. ± 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

This PR adds an admin-only archive action for Categories in the Web UI/client and extends Issue listing to support filtering by Status and Category across Shared contracts, API, and Web.

Changes:

  • Add ArchiveAsync to ICategoryApiClient and wire a new Archive button + confirmation dialog into CategoriesPage.
  • Add StatusName / CategoryName filters to ListIssuesQuery, API endpoint/handler/repository, and Web IssueApiClient/IssuesPage.
  • Update API unit tests to match the expanded IIssueRepository.GetAllAsync signature.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/Api.Tests.Unit/Handlers/Issues/ListIssuesHandlerTests.cs Updates mocks/expectations for expanded repository filter parameters.
tests/Api.Tests.Unit/Endpoints/IssueEndpointsTests.cs Updates endpoint test mock signature for issue listing.
src/Web/Components/Features/Issues/IssuesPage.razor Passes status/category filter values into the issue list API call.
src/Web/Components/Features/Issues/IssueApiClient.cs Extends GetAllAsync API to include status/category query params.
src/Web/Components/Features/Categories/CategoryApiClient.cs Adds ArchiveAsync calling DELETE /api/v1/categories/{id}.
src/Web/Components/Features/Categories/CategoriesPage.razor.cs Adds archive dialog state + confirm/cancel handlers and optimistic removal.
src/Web/Components/Features/Categories/CategoriesPage.razor Adds Archive button (admin-only) and confirmation dialog markup.
src/Shared/Contracts/ListIssuesQuery.cs Adds StatusName and CategoryName filter properties.
src/Api/Handlers/Issues/ListIssuesHandler.cs Passes new filters to IIssueRepository.GetAllAsync.
src/Api/Handlers/Issues/IssueEndpoints.cs Accepts statusName and categoryName query params and maps them onto ListIssuesQuery.
src/Api/Data/IssueRepository.cs Adds Mongo filters for status/category via regex.
src/Api/Data/Interfaces/IIssueRepository.cs Expands GetAllAsync signature to include status/category filter params.

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.

The PR description focuses on adding an admin-only archive action for Categories, but this diff also introduces new Issue list filtering parameters (statusName, categoryName) across Shared contracts, API endpoints/repository, and Web UI/client. Either update the PR description to include this additional scope or split the Issue filtering work into a separate PR to keep review/rollback isolated.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +46
<AuthorizeView Policy="Admin">
<Authorized>
<RadzenButton Icon="archive" ButtonStyle="ButtonStyle.Danger" Size="ButtonSize.Small"
Click="@(() => HandleArchive(cat.Id, cat.CategoryName))" @onclick:stopPropagation="true"
Class="ms-1" />
</Authorized>
</AuthorizeView>
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.

AuthorizeView is using Policy="Admin", but the Web app appears to use role-based checks ([Authorize(Roles = "Admin")], <AuthorizeView Roles="Admin">) and no "Admin" policy is configured. This can hide the Archive button for admins or throw at runtime when the policy can't be found. Use Roles="Admin" here (or define an Admin authorization policy in AuthExtensions).

Copilot uses AI. Check for mistakes.
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.

New query fields StatusName and CategoryName were added, but ListIssuesQueryValidator currently only constrains SearchTerm/AuthorName length. To keep input validation consistent (and avoid extremely long values being passed through to Mongo regex filters), add MaximumLength rules for StatusName and CategoryName similar to the existing ones.

Copilot uses AI. Check for mistakes.
/// <param name="categoryName">Optional category name to filter by.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<PaginatedResponse<IssueDto>> GetAllAsync(int page = 1, int pageSize = 20, string? searchTerm = null, string? authorName = null, CancellationToken cancellationToken = default);
Task<PaginatedResponse<IssueDto>> GetAllAsync(int page = 1, int pageSize = 20, string? searchTerm = null, string? authorName = null, string? statusName = null, string? categoryName = null, CancellationToken cancellationToken = default);
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.

IIssueApiClient.GetAllAsync signature has changed (added statusName and categoryName). There are still call sites in the repo (e.g. tests/Web.Tests.Bunit/Components/Features/Issues/IssuesPageTests.cs) using the old 5-parameter overload, which will fail to compile. Update those mocks/calls to include the new optional parameters (or switch to named arguments) so the solution builds/tests pass.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +70
if (!string.IsNullOrWhiteSpace(statusName))
{
url += $"&statusName={Uri.EscapeDataString(statusName)}";
}
if (!string.IsNullOrWhiteSpace(categoryName))
{
url += $"&categoryName={Uri.EscapeDataString(categoryName)}";
}
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.

GetAllAsync now appends statusName and categoryName to the query string, but the existing unit tests for IssueApiClient only cover searchTerm and authorName. Add tests that assert these new parameters are included/escaped correctly when provided (and omitted when null/whitespace).

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.

Filtering by statusName/categoryName was added to the Mongo query, but there are no integration tests asserting that these new filters actually constrain results. Add IssueRepositoryTests coverage that creates issues with different embedded StatusDto.StatusName / CategoryDto.CategoryName values and verifies GetAllAsync(..., statusName: ..., categoryName: ...) returns only matching items.

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 15, 2026

Codecov Report

❌ Patch coverage is 0% with 55 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.55%. Comparing base (ced28d8) to head (d69bd95).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...Components/Features/Statuses/StatusesPage.razor.cs 0.00% 15 Missing and 2 partials ⚠️
...onents/Features/Categories/CategoriesPage.razor.cs 0.00% 14 Missing and 2 partials ⚠️
...eb/Components/Features/Statuses/StatusesPage.razor 0.00% 10 Missing and 1 partial ⚠️
...omponents/Features/Categories/CategoryApiClient.cs 0.00% 5 Missing ⚠️
...eb/Components/Features/Statuses/StatusApiClient.cs 0.00% 5 Missing ⚠️
...omponents/Features/Categories/CategoriesPage.razor 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #138      +/-   ##
==========================================
- Coverage   55.39%   54.55%   -0.84%     
==========================================
  Files         128      128              
  Lines        2939     2984      +45     
  Branches      332      336       +4     
==========================================
  Hits         1628     1628              
- Misses       1068     1109      +41     
- Partials      243      247       +4     
Files with missing lines Coverage Δ
...omponents/Features/Categories/CategoriesPage.razor 0.00% <0.00%> (ø)
...omponents/Features/Categories/CategoryApiClient.cs 73.91% <0.00%> (-20.54%) ⬇️
...eb/Components/Features/Statuses/StatusApiClient.cs 73.91% <0.00%> (-20.54%) ⬇️
...eb/Components/Features/Statuses/StatusesPage.razor 0.00% <0.00%> (ø)
...onents/Features/Categories/CategoriesPage.razor.cs 4.47% <0.00%> (-1.41%) ⬇️
...Components/Features/Statuses/StatusesPage.razor.cs 4.41% <0.00%> (-1.48%) ⬇️
🚀 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.

Scribe and others added 3 commits April 15, 2026 10:09
- Add ArchiveAsync method to ICategoryApiClient interface
- Implement ArchiveAsync in CategoryApiClient (DELETE /api/v1/categories/{id})
- Add Archive button to CategoriesPage visible only to admins
- Add ConfirmDialog for archive confirmation
- Implement optimistic UI update after successful archive
- Use confirmation message: 'Archive '{CategoryName}'? It will no longer appear in issue forms.'

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add ArchiveAsync method to IStatusApiClient interface and implementation
- Add archive button (admin-only) to StatusesPage with confirmation dialog
- Display confirmation message warning about status reassignment
- Optimistically remove archived status from local list on success
- Follow existing UI patterns from IssueDetailPage and CategoriesPage

Working as Legolas (Frontend Developer)

Closes #123
Depends on #121

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ge bunit tests

AuthorizeView in CategoriesPage and StatusesPage requires IAuthorizationPolicyProvider.
Add _ctx.AddAuthorization() to test constructors so row templates render correctly
when the grid has data.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mpaulosky mpaulosky force-pushed the squad/124-categories-page-archive-ui branch from e6f43d9 to d69bd95 Compare April 15, 2026 17:10
@mpaulosky mpaulosky enabled auto-merge (squash) April 15, 2026 17:10
@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 3f1f553 into main Apr 15, 2026
19 checks passed
@mpaulosky mpaulosky deleted the squad/124-categories-page-archive-ui branch April 15, 2026 17:13
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.

[Feature] UI: Add archive action to CategoriesPage (admin-only)

2 participants