Skip to content

feat: add warp route visualization card for message details - #257

Merged
nambrot merged 25 commits into
mainfrom
nam/warp-route-visualization
Feb 17, 2026
Merged

feat: add warp route visualization card for message details#257
nambrot merged 25 commits into
mainfrom
nam/warp-route-visualization

Conversation

@nambrot-agent

@nambrot-agent nambrot-agent commented Jan 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Add a collapsible card that visualizes the entire warp route when viewing warp transfer messages. Shows all chains in the route with their token type (collateral, synthetic, native, xERC20), addresses, and collateral balances for EVM chains.

Uses registry data for token types (no RPC calls on page load). Balance fetches are deferred until the user expands the card.

Features

  • Graph visualization with origin/destination highlighted
  • Token type badges with color coding (from registry standard field)
  • Collateral balances and synthetic supply display (fetched on expand)
  • Transfer amount shown on edge between origin/destination
  • Block explorer links for addresses
  • Manual refresh button for balances
  • Collapsed view for routes with >6 chains
  • Destination marked red if insufficient collateral

Performance

  • Zero RPC calls on page load (token types from registry)
  • Balance RPCs only triggered when user expands the card
  • Infinite staleTime prevents refetching

Limitations

  • Balance fetching only supported for EVM chains (Solana/StarkNet adapters require native dependencies that don't bundle for browser)

Test URLs

Files Changed

  • Added WarpRouteVisualizationCard.tsx - Main collapsible card component
  • Added warpVisualization/ directory with:
    • WarpRouteGraph.tsx - SVG + HTML graph visualization
    • useWarpRouteVisualization.ts - Hook to build visualization from registry
    • useWarpRouteBalances.ts - Hook to fetch balances (deferred)
    • types.ts - TypeScript interfaces
  • Modified MessageDetails.tsx - Integrated the new card
  • Modified store.ts - Added warpRouteConfigs to store
  • Modified types.ts - Added WarpRouteConfigs type

Summary by CodeRabbit

  • New Features

    • Adds a Warp Route visualization card to message details: interactive route graph, copyable route ID, explorer links, transfer-amount display, insufficiency cues, loading states, manual refresh, collapsible view, and optional blur.
  • Chores

    • Adds background visualization data and balance fetching (balances loaded on expand) and persists warp route configs for runtime visualizations.

Add a collapsible card that visualizes the entire warp route when viewing
warp transfer messages. Shows all chains in the route with their token
type (collateral, synthetic, native, xERC20), addresses, owners, and
collateral balances for EVM chains.

Features:
- Graph visualization with origin/destination highlighted
- Token type badges with color coding
- Collateral balances and synthetic supply display
- Transfer amount shown on edge between origin/destination
- Block explorer links for addresses
- Manual refresh button for balances
- Collapsed view for routes with >6 chains
- Destination marked red if insufficient collateral

Limitations:
- Balance fetching only supported for EVM chains (Solana/StarkNet
  adapters require native dependencies that don't bundle for browser)
@nambrot-agent
nambrot-agent requested a review from Xaroz as a code owner January 23, 2026 20:13
@vercel

vercel Bot commented Jan 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperlane-explorer Ready Ready Preview, Comment Feb 17, 2026 2:59pm

Request Review

@coderabbitai

coderabbitai Bot commented Jan 23, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

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

⌛ 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.

📝 Walkthrough

Walkthrough

Adds a Warp Route visualization feature: new visualization types and hooks, a WarpRouteGraph component and WarpRouteVisualizationCard UI, store/type plumbing for warpRouteConfigs, and MessageDetails now renders the new card. (<=50 words)

Changes

Cohort / File(s) Summary
Store & Types
src/store.ts, src/types.ts
Add WarpRouteConfigs type; persist warpRouteConfigs in store and hydration; buildMultiProvider/buildWarpRouteMaps now return and propagate warpRouteConfigs.
Visualization Types
src/features/messages/warpVisualization/types.ts
New interfaces: WarpRouteTokenVisualization, WarpRouteVisualization, ChainBalance, WarpRouteBalances.
Visualization Hooks
src/features/messages/warpVisualization/useWarpRouteVisualization.ts, src/features/messages/warpVisualization/useWarpRouteBalances.ts
New hooks: useWarpRouteVisualization (derives visualization from configs) and useWarpRouteBalances (creates adapters, fetches per-chain bridged balances, exposes refetch and isBalanceInsufficient).
Graph Component
src/features/messages/warpVisualization/WarpRouteGraph.tsx
New WarpRouteGraph component: SVG backbone with HTML node overlays, layout for origin/destination and intermediates, explorer links, token/type badges, balance displays, and transfer-amount edge label.
UI Card & Integration
src/features/messages/cards/WarpRouteVisualizationCard.tsx, src/features/messages/MessageDetails.tsx
New WarpRouteVisualizationCard added and rendered by MessageDetails; supports expand/blur, on-demand balance fetch, refresh control, and passes visualization/balances into WarpRouteGraph.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant U as User
    participant MD as MessageDetails
    participant C as WarpRouteVisualizationCard
    participant V as useWarpRouteVisualization
    participant B as useWarpRouteBalances
    participant S as Store/MultiProvider
    participant G as WarpRouteGraph

    U->>MD: open message view
    MD->>C: mount card (message, warpRouteDetails, blur)
    C->>V: request visualization data
    V->>S: read warpRouteConfigs / chain metadata
    V-->>C: return visualization (or undefined)
    C->>B: request balances when expanded
    B->>S: create adapters / fetch bridged supplies
    B-->>C: return balances + refresh()
    C->>G: render graph with tokens, chains, balances
    G-->>U: display interactive graph
    U->>C: click refresh
    C->>B: call refresh()
    B->>S: refetch adapter queries
    B-->>C: updated balances
    C->>G: re-render with updated balances
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

A wee graph winds through chain and sod,
Tokens trek safe, no need for nod,
Click to bloom routes, refresh the well,
Balances hum and stories tell,
Warp's a-visual — clever as a spell.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature added—a warp route visualization card component for the message details page.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch nam/warp-route-visualization

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

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@src/features/messages/cards/WarpRouteVisualizationCard.tsx`:
- Around line 33-38: The code uses the || operator when falling back to decimals
(e.g., in the call to toWei inside the useWarpRouteBalances invocation and the
similar call around line 55), which treats 0 as falsy and incorrectly replaces
zero decimals with 18; change those fallbacks from "originToken.decimals || 18"
(and the corresponding "destinationToken.decimals || 18") to use nullish
coalescing "originToken.decimals ?? 18" and "destinationToken.decimals ?? 18" so
zero-decimal tokens are preserved.
- Around line 74-79: Replace the template-string conditional class on the Card
with clsx: import clsx at the top of WarpRouteVisualizationCard.tsx, then change
the Card's className to use clsx to combine "w-full" with the conditional blur
class (based on the blur prop/state). Also update the button's className usage
if similar patterns exist; refer to the Card component, the blur identifier, and
the isExpanded/setIsExpanded toggle to locate the change.

In `@src/features/messages/warpVisualization/useWarpRouteVisualization.ts`:
- Around line 26-30: The current match uses toLowerCase() unconditionally which
can corrupt case‑sensitive IDs; update the matching in useWarpRouteVisualization
so you only normalize case for hex addresses: detect hex by testing tokenAddress
(and t.addressOrDenom when present) against a hex pattern like
/^0x[0-9a-fA-F]+$/ and apply toLowerCase() only in that branch, otherwise
compare tokenAddress and t.addressOrDenom as-is; keep the chainName equality
check unchanged and ensure you reference tokenAddress, t.addressOrDenom, and
config.tokens.find when making the change.
- Around line 162-177: In the tokens mapping inside useWarpRouteVisualization
(mapping warpRoute.config.tokens to WarpRouteTokenVisualization), replace the
fallback for decimals that currently uses "decimals || 18" with the nullish
coalescing operator so legitimate zero values are preserved (i.e., use "decimals
?? 18"); update the decimals assignment in the returned object to use
token.decimals ?? 18 so only null/undefined get the default.

In `@src/features/messages/warpVisualization/WarpRouteGraph.tsx`:
- Around line 351-354: The isExpanded state is initialized from
shouldCollapseByDefault but never syncs when tokens load asynchronously, so
routes that grow beyond COLLAPSE_THRESHOLD remain expanded; update the component
to watch tokens (or tokens.length) and set isExpanded to
!shouldCollapseByDefault when tokens change unless the user has manually toggled
expansion—implement a manualToggle flag (e.g., a useRef or separate state like
userToggled) that is set when setIsExpanded is invoked by user action, and add a
useEffect that recalculates shouldCollapseByDefault and only calls
setIsExpanded(!shouldCollapseByDefault) when userToggled is false, referencing
shouldCollapseByDefault, isExpanded, setIsExpanded, tokens, and
COLLAPSE_THRESHOLD (apply same change for the other occurrences around the lines
noted).
- Around line 96-118: The formatCompactBalance function currently converts the
full-precision string from fromWei to a JS Number, which can lose precision for
very large values; update formatCompactBalance to use BigNumber (from
bignumber.js or the project's BigNumber helper) or use fromWeiRounded() to parse
the value safely, then perform the comparisons/divisions and formatting using
BigNumber methods (or convert the rounded value to a string first) so the output
remains consistent (e.g., "1.2M", "500K", fixed decimals or exponential) without
switching to a raw unformatted string; locate formatCompactBalance and replace
Number()/value math with BigNumber-based comparisons, division and
toFixed/toFormat calls to preserve precision and consistent display.
🧹 Nitpick comments (2)
src/store.ts (1)

183-190: Log registry fetch failures with context.
The catch block drops the error, which makes debugging harder. Consider logging the error object.

🔧 Suggested tweak
-  } catch {
-    logger.debug(
-      'Failed to build warp route data from GithubRegistry. Using published warp route configs.',
-    );
+  } catch (err) {
+    logger.warn(
+      'Failed to build warp route data from GithubRegistry. Using published warp route configs.',
+      err,
+    );
src/features/messages/warpVisualization/WarpRouteGraph.tsx (1)

172-214: Use clsx() for those conditional classNames.
Right now you've got template literals scattered about with conditional bits sprinkled in. clsx() is already in your dependencies and keeps things tidier, just like your coding guidelines suggest.

♻️ Example refactor (apply similarly in other spots)
-import { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
+import clsx from 'clsx';
...
-    <div
-      className={`flex min-w-[130px] flex-col items-center rounded-lg border-2 bg-white p-2 shadow-sm ${borderColor} ${hasInsufficientBalance ? 'bg-red-50' : ''}`}
-    >
+    <div
+      className={clsx(
+        'flex min-w-[130px] flex-col items-center rounded-lg border-2 bg-white p-2 shadow-sm',
+        borderColor,
+        hasInsufficientBalance && 'bg-red-50',
+      )}
+    >
...
-        <div
-          className={`mt-1 rounded px-1.5 py-0.5 text-[10px] font-medium ${
-            hasInsufficientBalance
-              ? 'bg-red-100 text-red-700'
-              : isSynthetic
-                ? 'bg-purple-100 text-purple-700'
-                : 'bg-gray-100 text-gray-700'
-          }`}
-        >
+        <div
+          className={clsx(
+            'mt-1 rounded px-1.5 py-0.5 text-[10px] font-medium',
+            hasInsufficientBalance
+              ? 'bg-red-100 text-red-700'
+              : isSynthetic
+                ? 'bg-purple-100 text-purple-700'
+                : 'bg-gray-100 text-gray-700',
+          )}
+        >

Also applies to: 236-243, 578-586

Comment thread src/features/messages/cards/WarpRouteVisualizationCard.tsx
Comment thread src/features/messages/cards/WarpRouteVisualizationCard.tsx Outdated
Comment thread src/features/messages/warpVisualization/useWarpRouteVisualization.ts Outdated
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
- Fix ESLint errors for missing queryKey dependencies with disable comments
- Use nullish coalescing (??) for decimals to preserve zero values
- Use clsx for conditional classNames in WarpRouteVisualizationCard
- Fix case-folding for non-hex addresses (preserve base58 case)
- Sync expanded state when tokens load asynchronously in WarpRouteGraph
- Apply prettier formatting
Comment thread src/features/messages/cards/WarpRouteVisualizationCard.tsx Outdated
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
Co-authored-by: Xaroz <xaroz@users.noreply.github.com>
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
Comment thread src/features/messages/warpVisualization/useWarpRouteBalances.ts Outdated
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx
Comment thread src/features/messages/cards/WarpRouteVisualizationCard.tsx
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx
Comment thread src/features/messages/cards/WarpRouteVisualizationCard.tsx Outdated
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
Comment thread src/features/messages/warpVisualization/useWarpRouteVisualization.ts Outdated
- Replace custom formatCompactBalance with formatAmountCompact from utils/amount.ts
- Replace custom truncateAddress with shortenAddress from @hyperlane-xyz/utils
- Replace synchronous getExplorerAddressUrl with async tryGetBlockExplorerAddressUrl
- Use refetch from useQuery instead of custom refresh callback via queryClient
- Change origin border color from green to blue (both use same color now)
- Remove Origin/Destination text labels (arrow direction is self-explanatory)
- Add stopPropagation to CopyButton wrapper in header to prevent toggle on copy
The async useExplorerUrls hook was causing excessive network requests
on every render due to the tokens array being a new reference each time.
Reverted to the original synchronous approach that builds URLs from
local chain metadata without making network calls.
- Use fixed width (w-[140px]) for CompactChainNode and (w-[80px]) for MinimalChainNode
- Use chain displayName from metadata instead of chainName
- Add text-center for better text alignment
- Replace custom normalizeAddress with normalizeAddressToHex from utils/yamlParsing

Co-authored-by: paulbalaji <paulbalaji@users.noreply.github.com>
Co-authored-by: Xaroz <xaroz@users.noreply.github.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/features/messages/warpVisualization/WarpRouteGraph.tsx`:
- Around line 586-590: The expanded node rendering in WarpRouteGraph.tsx is
using node.token.chainName directly instead of the metadata displayName like
CompactChainNode and MinimalChainNode; update the expanded view to resolve
displayName from multiProvider.tryGetChainMetadata (or use the displayName
computed in nodePositions memo) and render that value in place of
node.token.chainName so all node views consistently use the chain metadata
displayName.
🧹 Nitpick comments (1)
src/features/messages/warpVisualization/WarpRouteGraph.tsx (1)

578-586: Consider using clsx() for complex conditional classNames.

The nested ternary for the border/background classes works, but per the coding guidelines, clsx() would make this a bit easier to read – especially when ye got multiple conditions piled up like layers in an onion.

♻️ Optional refactor with clsx()
+import clsx from 'clsx';
...
             <div
-              className={`flex min-w-[120px] flex-col items-center rounded-lg border-2 bg-white p-2 shadow-sm ${
-                isOrigin || isDestination
-                  ? hasInsufficientBalance
-                    ? 'border-red-500 bg-red-50'
-                    : 'border-blue-500'
-                  : 'border-gray-200'
-              }`}
+              className={clsx(
+                'flex min-w-[120px] flex-col items-center rounded-lg border-2 bg-white p-2 shadow-sm',
+                {
+                  'border-red-500 bg-red-50': (isOrigin || isDestination) && hasInsufficientBalance,
+                  'border-blue-500': (isOrigin || isDestination) && !hasInsufficientBalance,
+                  'border-gray-200': !isOrigin && !isDestination,
+                }
+              )}
             >

This applies to similar patterns throughout the file (lines 157, 195-201, 650-656). As per coding guidelines: use clsx() for conditional className assignment.

Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
@Xaroz

Xaroz commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

Few more nitpicks,

  1. Although the RPC flood has stopped, it seems that its not really retrieving balances anymore.
  2. I am not sure the refresh balance button is doing anything, nothing seems to happen, should include some sort of loading/disable state
  3. The button when you click show details and then when you it changes to collapse has a mismatch in style, the collapse button ends up a bit to the left
  4. For routes with a big amount of connections, like the oUSDT route, the connection graph makes almost no sense and it is hard to tell apart
image image

Remove fully connected graph expansion per Jason's feedback. Keep only
simple view: origin/destination at top with transfer amount arrow,
remaining chains below in compact view. Add xERC20 support with total
supply and lockbox balance display.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@nambrot

nambrot commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

so xerc20's were previously not supported either, but i just added support for it and then removed the graph visualization

Keep both warpRouteConfigs (for visualization) and warpRouteIdToAddressesMap
(for main's functionality).

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/features/messages/warpVisualization/WarpRouteGraph.tsx`:
- Around line 37-48: The getTokenTypeLabel function currently checks for
'XERC20' before 'Lockbox', so values like "EvmHypXERC20Lockbox" match XERC20
first and never return Lockbox; update getTokenTypeLabel to detect Lockbox
before XERC20 (move the if (standard.includes('Lockbox')) branch above the
XERC20 check) or explicitly handle the combined case (e.g., if
standard.includes('XERC20') && standard.includes('Lockbox') return 'xERC20
Lockbox') so Lockbox labels surface correctly.
🧹 Nitpick comments (1)
src/features/messages/warpVisualization/WarpRouteGraph.tsx (1)

123-165: Use clsx for conditional className branches.
There are a few template‑string conditionals; swapping to clsx keeps styling consistent with the project standard.

♻️ Example refactor (apply similarly in MinimalChainNode)
-      <span
-        className={`mt-1 rounded border px-1.5 py-0.5 text-[9px] font-medium ${getTokenTypeColor(token.standard)}`}
-      >
+      <span
+        className={clsx(
+          'mt-1 rounded border px-1.5 py-0.5 text-[9px] font-medium',
+          getTokenTypeColor(token.standard),
+        )}
+      >
         {getTokenTypeLabel(token.standard)}
       </span>
-        <div
-          className={`mt-1 rounded px-1.5 py-0.5 text-[10px] font-medium ${
-            hasInsufficientBalance
-              ? 'bg-red-100 text-red-700'
-              : isSynthetic
-                ? 'bg-purple-100 text-purple-700'
-                : 'bg-gray-100 text-gray-700'
-          }`}
-        >
+        <div
+          className={clsx(
+            'mt-1 rounded px-1.5 py-0.5 text-[10px] font-medium',
+            hasInsufficientBalance
+              ? 'bg-red-100 text-red-700'
+              : isSynthetic
+                ? 'bg-purple-100 text-purple-700'
+                : 'bg-gray-100 text-gray-700',
+          )}
+        >
As per coding guidelines: Use `clsx()` for conditional classNames instead of manual concatenation.

Also applies to: 214-224

Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
- Remove unnecessary balancesWithSufficiency memo in useWarpRouteBalances
- Fix CopyButton toggle issue by moving route ID pill outside toggle button

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@nambrot

nambrot commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Addressed in 38f2eb3. Changed chainBalance && to !!chainBalance && to avoid potential issues with falsy value rendering in React conditionals.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/features/messages/warpVisualization/WarpRouteGraph.tsx`:
- Around line 326-333: The transfer label pill in WarpRouteGraph is being
rendered even when transferAmountDisplay or tokenSymbol are undefined, causing
"undefined undefined" to appear; update the JSX rendering logic around the pill
(the div containing transferAmountDisplay and tokenSymbol) to only render when
the values are present (e.g., guard on transferAmountDisplay and tokenSymbol) so
the pill is hidden until both values are ready.
🧹 Nitpick comments (2)
src/features/messages/warpVisualization/WarpRouteGraph.tsx (2)

152-161: Prefer clsx for conditional badge styles.
Right now the conditional classes are stitched in template strings. Using clsx keeps it cleaner and consistent with the codebase style.

♻️ Suggested refactor
-        <div
-          className={`mt-1 rounded px-1.5 py-0.5 text-[10px] font-medium ${
-            hasInsufficientBalance
-              ? 'bg-red-100 text-red-700'
-              : isSynthetic
-                ? 'bg-purple-100 text-purple-700'
-                : 'bg-gray-100 text-gray-700'
-          }`}
-        >
+        <div
+          className={clsx(
+            'mt-1 rounded px-1.5 py-0.5 text-[10px] font-medium',
+            hasInsufficientBalance
+              ? 'bg-red-100 text-red-700'
+              : isSynthetic
+                ? 'bg-purple-100 text-purple-700'
+                : 'bg-gray-100 text-gray-700',
+          )}
+        >
-        <div
-          className={`mt-0.5 rounded px-1 py-0.5 text-[8px] font-medium ${
-            isSynthetic ? 'bg-purple-100 text-purple-700' : 'bg-gray-100 text-gray-700'
-          }`}
-        >
+        <div
+          className={clsx(
+            'mt-0.5 rounded px-1 py-0.5 text-[8px] font-medium',
+            isSynthetic ? 'bg-purple-100 text-purple-700' : 'bg-gray-100 text-gray-700',
+          )}
+        >
As per coding guidelines: Use `clsx()` for conditional classNames instead of manual concatenation.

Also applies to: 221-224


262-292: Guard against stale explorer URL results.
If tokens changes quickly, an older fetch can still win and overwrite newer URLs. A simple “still active” flag keeps state updates from going swampy.

🛠️ Safer async pattern
   useEffect(() => {
+    let isActive = true;
     const fetchExplorerUrls = async () => {
       const urls: Record<string, string | null> = {};
       const fetchTasks: { key: string; promise: Promise<string | null> }[] = [];
@@
-      setExplorerUrls(urls);
+      if (isActive) {
+        setExplorerUrls(urls);
+      }
     };
 
     if (tokens.length > 0) {
       fetchExplorerUrls();
     }
+
+    return () => {
+      isActive = false;
+    };
   }, [tokens, multiProvider]);

Comment thread src/features/messages/warpVisualization/WarpRouteGraph.tsx Outdated
@nambrot
nambrot requested a review from Xaroz February 6, 2026 15:45
@nambrot
nambrot merged commit 08fca6d into main Feb 17, 2026
11 checks passed
@nambrot
nambrot deleted the nam/warp-route-visualization branch February 17, 2026 15:01
@coderabbitai coderabbitai Bot mentioned this pull request Mar 24, 2026
4 tasks
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.

4 participants