feat: add warp route ID search and pending message status filter - #263
Conversation
- Add status filter (All/Delivered/Pending) to the search filter bar - For pending filter, use client-side filtering since DB query for is_delivered=false is slow (no index on absence of record) - Implement progressive loading with 'Load More' button for pending filter to allow fetching older messages - Use larger batch size (500) for pending filter since most messages are delivered quickly - Add warp route ID search support (e.g., 'USDC/mainnet-cctp') - Build warp route ID to addresses map from registry data
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds message status filtering and warp-route ID detection; resolves warp-route addresses from store; extends query builder and query hook to accept status and warp-route address filters (including pending-specific batching and client-side filtering); introduces warp-route maps and hook in the store, new types, utility and tests, and expands transpile packages. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as Search UI
participant Store as App Store
participant QB as Query Builder
participant API as GraphQL API
participant Results
User->>UI: Enter search text or warp-route ID and select status
UI->>Store: Read warpRouteIdToAddressesMap
Store-->>UI: Return mapping
alt input is warp-route ID
UI->>UI: Determine looksLikeWarpRoute / isUnknownWarpRoute
UI->>QB: Build query with warpRouteAddresses + statusFilter
else regular text
UI->>UI: Sanitize input
UI->>QB: Build query with sanitized input + statusFilter
end
QB->>API: Execute GraphQL query (includes warp addresses/status vars)
API-->>QB: Return messages batch
QB->>QB: Apply client-side pending filter if statusFilter == 'pending'
QB-->>Results: Render messages
User->>UI: Request more
UI->>QB: Fetch next batch
QB->>API: Fetch next batch
API-->>Results: Append messages
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/features/messages/queries/build.ts (1)
84-184: Filter undefined values from warp address conversion to keep queries valid.
searchValueToPostgresByteareturnsstring | undefined, sowarpAddressesByteacan contain undefined values. These undefined values would violate the[bytea!]type declaration (non-null bytea array) and could break the query. Additionally,hasFilterschecks the rawwarpRouteAddresses.lengthwhile the variable uses the converted array—if all addresses fail conversion, the mismatch means the query might declare$warpAddressesinconsistently.Filter out undefined values when converting, use the filtered array's length for
hasFilters, and pass the filtered array tobuildWarpRouteWhereClause:Fix
-const warpAddressesBytea = warpRouteAddresses.map((addr) => searchValueToPostgresBytea(addr)); +const warpAddressesBytea = warpRouteAddresses + .map((addr) => searchValueToPostgresBytea(addr)) + .filter((addr): addr is string => !!addr); ... - warpRouteAddresses.length > 0 + warpAddressesBytea.length > 0 ... -const warpRouteWhereClause = buildWarpRouteWhereClause(warpRouteAddresses); +const warpRouteWhereClause = buildWarpRouteWhereClause(warpAddressesBytea); ... -function buildWarpRouteWhereClause(warpRouteAddresses: string[]): string { - if (warpRouteAddresses.length === 0) return ''; +function buildWarpRouteWhereClause(warpAddressesBytea: string[]): string { + if (warpAddressesBytea.length === 0) return ''; return '{_or: [{sender: {_in: $warpAddresses}}, {recipient: {_in: $warpAddresses}}]},'; }
🤖 Fix all issues with AI agents
In `@src/features/messages/queries/useMessageQuery.ts`:
- Around line 132-154: The useEffect currently bails out early when data is
falsy so setIsLoadingMore(false) never runs on failed/empty fetches; update the
effect (watching the query's isFetching) so it doesn't return before clearing
the loading flag and explicitly call setIsLoadingMore(false) whenever isFetching
transitions to false (regardless of data), e.g. include isFetching in the
dependency list and handle the isFetching === false case before or alongside the
existing data handling inside the useEffect that references
parseMessageStubResult, currentOffset, setAccumulatedMessages, and
setHasMorePages.
…ger request - Remove all pagination/load more logic for pending filter - Use larger batch size (500) only when pending filter is active - Keep normal query limits (50/100) for other searches - Apply client-side filtering for pending messages - Fix warp addresses bytea conversion to filter out invalid addresses - Address PR review feedback to simplify the implementation
PR Review SummaryOverallGood feature additions - warp route ID search and pending status filter are useful. CI passes. A few issues to address: 🔴 Bug: Pending Filter Silently Excludes Testnet Messages (P1)Location: When user selects "Pending" without other filters, testnet messages are excluded. But "Delivered" shows both mainnet AND testnet. This inconsistency happens because: // useMessageQuery.ts
const dbStatusFilter = isPendingFilter ? 'all' : statusFilter; // pending → 'all'
buildMessageSearchQuery(..., dbStatusFilter, ...) // passes 'all' to build.ts// build.ts
const hasFilters = !!(
// ...
statusFilter !== 'all' || // 'all' !== 'all' = false!
);When Suggested fix: Pass an const hasFilters = !!(
// ...existing conditions...
statusFilter !== 'all' ||
isPendingFilter || // ← Add this
warpAddressesBytea.length > 0
);🟡 Minor: Warp Route ID Detection (P3)
✅ What's Good
Test Suggestions
|
- Move isWarpRouteIdFormat function from MessageSearch.tsx to utils/string.ts - Add unit tests for isWarpRouteIdFormat and sanitizeString in string.test.ts - Add all @hyperlane-xyz/* packages to transpilePackages in next.config.js to fix Jest ESM module resolution with pnpm
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/features/messages/queries/build.ts`:
- Around line 101-109: The current hasFilters boolean misses the "pending"
client-side filter so testnet pending messages get filtered out; update the
function signature (the query builder function in
src/features/messages/queries/build.ts) to accept an extra boolean parameter
isPendingFilter, include isPendingFilter in the hasFilters expression (i.e.
treat pending as a filter alongside originDomainIdFilter, destDomainIdFilter,
startTimeFilter, endTimeFilter, searchInput, statusFilter check, and
warpAddressesBytea), and update callers (e.g., useMessageQuery.ts where
dbStatusFilter is 'all' for pending) to pass the appropriate isPendingFilter
flag so buildDomainIdWhereClause no longer forces mainnet-only when pending is
the only filter.
In `@src/features/messages/queries/useMessageQuery.ts`:
- Around line 72-83: The call to buildMessageSearchQuery in useMessageQuery.ts
omits the isPendingFilter flag, so buildMessageSearchQuery can't include pending
status in its hasFilters logic and testnet messages get excluded; update the
invocation of buildMessageSearchQuery (the const { query, variables } =
buildMessageSearchQuery(...) line) to pass the isPendingFilter boolean as an
additional argument (after warpAddresses or in the correct position expected by
buildMessageSearchQuery) so the function can account for pending-filter when
computing hasFilters and building the query.
🧹 Nitpick comments (3)
src/utils/string.ts (1)
24-29: Consider tightening the format validation, if ye don't mind.The current check is fairly relaxed - it'll accept things like
123/456or inputs with special characters that aren't valid warp route IDs per the registry pattern. Since the downstream lookup inwarpRouteIdToAddressesMaphandles unknown routes gracefully, this isn't a swamp-level crisis. But if ye want to catch obviously invalid inputs earlier (before the map lookup), consider aligning with the registry pattern:♻️ Optional: stricter regex validation
export function isWarpRouteIdFormat(input: string): boolean { const trimmed = input.trim(); if (!trimmed || trimmed.length <= 2) return false; if (trimmed.startsWith('0x')) return false; - const slashCount = (trimmed.match(/\//g) || []).length; - return slashCount === 1; + // Match registry pattern: SYMBOL/route-name + return /^[a-zA-Z0-9.*]+\/[a-z0-9-]+$/.test(trimmed); }src/utils/string.test.ts (1)
19-39: Tests look solid, but there's one wee edge case lurkin' in the swamp.The tests cover the main scenarios well. One thing worth adding: input that starts with a slash like
/abcwould currently pass the validation (length > 2, one slash, no 0x prefix). If that's not a valid warp route format, consider adding a test case for it.💡 Optional: additional edge case test
// Too short expect(isWarpRouteIdFormat('')).toBe(false); expect(isWarpRouteIdFormat('/')).toBe(false); expect(isWarpRouteIdFormat('a/')).toBe(false); + + // Starts with slash (invalid format) + expect(isWarpRouteIdFormat('/abc')).toBe(false); + expect(isWarpRouteIdFormat('/ethereum-base')).toBe(false); // Just whitespace expect(isWarpRouteIdFormat(' ')).toBe(false); });src/features/messages/MessageSearch.tsx (1)
257-276: The loading and error states look fine, but consider a wee accessibility touch.The states render correctly and give good feedback. For screen reader users, ye might want to add an
aria-live="polite"attribute so the status changes are announced automatically.💡 Optional: accessibility enhancement
- {looksLikeWarpRoute && !isWarpRouteMapLoaded && ( - <div className="absolute left-0 right-0 top-10"> + {looksLikeWarpRoute && !isWarpRouteMapLoaded && ( + <div className="absolute left-0 right-0 top-10" aria-live="polite">
When pending filter is active, we pass dbStatusFilter='all' to avoid slow DB queries. However, this caused hasFilters to be false when no other filters were set, which restricted results to mainnet-only. Fix by passing isPendingFilter as a separate flag and including it in the hasFilters calculation.
Pending filter uses client-side filtering, so this branch never executes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/features/messages/queries/build.ts`:
- Around line 84-87: The current map+filter silently drops invalid warp-route
addresses when building warpAddressesBytea; update the logic around
warpRouteAddresses and searchValueToPostgresBytea so invalid conversions are not
swallowed—detect any addr where searchValueToPostgresBytea(addr) returns falsy
and either throw an Error (including the offending addr and context) or log a
clear processLogger.error/console.error and then throw; ensure the failure
occurs before proceeding with the query so broken registry data cannot widen
results or trigger a default path.
Summary
This PR adds two new search/filter capabilities to the explorer:
USDC/ethereum-base) directly in the search barChanges
Warp Route ID Search
SYMBOL/route-name) in the search inputStatus Filter
is_delivered=falseis slow (no index on absence of record)Technical Details
Why client-side filtering for pending?
The
message_viewcomputesis_deliveredasdmsg.id IS NOT NULLfrom a LEFT JOIN with thedelivered_messagetable. Filtering foris_delivered = falserequires a full table scan since there's no index for "absence of record". Filtering foris_delivered = trueis fast because it can use thedelivered_message_msg_id_idxindex.Files Changed
src/store.ts- Added warp route ID to addresses map from registrysrc/types.ts- AddedMessageStatusFilterandWarpRouteIdToAddressesMaptypessrc/components/search/SearchFilterBar.tsx- Added StatusSelector componentsrc/features/messages/MessageSearch.tsx- Integrated warp route search and status filtersrc/features/messages/queries/build.ts- Added status filter clause and warp route address filteringsrc/features/messages/queries/useMessageQuery.ts- Added client-side pending filter with larger batch sizeSummary by CodeRabbit
New Features
Bug Fixes / UX
Tests
Chores