Fix hidden mobile submit dropdown and stalled MetaMask connections#904
Conversation
The Submit Contribution type and mission dropdown opened below the bottom edge of the form shell on mobile, where it was swallowed by the shell's scroll clipping, so before picking a type users saw almost none of the menu. The shell now clips only horizontal bleed without becoming a vertical scroll container, letting the menu overflow and render in full. The menu also layers above the linked-project panel, which the project picker rework had raised above it, so reopening the dropdown with a milestone type selected no longer hides it behind that panel. ## Claude Implementation Notes - frontend/src/components/portal/submit-contribution/SubmitContribution.svelte: mobile `.submit-form-shell` rule changed from `overflow-x: hidden` to `overflow-x: clip` (hidden forces computed overflow-y to auto, creating a scroll container that clipped the absolutely-positioned type dropdown); `.type-dropdown-menu` raised from `z-10` to `z-[60]` so it paints above the `relative z-20` linked-project panel introduced by PR #900 - frontend/CLAUDE.md: documented the overflow-x hidden vs clip gotcha and the dropdown z-layering convention under Common Issues & Solutions
Choosing MetaMask now tears down any persisted Connect SDK session before connecting. Previously, a session whose wallet side was gone (app reinstalled, session expired, or left over from an earlier flow iteration) made the SDK send the connection request over the dead relay channel and open MetaMask through a payload-less deeplink: the app came to the foreground with nothing to approve and the portal hung forever. The same wedge occurred when a prior attempt was still pending. A fresh pairing embeds the approval request in the deeplink itself, so the MetaMask app always shows the connect sheet. Teardown is time-boxed so an unreachable relay cannot stall the flow, and the desktop QR modal and extension routing are unchanged. ## Claude Implementation Notes - frontend/src/lib/metamaskConnect.js: getMetaMaskConnectProvider now awaits client.disconnect() (swallowing errors, capped at 3s via Promise.race) before client.connect(); disconnect resets the SDK core status from 'connecting', tears down the MWP transport, and clears the persisted transport type, guaranteeing the fresh-pairing deeplink branch that carries the request payload - frontend/src/tests/metamaskConnect.test.js: new unit tests covering disconnect-before-connect ordering, tolerance of a hanging disconnect (fake timers past the 3s cap), tolerance of a rejecting disconnect, and normalization of SDK user-cancel errors to EIP-1193 code 4001
The Submit Contribution shortcut in the mobile sidebar's pinned bottom
area now only renders for signed-in users, alongside My Submissions,
instead of routing visitors into the wallet-connect flow.
## Claude Implementation Notes
- frontend/src/components/Sidebar.svelte: moved the Submit Contribution button inside the existing `{#if $authState.isAuthenticated}` block that gates My Submissions in the mobile pinned area; handleSubmitContribution and its analytics tracking are unchanged
|
Warning Review limit reached
Next review available in: 51 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR fixes mobile dropdown clipping in the Submit Contribution form via z-index and overflow adjustments, gates the sidebar's mobile "Submit Contribution" button behind authentication, and adds stale-session cleanup before MetaMask connect with a timeout-bounded disconnect and corresponding tests. ChangesMobile dropdown clipping and sidebar visibility fix
MetaMask stale session recovery
Estimated code review effort: 2 (Simple) | ~12 minutes Sequence Diagram(s)sequenceDiagram
participant App
participant getMetaMaskConnectProvider
participant SDKClient
App->>getMetaMaskConnectProvider: request provider
getMetaMaskConnectProvider->>SDKClient: disconnect()
getMetaMaskConnectProvider->>getMetaMaskConnectProvider: race disconnect vs 3s timeout
SDKClient-->>getMetaMaskConnectProvider: resolve/reject/timeout (ignored)
getMetaMaskConnectProvider->>SDKClient: connect()
SDKClient-->>getMetaMaskConnectProvider: provider or user-rejection error
getMetaMaskConnectProvider-->>App: return provider
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/src/lib/metamaskConnect.js`:
- Around line 94-107: The disconnect timeout value is hardcoded in Metamask
connect logic and duplicated in tests, so extract it into a shared exported
constant from metamaskConnect.js. Update the Promise.race timeout in the connect
flow to use that constant, and have the related test import the same symbol
instead of advancing timers by a literal so both stay in sync.
- Around line 104-107: The disconnect flow in metamaskConnect still leaves the
fallback setTimeout running after Promise.race settles, so update that logic to
keep a timer handle and clear it once client.disconnect() or the timeout branch
completes. Make the fix in the disconnect/cleanup path around the Promise.race
call so the timer is always cleared on both success and failure, preventing
stray pending timers during repeated connect attempts.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 9071b1df-03c7-40eb-92f5-39a4452fac36
📒 Files selected for processing (6)
CHANGELOG.mdfrontend/CLAUDE.mdfrontend/src/components/Sidebar.sveltefrontend/src/components/portal/submit-contribution/SubmitContribution.sveltefrontend/src/lib/metamaskConnect.jsfrontend/src/tests/metamaskConnect.test.js
Summary
overflow-x: hiddenforced computedoverflow-y: auto, turning the shell into a scroll container that clipped the menu below its bottom edge (only ~15px of ~320px was visible before a type was picked).overflow-x: clipkeeps the horizontal clipping without capturing vertical overflow. PR Fix mobile navigation and project dropdown #900 only rebuilt the project picker; the type dropdown was never fixed.z-10→z-[60]) above the linked-project panel that PR Fix mobile navigation and project dropdown #900 raised toz-20, which otherwise paints over the reopened dropdown when a milestone type is selected.connect(). With a stale session, the SDK sent the request over a dead relay channel and opened MetaMask via a payload-less deeplink — the app foregrounded with nothing to approve and the portal hung. The same wedge hit retries while a prior attempt was stillconnecting. A fresh pairing embeds the approval request in the deeplink itself, so the MetaMask app always shows the connect sheet. Desktop QR modal and extension routing unchanged (explicit selection already re-prompts viaforceRequest).Validation
overflow-x: hiddencomputedoverflow-yisautoand only 15px of the 322px menu is visible; withclipit staysvisibleand the menu renders in full above thez-20panel.display_urifires withmetamask://connect/mwp?p=<payload>(fresh pairing carrying the request).npx vitest run: 177 passed / 23 failed, failures identical to the pre-existing dev baseline (Profile, api, routes, AuthButton, meta); includes 4 new tests for the disconnect-first behavior.npm run buildpasses.Summary by CodeRabbit
New Features
Bug Fixes