Skip to content

fix(ux/settings): override surfaces reuse commitmentOptions validity rules (closes #107)#176

Merged
cristim merged 2 commits intofeat/multicloud-web-frontendfrom
fix/issue-107-override-commitment-validation
Apr 30, 2026
Merged

fix(ux/settings): override surfaces reuse commitmentOptions validity rules (closes #107)#176
cristim merged 2 commits intofeat/multicloud-web-frontendfrom
fix/issue-107-override-commitment-validation

Conversation

@cristim
Copy link
Copy Markdown
Member

@cristim cristim commented Apr 28, 2026

Summary

Closes #107.

The two override UIs (inline payment selector from #72 and create-modal from #106) accepted any (service, term, payment) combination — including ones the global Settings → Purchasing cards already block. Concrete example: RDS 3yr no-upfront is hidden in the global RDS card via commitmentOptions.invalidCombinations, but the override modal saved it cleanly and the inline selector let the user pick it.

What changed

Surface Behavior
Inline payment selector (buildPaymentOverrideSelect) Filters via getValidPaymentOptions(provider, service, term). RDS+term=3 row shows only all-upfront + partial-upfront. Falls back to full list when term is unset. Stale current-payment values are kept (so the row isn't silently mutated) but flagged with "(invalid for term Ny — Delete the override and recreate)".
Override-create modal (openOverrideModal) New syncOverridePaymentOptions helper repopulates the payment dropdown on every service or term change, snapping back to "Inherit" when the previously-chosen payment becomes invalid.
Submit-side validation (submitOverrideForm) Refuses to save invalid combos even if a stale select option leaked through — mirror of the global card's checkCommitmentOptionCombo.

Tests

  • inline payment selector hides invalid options for RDS term=3 row — RDS-no-3yr-no-upfront case pinned.
  • inline payment selector shows full list when term is unset — fallback case pinned.
  • override-create modal hides invalid payment options on service+term change — dependency loop + snap-to-Inherit pinned.
  • All 40 existing settings-accounts tests still pass (43 total).

Out of scope

  • Backend save-side guard (the issue's third bullet) — frontend gates close the practical bug; backend mirror via the existing commitmentopts.Service.Validate machinery is its own PR-sized change touching internal/api/handler_accounts.go and would need probe-data integration tests. Worth filing as a follow-up.
  • Azure/GCP override surfaces — they don't have a create modal yet (still in ux(settings): create-override modal for Azure and GCP accounts (V2 of #106) #109 follow-up); inline editing is AWS-only today.

Drive-by

Removed unused formatRelativeTime import in frontend/src/recommendations.ts (pre-existing TS6133 blocking the pre-commit Run frontend tests hook on every commit on this branch — same fix as PR #174).

🤖 Generated with claude-flow

Summary by CodeRabbit

  • Tests

    • Added coverage for override payment-option filtering in both inline overrides and the create-override modal.
  • Chores

    • Removed an unused utility import.
  • Bug Fixes

    • Payment options are now filtered to valid (service, term) combinations.
    • Invalid saved payment selections are preserved but clearly marked as stale.
    • Payment dropdowns update dynamically when service or term changes.
    • Submission now blocks and surfaces an error for invalid option combinations.

@cristim
Copy link
Copy Markdown
Member Author

cristim commented Apr 28, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Warning

Rate limit exceeded

@cristim has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 15 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d8617fba-94f9-4264-afec-516630fafe84

📥 Commits

Reviewing files that changed from the base of the PR and between f050458 and ddcc9a9.

📒 Files selected for processing (2)
  • frontend/src/__tests__/settings-accounts.test.ts
  • frontend/src/settings.ts
📝 Walkthrough

Walkthrough

This PR wires commitmentOptions validation into override UIs: inline override selectors and the create-override modal now limit payment options by valid (provider, service, term) combos, dynamically sync options on changes, and perform submit-side validation; tests added and two functions exported for test use.

Changes

Cohort / File(s) Summary
Override Validation Logic
frontend/src/settings.ts
Constrain inline payment selects via getValidPaymentOptions, add syncOverridePaymentOptions to repopulate modal payment dropdown on service/term changes, surface invalid/stale saved options as visible-but-marked, add submit-side isValidCombination validation with error message, and export loadOverridesPanel & openOverrideModal.
Override Validation Tests
frontend/src/__tests__/settings-accounts.test.ts
Add tests that mock listAccountServiceOverrides and verify inline panel and create-override modal hide/block invalid combinations (e.g., RDS 3yr no-upfront) and that dynamic payment-option updates occur on service/term changes.
Import Cleanup
frontend/src/recommendations.ts
Remove unused formatRelativeTime import from ./utils.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as Override UI (Inline/Modal)
    participant Validation as commitmentOptions
    participant API as Backend

    User->>UI: Open modal / edit inline row
    UI->>Validation: getValidPaymentOptions(provider, service, term)
    Validation-->>UI: valid payment list
    UI->>UI: Render payment dropdown (omit invalid options)

    User->>UI: Change service or term
    UI->>Validation: getValidPaymentOptions(provider, newService, newTerm)
    Validation-->>UI: updated valid payment list
    UI->>UI: Repopulate payment dropdown (preserve valid selection or reset)

    User->>UI: Submit override (service, term, payment)
    UI->>Validation: isValidCombination(provider, service, term, payment)
    alt valid
        Validation-->>UI: true
        UI->>API: POST/PUT override
        API-->>UI: Success
    else invalid
        Validation-->>UI: false
        UI->>User: Show override-form-error, block submit
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Suggested labels

severity/high

Poem

🐰 I hopped into settings, ears alert and bright,

I pruned the invalid combos out of sight.
RDS three-year no-upfront — gone from the view,
Now overrides match rules old and new. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main change: applying commitmentOptions validity rules to override surfaces, directly addressing issue #107.
Linked Issues check ✅ Passed The PR implements all coding objectives from #107: inline selector filters via getValidPaymentOptions, modal repopulates on service/term change with syncOverridePaymentOptions, submit validates with isValidCombination, and tests cover modal/inline selector behaviors.
Out of Scope Changes check ✅ Passed All changes are directly scoped to #107: override UI validation logic, tests for override surfaces, and a minor unused import removal (formatRelativeTime) to fix a pre-commit hook issue.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-107-override-commitment-validation

Review rate limit: 0/5 reviews remaining, refill in 5 minutes and 15 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim cristim added triaged Item has been triaged priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-sprint Within the current sprint impact/many Affects most users effort/m Days type/bug Defect labels Apr 28, 2026
@cristim
Copy link
Copy Markdown
Member Author

cristim commented Apr 28, 2026

P2 bug fix: override UI surfaces previously ignored commitmentOptions.invalidCombinations rules (#107). Without this, users could save e.g. RDS 3yr no-upfront which the global purchasing card explicitly disallows — silent data inconsistency. Frontend gates close the practical bug; backend mirror noted as follow-up. CI green, mergeable. (triage agent wave2-F)

@cristim
Copy link
Copy Markdown
Member Author

cristim commented Apr 29, 2026

Re-requesting review now that the earlier CodeRabbit rate-limit window has passed.\n\n@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

@cristim: Sure! Triggering a review of the PR now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/settings.ts`:
- Around line 910-915: openOverrideModal currently creates a new onChange
function each time so removeEventListener is ineffective and handlers
accumulate; fix by defining and reusing a stable handler reference (e.g., move
the onChange function for syncOverridePaymentOptions out of openOverrideModal
into module scope or store it on the element as a property) or by using an
AbortController/Signal to attach listeners that can be aborted when the modal
closes; ensure you do not overwrite existing onchange logic like
handlePaymentOverrideChange — attach the reused handler to select and
override-term (or register with AbortController) so removeEventListener (or
abort) actually removes the prior listener instead of stacking handlers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e4c82a72-ea03-4eda-b816-87053101f98a

📥 Commits

Reviewing files that changed from the base of the PR and between 3e655cb and a48b5fa.

📒 Files selected for processing (3)
  • frontend/src/__tests__/settings-accounts.test.ts
  • frontend/src/recommendations.ts
  • frontend/src/settings.ts

Comment thread frontend/src/settings.ts Outdated
@cristim
Copy link
Copy Markdown
Member Author

cristim commented Apr 29, 2026

Addressed the latest listener cleanup comment: override payment-option listeners are now scoped to a per-open AbortController, aborted before re-open and on close, so stale service/term handlers cannot stack. Verification: npm test -- --runTestsByPath src/__tests__/settings-accounts.test.ts --runInBand --watchman=false --no-coverage; pre-commit frontend build/tests passed. @coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

@cristim: Thanks for the update! The AbortController-scoped listener pattern is a clean approach — aborting before re-open and on close ensures stale service/term change handlers cannot accumulate across modal invocations. Triggering a review now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

cristim and others added 2 commits April 30, 2026 00:46
…rules

Closes #107.

The two override UIs (inline payment selector from #72 and create-modal
from #106) accepted any (service, term, payment) combination — including
ones the global Settings → Purchasing cards already block as invalid.
Concrete example: RDS 3yr no-upfront is hidden in the global RDS card
via commitmentOptions.invalidCombinations, but the override modal saved
it cleanly and the inline selector let the user pick it.

Wired the override surfaces through the same commitmentOptions helpers
the global cards use:

1. **Inline payment selector (`buildPaymentOverrideSelect`)**: now calls
   `getValidPaymentOptions(provider, service, term)` and only renders
   options that pass. For an RDS row with term=3, no-upfront is gone.
   When term is unset (override row created without a term), falls back
   to the full AWS list — can't pre-validate without it. If the row's
   CURRENT payment somehow isn't in the valid set (e.g. saved via
   direct API curl before this filter shipped, or AWS tightened the
   rules), still renders it as a dedicated "(invalid for term Ny —
   Delete the override and recreate)" option so the row isn't silently
   mutated.

2. **Override-create modal (`openOverrideModal`)**: new
   `syncOverridePaymentOptions` helper repopulates the payment dropdown
   on every service or term change, dropping invalid combinations
   automatically and snapping the selection back to "Inherit" if the
   previously-chosen payment is no longer valid for the new (service,
   term) pair.

3. **Submit-side validation (`submitOverrideForm`)**: when both term
   and payment are explicitly set, refuses to save invalid combos even
   if a stale select option leaked through (e.g. browser back-button
   restoring a stale dropdown state). Mirror of the global Settings →
   Purchasing card's checkCommitmentOptionCombo.

Side change: exported `loadOverridesPanel` and `openOverrideModal` so
the new tests can drive the panel and modal directly. Both are coherent
units; just needed the export.

Drive-by: removed unused `formatRelativeTime` import in
`frontend/src/recommendations.ts` (pre-existing TS6133 blocking the
pre-commit Run frontend tests hook on this branch — same fix as PR

Tests:
  - `inline payment selector hides invalid options for RDS term=3 row`
    pins the RDS-no-3yr-no-upfront case.
  - `inline payment selector shows full list when term is unset`
    pins the fallback case.
  - `override-create modal hides invalid payment options on
    service+term change` pins the dependency loop and the reset-
    to-Inherit-when-stale snap.
  - All 40 existing settings-accounts tests still pass; 43 total.

Backend save-side guard (the issue's third bullet) is deferred — the
frontend gates close the practical bug; a backend mirror via the
existing `commitmentopts.Service.Validate` machinery is its own
PR-sized change touching `internal/api/handler_accounts.go` and would
need probe-data integration tests. Worth filing as a follow-up.
Scope override payment-option listeners to an AbortController per modal open so
reopening the modal cannot accumulate stale service/term handlers.
@cristim cristim force-pushed the fix/issue-107-override-commitment-validation branch from f050458 to ddcc9a9 Compare April 29, 2026 22:48
@cristim
Copy link
Copy Markdown
Member Author

cristim commented Apr 29, 2026

Rebased onto current feat/multicloud-web-frontend. Conflict resolution: kept BOTH the upstream #114 "Delete-override" wording test AND this PR's three #107 commitmentOptions parity tests in the same describe block — they're independent. The original pre-commit failure was a duplicate migration #42; the rebase auto-resolved it. Frontend tests + tsc clean (1390/1390). @coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

@cristim: Thanks for the rebase update! The conflict resolution sounds clean — keeping both the upstream #114 "Delete-override" wording test and the three #107 commitmentOptions parity tests as independent cases in the same describe block is the right call. Good to hear tsc and all 1390 tests are passing. Triggering a review now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Labels

effort/m Days impact/many Affects most users priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/bug Defect urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant