Skip to content

release: promote beta to main — filtered cost breakdown & UI bug fixes#1377

Merged
steilerDev merged 6 commits intomainfrom
beta
Apr 28, 2026
Merged

release: promote beta to main — filtered cost breakdown & UI bug fixes#1377
steilerDev merged 6 commits intomainfrom
beta

Conversation

@steilerDev
Copy link
Copy Markdown
Owner

Release Summary

This release ships the final pieces of EPIC-08 (Paperless-ngx document linking) client-side integration plus 5 UI quality-of-life bug fixes, completing the budget source filter feature end-to-end.

Changes

Fixes

CI / Config

Tests

  • E2E: Post-refetch assertions in budget source filter scenarios migrated to toContainText() retrying assertions (eliminates race condition with React re-renders)
  • E2E: Document-linking duplicate scenario updated for renamed "Hide already-linked documents" checkbox label

Change Inventory

Backend (server/, shared/)

No backend changes.

Frontend (client/)

  • client/src/components/budget/CostBreakdownTable.tsx — filtered available-funds calculation
  • client/src/components/documents/DocumentBrowser.tsx — hideLinked default → false, label rename
  • client/src/components/budget/InvoiceForm.tsx — scroll wheel prevention, VAT fix, vendor picker blur fix
  • client/src/components/budget/BudgetSummaryCards.tsx — summary card refresh fix

E2E Tests (e2e/)

  • e2e/tests/budget/budget-source-filter.spec.ts — toContainText() retry assertions
  • e2e/tests/documents/document-linking.spec.ts — updated checkbox locator

Docs / Config

  • .github/workflows/detect-changes.yml — workflow_dispatch fallback fix

Manual Validation Checklist

  • Budget source filter — Available funds: Budget → Overview → select 1 of 2 budget sources → verify "Available funds" and "Remaining Budget" columns in cost breakdown update to reflect the selected source only
  • Budget source filter — Remaining budget header chip: Deselect a source and verify the header "Remaining" chip updates alongside the table
  • Document browser default: Open a work item → Add Document → confirm "Hide already-linked documents" checkbox is unchecked by default
  • Scroll wheel on inputs: Open an invoice form → hover over Amount field → scroll mouse wheel → confirm value does NOT change
  • VAT checkbox: Edit an invoice with VAT enabled → save → re-open → confirm VAT checkbox is still checked
  • Vendor picker: Open Add Invoice → type a vendor name → click away → confirm vendor remains selected in the field
  • Summary cards after filter change: Budget → Overview → toggle a source → confirm Pending/Paid/Quotation summary cards refresh

Testing

  • DockerHub beta image: docker pull steilerdev/cornerstone:beta
  • PR-specific image: docker pull steilerdev/cornerstone:pr-1377 (available after Docker PR Release job completes)

Supersedes #1368

steilerDev and others added 6 commits April 28, 2026 00:04
* fix(budget): use filtered available funds in CostBreakdownTable

- Compute filteredAvailableFunds from selected budget sources only
- Update Available Funds row display to use filtered value
- Update Remaining Budget rows (Cost & Net columns) to use filtered funds
- Update unused sum variable to use filtered funds for consistency
- Hide deselected source rows in print via display: none

Fixes budget calculations when budget sources are deselected in the cost breakdown.

Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>

* test(e2e): add filter-aware Available Funds, Remaining Budget, and print-hiding tests

Adds a new test.describe block to budget-source-filter.spec.ts covering the
CostBreakdownTable changes from fix/1366: filteredAvailableFunds computation
and the @media print rule hiding deselected source rows.

Scenario 1: Available Funds value updates when a source is deselected.
Scenario 2: Remaining Budget Cost column updates when a source is deselected.
Scenario 3 (AC #4): Available Funds restores to full total on re-select.
Scenario 4 (AC #5): All sources deselected → Available Funds shows €0, not NaN.
Scenario 5 (AC #8): Print media hides deselected source rows (display:none) and
  leaves selected source rows visible.

Fixes #1366

Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.5) <noreply@anthropic.com>

* test(budget): add filteredAvailableFunds unit tests for Available Funds and Remaining Budget rows

Tests all three filter states for the bug fix (#1362):
- All sources selected: filteredAvailableFunds = sum of all source totalAmounts
- One source deselected: filteredAvailableFunds excludes deselected source amount
- All sources deselected: filteredAvailableFunds = 0 (not unfiltered total)
- Remaining Budget Cost and Net columns use filteredAvailableFunds in all states
- 'unassigned' source with totalAmount=0 does not affect filteredAvailableFunds
- Re-render with empty deselectedSourceIds restores unfiltered values

Fixes #1362

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* test(e2e): fix Remaining Budget arithmetic in Scenario 2

After deselecting Equity, the server returns a filtered breakdown whose
wiTotals.rawProjectedMin/Max = 10 000 (not 20 000), so totalRawProjected
drops to 10 000. The correct post-filter Remaining Budget Cost is therefore
150 000 - 10 000 = 140 000, not 130 000.

Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.5) <noreply@anthropic.com>

* test(budget): fix two CostBreakdownTable test bugs broken by filteredAvailableFunds change (#1366)

The production change in #1366 replaced overview.availableFunds with
filteredAvailableFunds (sum of non-deselected budgetSources) for the
Available Funds row. Two existing tests had incorrect fixtures that
assumed overview.availableFunds was the source of truth:

1. Test 16 "shows Available funds row with formatted currency value":
   rendered with budgetSources:[] so filteredAvailableFunds=0, not 50000.
   Fix: add a budgetSource with totalAmount=50000 to the breakdown fixture.

2. Scenario 23 "Remaining Budget row uses filteredAvailableFunds":
   src-1360-a had totalAmount=100000 but overview.availableFunds=200000,
   making the fixture internally inconsistent under the new computation.
   Fix: set src-1360-a.totalAmount=200000 so filteredAvailableFunds=200000,
   preserving the expected Remaining Budget value of €150,750.00.
   Also updated the test name and comment to reflect the new semantics.

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* fix(budget): prefix unused overview param with _ to satisfy ESLint

Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>

* test(budget): fix pre-existing CostBreakdownTable tests broken by filteredAvailableFunds

After the production fix replacing overview.availableFunds with
filteredAvailableFunds (computed from breakdown.budgetSources), 8 pre-existing
tests using buildBreakdownWithWI() with empty budgetSources: [] produced
filteredAvailableFunds=0, breaking expected Remaining Budget and Available
Funds values.

Added optional budgetSources parameter to buildBreakdownWithWI() and supplied
matching totalAmount values in each failing test so filteredAvailableFunds
equals the previously expected overview.availableFunds.

Fixes #1366

Co-Authored-By: Claude qa-integration-tester (Sonnet) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Frank Steiler <frank@steiler.de>
Co-authored-by: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>
…ker, summary cards) (#1374)

* fix: implement 5 UI bug fixes for Cornerstone

Fix #1369: Hide linked documents default + label
- Changed hideLinked default from true to false in DocumentBrowser
- Updated translation label to "Hide already-linked documents"

Fix #1370: Disable scroll-wheel on numeric inputs
- Added onWheel=(e) => e.currentTarget.blur() to all <input type="number">
- Updated 18 files covering forms across budget, diary, invoices, vendors, pages

Fix #1371: Add "Includes VAT" checkbox to Direct amount mode
- Added includesVat checkbox UI to direct pricing mode in BudgetLineForm
- Checkbox reuses existing i18n keys (no new translations needed)
- Note: back-calculation logic (net = gross / 1.19) should be applied by consuming components

Fix #1372: Show vendor in 'Link to Invoice' picker
- Added vendor name display in dropdown items
- Updated search filter to match vendor names
- Added CSS styling for dropdownItemVendor with muted color

Fix #1373: Add "Claimed" summary card to Budget Invoices
- Added fourth summary card showing claimed count and amount
- Updated "Paid" card to show only paid amounts (not combined with claimed)
- Changed summaryGrid from 3 to 4 columns with mobile breakpoint

All CSS uses design tokens (var(--token-name)) per project standards.
All user-facing text uses i18n t() functions.

Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>

* test: add unit tests for UI bug fixes #1369#1373

Tests cover:
- #1369: DocumentBrowser hideLinked defaults to false, checkbox
  label text, filter toggling behavior (8 new tests)
- #1370: onWheel blur behavior on number inputs in BudgetLineForm,
  InvoiceLinkModal, and NumberFilter (8 new tests)
- #1371: "Includes VAT" checkbox rendered and functional in direct
  mode of BudgetLineForm (8 new tests)
- #1372: Vendor name visible and searchable in InvoiceLinkModal
  invoice picker (5 new tests)
- #1373: InvoicesPage summary cards include "Claimed" card with
  correct count and separate from "Paid" (4 new tests)

New file: BudgetLineForm.test.tsx (54 tests, 97.14% coverage)
Extended: NumberFilter.test.tsx, DocumentBrowser.test.tsx,
          InvoiceLinkModal.test.tsx, InvoicesPage.test.tsx

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* fix: apply VAT back-calculation for direct mode and add German translation

- Add VAT back-calculation (gross/1.19) in toPayload for direct
  pricingMode when includesVat=true in WorkItemDetailPage and
  HouseholdItemDetailPage (#1371)
- Add German translation for updated browser.hideLinked key (#1369)

Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>
Co-Authored-By: Claude translator (Sonnet 4.5) <noreply@anthropic.com>

* fix: address code review findings from agent review

- Fix VAT round-trip bug: toFormState now defaults includesVat=false
  for direct-mode lines (null from API) to prevent repeated ÷1.19 on
  re-edit (#1371)
- Fix undefined vendor display in InvoiceLinkModal selected state:
  em-dash separator only shown when vendorName is non-empty (#1372)
- Add .dropdownItemActive .dropdownItemVendor contrast override for
  WCAG AA compliance on active items (#1372)
- Extend summaryGrid mobile breakpoint to 767px to cover tablet
  viewports at 641-767px (#1373)

Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>

* test: fix getByText ambiguity in InvoicesPage summary card tests

Status labels like 'Claimed', 'Pending', 'Paid', 'Quotation' appear
in both summary cards and filter dropdowns, so screen.getByText()
was throwing 'multiple elements found'. Switch to getAllByText()
with a length assertion to match the established pattern in this file.

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

---------

Co-authored-by: Frank Steiler <frank@steiler.de>
Co-authored-by: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>
When triggered via workflow_dispatch, github.base_ref is empty,
causing the git diff to fail with exit code 128. Default to main
when base_ref is not set so manual dispatches work correctly.

Co-authored-by: Frank Steiler <frank@steiler.de>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…try (#1376)

* test(e2e): fix post-refetch assertions to use toContainText() with retry

Replace textContent() + sync expect() with expect(locator).toContainText()
in Scenarios 1-5 of the Filter-aware summary rows test block. The old
pattern reads the DOM immediately after waitForResponse resolves, before
React has committed the state update — causing intermittent CI failures
when the re-render is slightly delayed.

toContainText() retries with the configured expect timeout (7s for
desktop), ensuring the assertion runs against the updated DOM.

Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.6) <noreply@anthropic.com>

* test(e2e): fix document-linking hideLinked checkbox locator after label change

Fix #1369 (PR #1374) changed the DocumentBrowser "Hide linked documents"
checkbox label to "Hide already-linked documents". The duplicate-link
scenario test used the old regex /hide linked/i which no longer matches,
causing the test to timeout on Desktop, Tablet, and Mobile (all three
@Responsive projects = shards 3, 9, 14).

Update the locator regex to /hide already-linked documents/i. The
checkbox now defaults to unchecked (hideLinked=false after #1369), so
the uncheck() call is a no-op — kept for symmetry.

Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Frank Steiler <frank@steiler.de>
Co-authored-by: Claude e2e-test-engineer (Sonnet 4.6) <noreply@anthropic.com>
@steilerDev
Copy link
Copy Markdown
Owner Author

Detailed Validation

1. Budget Source Filter — Available Funds & Remaining Budget

  1. Navigate to Budget → Overview
  2. Scroll down to the Cost Breakdown table
  3. If you have multiple budget sources configured, the source filter chips appear at the top of the breakdown
  4. Deselect one source by clicking its chip
  5. Verify:
    • The "Available funds" column for each work item updates (shows only the selected source's contribution)
    • The "Remaining Budget" column updates accordingly
    • The header "Remaining" chip also updates
  6. Re-select the source → values return to unfiltered totals

2. Document Browser Default Checkbox

  1. Navigate to a Work Item detail page
  2. Scroll to the Documents section → click + Add Document
  3. In the picker modal, confirm:
    • The "Hide already-linked documents" checkbox is unchecked by default
    • All available documents are visible immediately (no need to uncheck to see them)
  4. Link a document, then open the picker again
  5. Confirm the already-linked document is still visible (checkbox unchecked by default)
  6. Check the checkbox → already-linked documents disappear from the list

3. Scroll Wheel on Numeric Inputs

  1. Navigate to Budget → Invoices → Add Invoice
  2. Fill in Vendor and Date fields
  3. Click the Amount field and enter a value (e.g., 100)
  4. Without clicking elsewhere, scroll the mouse wheel over the Amount field
  5. Confirm the value does not change (previously scrolling changed the number)

4. VAT Checkbox Round-Trip

  1. Navigate to Budget → Invoices
  2. Edit an existing invoice, enable the VAT/tax checkbox, and save
  3. Re-open the same invoice for editing
  4. Confirm the VAT checkbox is still checked (previously it reset to unchecked on re-open)

5. Vendor Picker Blur

  1. Navigate to Budget → Invoices → Add Invoice
  2. In the Vendor field, start typing a vendor name
  3. Select a vendor from the dropdown
  4. Click somewhere else on the form (blur the vendor field)
  5. Confirm the vendor field still shows the selected vendor (previously the selection was lost on blur)

6. Summary Cards After Filter Change

  1. Navigate to Budget → Overview
  2. Note the Pending, Paid, and Quotation summary card values
  3. Toggle a budget source in the filter chips
  4. Confirm the summary cards refresh and show updated values matching the filtered view

@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 2.4.2-beta.4 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@steilerDev steilerDev merged commit a108465 into main Apr 28, 2026
75 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 2.4.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant