[Sprint 19] Polish category UX, test naming, and documentation#342
Conversation
- Merge four decisions from inbox to decisions.md: * Backend data model (Sam): separate collection, nullable FK, unique name index * Test strategy (Gimli): staged test pattern, validator/handler coverage * UI cross-feature dependency (Legolas): BlogPosts -> Categories read-only query * PR #338 skill compliance (Sam): Codecov gating language clarification - Delete merged inbox files - Append orchestration summaries to affected agents' history.md - Decision metadata and consequences documented for team reference Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Appended orchestration summary to aragorn/history.md - Appended test coverage summary to gimli/history.md - Appended frontend implementation summary to legolas/history.md - Appended backend implementation and PR #338 skill notes to sam/history.md - Appended session closure to scribe/history.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ndValidatorTests #341 Align test file/class name with production EditCategoryCommand naming. Behavior assertions unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- gh-pr-comments-fallback/SKILL.md: change 'due' to 'due to' (2 instances) - legolas/history.md: correct placeholder date 2025-07-XX to actual 2026-05-15 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ale state (#341) - Create.razor & Edit.razor: CategoryId is now required only when IsPublished is true. Asterisk and 'required when publishing' hint are rendered conditionally. Drafts may be saved without a category. - Create.razor & Edit.razor: track _categoriesLoadFailed; surface load error via _error and block publish submit when categories could not be loaded. - Categories/List/Index.razor LoadAsync: clear _error on success and reset _categories = [] on failure to prevent stale UI state. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…for General category (#341) The General category is seeded via ReplaceOneAsync with IsUpsert=true. Updated three log strings so they accurately reflect the actual upsert behavior: - Invocation log: 'inserting seed data' → 'upserting General category and inserting blog posts' - Completion log: '1 category + N post(s) inserted' → '1 category upserted + N post(s) inserted' - Result message: 'categories: 1 inserted (General)' → 'categories: 1 upserted (General)' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🏗️ PR Added to Squad Triage QueueThis PR has been labeled with Next steps:
|
There was a problem hiding this comment.
Pull request overview
Polishes the Category UX across BlogPost create/edit flows and category management, while also aligning test naming and updating squad/process documentation to reflect recent decisions and learnings.
Changes:
- Make Category selection required only when publishing, and surface category-load failures in Create/Edit while guarding publish.
- Fix stale state handling in Categories list load (clear
_erroron success; clear_categorieson failure). - Rename Category validator test to
Edit*, adjust AppHost seed log wording for upsert semantics, and apply documentation/history updates.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Web.Tests/Features/Categories/Commands/EditCategoryCommandValidatorTests.cs | Renames test class/header to match EditCategoryCommandValidator. |
| src/Web/Features/Categories/List/Index.razor | Resets error/list state correctly on load success/failure. |
| src/Web/Features/BlogPosts/Edit/Edit.razor | Conditional “required when publishing” UI + category-load failure handling + publish guard. |
| src/Web/Features/BlogPosts/Create/Create.razor | Conditional “required when publishing” UI + category-load failure handling + publish guard. |
| src/AppHost/MongoDbResourceBuilderExtensions.cs | Updates seed logs/messages to reflect upsert behavior for the General category. |
| .squad/skills/gh-pr-comments-fallback/SKILL.md | Grammar fix (“due” → “due to”). |
| .squad/decisions/decisions.md | Adds/merges decisions related to issue #339 and PR #338 documentation. |
| .squad/agents/scribe/history.md | Session closure log entry for issue #339 work/decision merges. |
| .squad/agents/sam/history.md | Adds backend/seed-log wording learnings and summaries. |
| .squad/agents/legolas/history.md | Adds UI polish learnings and fixes placeholder date. |
| .squad/agents/gimli/history.md | Documents the test rename work and validation. |
| .squad/agents/frodo/history.md | Documents documentation polish work. |
| .squad/agents/aragorn/history.md | Adds triage summary and routing notes for issue #341. |
| @@ -113,7 +125,13 @@ else if (_model is not null) | |||
| await Task.WhenAll(categoriesTask, postTask); | |||
|
|
|||
| var categoriesResult = await categoriesTask; | |||
| if (categoriesResult is { Success: true }) _categories = categoriesResult.Value!; | |||
| if (categoriesResult is { Success: true }) | |||
| _categories = categoriesResult.Value!; | |||
| else | |||
| { | |||
| _categoriesLoadFailed = true; | |||
| _error = "Failed to load categories. You may save as a draft, but cannot publish until categories are available."; | |||
| } | |||
| if (_model is null) return; | ||
| if (_categories.Any() && _model.CategoryId is null) | ||
| if (_model.IsPublished && (_categoriesLoadFailed || _model.CategoryId is null)) | ||
| { | ||
| _error = "Please select a category."; | ||
| _error = _categoriesLoadFailed | ||
| ? "Categories failed to load. Cannot publish until categories are available." | ||
| : "Please select a category before publishing."; | ||
| return; | ||
| } |
**Orchestration:** Created orchestration logs for Gimli, Frodo, Legolas, Sam, Boromir; created session log for issue #341 polish. **Decisions:** Merged PR #336 self-authored gate handling, PR #338 process-contract blocking, and PR #340 categories gate outcome from inbox → decisions.md. Deleted inbox files. **Agent History:** Appended Boromir issue #341 orchestration notes to .squad/agents/boromir/history.md. **Status:** Issue #341 (PR #342 polish cycle) complete. All team members' work recorded. Decisions committed to long-lived history. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Test Results Summary475 tests +3 474 ✅ +3 28s ⏱️ ±0s Results for commit a15444a. ± Comparison against base commit ec92657. This pull request removes 6 and adds 9 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #342 +/- ##
==========================================
+ Coverage 80.04% 80.14% +0.09%
==========================================
Files 68 68
Lines 1664 1682 +18
Branches 195 201 +6
==========================================
+ Hits 1332 1348 +16
- Misses 243 244 +1
- Partials 89 90 +1
🚀 New features to boost your workflow:
|
|
🛑 PR GATE — BLOCKED by Aragorn (Lead)
CI is green and all suites pass. However, two real logic bugs flagged by GitHub Copilot's automated review in Blocking issues
Verify same patterns in
|
|
🛑 Routing correction — strict lockout enforcement (Aragorn) My prior comment routed the fix back to Legolas, who authored the rejected Eligibility analysis (Edit.razor revision)
Escalation — human owner decision requiredNo active agent has Razor UI as primary domain and is eligible for this revision cycle. Two acceptable paths; @mpaulosky to choose:
Either way, Legolas remains locked out for this revision cycle. Re-review will be performed by Aragorn after CI re-passes. PR remains BLOCKED until the chosen owner pushes the fix. — Aragorn (Lead) |
…r-blocking - Reset _categoriesLoadFailed and _categories at start of OnParametersSetAsync so stale failure UI does not persist across re-navigation to the edit page. - Change publish guard to block only when _model.CategoryId is null, not when _categoriesLoadFailed is true; already-categorized published posts can now be saved even when the category list fails to reload. - Helpful error message still distinguishes between a load failure and a missing selection, surfaced when the user actually tries to publish without a category. Fixes blocker comments on PR #342 (issue #341). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- EditClearsCategoryLoadFailureAfterRenavigationToPostWhoseCategoriesLoad: verifies _categoriesLoadFailed is reset in OnParametersSetAsync on re-navigation so a prior failure banner does not persist. - EditAllowsSaveOfPublishedPostThatAlreadyHasCategoryEvenWhenCategoryListFails: verifies the publish guard does not block an already-categorized post when the category list fails to load (guard must only check CategoryId). - EditBlocksPublishWhenCategoryIdIsNullAndCategoryListFailed: guard-rail — verifies publishing is still blocked when CategoryId is null and no category list is available to select from. Closes #341 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
✅ PR GATE — APPROVED by Aragorn (Lead) Re-gate after Sam's UI fix ( Source verification
Regression coverage (Gimli,
|
Closes #341
Changes
Completed slices:
Tests
All pre-push gates passed ✅