feat(household-items): display area tree on household item pages and pickers#1275
Conversation
…pickers - Compact AreaBreadcrumb wired into HouseholdItemsPage list rows so each item shows its area ancestry inline - Default AreaBreadcrumb added below the title in HouseholdItemDetailPage header for at-a-glance location context - HouseholdItemPicker renderSecondary slot populated with compact AreaBreadcrumb, surfacing area context in search results Fixes #1240 Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com> Co-Authored-By: Claude qa-integration-tester (Haiku 4.5) <noreply@anthropic.com> Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.5) <noreply@anthropic.com> Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>
|
Thank you for your submission! We require all contributors to sign our Contributor License Agreement before we can accept your contribution. I have read the CLA Document and I hereby sign the CLA Frank Steiler seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. |
- HouseholdItemDetailPage.test.tsx: scope "No area" query to the dep search dropdown button; the page header now also renders "No area" via AreaBreadcrumb when item.area is null - HouseholdItemPicker.breadcrumb.test.tsx: use getAllByText for compact breadcrumb text, which Tooltip duplicates in the visible span and hidden role="tooltip" span - budget-source-lines.spec.ts:548: use exact: true for "Unassigned" to disambiguate from "Select all in Unassigned" checkbox label introduced by #1248 Refs #1240 Co-Authored-By: Claude qa-integration-tester (Haiku 4.5) <noreply@anthropic.com> Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.6) <noreply@anthropic.com>
steilerDev
left a comment
There was a problem hiding this comment.
[product-owner] Requirements review for #1240 — final story of the area-tree mini-epic (#1236).
Verdict: ACCEPTED (posted as comment rather than approval because the reviewing account owns the PR).
Acceptance Criteria Verification
| # | Criterion | Status | Evidence |
|---|---|---|---|
| 1 | List + detail show breadcrumb under title (compact + default) | PASS | HouseholdItemsPage.tsx wraps the name column in .titleCell with AreaBreadcrumb variant="compact" below the item link; HouseholdItemDetailPage.tsx renders AreaBreadcrumb variant="default" inside .titleBreadcrumb directly beneath the <h1> page title. |
| 2 | Null-area fallback "No area" on list + detail | PASS | Both surfaces pass item.area ?? null to AreaBreadcrumb, which renders the muted "No area" span when null. Covered by HouseholdItemsPage.breadcrumb.test.tsx (Scenario 2), HouseholdItemDetailPage.breadcrumb.test.tsx (header — area null), and E2E Scenarios 4 & 5. |
| 3 | Household item picker secondary slot shows breadcrumb | PASS | HouseholdItemPicker.tsx adds renderSecondary={(item) => <AreaBreadcrumb area={item.area ?? null} variant="compact" />}. Covered by HouseholdItemPicker.breadcrumb.test.tsx and E2E Scenario 6 (via the Add Budget Line modal). |
| 4 | Mobile compact truncation + tooltip | PASS | Compact variant wraps text in a Tooltip (shared from #1237). Unit tests assert role="tooltip" elements carry the full path; E2E Scenario 3 focuses the compact span and verifies tooltip visibility with the full path across viewports. |
Test Coverage
- 28 unit tests across 3 new breadcrumb-specific test files (list, detail, picker)
- 6 E2E scenarios in
household-item-breadcrumb.spec.ts; list and detail scenarios are@responsive-tagged, so they run across desktop / tablet / mobile - POM additions on
HouseholdItemDetailPage.ts(areaBreadcrumbNav,areaBreadcrumb) mirror the pattern established for work items in #1238
Scope Observations (non-blocking)
- One unrelated change in
e2e/tests/budget/budget-source-lines.spec.ts(tightensgetByText('Unassigned')to{ exact: true }). Looks like a test-stability fix likely needed because the new "No area"-style text caused a loose match to hit more rows. Non-blocking but ideally isolated in a follow-up for a cleaner history. - PR body co-author trailer lists only
dev-team-lead. Per CLAUDE.md delegation rules, the commits themselves should carryqa-integration-testertrailers on the component.test.tsxfiles ande2e-test-engineertrailers on thee2e/files. The orchestrator's trailer verification enforces this at commit time — noting for the record, not as a blocker. - CLA Assistant gate is FAILURE (contributor signature required). This is a process gate, not a spec issue.
Verdict
All four acceptance criteria met with proper unit + E2E coverage. Implementation cleanly mirrors the work-item breadcrumb pattern already shipped in #1238 and #1239. This story closes out the 5-story area-tree mini-epic (#1236, #1237, #1238, #1239, #1240). No PO-side blockers — cleared for merge once Quality Gates turns green and the CLA signature is in place.
steilerDev
left a comment
There was a problem hiding this comment.
[product-architect]
Approving (posted as comment — cannot self-approve own PR). UI-only composition of existing shared components, perfect parallelism with #1238 (applied to household items instead of work items).
Verified
- Component reuse:
AreaBreadcrumb(from #1237) consumed viavariant="compact"(list + picker) andvariant="default"(detail header) — no parallel implementations.SearchPicker.renderSecondaryslot consumed as designed in #1237. - Pattern parallelism:
HouseholdItemsPage.module.css .titleCell+HouseholdItemDetailPage.module.css .titleBreadcrumbmirror the exact class names and structure fromWorkItemsPage/WorkItemDetailPagein #1238. No drift. - Strict TS: New code uses
item.area ?? nulldefensive null coalescing. Typed props flow fromHouseholdItemSummary.area: AreaSummary | null(established in #1236) throughAreaBreadcrumb. No newanytypes in production code. - Token-only CSS:
titleCellusesvar(--spacing-1);titleBreadcrumbusesvar(--spacing-2). No hardcoded values. - i18n: No new keys introduced.
AreaBreadcrumbownsareas.pathLabel/areas.noAreafrom #1237 — correct. - Test coverage: 28 unit tests (list 11, detail 9, picker 8) + 6 E2E scenarios covering @Responsive (desktop/tablet/mobile), tooltip focus, null-area fallback, and the picker-in-modal integration via InvoiceDetailPage. The pre-existing sibling test file adjustment (scoping "No area" assertion to the WI dropdown button now that the header also renders it) is correct.
- POM additions:
areaBreadcrumbNav/areaBreadcrumbonHouseholdItemDetailPagefollow the same locator shape asWorkItemDetailPage. - No wiki/schema/API/ADR changes needed: pure UI composition — architecture docs unaffected, consistent with how #1238 landed.
Informational (not blocking)
- The in-diff change to
e2e/tests/budget/budget-source-lines.spec.tsline 548 (getByText('Unassigned')→getByText('Unassigned', { exact: true })) is a drive-by fix unrelated to the breadcrumb story. Minor scope creep but it tightens an ambiguous locator — fine. - Static Analysis, Docker, all 6 Jest shards, Coverage Report: green. E2E shards running; no concerns given the scope is UI composition and the E2E suite explicitly covers the three integration surfaces.
No architectural concerns. Clean parallel of the established pattern.
steilerDev
left a comment
There was a problem hiding this comment.
[ux-designer]
PR #1275 — Design Review: Area tree on household item pages and pickers
Reviewed against: wiki/Style-Guide.md, client/src/styles/tokens.css, and the established WI breadcrumb pattern (PR #1262 reference).
Summary
This PR is a faithful, token-compliant port of the work-item area-tree pattern onto household item surfaces. All three integration points (list page name column, detail page header, HouseholdItemPicker renderSecondary) mirror the WI implementation exactly. No new CSS classes were introduced without token backing.
Checklist
Token adherence
PASS. All new CSS properties use design tokens:
HouseholdItemsPage.module.css—.titleCellusesvar(--spacing-1)for gap.HouseholdItemDetailPage.module.css—.titleBreadcrumbusesvar(--spacing-2)formargin-top.AreaBreadcrumb.module.css(existing, unchanged) — all properties usevar(--font-size-xs),var(--font-weight-normal),var(--color-text-muted),var(--shadow-focus). No hardcoded values.
No magic numbers or hex literals introduced.
Dark mode
PASS. All colour references go through var(--color-text-muted), which flips correctly under [data-theme="dark"]. No new hardcoded colours. The component has no shadow or border colours requiring special dark-mode treatment.
Component reuse
PASS. AreaBreadcrumb (shared component introduced in Story #1237) is imported and applied identically to the WI pattern. No parallel implementation created.
SearchPicker.renderSecondary prop is used in HouseholdItemPicker — consistent with the WI picker pattern.
ARIA / Accessibility
PASS.
- Default variant:
<nav aria-label={t('pathLabel')}>with<ol>+<li>segments. Separators carryaria-hidden="true". Correct and consistent with WI. - Compact variant:
<span tabIndex={0}>withbox-shadow: var(--shadow-focus)on:focus-visible. Focus ring uses the--shadow-focustoken — correct (nooutlineshortcut). - Null-area fallback: muted
<span>with no landmark role — appropriate; no navigation semantics needed for a static label. Tooltipwraps the compact span; tooltip content is the full path string, which is already visible as the span text. Redundancy is acceptable here (compact display may be truncated viatext-overflow: ellipsis).
Touch targets: compact span has tabIndex={0} but no explicit min-height. This matches the established WI pattern and is acceptable in a secondary-info slot inside a larger table row or card touch target.
Responsive behaviour
PASS. E2E test household-item-breadcrumb.spec.ts branches on viewport.width >= 768 to target table rows vs. cards — consistent with the HI page breakpoint. .titleCell uses flex-direction: column which stacks correctly at all widths.
Animations / transitions
No new animations introduced. Not applicable.
Visual consistency with WI pattern
PASS. Side-by-side structural comparison:
| Surface | WI implementation | HI implementation |
|---|---|---|
| List page name column | titleCell flex column + compact AreaBreadcrumb |
Identical .titleCell + compact AreaBreadcrumb |
| Detail page header | .titleBreadcrumb wrapper + default AreaBreadcrumb |
Identical .titleBreadcrumb + default AreaBreadcrumb |
Picker renderSecondary |
<AreaBreadcrumb area={item.area ?? null} variant="compact" /> |
Identical prop call |
Existing test fix (budget-source-lines.spec.ts)
The { exact: true } guard on getByText('Unassigned') prevents false positives from breadcrumb text containing "Unassigned". Correct defensive fix.
Verdict
No findings. Approving.
Summary
AreaBreadcrumbwired into HouseholdItemsPage list rows, showing each item's full area ancestry inlineAreaBreadcrumbadded below the title in HouseholdItemDetailPage header for at-a-glance location contextrenderSecondaryslot populated with compactAreaBreadcrumb, surfacing area context in search/pick resultsFixes #1240
Test plan
household-item-breadcrumb.spec.ts+ POM locator additionsCo-Authored-By: Claude dev-team-lead (Sonnet 4.6) noreply@anthropic.com