UI: Trade; pair selector cannot switch to a different pair; changing the selection has no effect #301

Closed
opened 2026-06-04 11:05:14 +00:00 by totdking · 16 comments
totdking commented 2026-06-04 11:05:14 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-06-04 11:37:27 +00:00 (Migrated from gitlab.com)

Summary

On the /trade page, clicking the Pair dropdown and selecting a different pair does not switch the active workspace. The pair selector appears interactive (it opens a dropdown) but the trade workspace, chart, order book, and ticket all remain on the originally loaded pair. The user is effectively stuck on the first pair loaded and cannot change trading pairs from the UI.

Environment confirmed: The LocalTerra factory contract (terra1uusdu3ea03yg9jp2r9247hgwqtlz3a2fj3qjf8z7vrmemt78g9wspf8zdx) has 25 pairs deployed and responding on-chain (verified via direct LCD query). This rules out a missing-deployment explanation — the bug is in the frontend.


Root cause (code investigation)

The pair-switch flow in code is:

  1. MenuSelect at TradePage.tsx:365–374 calls onPairChange when a new option is selected
  2. onPairChange (TradePage.tsx:309–321) calls navigate(/trade/${addr}) and setPairAddr(addr)
  3. A useEffect at TradePage.tsx:143–167 watches routePair and calls setPairAddr(routePair) when a known factory pair is detected

The code logic is structurally correct for the happy path. Two candidate causes remain:

Candidate 1 — getAllPairsPaginated() returns only a partial pair list: TradePage.tsx:116 calls getAllPairsPaginated() to populate the dropdown. If that function has a pagination bug or a low page-limit default, the MenuSelect may only receive a subset of pairs (e.g. just the first page, which contains EMBER/CORAL). With only one option visible, re-selecting the current pair does not trigger onChange — MenuSelect guards same-value selections:

if (next !== value) onChange(next)  // MenuSelect.tsx:74

Candidate 2 — portal dropdown z-index / click interception: The MenuSelect dropdown renders via createPortal into document.body using position: fixed coords from usePortalListbox. If any overlay or DevTools panel intercepts pointer events above the portal layer, clicks on dropdown items would not register. The console shows 36× [Violation] 'setTimeout' handler took <N>ms, indicating main-thread jank that can delay or swallow click events.


Steps to reproduce

  1. Open /trade/:pairAddr for any pair (e.g. EMBER/CORAL)
  2. Click the Pair dropdown at the top of the page
  3. Observe how many pairs appear in the dropdown list
  4. Select any pair other than the currently active one
  5. Observe: the workspace (chart, order book, ticket) does not change and the URL does not update

Expected: Selecting a different pair updates the URL to /trade/:newPairAddr, replaces the chart, order book, and order ticket with data for the new pair. Actual: No change occurs — the workspace stays on EMBER/CORAL.


Expected behavior

Selecting a pair from the dropdown should:

  1. Update the URL to /trade/:newPairAddr
  2. Update the chart, order book, tape, and order ticket to reflect the new pair

Actual behavior

The workspace does not change after selecting a different pair. 25 pairs exist on-chain but the selector either does not load them all, or selection clicks are not being registered.


Screen record

Screen Recording 2026-06-04 at 12.07.21.mov{width=900 height=553}


Additional notes

  • Direct LCD query to the factory contract confirms 25 pairs on-chain — the deployment is complete and not the cause.
  • The CSP violation logged in the console (Creating a worker from 'blob:...' violates Content Security Policy) may cause chart worker instability but is unlikely to affect dropdown click registration.

Environment

  • Chain: localterra
  • LCD: http://localhost:1317
  • Factory: terra1uusdu3ea03yg9jp2r9247hgwqtlz3a2fj3qjf8z7vrmemt78g9wspf8zdx (25 pairs confirmed on-chain)
  • Wallet: Keplr (Terra Classic)
  • Browser: Chrome
  • Page: /trade/terra1xdwrxunda29fjc972uf0kqchpurzs3gzfvr0snr8mrqw9l3zhtyq80qhdn (EMBER/CORAL)
  • Network throttle applied: Fast 4G (DevTools)

Severity: P1 ~"blocker:hybrid" — pair switching is a fundamental navigation requirement; confirmed broken on LocalTerra with 25 pairs available.

cc: @PlasticDigits

### Summary On the `/trade` page, clicking the **Pair** dropdown and selecting a different pair does not switch the active workspace. The pair selector appears interactive (it opens a dropdown) but the trade workspace, chart, order book, and ticket all remain on the originally loaded pair. The user is effectively stuck on the first pair loaded and cannot change trading pairs from the UI. **Environment confirmed:** The LocalTerra factory contract (`terra1uusdu3ea03yg9jp2r9247hgwqtlz3a2fj3qjf8z7vrmemt78g9wspf8zdx`) has **25 pairs** deployed and responding on-chain (verified via direct LCD query). This rules out a missing-deployment explanation — the bug is in the frontend. --- ### Root cause (code investigation) The pair-switch flow in code is: 1. `MenuSelect` at **`TradePage.tsx:365–374`** calls `onPairChange` when a new option is selected 2. `onPairChange` (**`TradePage.tsx:309–321`**) calls `navigate(`/trade/${addr}`)` and `setPairAddr(addr)` 3. A `useEffect` at **`TradePage.tsx:143–167`** watches `routePair` and calls `setPairAddr(routePair)` when a known factory pair is detected The code logic is structurally correct for the happy path. Two candidate causes remain: **Candidate 1 — `getAllPairsPaginated()` returns only a partial pair list:** `TradePage.tsx:116` calls `getAllPairsPaginated()` to populate the dropdown. If that function has a pagination bug or a low page-limit default, the `MenuSelect` may only receive a subset of pairs (e.g. just the first page, which contains EMBER/CORAL). With only one option visible, re-selecting the current pair does not trigger `onChange` — `MenuSelect` guards same-value selections: ```ts if (next !== value) onChange(next) // MenuSelect.tsx:74 ``` **Candidate 2 — portal dropdown z-index / click interception:** The `MenuSelect` dropdown renders via `createPortal` into `document.body` using `position: fixed` coords from `usePortalListbox`. If any overlay or DevTools panel intercepts pointer events above the portal layer, clicks on dropdown items would not register. The console shows 36× `[Violation] 'setTimeout' handler took <N>ms`, indicating main-thread jank that can delay or swallow click events. --- ### Steps to reproduce 1. Open `/trade/:pairAddr` for any pair (e.g. EMBER/CORAL) 2. Click the **Pair** dropdown at the top of the page 3. Observe how many pairs appear in the dropdown list 4. Select any pair other than the currently active one 5. Observe: the workspace (chart, order book, ticket) does not change and the URL does not update **Expected:** Selecting a different pair updates the URL to `/trade/:newPairAddr`, replaces the chart, order book, and order ticket with data for the new pair. **Actual:** No change occurs — the workspace stays on EMBER/CORAL. --- ### Expected behavior Selecting a pair from the dropdown should: 1. Update the URL to `/trade/:newPairAddr` 2. Update the chart, order book, tape, and order ticket to reflect the new pair --- ### Actual behavior The workspace does not change after selecting a different pair. 25 pairs exist on-chain but the selector either does not load them all, or selection clicks are not being registered. --- ## Screen record ![Screen Recording 2026-06-04 at 12.07.21.mov](/uploads/5d8605892d9e0521fc7d89b10071b174/Screen_Recording_2026-06-04_at_12.07.21.mov){width=900 height=553} --- ### Additional notes - Direct LCD query to the factory contract confirms 25 pairs on-chain — the deployment is complete and not the cause. - The CSP violation logged in the console (`Creating a worker from 'blob:...' violates Content Security Policy`) may cause chart worker instability but is unlikely to affect dropdown click registration. --- ### Environment - Chain: localterra - LCD: [http://localhost:1317](http://localhost:1317) - Factory: `terra1uusdu3ea03yg9jp2r9247hgwqtlz3a2fj3qjf8z7vrmemt78g9wspf8zdx` (25 pairs confirmed on-chain) - Wallet: Keplr (Terra Classic) - Browser: Chrome - Page: `/trade/terra1xdwrxunda29fjc972uf0kqchpurzs3gzfvr0snr8mrqw9l3zhtyq80qhdn` (EMBER/CORAL) - Network throttle applied: Fast 4G (DevTools) --- **Severity:** P1 ~"blocker:hybrid" — pair switching is a fundamental navigation requirement; confirmed broken on LocalTerra with 25 pairs available. cc: @PlasticDigits
Brouie commented 2026-06-05 03:04:35 +00:00 (Migrated from gitlab.com)

Dug into this at the source layer — your Candidate 1 (partial pair list) is ruled out, which should narrow it to the browser layer.

getAllPairsPaginated() (factory.ts) paginates correctly: it loops 50 at a time until a short page returns, capped at 200. With 25 pairs it returns all 25 in one page, so the dropdown gets the full list. The option value is the pair contract address (pairMenuOptions.ts:50), onPairChange navigates to /trade/:addr + setPairAddr, and the routePair useEffect (TradePage.tsx ~163) calls setPairAddr(routePair) when it resolves to a known factory pair. So the happy path is wired correctly in code — selecting a different pair should switch.

That leaves your Candidate 2 (the portal dropdown's click/pointer-event interception) as the likely cause, which is a browser/DOM-layer thing I can't repro or fix from source — it's yours to pin in the browser. One thing that would settle it fast: in the repro, check how many options the dropdown actually renders and what getAllPairsPaginated returns at runtime; if it's only one despite 25 on-chain, that's a live query failure (not the pagination logic, which is sound), and re-selecting the same value won't fire onChange (MenuSelect guards next !== value). @PlasticDigits

Dug into this at the source layer — your Candidate 1 (partial pair list) is ruled out, which should narrow it to the browser layer. getAllPairsPaginated() (factory.ts) paginates correctly: it loops 50 at a time until a short page returns, capped at 200. With 25 pairs it returns all 25 in one page, so the dropdown gets the full list. The option value is the pair contract address (pairMenuOptions.ts:50), onPairChange navigates to /trade/:addr + setPairAddr, and the routePair useEffect (TradePage.tsx ~163) calls setPairAddr(routePair) when it resolves to a known factory pair. So the happy path is wired correctly in code — selecting a different pair should switch. That leaves your Candidate 2 (the portal dropdown's click/pointer-event interception) as the likely cause, which is a browser/DOM-layer thing I can't repro or fix from source — it's yours to pin in the browser. One thing that would settle it fast: in the repro, check how many options the dropdown actually renders and what getAllPairsPaginated returns at runtime; if it's only one despite 25 on-chain, that's a live query failure (not the pagination logic, which is sound), and re-selecting the same value won't fire onChange (MenuSelect guards next !== value). @PlasticDigits
PlasticDigits commented 2026-06-05 04:05:09 +00:00 (Migrated from gitlab.com)

Postponed as we need to have intelligent search

Postponed as we need to have intelligent search
PlasticDigits commented 2026-06-06 07:00:06 +00:00 (Migrated from gitlab.com)

For this item, verify that our pair dropdown has been replaced with a search. Additionally, the search bar should show "top pairs" when no text is entered, sorted by volume in last 24 hours, up to 20 items

For this item, verify that our pair dropdown has been replaced with a search. Additionally, the search bar should show "top pairs" when no text is entered, sorted by volume in last 24 hours, up to 20 items
ghost1 commented 2026-06-06 07:03:42 +00:00 (Migrated from gitlab.com)

mentioned in commit 6482e8c54b

mentioned in commit 6482e8c54bb8a25c93dacf7cf45fae89b4abf449
PlasticDigits commented 2026-06-06 07:04:09 +00:00 (Migrated from gitlab.com)

mentioned in merge request !825

mentioned in merge request !825
PlasticDigits commented 2026-06-06 07:04:21 +00:00 (Migrated from gitlab.com)

Implementation verification (#301)

Verified per PlasticDigits comment: the Trade pair selector has been replaced with PairSearchSelect (landed via #314). The original MenuSelect click-interception bug is resolved by the searchable combobox with onMouseDown preventDefault on options.

Acceptance checklist

Criterion How verified Result
Pair dropdown replaced with search on /trade Code review: TradePage.tsx uses PairSearchSelect (combobox input); unit test PairSearchSelect.issue301.test.tsx PASS
Empty search shows top pairs by 24h volume, up to 20 PairSearchSelect calls getPairs({ sort: 'volume_24h', order: 'desc', limit: 20 }) when query empty; unit test asserts call PASS
Selecting a different pair switches workspace onPairChange → navigate(/trade/:addr) + setPairAddr; unit tests for onChange and TradePage URL/getPair PASS

Commands run

export PATH="$HOME/.nvm/versions/node/$(cat .nvmrc)/bin:$PATH"
cd frontend-dapp
npm test -- --run src/components/trade/__tests__/PairSearchSelect.issue301.test.tsx
npm test -- --run src/pages/TradePage.test.tsx -t "GitLab #301"
make lint-frontend  # 0 errors

MR

Regression tests + doc cross-link: !825

Issue stays open until MR merges; close then with final verification.

## Implementation verification (#301) Verified per [PlasticDigits comment](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/301#note_): the Trade pair selector has been replaced with [`PairSearchSelect`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/trade/PairSearchSelect.tsx) (landed via #314). The original `MenuSelect` click-interception bug is resolved by the searchable combobox with `onMouseDown` preventDefault on options. ### Acceptance checklist | Criterion | How verified | Result | |-----------|--------------|--------| | Pair dropdown replaced with search on `/trade` | Code review: `TradePage.tsx` uses `PairSearchSelect` (combobox input); unit test `PairSearchSelect.issue301.test.tsx` | **PASS** | | Empty search shows top pairs by 24h volume, up to 20 | `PairSearchSelect` calls `getPairs({ sort: 'volume_24h', order: 'desc', limit: 20 })` when query empty; unit test asserts call | **PASS** | | Selecting a different pair switches workspace | `onPairChange` → `navigate(/trade/:addr)` + `setPairAddr`; unit tests for `onChange` and TradePage URL/`getPair` | **PASS** | ### Commands run ```bash export PATH="$HOME/.nvm/versions/node/$(cat .nvmrc)/bin:$PATH" cd frontend-dapp npm test -- --run src/components/trade/__tests__/PairSearchSelect.issue301.test.tsx npm test -- --run src/pages/TradePage.test.tsx -t "GitLab #301" make lint-frontend # 0 errors ``` ### MR Regression tests + doc cross-link: [!825](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/107) Issue stays **open** until MR merges; close then with final verification.
PlasticDigits commented 2026-06-06 07:10:53 +00:00 (Migrated from gitlab.com)

mentioned in commit 6ff5483ab6

mentioned in commit 6ff5483ab6c1a1123b724b09fac0517f491b990e
PlasticDigits commented 2026-06-06 08:55:48 +00:00 (Migrated from gitlab.com)

Verification complete — GitLab #301

Issue: UI: Trade; pair selector cannot switch to a different pair

Per PlasticDigits comment (2026-06-06): verify the Trade pair dropdown was replaced with intelligent search; empty search shows top pairs by 24h volume (≤20); selecting a different pair switches the workspace.

Implementation landed on main via PairSearchSelect (#314); regression tests/docs in merged !825.

Acceptance checklist

Criterion How verified Result
Pair dropdown replaced with search combobox on /trade Code: TradePage.tsx uses PairSearchSelect (role=combobox, type=text, placeholder Search pairs…); unit test PairSearchSelect.issue301.test.tsx PASS
Empty search shows top pairs by 24h volume, up to 20 Unit test asserts getPairs({ sort: 'volume_24h', order: 'desc', limit: 20 }); browser QA on LocalTerra stack — 20 options with VOL badges, indexer request sort=volume_24h&order=desc&limit=20 PASS
Selecting a different pair switches workspace (URL + chart/book/ticket) Unit + TradePage.test.tsx (GitLab #301); browser QA — from EMBER/CORAL selected ONYX/OPAL → URL /trade/terra1mrmvu6…0p5uul, trade-desktop-workspace visible PASS

Commands / logs

export PATH="$HOME/.nvm/versions/node/$(cat .nvmrc)/bin:$PATH"
cd frontend-dapp
npm test -- --run src/components/trade/__tests__/PairSearchSelect.issue301.test.tsx
# ✓ 3 passed

npm test -- --run src/pages/TradePage.test.tsx -t "GitLab #301"
# ✓ 1 passed

npm run lint
# 0 errors (5 pre-existing warnings)

# Manual browser QA (LocalTerra + indexer + make dev on :5173)
# Playwright + system Chrome; risk ack pre-seeded in localStorage
# Result: {"pass":true,"optionCount":20,"api":{"sort":"volume_24h","order":"desc","limit":"20"},
#   "finalUrl":"http://127.0.0.1:5173/trade/terra1mrmvu6…0p5uul"}

Original MenuSelect click-interception bug is resolved by the searchable combobox (onMouseDown preventDefault on options + button onClick).

## Verification complete — GitLab #301 Issue: [UI: Trade; pair selector cannot switch to a different pair](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/301) Per [PlasticDigits comment (2026-06-06)](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/301#note_): verify the Trade pair dropdown was replaced with intelligent search; empty search shows top pairs by 24h volume (≤20); selecting a different pair switches the workspace. Implementation landed on `main` via [`PairSearchSelect`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/trade/PairSearchSelect.tsx) ([#314](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/314)); regression tests/docs in merged [!825](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/107). ### Acceptance checklist | Criterion | How verified | Result | |-----------|--------------|--------| | Pair dropdown replaced with search combobox on `/trade` | Code: `TradePage.tsx` uses `PairSearchSelect` (`role=combobox`, `type=text`, placeholder `Search pairs…`); unit test `PairSearchSelect.issue301.test.tsx` | **PASS** | | Empty search shows top pairs by 24h volume, up to 20 | Unit test asserts `getPairs({ sort: 'volume_24h', order: 'desc', limit: 20 })`; browser QA on LocalTerra stack — 20 options with `VOL` badges, indexer request `sort=volume_24h&order=desc&limit=20` | **PASS** | | Selecting a different pair switches workspace (URL + chart/book/ticket) | Unit + `TradePage.test.tsx` (`GitLab #301`); browser QA — from EMBER/CORAL selected ONYX/OPAL → URL `/trade/terra1mrmvu6…0p5uul`, `trade-desktop-workspace` visible | **PASS** | ### Commands / logs ```bash export PATH="$HOME/.nvm/versions/node/$(cat .nvmrc)/bin:$PATH" cd frontend-dapp npm test -- --run src/components/trade/__tests__/PairSearchSelect.issue301.test.tsx # ✓ 3 passed npm test -- --run src/pages/TradePage.test.tsx -t "GitLab #301" # ✓ 1 passed npm run lint # 0 errors (5 pre-existing warnings) # Manual browser QA (LocalTerra + indexer + make dev on :5173) # Playwright + system Chrome; risk ack pre-seeded in localStorage # Result: {"pass":true,"optionCount":20,"api":{"sort":"volume_24h","order":"desc","limit":"20"}, # "finalUrl":"http://127.0.0.1:5173/trade/terra1mrmvu6…0p5uul"} ``` Original `MenuSelect` click-interception bug is resolved by the searchable combobox (`onMouseDown` preventDefault on options + button `onClick`).
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-06 08:55:52 +00:00
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 67ba260b93

mentioned in commit 67ba260b934b78e1861b502a8fc9796469312da7
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit b4a64ef77f

mentioned in commit b4a64ef77f61c82d6560cd058b3a8b4189a2680d
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 36cfbc8d02

mentioned in commit 36cfbc8d020a195e0eeb5c2aba171b558905493b
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 36cfbc8d02

mentioned in commit 36cfbc8d020a195e0eeb5c2aba171b558905493b
PlasticDigits commented 2026-06-08 13:42:29 +00:00 (Migrated from gitlab.com)

mentioned in commit 4f68221de6

mentioned in commit 4f68221de647431cf6db5057282d75633e524eff
totdking commented 2026-06-09 13:52:13 +00:00 (Migrated from gitlab.com)

mentioned in issue #350

mentioned in issue #350
PlasticDigits commented 2026-07-12 11:13:48 +00:00 (Migrated from gitlab.com)

mentioned in issue #481

mentioned in issue #481
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#301
No description provided.