Skip to content

feat(household-items): display area tree on household item pages and pickers#1275

Merged
steilerDev merged 2 commits into
betafrom
feat/1240-area-tree-household-items
Apr 17, 2026
Merged

feat(household-items): display area tree on household item pages and pickers#1275
steilerDev merged 2 commits into
betafrom
feat/1240-area-tree-household-items

Conversation

@steilerDev
Copy link
Copy Markdown
Owner

Summary

  • Compact AreaBreadcrumb wired into HouseholdItemsPage list rows, showing each item's full 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/pick results

Fixes #1240

Test plan

  • 28 new unit tests across 3 breadcrumb test files (HouseholdItemsPage, HouseholdItemDetailPage, HouseholdItemPicker)
  • 6 new E2E scenarios in household-item-breadcrumb.spec.ts + POM locator additions
  • Pre-commit hook quality gates pass

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) noreply@anthropic.com

…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>
@github-actions
Copy link
Copy Markdown
Contributor

Thank you for your submission! We require all contributors to sign our Contributor License Agreement before we can accept your contribution.

To sign, please comment on this PR with:
I have read the CLA Document and I hereby sign the CLA


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.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

- 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>
Copy link
Copy Markdown
Owner Author

@steilerDev steilerDev left a comment

Choose a reason for hiding this comment

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

[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 (tightens getByText('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 carry qa-integration-tester trailers on the component .test.tsx files and e2e-test-engineer trailers on the e2e/ 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.

Copy link
Copy Markdown
Owner Author

@steilerDev steilerDev left a comment

Choose a reason for hiding this comment

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

[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 via variant="compact" (list + picker) and variant="default" (detail header) — no parallel implementations. SearchPicker.renderSecondary slot consumed as designed in #1237.
  • Pattern parallelism: HouseholdItemsPage.module.css .titleCell + HouseholdItemDetailPage.module.css .titleBreadcrumb mirror the exact class names and structure from WorkItemsPage / WorkItemDetailPage in #1238. No drift.
  • Strict TS: New code uses item.area ?? null defensive null coalescing. Typed props flow from HouseholdItemSummary.area: AreaSummary | null (established in #1236) through AreaBreadcrumb. No new any types in production code.
  • Token-only CSS: titleCell uses var(--spacing-1); titleBreadcrumb uses var(--spacing-2). No hardcoded values.
  • i18n: No new keys introduced. AreaBreadcrumb owns areas.pathLabel / areas.noArea from #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 / areaBreadcrumb on HouseholdItemDetailPage follow the same locator shape as WorkItemDetailPage.
  • 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.ts line 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.

Copy link
Copy Markdown
Owner Author

@steilerDev steilerDev left a comment

Choose a reason for hiding this comment

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

[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.titleCell uses var(--spacing-1) for gap.
  • HouseholdItemDetailPage.module.css.titleBreadcrumb uses var(--spacing-2) for margin-top.
  • AreaBreadcrumb.module.css (existing, unchanged) — all properties use var(--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 carry aria-hidden="true". Correct and consistent with WI.
  • Compact variant: <span tabIndex={0}> with box-shadow: var(--shadow-focus) on :focus-visible. Focus ring uses the --shadow-focus token — correct (no outline shortcut).
  • Null-area fallback: muted <span> with no landmark role — appropriate; no navigation semantics needed for a static label.
  • Tooltip wraps 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 via text-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.

@steilerDev steilerDev merged commit b3de8c3 into beta Apr 17, 2026
27 of 32 checks passed
@steilerDev steilerDev deleted the feat/1240-area-tree-household-items branch April 17, 2026 22:41
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 17, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant