Skip to content

Feature/rpc monitoring and UI optimization#28

Merged
Johnaverse merged 3 commits intomainfrom
feature/rpc-monitoring-and-ui-optimization
Mar 6, 2026
Merged

Feature/rpc monitoring and UI optimization#28
Johnaverse merged 3 commits intomainfrom
feature/rpc-monitoring-and-ui-optimization

Conversation

@Johnaverse
Copy link
Copy Markdown
Owner

Summary

  • Concurrent RPC monitoring with latency tracking, failed endpoint storage, and configurable concurrency/batching
  • BFS graph traversal helper (traverseRelations) for exploring chain relationships with configurable depth
  • New API endpoints: GET /stats for aggregate statistics and GET /relations/:id/graph for graph traversal
  • 3D visualization overhaul: glassmorphism UI, search with keyboard shortcuts, filter buttons, legend panel, debounced input, DocumentFragment-based DOM updates, and responsive mobile layout
  • Test coverage: unit tests and fuzz tests for all new functionality (493 tests passing)

Changes

Backend

  • rpcMonitor.js — concurrent batch processing with Promise.allSettled, latency tracking, failed endpoint counters
  • dataService.js — added traverseRelations(startChainId, maxDepth) BFS function
  • index.js — added GET /stats and GET /relations/:id/graph endpoints
  • mcp-tools.js — added get_stats, traverse_relations, get_rpc_monitor_by_id tools

Frontend (/public)

  • index.html — restructured with search dropdown, filter buttons, color legend, status badges
  • style.css — complete redesign with glassmorphism, responsive breakpoints, custom scrollbars
  • app.js — performance optimizations (debounce, DocumentFragment, reduced polygon count), safe DOM text highlighting, keyboard shortcuts

Tests

  • tests/unit/rpcMonitor.test.js — fixed mocks for concurrent monitoring behavior
  • tests/unit/dataService.test.js — fixed test ordering dependency

Test plan

  • All 493 tests pass (npm test)
  • Verify 3D graph loads and renders correctly in browser
  • Test search, filters, and keyboard shortcuts (/, Escape, arrow keys)
  • Test details panel on node click
  • Verify GET /stats and GET /relations/:id/graph endpoints respond correctly
  • Test responsive layout on mobile viewport

Johnaverse and others added 2 commits March 6, 2026 15:35
…stats endpoint

- RPC monitor: concurrent batch processing, latency tracking, store failed endpoints
- Add BFS graph traversal (traverseRelations) for chain relations
- Add GET /stats and GET /relations/:id/graph endpoints
- Add MCP tools: get_stats, traverse_relations, get_rpc_monitor_by_id
- Update unit, integration, and fuzz tests for all new behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Performance: debounced search, DocumentFragment for dropdown, reduced node resolution
- Performance: try local /export endpoint before GitHub raw (14MB)
- Security: replace innerHTML with safe DOM-based text highlighting
- UI: add stats bar, color legend, status badges, keyboard shortcuts (/ and arrow keys)
- UI: refined glassmorphism, responsive mobile layout, background click to dismiss
- Add rel=noopener to all external links

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 6, 2026 21:01
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces concurrent RPC monitoring with latency tracking, a BFS graph traversal helper (traverseRelations), two new REST API endpoints (GET /stats and GET /relations/:id/graph), three new MCP tools, and a comprehensive 3D visualization UI overhaul (glassmorphism styling, search with keyboard shortcuts, filter buttons, legend panel, and responsive mobile layout).

Changes:

  • Backend: rpcMonitor.js now processes chains in concurrent batches using Promise.allSettled with the RPC_CHECK_CONCURRENCY config, tracks latencyMs per endpoint, and records failedEndpoints separately. dataService.js gains the traverseRelations BFS function. index.js and mcp-tools.js add GET /stats and GET /relations/:id/graph endpoints and corresponding tools.
  • Frontend: Complete UI redesign with glassmorphism panels, new search UX (debouncing, DocumentFragment rendering, keyboard navigation with / shortcut and arrow keys), color legend, status badges, and responsive mobile breakpoints.
  • Tests: Fuzz tests and unit tests added/updated to cover the new endpoints and behavior changes.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
rpcMonitor.js Adds failedEndpoints counter, latencyMs tracking, concurrent batch processing; removes early-exit-on-failure behavior
dataService.js Adds traverseRelations BFS function
index.js Adds GET /stats and GET /relations/:id/graph endpoints; adds failedEndpoints to per-chain RPC response
mcp-tools.js Adds get_stats and traverse_relations tool definitions and handlers; adds latency to RPC monitor output
public/index.html Restructures header with search redesign, legend panel, status badges, and loading sub-text
public/style.css Complete redesign with glassmorphism, CSS variables for radius, responsive breakpoints, custom scrollbars
public/app.js Adds debounce, DocumentFragment DOM updates, keyboard shortcuts, highlightText helper, and safe URL parsing
tests/unit/rpcMonitor.test.js Fixes concurrent monitoring mock to use timer-based delays; updates endpoint-limiting test
tests/unit/mcp-tools.test.js Adds tests for get_stats, traverse_relations; updates tool count to 13
tests/unit/dataService.test.js Adds comprehensive traverseRelations tests
tests/integration/api.fuzz.test.js Adds fuzz tests for GET /stats and GET /relations/:id/graph

You can also share your feedback on Copilot code review. Take the survey.

const totalTestnets = chains.filter(c => c.tags?.includes('Testnet')).length;
const totalL2s = chains.filter(c => c.tags?.includes('L2')).length;
const totalBeacons = chains.filter(c => c.tags?.includes('Beacon')).length;
const totalMainnets = chains.filter(c => !c.tags?.includes('Testnet')).length;
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The inline totalMainnets calculation in the fuzz test stub (line 319) uses !c.tags?.includes('Testnet'), which is consistent with the actual implementation. However, both the test and the real code share the same semantics bug — L2s and Beacons are counted as mainnets. If the real implementation is corrected, this stub will also need to be updated.

Suggested change
const totalMainnets = chains.filter(c => !c.tags?.includes('Testnet')).length;
const totalMainnets = chains.filter(
c => !c.tags?.includes('Testnet') && !c.tags?.includes('L2') && !c.tags?.includes('Beacon')
).length;

Copilot uses AI. Check for mistakes.
expect(data.totalTestnets).toBe(1);
expect(data.totalL2s).toBe(1);
expect(data.totalBeacons).toBe(1);
expect(data.totalMainnets).toBe(3);
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The test expects totalMainnets to be 3 (Ethereum, Polygon/L2, Gnosis Beacon) with 4 chains including 1 testnet. This confirms the current implementation counts L2 and Beacon chains under totalMainnets, which is misleading. The test should be updated when the semantics are corrected.

Suggested change
expect(data.totalMainnets).toBe(3);

Copilot uses AI. Check for mistakes.
public/style.css Outdated
padding: 2px 6px;
border-radius: 4px;
font-size: 0.7rem;
font-family: 'Inter', monospace;
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The .search-hint class is applied to a <kbd> element (keyboard shortcut indicator) but its font-family is set to 'Inter', monospace, which means the Inter sans-serif font takes precedence over a monospace font. For keyboard shortcut indicators, it is conventional to use a monospace font. Consider using font-family: ui-monospace, monospace instead.

Suggested change
font-family: 'Inter', monospace;
font-family: ui-monospace, monospace;

Copilot uses AI. Check for mistakes.
index.js Outdated
const monitorResults = getMonitoringResults();

const totalChains = chains.length;
const totalMainnets = chains.filter(c => !c.tags?.includes('Testnet')).length;
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The totalMainnets field is calculated as chains that do NOT have the 'Testnet' tag (!c.tags?.includes('Testnet')), which means L2 chains and Beacon chains are also included in this count. The API already separately exposes totalL2s and totalBeacons, so consumers would reasonably expect totalMainnets to be the count of chains that are neither L2, Beacon, nor Testnet. As written, a chain tagged L2 is counted in both totalL2s and totalMainnets, which is misleading. The calculation should be chains.filter(c => !c.tags?.includes('Testnet') && !c.tags?.includes('L2') && !c.tags?.includes('Beacon')).length to count only true mainnet chains.

Suggested change
const totalMainnets = chains.filter(c => !c.tags?.includes('Testnet')).length;
const totalMainnets = chains
.filter(
c =>
!c.tags?.includes('Testnet') &&
!c.tags?.includes('L2') &&
!c.tags?.includes('Beacon')
).length;

Copilot uses AI. Check for mistakes.
mcp-tools.js Outdated
const monitorResults = getMonitoringResults();

const totalChains = chains.length;
const totalMainnets = chains.filter(c => !c.tags?.includes('Testnet')).length;
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

Same issue as in index.js: totalMainnets is calculated as chains without the 'Testnet' tag, incorrectly including L2 and Beacon chains in the count. This should exclude L2 and Beacon tags to truly represent mainnet-only chains.

Suggested change
const totalMainnets = chains.filter(c => !c.tags?.includes('Testnet')).length;
const totalMainnets = chains.filter(c => !['Testnet', 'L2', 'Beacon'].some(tag => c.tags?.includes(tag))).length;

Copilot uses AI. Check for mistakes.
Comment on lines +1320 to +1333
const relations = chain.relations || [];
for (const rel of relations) {
if (rel.chainId === undefined) continue;

edges.push({
from: chainId,
to: rel.chainId,
kind: rel.kind,
source: rel.source
});

if (!visited.has(rel.chainId)) {
queue.push({ chainId: rel.chainId, depth: depth + 1 });
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

In traverseRelations, edges are added for every relation encountered during BFS traversal, regardless of whether the target chain has already been visited. Because the graph includes bidirectional relations (e.g., a parent chain has parentOf edges to children, and child chains have l2Of or testnetOf edges back to the parent), the resulting edges array will contain both directions (e.g., A→B and B→A) as well as edges to already-visited nodes. This means totalEdges will be higher than the number of unique relationships, and graph consumers may render duplicate connections. To fix this, track visited pairs (e.g., using a Set of ${from}-${to} strings) or only add an edge when the target node has NOT been visited before adding it to the queue.

Copilot uses AI. Check for mistakes.
- Fix totalMainnets to exclude L2 and Beacon chains (was only excluding Testnet)
- Deduplicate bidirectional edges in traverseRelations BFS traversal
- Use monospace font stack for keyboard shortcut hint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Johnaverse Johnaverse merged commit 4f9e166 into main Mar 6, 2026
5 checks passed
@Johnaverse Johnaverse deleted the feature/rpc-monitoring-and-ui-optimization branch March 6, 2026 21:23
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.

2 participants