Skip to content

release: promote beta to main — filtered Available Funds & Remaining Budget#1368

Closed
steilerDev wants to merge 6 commits intomainfrom
beta
Closed

release: promote beta to main — filtered Available Funds & Remaining Budget#1368
steilerDev wants to merge 6 commits intomainfrom
beta

Conversation

@steilerDev
Copy link
Copy Markdown
Owner

Release Summary

Fixes the Cost Breakdown table so that Available Funds and Remaining Budget correctly respond to the per-source budget filter, and fully hides deselected funding sources when printing.

Changes

Fixes

Change Inventory

Frontend (client/)

  • client/src/components/CostBreakdownTable/CostBreakdownTable.tsx — replaced 4 overview.availableFunds references with filteredAvailableFunds computation
  • client/src/components/CostBreakdownTable/CostBreakdownTable.module.css — added @media print rule to hide deselected source rows

E2E Tests (e2e/)

  • e2e/tests/budget/budget-source-filter.spec.ts — 5 new E2E scenarios: Available Funds updates on deselect, Remaining Budget updates on deselect, restore on re-select, zero-sources shows €0, print media hides deselected rows

Tests

  • client/src/components/CostBreakdownTable/CostBreakdownTable.test.tsx — 9 new unit tests for filter-aware summary rows; 10 pre-existing tests updated to supply matching budgetSources fixtures

Manual Validation Checklist

  • Open the Budget page → Cost Breakdown tab
  • Confirm "Available funds" shows the total of all configured budget sources
  • Toggle off one budget source using its toggle button — verify "Available funds" decreases by that source's amount
  • Verify "Remaining Budget" (Cost and Net columns) also updates when the source is toggled
  • Toggle the source back on — verify both rows restore to their original values
  • Toggle off all sources — verify "Available funds" shows €0.00 and "Remaining Budget" shows a negative value equal to the projected cost
  • Print the Cost Breakdown page (Cmd/Ctrl+P or browser print preview) — verify deselected source detail rows are not visible in the print preview

Testing

  • DockerHub beta image: docker pull steilerdev/cornerstone:beta
  • PR-specific image: docker pull steilerdev/cornerstone:pr-1367

Fixes #1366

steilerDev and others added 2 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>
@steilerDev
Copy link
Copy Markdown
Owner Author

Detailed Validation — Issue #1366

1. Available Funds updates when toggling sources

  1. Navigate to Budget → Cost Breakdown
  2. Note the current "Available funds" value in the summary section (e.g. €X)
  3. Click the toggle button on any budget source row (e.g. "Bank Loan")
  4. Expected: "Available funds" immediately decreases by that source's totalAmount
  5. Click the toggle again to re-enable it
  6. Expected: "Available funds" restores to the original value

2. Remaining Budget updates when toggling sources

With the same source toggled off:

  • Remaining Budget (Cost column): should equal filteredAvailableFunds − totalRawProjectedCost
  • Remaining Budget (Net column): should equal filteredAvailableFunds − totalRawProjectedCost + subsidyPayback

Both values should update immediately — no page refresh needed.

3. All-sources-off edge case

Toggle off every budget source:

  • Expected: "Available funds" = €0.00, "Remaining Budget" shows a negative value equal to the negative of the projected cost

4. Print media — deselected sources hidden

  1. Toggle off one or more sources
  2. Open browser print preview (Cmd+P / Ctrl+P)
  3. Expected: Rows for deselected sources are completely absent from the print layout
  4. Re-enable all sources and confirm all rows appear in print preview

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

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

The release is available on GitHub release

Your semantic-release bot 📦🚀

@steilerDev steilerDev enabled auto-merge April 28, 2026 08:21
@steilerDev steilerDev closed this Apr 28, 2026
auto-merge was automatically disabled April 28, 2026 08:22

Pull request was closed

@steilerDev steilerDev reopened this Apr 28, 2026
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>
@github-actions
Copy link
Copy Markdown
Contributor

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

The release is available on GitHub release

Your semantic-release bot 📦🚀

…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

Superseded by updated promotion PR — E2E test fixes merged to beta (PR #1376). Re-creating with updated change inventory.

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.

Bug: Cost Breakdown — 'Available Funds' and 'Remaining Budget' do not respond to per-source filter

1 participant