Skip to content

fix boltz swaps scroll - #585

Merged
bordalix merged 2 commits into
masterfrom
fix_boltz_swaps_scroll
Apr 30, 2026
Merged

bordalix merged 2 commits into
masterfrom
fix_boltz_swaps_scroll

Conversation

@bordalix

@bordalix bordalix commented Apr 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Refactor
    • Restructured SwapsList component rendering to improve efficiency when displaying large transaction lists.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Apr 30, 2026 •

Copy link
Copy Markdown

Deploying wallet-mutinynet with  Cloudflare Pages  Cloudflare Pages

Latest commit: 428d748
Status: ✅  Deploy successful!
Preview URL: https://ca2ea316.arkade-wallet.pages.dev
Branch Preview URL: https://fix-boltz-swaps-scroll.arkade-wallet.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Apr 30, 2026 •

Copy link
Copy Markdown

Deploying wallet-bitcoin with  Cloudflare Pages  Cloudflare Pages

Latest commit: 428d748
Status: ✅  Deploy successful!
Preview URL: https://d7297981.wallet-bitcoin.pages.dev
Branch Preview URL: https://fix-boltz-swaps-scroll.wallet-bitcoin.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Apr 30, 2026 •

Copy link
Copy Markdown

Deploying tmp-boltz-upstream-mainnet-arkade-wallet with  Cloudflare Pages  Cloudflare Pages

Latest commit: 428d748
Status: ✅  Deploy successful!
Preview URL: https://9cbbdca8.tmp-boltz-upstream-mainnet-arkade-wallet.pages.dev
Branch Preview URL: https://fix-boltz-swaps-scroll.tmp-boltz-upstream-mainnet-arkade-wallet.pages.dev

View logs

@ghost ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review — fix boltz swaps scroll

🔴 Bug: Virtualizer initialized but never used (dead code)

src/components/SwapsList.tsx:173-178 — useVirtualizer is set up, but the render loop at line 221 still uses swapHistory.map(...) instead of virtualizer.getVirtualItems().map(...). This means:

  1. All items are rendered — no virtualization benefit, defeats the purpose of adding @tanstack/react-virtual
  2. Items are not absolutely positioned — the getTotalSize() wrapper div is there (line 218) but children flow normally instead of using transform: translateY(${virtualItem.start}px)
  3. Layout will be broken — the wrapper div reserves getTotalSize() pixels of height, but all items also render at their natural positions inside it, causing double-height or overlapping content

Reference: TransactionsList.tsx in this same repo implements virtualization correctly — use it as a template. Key differences needed:

// Instead of: swapHistory.map((swap) => ...)
// Use:
{virtualizer.getVirtualItems().map((virtualItem) => {
  const swap = swapHistory[virtualItem.index]
  return (
    <div
      key={key(swap)}
      style={{
        position: 'absolute',
        top: 0,
        left: 0,
        width: '100%',
        transform: `translateY(${virtualItem.start}px)`,
      }}
    >
      <Focusable
        id={key(swap)}
        inactive={!focused}
        ariaLabel={ariaLabel(swap)}
        onEscape={focusOnOuterShell}
        onEnter={() => handleClick(swap)}
      >
        <SwapLine onClick={() => handleClick(swap)} swap={swap} />
      </Focusable>
    </div>
  )
})}

🟡 Minor: Keyboard navigation not updated for virtualization

TransactionsList.tsx handles keyboard nav with virtualizer.scrollToIndex() + requestAnimationFrame focus. This PR's focusOnFirstRow uses document.getElementById directly, which will break when the virtualizer is actually wired up (off-screen items won't be in the DOM).

✅ What's good

  • The scroll container approach (height: calc(100dvh - 280px), overflowY: auto) is correct and matches TransactionsList.tsx
  • Moving scroll-fade to the scroll container is the right call
  • estimateSize: () => 61 and overscan: 5 match the existing pattern

Summary

The scroll container fix is correct, but the virtualizer is dead code — items aren't virtualized. Please wire up getVirtualItems() following the TransactionsList.tsx pattern, or remove the virtualizer entirely if the goal is just scroll containment (in which case, drop the useVirtualizer import and @tanstack/react-virtual isn't needed since it's already a dep for TransactionsList).

Not protocol-critical (UI only), but shipping dead code with a broken layout is a bug.

@coderabbitai

coderabbitai Bot commented Apr 30, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@bordalix has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 23 minutes and 52 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e60c4da9-7a96-413a-a335-9048cc51c9d3

📥 Commits

Reviewing files that changed from the base of the PR and between a1d535e and 428d748.

📒 Files selected for processing (1)
  • src/components/SwapsList.tsx

Walkthrough

SwapsList component adds list virtualization using TanStack's useVirtualizer hook. A scroll container reference is created and the virtualizer is configured with estimateSize: 61 and overscan: 5. The render structure is refactored from directly mapping swap items to using a virtualized scrollable container that dynamically renders visible items only.

Changes

Cohort / File(s) Summary
List Virtualization
src/components/SwapsList.tsx
Implements TanStack useVirtualizer for virtualized rendering of swap history list with scroll container reference, virtualizer configuration, and updated render structure using virtualized scrollable container and dynamic height calculation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • Kukks
  • pietro909
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 title 'fix boltz swaps scroll' directly relates to the main change: implementing list virtualization to fix scrolling in the SwapsList component.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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_boltz_swaps_scroll

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 23 minutes and 52 seconds.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/SwapsList.tsx (1)

182-188: Scroll virtualized index into view before focusing element.

focusOnFirstRow directly focuses by ID without scrolling the element into the virtual list. With virtualization, the element may not be mounted if the list is scrolled, causing focus to fail. TransactionsList.tsx implements the correct pattern: call virtualizer.scrollToIndex() first, then focus in requestAnimationFrame to ensure the DOM element exists.

Proposed fix
   const focusOnFirstRow = () => {
     setFocused(true)
     if (swapHistory.length === 0) return
-    const id = key(swapHistory[0])
-    const first = document.getElementById(id) as HTMLElement
-    if (first) first.focus()
+    virtualizer.scrollToIndex(0)
+    requestAnimationFrame(() => {
+      const id = key(swapHistory[0])
+      const first = document.getElementById(id) as HTMLElement | null
+      first?.focus()
+    })
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/SwapsList.tsx` around lines 182 - 188, The focusOnFirstRow
function focuses the first swap by ID but doesn't ensure a virtualized row is
scrolled/mounted first; change it to call virtualizer.scrollToIndex(0) (or
equivalent index for swapHistory[0]) before trying to focus, then perform the
DOM focus inside a requestAnimationFrame callback to ensure the element is
rendered; keep existing use of key(swapHistory[0]) to compute the element id and
only call first.focus() after confirming document.getElementById(id) is
non-null.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/SwapsList.tsx`:
- Around line 222-234: The list currently sets container height via
virtualizer.getTotalSize() but still renders every item using swapHistory.map(),
so replace the swapHistory.map(...) block with an iteration over
virtualizer.getVirtualItems() and render only those items; for each virtual
item, resolve the swap with swapHistory[virtualItem.index], use key(swap) or
virtualItem.key for the key/id, wrap SwapLine in Focusable as before, and apply
absolute positioning using style={{ position: 'absolute', top:
`${virtualItem.start}px`, height: `${virtualItem.size}px`, width: '100%' }} so
the virtualizer controls visible rows (keep onEnter, onEscape, ariaLabel and
handleClick logic).

---

Nitpick comments:
In `@src/components/SwapsList.tsx`:
- Around line 182-188: The focusOnFirstRow function focuses the first swap by ID
but doesn't ensure a virtualized row is scrolled/mounted first; change it to
call virtualizer.scrollToIndex(0) (or equivalent index for swapHistory[0])
before trying to focus, then perform the DOM focus inside a
requestAnimationFrame callback to ensure the element is rendered; keep existing
use of key(swapHistory[0]) to compute the element id and only call first.focus()
after confirming document.getElementById(id) is non-null.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ab86ea74-1d55-46ea-baad-5b74900f41fd

📥 Commits

Reviewing files that changed from the base of the PR and between 7152688 and a1d535e.

📒 Files selected for processing (1)
  • src/components/SwapsList.tsx

Comment thread src/components/SwapsList.tsx Resolved

@ghost ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Follow-up Review — fix virtualization (428d748)

The new commit addresses the dead-code issue from my previous review. Virtualization is now correctly wired up:

  • ✅ virtualizer.getVirtualItems().map(...) replaces swapHistory.map(...)
  • ✅ Items are absolutely positioned with translateY(virtualItem.start)
  • ✅ Scroll container has ref={parentRef}, overflowY: auto, fixed height
  • ✅ Total size wrapper is correct
  • ✅ Pattern matches existing TransactionsList.tsx implementation

Minor nit (non-blocking): TransactionsList includes data-index={virtualItem.index} on each virtual item div. Not strictly required without measureElement, but worth adding for consistency and future-proofing.

No protocol-critical code touched — this is UI-only (swap history list rendering). LGTM.

@ghost ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Follow-up Review — fix virtualization (428d748)

The new commit addresses the dead-code issue from my previous review. Virtualization is now correctly wired up:

  • ✅ virtualizer.getVirtualItems().map(...) replaces swapHistory.map(...)
  • ✅ Items are absolutely positioned with translateY(virtualItem.start)
  • ✅ Scroll container has ref={parentRef}, overflowY: auto, fixed height
  • ✅ Total size wrapper is correct
  • ✅ Pattern matches existing TransactionsList.tsx implementation

Minor nit (non-blocking): TransactionsList includes data-index={virtualItem.index} on each virtual item div. Not strictly required without measureElement, but worth adding for consistency and future-proofing.

No protocol-critical code touched — this is UI-only (swap history list rendering). LGTM.

@bordalix
bordalix merged commit 39d05b8 into master Apr 30, 2026
6 checks passed
@bordalix
bordalix deleted the fix_boltz_swaps_scroll branch May 18, 2026 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant