Skip to content

Added agreement list summary cards #5114

Merged
Santi-3rd merged 34 commits intomainfrom
OPS-4142/agreement-list-summary-cards
Mar 5, 2026
Merged

Added agreement list summary cards #5114
Santi-3rd merged 34 commits intomainfrom
OPS-4142/agreement-list-summary-cards

Conversation

@Santi-3rd
Copy link
Copy Markdown
Contributor

@Santi-3rd Santi-3rd commented Feb 18, 2026

What changed

Added new summary cards to the agreement list page.

Issue

#4142

How to test

  • e2e tests pass
  • go to /agreements
  • filter the list in different ways and ensure the information on the cards changes correctly

Screenshots

image

Definition of Done Checklist

  • OESA: Code refactored for clarity
  • OESA: Dependency rules followed
  • Automated unit tests updated and passed
  • Automated integration tests updated and passed
  • Automated quality tests updated and passed
  • Automated load tests updated and passed
  • Automated a11y tests updated and passed
  • Automated security tests updated and passed
  • 90%+ Code coverage achieved
  • [-] Form validations updated

@Santi-3rd Santi-3rd self-assigned this Mar 3, 2026
@Santi-3rd Santi-3rd marked this pull request as ready for review March 3, 2026 16:54
@Santi-3rd Santi-3rd changed the title feat: added summary cards and removed button Added agreement list summary cards Mar 3, 2026
@fpigeonjr fpigeonjr requested a review from Copilot March 3, 2026 19:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds two summary cards to the Agreements list page to support reporting needs (Issue #4142), and updates API/UI plumbing so the cards can compute agreement counts and spending breakdowns by agreement type.

Changes:

  • Adds an AgreementSummaryCardsSection to the agreements list layout, and removes the “Add Agreement” CTA from the listing.
  • Introduces new summary card components (FY agreement counts + spending-by-type donut/legend) with unit and e2e coverage.
  • Expands the backend agreement list schema to include additional budget line item fields needed for the spending totals.

Reviewed changes

Copilot reviewed 16 out of 18 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
frontend/src/pages/agreements/list/AgreementsList.jsx Wires the new summary cards section into the agreements list page; removes “Add Agreement” button/link.
frontend/src/helpers/agreement.helpers.js Adds helpers to compute agreement spending totals grouped by agreement type.
frontend/src/components/UI/Tag/Tag.jsx Adds new active tag styles for agreement-type legend highlighting.
frontend/src/components/UI/DataViz/ResponsiveDonutWithInnerPercent/ResponsiveDonutWithInnerPercent.jsx Updates donut chart a11y handling using a MutationObserver to set attributes after async SVG render.
frontend/src/components/Agreements/AgreementTypeSummaryCard/index.js Re-export for the new agreement type spending summary card.
frontend/src/components/Agreements/AgreementTypeSummaryCard/AgreementTypeSummaryCard.jsx New donut + legend card showing spending split across agreement types.
frontend/src/components/Agreements/AgreementTypeSummaryCard/AgreementTypeSummaryCard.test.jsx Unit tests for the agreement type spending card.
frontend/src/components/Agreements/AgreementSummaryCardsSection/index.js Re-export for the new summary section wrapper.
frontend/src/components/Agreements/AgreementSummaryCardsSection/AgreementSummaryCardsSection.jsx New wrapper that computes totals and renders both summary cards.
frontend/src/components/Agreements/AgreementSummaryCardsSection/AgreementSummaryCardsSection.test.jsx Unit tests for the wrapper’s computed totals and props passed to child cards.
frontend/src/components/Agreements/AgreementFYSpendingSummaryCard/index.js Re-export for the FY agreement count/breakdown card.
frontend/src/components/Agreements/AgreementFYSpendingSummaryCard/AgreementFYSpendingSummaryCard.jsx New card showing total/new/continuing counts and type breakdown tags.
frontend/src/components/Agreements/AgreementFYSpendingSummaryCard/AgreementFYSpendingSummaryCard.test.jsx Unit tests for FY spending summary card behavior.
frontend/sass/uswds/styles.scss Adds CSS variables/theme color mappings for agreement-type data viz colors.
frontend/cypress/e2e/agreementList.cy.js Updates filter-tag selector assertions and adds e2e coverage for new summary cards.
backend/ops_api/ops/schemas/agreements.py Expands AgreementListResponse.budget_line_items nested fields to include amount/fees/status/is_obe for totals.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

product_service_code = fields.Nested(ProductServiceCodeSchema)
budget_line_items = fields.List(fields.Nested(BudgetLineItemResponseSchema, only=["id", "status"]), allow_none=True)
budget_line_items = fields.List(
fields.Nested(BudgetLineItemResponseSchema, only=["id", "amount", "fees", "status", "is_obe"]),
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The summary cards are labeled per selected FY (e.g., “FY 2044 Spending by Agreement Type”), but the totals are computed by summing all budget_line_items on each agreement. Since the list response doesn’t include a fiscal_year field on each nested budget line item, the frontend can’t filter totals to the selected FY (and the backend list query only filters which agreements are returned, not which BLIs are nested). Consider including fiscal_year in the nested BLI fields (or returning server-side aggregates by FY/type) so the card can accurately reflect the selected FY.

Suggested change
fields.Nested(BudgetLineItemResponseSchema, only=["id", "amount", "fees", "status", "is_obe"]),
fields.Nested(
BudgetLineItemResponseSchema,
only=["id", "amount", "fees", "status", "is_obe", "fiscal_year"],
),

Copilot uses AI. Check for mistakes.
Comment on lines +371 to +385
it("Agreement summary card counts match the table row count by type", () => {
// Get the total count from the FY spending card
cy.get('[data-cy="agreement-fy-spending-summary-card"]').within(() => {
cy.get(".font-sans-xl.text-bold")
.invoke("text")
.then((cardCountText) => {
const cardTotal = parseInt(cardCountText, 10);

// Navigate through all pages to count total table rows
// First, get the total from pagination if it exists
// The card count should match the total number of agreements across all pages
expect(cardTotal).to.be.greaterThan(0);
});
});
});
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This test case name implies it verifies that summary card counts match the table row counts, but it currently only asserts the card total is > 0 and never compares against the table (or per-type counts). This can create false confidence in the behavior; either add the missing assertions (e.g., compute counts from the rendered table across pagination) or rename the test to reflect what it actually checks.

Copilot uses AI. Check for mistakes.
Comment thread frontend/src/helpers/agreement.helpers.js Outdated
Copy link
Copy Markdown
Contributor

@josbell josbell left a comment

Choose a reason for hiding this comment

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

PR Review: Agreement List Summary Cards

I've completed a comprehensive review of this PR. Overall, this is a well-implemented feature with strong frontend quality, but there are some issues that need attention.

Summary

This PR adds two summary cards to the agreements list page:

  1. Agreement Count Summary Card - Shows total agreements with breakdown by type (Contract/Partner/Grant/Direct Obligation) and award status (New/Continuing)
  2. Agreement Spending Summary Card - Displays spending by type with a donut chart visualization

✅ Strengths

1. Strong Frontend Test Coverage

  • Comprehensive unit tests for both new components (190+ lines of test code)
  • Multiple E2E tests covering various scenarios
  • Edge cases well handled (null data, zero values, single types)

2. Good Architecture

  • Clean component separation and reusability
  • Backend aggregation computed once before pagination (efficient)
  • Proper handling of Partner agreements (AA + IAA grouped together)
  • Backend uses existing agreement_total property (correctly sums amounts + fees)

3. Accessibility

  • ARIA labels added to charts and interactive elements
  • Semantic HTML structure

4. Data Consistency

  • Backend calculation matches frontend logic (non-DRAFT budget lines, includes fees)
  • Proper handling of OBE budget lines

⚠️ Issues Found

1. Critical: Missing Backend Tests 🚨

The _compute_agreement_totals() function (lines 825-873 in backend/ops_api/ops/services/agreements.py) has no unit tests. This function performs financial calculations and aggregations that are displayed to users, so testing is critical.

Recommendation: Add unit tests in backend/ops_api/tests/ops/services/test_agreements.py to verify:

  • Correct summation by agreement type
  • Proper grouping of AA/IAA as partner agreements
  • New vs. Continuing classification logic
  • Type counts accuracy
  • Edge cases (empty results, mixed types, null values)

2. UI Change: "Add Agreement" Button Removed

The PR removes the "Add Agreement" button from the list page without explanation.

Files: frontend/src/pages/agreements/list/AgreementsList.jsx:320-321, 400-401

Questions:

  • Is this intentional or accidental?
  • Was this discussed with stakeholders?
  • Should users still be able to create agreements? If so, where?

3. Potentially Inaccurate Description Text

Changed from "all agreements across OPRE" to "for the selected fiscal year", but when "All" is selected, the text says "for the selected fiscal year" which is misleading.

Location: frontend/src/pages/agreements/list/AgreementsList.jsx:163

Current:

let details = "This is a list of all agreements across OPRE for the selected fiscal year. Draft budget lines are not included in the Totals.";

Recommendation: Make it conditional:

let details = `This is a list of all agreements across OPRE${selectedFiscalYear !== "All" ? " for the selected fiscal year" : ""}. Draft budget lines are not included in the Totals.`;

4. Minor: Schema Change Exposes More BLI Data

The PR adds amount, fees, and is_obe fields to the BudgetLineItemResponseSchema for list responses. While not necessarily wrong, this increases payload size.

Location: backend/ops_api/ops/schemas/agreements.py:224-226

Question: Are these fields needed by the frontend, or is the backend totals object sufficient?


📋 Additional Observations

1. Commit History
Many merge commits and incremental changes. Consider squashing before merging to main.

2. Unused Helper Functions?
New frontend helper functions added but appear unused:

  • getContractAgreementBLITotal
  • getPartnerAgreementBLITotal
  • getGrantAgreementBLITotal
  • getDirectObligationAgreementBLITotal

These calculate totals from frontend data, but the component uses backend-computed totals. Consider removing if truly unused.

3. E2E Test Quality
Well-structured E2E tests that verify:

  • Card rendering and data accuracy
  • Fiscal year filter updates
  • Percentage calculations sum to ~100%

🎯 Recommendations

Must Fix:

  1. ✋ Add backend unit tests for _compute_agreement_totals()
  2. ✋ Clarify intent of "Add Agreement" button removal

Should Fix:
3. Fix description text to be conditional on fiscal year selection
4. Remove unused helper functions if they're not needed

Nice to Have:
5. Squash commits before merging
6. Consider if the extra BLI schema fields are necessary


Overall Assessment

This is a well-implemented feature with strong frontend quality, but needs backend test coverage before merging. The missing tests represent a risk for financial calculations that are displayed to users. The UI changes (button removal, description text) also need clarification.

🤖 Generated with Claude Code

Comment thread frontend/src/helpers/agreement.helpers.js Outdated
@Santi-3rd Santi-3rd merged commit 6c33d2e into main Mar 5, 2026
55 checks passed
@Santi-3rd Santi-3rd deleted the OPS-4142/agreement-list-summary-cards branch March 5, 2026 21:45
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 5, 2026

🎉 This PR is included in version 1.318.0 🎉

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants