Skip to content

fix(frontend): name instance types and price change in RI exchange - #1363

Merged
IAmJSD merged 2 commits into
LeanerCloud:mainfrom
IAmJSD:ui/issue-709
Oct 24, 2026
Merged

IAmJSD merged 2 commits into
LeanerCloud:mainfrom
IAmJSD:ui/issue-709

Conversation

@IAmJSD

@IAmJSD IAmJSD commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

The RI exchange Execute confirm was already fixed on main by #781, but two related surfaces still showed the opaque view: the quote summary listed raw source and target hourly prices with no delta, and the Approve confirm in Exchange History led with the target offering UUID in one run-on paragraph. This PR adds an hourly price change row to the quote summary and gives the Approve confirm the same labeled, instance-type-first lines as Execute.

Refs #709
Partial: the Approve confirm still cannot show a price delta, because exchange history records carry no hourly prices (needs a backend change), and Payment Due stays the exact raw string.

What changed

  • New frontend/src/riexchange-confirm.ts with hourlyPriceDelta(), buildExchangeConfirmBody() (moved unchanged from riexchange.ts) and a new buildApproveConfirmBody().
  • frontend/src/riexchange.ts: the quote summary gets an "Hourly Price Change" row (for example -0.0200 USD/hr, about -14.60 USD/month), and the Approve dialog uses buildApproveConfirmBody().
  • The Approve confirm now reads as labeled lines, like Execute: "Previously quoted payment", "Exchange: 2 x m5.large (ri ids)", "For: 1 x m5.xlarge (offering <uuid>)", "Region", then the warning. It falls back to ids when the history record has no instance types.
  • Tests: new riexchange-confirm.test.ts, a quote-summary test in riexchange.test.ts, and updated assertions in tests-e2e/ri-exchange-confirmation.spec.ts.

Why this approach

The in-app Execute and Approve confirms now share one formatter, so they can't drift apart again. Main's email deep-link approve confirm (riexchange-deeplink.ts, #1353) still has its own wording; it could move to buildApproveConfirmBody() in a follow-up. Moving the builders out also shrinks riexchange.ts (2125 lines on main, 2061 here, well over the 500-line guideline) instead of growing it. The exact offering id stays next to the instance type, as the #781 follow-up wanted. Payment Due stays as the exact raw string because the execute cap (max_payment_due_usd) is that string, and rounding it on screen would hide what is sent.

Screenshots

Screenshots were taken before this branch was merged with main; before = main at a14dc8f. After is this branch. Both are headless Chromium at 1440x900 against the repo's mocked e2e API.

Before After
approve-confirm before approve-confirm after
quote-summary before quote-summary after
  • Approve confirm: before, one paragraph with the target as 1 x <offering UUID> (m5.xlarge); after, labeled lines with "Exchange: 2 x m5.large" and "For: 1 x m5.xlarge (offering ...)".
  • Quote summary: before, raw source and target hourly prices with no delta; after, a new "Hourly Price Change: -0.0200 USD/hr, about -14.60 USD/month" row.

Verification

Run on this branch's head 87e4a930, from frontend/:

  • Merged with main at 5fbedae; conflicts in frontend/src/riexchange.ts resolved, see the merge commit.
  • lint: 0 errors; typecheck clean; build OK.
  • jest: 3873 of 3874 passed, 1 skipped. New: riexchange-confirm.test.ts (6 tests) and a quote-summary test in riexchange.test.ts.
  • jest --randomize over riexchange.test.ts: 80/80.
  • Playwright (e2e-local.sh, full suite): 201 passed. ri-exchange-confirmation.spec.ts now asserts the quote-summary delta and the Approve instance-type lines.
  • Secrets scan clean (planted key flagged); scripts/test-git-secrets-allowlist.sh: 137 PASS, 0 FAIL.

Notes for review

Overlaps

None. This branch merges cleanly with every other open UI branch.

Note for the UI owner

This changes UI code that @cristim owns. IAmJSD reviewed the before/after screenshots and asked for it to be merged; any design point you disagree with can be a follow-up.

🤖 Generated with Claude Code

…e approve and quote

The Execute confirm already names instance types and the hourly price
change (LeanerCloud#781), but two money surfaces still showed the opaque view: the
quote summary listed raw source and target hourly prices with no delta,
and the Approve confirm in exchange history led with the target offering
UUID as one run-on sentence. The quote summary now adds an Hourly Price
Change row, and the Approve confirm uses the same labeled lines as
Execute (Exchange: 2 x m5.large (ri ids), For: 1 x m5.xlarge (offering
id)), so the user can see what an irreversible exchange swaps before
committing.

The confirm body builders move to riexchange-confirm.ts so the Execute
and Approve dialogs share one formatter and riexchange.ts shrinks. The
two openExchangeModal describes now re-seed listTargetOfferings, since a
resetAllMocks elsewhere in the file broke them under --randomize.

Refs LeanerCloud#709

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IAmJSD IAmJSD added priority/p2 Backlog-worthy triaged Item has been triaged severity/high Significant harm urgency/this-quarter Within the quarter impact/few Limited audience effort/s Hours type/bug Defect labels Oct 24, 2026
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Caution

Review failed

The pull request is closed.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

Conflicts:
- frontend/src/riexchange.ts (imports): kept LeanerCloud#709's riexchange-confirm
  import and main's narrowed lib/column-filters import plus the new
  lib/column-filter-popover import (LeanerCloud#1315).
- frontend/src/riexchange.ts (confirm builders): kept main's new
  revealExchangeHistory() (LeanerCloud#1375); dropped main's in-file
  ExchangeConfirmParts/HOURS_PER_MONTH/buildExchangeConfirmBody because
  LeanerCloud#709 moved them to riexchange-confirm.ts. Main's only change to that
  builder (LeanerCloud#1350: quote.Region is now required, so `?? ''` was removed) is
  ported into riexchange-confirm.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IAmJSD

IAmJSD commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): APPROVE 87e4a9309b69ddbdc2f0999f64f98ac1e8aaafdc

Blocking:

  • none
    Non-blocking:
  • frontend/src/riexchange-deeplink.ts:77-89: main's email deep-link approve confirm (fix(frontend): add confirm-then-POST deep link for RI-exchange approval #1353) has its own describeExchange(), which renders "2x m5.large -> 1x m5.xlarge in us-east-1, previously quoted payment USD ...". This PR's buildApproveConfirmBody() (riexchange-confirm.ts:72) renders "2 × m5.large (ids) / For: 1 × m5.xlarge (offering uuid)". That gives two formatters for the same approve confirm that already read differently, and the deep-link one has no fallback for empty instance types. Not introduced here; a follow-up could make the deep link use buildApproveConfirmBody().
  • frontend/src/riexchange-confirm.ts:30-34: an hourly delta under 0.00005 shows "-0.0000 USD/hr" / "+0.0000 USD/hr". Cosmetic.
    Attacked: git diff HEAD^2 HEAD matches git diff origin/main...HEAD exactly (5 files), so nothing else on main was touched. In the conflicted riexchange.ts, main's refactor(frontend): share one column-filter popover across Plans and RI #1315 popover imports and fix(frontend): announce RI exchange results and keep the exchange ID #1375 revealExchangeHistory() survive. The in-file buildExchangeConfirmBody was removed cleanly, and main's only edit to it (chore(riexchange): make the exchange region required in the TS types #1350, dropping ?? '' on Region) is ported to riexchange-confirm.ts:57; the moved builder produces the same strings.
    Both bodies use textContent/append only, with no innerHTML or inline styles. "USD ${payment_due}" is safe behind main's guard at riexchange.ts:2028. The e2e fixture has real source fields. Scratch jest: confirm/riexchange/deeplink/currency 110/110, and riexchange.test.ts --randomize 80/80.

@IAmJSD

IAmJSD commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Local verification at 87e4a930 merged onto current main (fda37861; merge-tree 96d1f61b; Linux, Node, headless Chromium):

  • This branch's own checks passed at this head: lint, typecheck, build, the full jest suite, the full Playwright e2e suite, and the git-secrets checks (see Verification in the PR body).
  • The combined tree of every UI PR in this merge wave (tree dc090cc2, main plus 17 PRs) passes npm ci, lint, typecheck, build, jest (1 skipped, 4097 passed, 4098 total), and the full Playwright suite (232 passed).
  • CI is green on 87e4a930 (CI Success, Run pre-commit hooks).
  • The independent review above approves this exact head.
  • Nothing was applied to any cloud.

@IAmJSD
IAmJSD marked this pull request as ready for review October 24, 2026 19:27
@IAmJSD
IAmJSD merged commit 15e021d into LeanerCloud:main Oct 24, 2026
29 checks passed
@IAmJSD

IAmJSD commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Marked ready and merged by IAmJSD's agent, at IAmJSD's request (IAmJSD reviewed the before/after screenshots; cristim is traveling), after the independent review and local verification above, all at 87e4a930.

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

Labels

effort/s Hours impact/few Limited audience priority/p2 Backlog-worthy severity/high Significant harm triaged Item has been triaged type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant