Add dedicated explorer routes page

This commit is contained in:
defiQUG
2026-03-28 15:04:42 -07:00
parent f309c303ff
commit bf83ff7776
3 changed files with 93 additions and 20 deletions

View File

@@ -876,7 +876,7 @@
// View switch helper: works even if rest of script fails. Do NOT set location.hash here (we use path-based URLs).
function switchToView(viewName) {
if (viewName !== 'pools' && _poolsRouteTreeRefreshTimer) {
if (viewName !== 'pools' && viewName !== 'routes' && _poolsRouteTreeRefreshTimer) {
clearInterval(_poolsRouteTreeRefreshTimer);
_poolsRouteTreeRefreshTimer = null;
}
@@ -885,7 +885,7 @@
_blocksScrollAnimationId = null;
}
currentView = viewName;
var detailViews = ['blockDetail','transactionDetail','addressDetail','tokenDetail','nftDetail','watchlist','searchResults','tokens','addresses','pools','liquidity','more'];
var detailViews = ['blockDetail','transactionDetail','addressDetail','tokenDetail','nftDetail','watchlist','searchResults','tokens','addresses','pools','routes','liquidity','more'];
if (detailViews.indexOf(viewName) === -1) currentDetailKey = '';
var homeEl = document.getElementById('homeView');
if (homeEl) homeEl.style.display = viewName === 'home' ? 'block' : 'none';
@@ -906,6 +906,7 @@
window.openPoolsView = openPoolsView;
// Back-compat alias for older menu wiring; prefer openPoolsView() and renderPoolsView().
window.showPools = openPoolsView;
window.showRoutes = function() { if (_inNavHandler) return; _inNavHandler = true; try { switchToView('routes'); if (typeof renderRoutesView === 'function') renderRoutesView(); } finally { _inNavHandler = false; } };
window.showLiquidityAccess = function() { if (_inNavHandler) return; _inNavHandler = true; try { switchToView('liquidity'); if (typeof renderLiquidityAccessView === 'function') renderLiquidityAccessView(); } finally { _inNavHandler = false; } };
window.showMore = function() { if (_inNavHandler) return; _inNavHandler = true; try { switchToView('more'); if (window._showMore) window._showMore(); } finally { _inNavHandler = false; } };
window.showTokensList = function() { if (_inNavHandler) return; _inNavHandler = true; try { switchToView('tokens'); if (window._loadTokensList) window._loadTokensList(); } finally { _inNavHandler = false; } };
@@ -2316,6 +2317,7 @@
if (parts[0] === 'weth') { if (currentView !== 'weth') showWETHUtilities(); return; }
if (parts[0] === 'watchlist') { if (currentView !== 'watchlist') showWatchlist(); return; }
if (parts[0] === 'pools') { if (currentView !== 'pools') openPoolsView(); return; }
if (parts[0] === 'routes') { if (currentView !== 'routes') showRoutes(); return; }
if (parts[0] === 'liquidity') { if (currentView !== 'liquidity') showLiquidityAccess(); return; }
if (parts[0] === 'more') { if (currentView !== 'more') showMore(); return; }
if (parts[0] === 'tokens') { if (typeof showTokensList === 'function') showTokensList(); else focusSearchWithHint('token'); return; }
@@ -2421,6 +2423,11 @@
breadcrumbHTML += '<span class="breadcrumb-separator">/</span>';
breadcrumbHTML += '<span class="breadcrumb-current">Pools</span>';
break;
case 'routes':
breadcrumbContainer = document.getElementById('routesBreadcrumb');
breadcrumbHTML += '<span class="breadcrumb-separator">/</span>';
breadcrumbHTML += '<span class="breadcrumb-current">Routes</span>';
break;
case 'more':
breadcrumbContainer = document.getElementById('moreBreadcrumb');
breadcrumbHTML += '<span class="breadcrumb-separator">/</span>';
@@ -3549,8 +3556,9 @@
badge.style.display = n > 0 ? 'inline-block' : 'none';
}
async function loadLiveRouteTrees() {
var container = document.getElementById('poolRouteTreeContent');
async function loadLiveRouteTrees(targetId) {
var containerId = targetId || (currentView === 'routes' ? 'routesRouteTreeContent' : 'poolRouteTreeContent');
var container = document.getElementById(containerId);
if (!container) return;
container.innerHTML = '<div class="loading"><i class="fas fa-spinner"></i> Loading live route tree...</div>';
@@ -3604,6 +3612,48 @@
}
}
function buildRoutesLandingHtml() {
var html = '';
html += '<div class="card" style="margin:0 0 1rem 0; box-shadow:none;">';
html += '<div class="card-header" style="align-items:flex-start; gap:0.75rem;">';
html += '<div>';
html += '<h3 class="card-title" style="margin-bottom:0.25rem;"><i class="fas fa-diagram-project"></i> Live Route Decision Tree</h3>';
html += '<div style="color:var(--text-light); line-height:1.5;">This dedicated view follows the Chain 138 routing graph end-to-end. It keeps the live coverage sweep, direct-pair diagnostics, and bridge-path branches together in one place so route investigations do not get buried inside the pools inventory.</div>';
html += '</div>';
html += '<div style="display:flex; gap:0.5rem; flex-wrap:wrap; margin-left:auto;">';
html += '<button type="button" class="btn btn-primary" onclick="loadLiveRouteTrees(\'routesRouteTreeContent\')" aria-label="Refresh live routes"><i class="fas fa-sync-alt"></i> Refresh</button>';
html += '<button type="button" class="btn btn-secondary" onclick="showPools(); updatePath(\'/pools\')" aria-label="Open pools inventory"><i class="fas fa-water"></i> Pools inventory</button>';
html += '<button type="button" class="btn btn-secondary" onclick="showLiquidityAccess(); updatePath(\'/liquidity\')" aria-label="Open liquidity access"><i class="fas fa-wave-square"></i> Liquidity access</button>';
html += '</div>';
html += '</div>';
html += '<div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(220px, 1fr)); gap:0.75rem;">';
html += '<div style="padding:0.9rem; border:1px solid var(--border); border-radius:10px; background:var(--light);"><div style="font-size:0.82rem; color:var(--text-light); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.35rem;">Best for</div><div style="font-weight:700;">Route debugging and operator review</div><div style="color:var(--text-light); font-size:0.9rem; margin-top:0.35rem;">Use this page when a user route, destination branch, or quote-token path looks wrong.</div></div>';
html += '<div style="padding:0.9rem; border:1px solid var(--border); border-radius:10px; background:var(--light);"><div style="font-size:0.82rem; color:var(--text-light); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.35rem;">Includes</div><div style="font-weight:700;">Coverage sweep + priority route cards</div><div style="color:var(--text-light); font-size:0.9rem; margin-top:0.35rem;">The pools page now links here instead of embedding the full route tree inline.</div></div>';
html += '<div style="padding:0.9rem; border:1px solid var(--border); border-radius:10px; background:var(--light);"><div style="font-size:0.82rem; color:var(--text-light); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.35rem;">Data source</div><div style="font-weight:700;">Live token-aggregation route tree API</div><div style="color:var(--text-light); font-size:0.9rem; margin-top:0.35rem;">Every refresh re-reads current Chain 138 PMM and bridge state.</div></div>';
html += '</div>';
html += '</div>';
html += '<div id="routesRouteTreeContent"><div class="loading"><i class="fas fa-spinner"></i> Loading live route tree...</div></div>';
return html;
}
function renderRoutesView() {
showView('routes');
if ((window.location.pathname || '').replace(/^\//, '').split('/')[0] !== 'routes') updatePath('/routes');
updateBreadcrumb('routes');
var container = document.getElementById('routesContent');
if (!container) return;
container.innerHTML = buildRoutesLandingHtml();
setTimeout(function() {
loadLiveRouteTrees('routesRouteTreeContent');
}, 0);
_poolsRouteTreeRefreshTimer = setInterval(function() {
if (currentView === 'routes') {
loadLiveRouteTrees('routesRouteTreeContent');
}
}, ROUTE_TREE_REFRESH_MS);
}
window.renderRoutesView = renderRoutesView;
function summarizePoolRows(rows) {
var summary = {
liveLocal: 0,
@@ -3752,21 +3802,24 @@
html += '</tbody></table></div>';
html += '<div class="card" style="margin-top:1.2rem; box-shadow:none;">';
html += '<div class="card-header" style="align-items:flex-start; gap:0.75rem;">';
html += '<h3 class="card-title" style="margin-bottom:0;"><i class="fas fa-diagram-project"></i> Live Route Decision Tree</h3>';
html += '<button type="button" class="btn btn-secondary" onclick="loadLiveRouteTrees()" aria-label="Refresh live route tree"><i class="fas fa-sync-alt"></i> Refresh live routes</button>';
html += '<div>';
html += '<h3 class="card-title" style="margin-bottom:0.25rem;"><i class="fas fa-diagram-project"></i> Live Route Decision Tree</h3>';
html += '<div style="color:var(--text-light); line-height:1.5;">The full route sweep and priority route cards now live on their own dedicated page so investigations can open directly into the routing graph.</div>';
html += '</div>';
html += '<div style="display:flex; gap:0.5rem; flex-wrap:wrap; margin-left:auto;">';
html += '<button type="button" class="btn btn-primary" onclick="showRoutes(); updatePath(\'/routes\')" aria-label="Open dedicated routes page"><i class="fas fa-arrow-right"></i> Open routes page</button>';
html += '<button type="button" class="btn btn-secondary" onclick="showLiquidityAccess(); updatePath(\'/liquidity\')" aria-label="Open liquidity access page"><i class="fas fa-wave-square"></i> Liquidity</button>';
html += '</div>';
html += '</div>';
html += '<div style="display:grid; gap:0.75rem;">';
html += '<div style="padding:0.9rem; border:1px solid var(--border); border-radius:10px; background:var(--light); color:var(--text-light); line-height:1.5;">Use <strong>Routes</strong> for the live route coverage sweep, bridge-path diagnostics, and missing quote-token review. The pools table above stays focused on pool inventory and funding state.</div>';
html += '<div style="display:flex; flex-wrap:wrap; gap:0.6rem;">';
html += '<a class="btn btn-secondary" href="/routes" onclick="event.preventDefault(); showRoutes(); updatePath(\'/routes\');" style="text-decoration:none;"><i class="fas fa-diagram-project"></i> Routes</a>';
html += '<a class="btn btn-secondary" href="/liquidity" onclick="event.preventDefault(); showLiquidityAccess(); updatePath(\'/liquidity\');" style="text-decoration:none;"><i class="fas fa-plug"></i> Public access points</a>';
html += '</div>';
html += '</div>';
html += '<div style="color:var(--text-light); margin-bottom:0.85rem; line-height:1.5;">This live panel follows the Chain 138 DEX and bridge graph end-to-end so we can see direct pool depth, bridge leg availability, destination swap branches, and any missing quote-token metadata that still needs cleanup.</div>';
html += '<div id="poolRouteTreeContent"><div class="loading"><i class="fas fa-spinner"></i> Loading live route tree...</div></div>';
html += '</div>';
container.innerHTML = html;
setTimeout(function() {
loadLiveRouteTrees();
}, 0);
_poolsRouteTreeRefreshTimer = setInterval(function() {
if (currentView === 'pools') {
loadLiveRouteTrees();
}
}, ROUTE_TREE_REFRESH_MS);
} catch (err) {
container.innerHTML = '<div class="error">Failed to load pools: ' + escapeHtml(err.message || 'Unknown error') + '</div>';
}
@@ -3909,9 +3962,10 @@
});
html += '</div></div>';
html += '<div class="card" style="margin:0; box-shadow:none;"><div class="card-header"><h3 class="card-title"><i class="fas fa-compass"></i> Related Explorer Tools</h3></div><div style="display:grid; gap:0.75rem; color:var(--text-light); line-height:1.6;">';
html += '<div>Use Wallet for network onboarding and the explorer token list URL, then use Pools for live route-tree diagnostics and contract-state checks.</div>';
html += '<div>Use Wallet for network onboarding and the explorer token list URL, then open Routes for live route-tree diagnostics and Pools for contract-state inventory checks.</div>';
html += '<div style="display:flex; flex-wrap:wrap; gap:0.6rem; margin-top:0.2rem;">';
html += '<button type="button" class="btn btn-primary" onclick="showPools(); updatePath(\'/pools\')" aria-label="Open pools view"><i class="fas fa-water"></i> Pools view</button>';
html += '<button type="button" class="btn btn-primary" onclick="showRoutes(); updatePath(\'/routes\')" aria-label="Open routes view"><i class="fas fa-diagram-project"></i> Routes view</button>';
html += '<button type="button" class="btn btn-secondary" onclick="showPools(); updatePath(\'/pools\')" aria-label="Open pools view"><i class="fas fa-water"></i> Pools view</button>';
html += '<button type="button" class="btn btn-secondary" onclick="showWETHUtilities(); updatePath(\'/weth\')" aria-label="Open WETH tools"><i class="fas fa-coins"></i> WETH tools</button>';
html += '<a class="btn btn-secondary" href="/docs.html" style="text-decoration:none;"><i class="fas fa-book"></i> Explorer docs</a>';
html += '</div></div></div>';
@@ -3942,7 +3996,7 @@
title: 'Explore',
items: [
{ title: 'Gas Tracker', icon: 'fa-gas-pump', status: 'Live', badgeClass: 'badge-success', desc: 'Review live gas, block time, TPS, and chain health from the analytics and home dashboards.', action: 'showAnalytics();', href: '/analytics' },
{ title: 'DEX Tracker', icon: 'fa-chart-line', status: 'Live', badgeClass: 'badge-success', desc: 'Open liquidity discovery, PMM pool status, live route trees, and partner payload access points.', action: 'showLiquidityAccess();', href: '/liquidity' },
{ title: 'DEX Tracker', icon: 'fa-chart-line', status: 'Live', badgeClass: 'badge-success', desc: 'Open liquidity discovery, PMM pool status, live route trees, and partner payload access points.', action: 'showRoutes();', href: '/routes' },
{ title: 'Node Tracker', icon: 'fa-server', status: 'Live', badgeClass: 'badge-success', desc: 'Inspect bridge and operator infrastructure surfaces already exposed in the Bridge and Operator panels.', action: 'showOperator();', href: '/operator' },
{ title: 'Label Cloud', icon: 'fa-tags', status: 'Live', badgeClass: 'badge-success', desc: 'Browse labeled addresses, contracts, and address activity through the explorer address index.', action: 'showAddresses();', href: '/addresses' },
{ title: 'Domain Name Lookup', icon: 'fa-magnifying-glass', status: 'Live', badgeClass: 'badge-success', desc: 'Use the smart search launcher to resolve ENS-style names, domains, addresses, hashes, and token symbols.', action: 'openSmartSearchModal(\'\');', href: '/more' }

View File

@@ -1038,6 +1038,7 @@
<li role="none"><a href="/bridge" role="menuitem" onclick="event.preventDefault(); showBridgeMonitoring(); updatePath('/bridge'); closeNavMenu();" aria-label="View bridge monitoring"><i class="fas fa-bridge" aria-hidden="true"></i> <span data-i18n="bridge">Bridge</span></a></li>
<li role="none"><a href="/weth" role="menuitem" onclick="event.preventDefault(); showWETHUtilities(); updatePath('/weth'); closeNavMenu();" aria-label="View WETH utilities"><i class="fas fa-coins" aria-hidden="true"></i> <span data-i18n="weth">WETH</span></a></li>
<li role="none"><a href="/liquidity" role="menuitem" onclick="event.preventDefault(); showLiquidityAccess(); updatePath('/liquidity'); closeNavMenu();" aria-label="View liquidity access"><i class="fas fa-wave-square" aria-hidden="true"></i> <span>Liquidity</span></a></li>
<li role="none"><a href="/routes" role="menuitem" onclick="event.preventDefault(); showRoutes(); updatePath('/routes'); closeNavMenu();" aria-label="View route decision tree"><i class="fas fa-diagram-project" aria-hidden="true"></i> <span>Routes</span></a></li>
<li role="none"><a href="/tokens" role="menuitem" onclick="event.preventDefault(); if(typeof showTokensList==='function')showTokensList();else focusSearchWithHint('token'); updatePath('/tokens'); closeNavMenu();" aria-label="View token list"><i class="fas fa-tag" aria-hidden="true"></i> <span data-i18n="tokens">Tokens</span></a></li>
<li role="none"><a href="/pools" role="menuitem" onclick="event.preventDefault(); showPools(); updatePath('/pools'); closeNavMenu();" aria-label="View pools"><i class="fas fa-water" aria-hidden="true"></i> <span data-i18n="pools">Pools</span> <span id="poolsMissingQuoteBadge" class="badge badge-warning" style="display:none; margin-left:0.35rem; vertical-align:middle;">0</span></a></li>
<li role="none"><a href="/watchlist" role="menuitem" onclick="event.preventDefault(); showWatchlist(); updatePath('/watchlist'); closeNavMenu();" aria-label="Watchlist"><i class="fas fa-star" aria-hidden="true"></i> <span data-i18n="watchlist">Watchlist</span></a></li>
@@ -1503,6 +1504,22 @@
</div>
</div>
<div id="routesView" class="detail-view">
<div class="breadcrumb" id="routesBreadcrumb"><a href="/">Home</a><span class="breadcrumb-separator">/</span><span class="breadcrumb-current">Routes</span></div>
<div class="card">
<div class="card-header">
<button class="btn btn-secondary" onclick="showHome()" aria-label="Go back to home page"><i class="fas fa-arrow-left" aria-hidden="true"></i> Back</button>
<h2 class="card-title"><i class="fas fa-diagram-project"></i> Routes</h2>
<div style="display:flex; gap:0.5rem; margin-left:auto; flex-wrap:wrap;">
<button type="button" class="btn btn-primary" onclick="renderRoutesView()" style="padding: 0.5rem 1rem;"><i class="fas fa-sync-alt"></i> Refresh</button>
</div>
</div>
<div id="routesContent">
<div class="loading"><i class="fas fa-spinner"></i> Loading routes...</div>
</div>
</div>
</div>
<div id="moreView" class="detail-view">
<div class="breadcrumb" id="moreBreadcrumb"><a href="/">Home</a><span class="breadcrumb-separator">/</span><span class="breadcrumb-current">More</span></div>
<div class="card">
@@ -1560,6 +1577,7 @@
<div class="site-footer-links">
<a href="/docs.html">Docs landing page</a>
<a href="/liquidity">Liquidity access</a>
<a href="/routes">Routes</a>
<a href="/privacy.html">Privacy Policy</a>
<a href="/terms.html">Terms of Service</a>
</div>
@@ -1576,6 +1594,6 @@
</div>
</footer>
<script src="/explorer-spa.js?v=28"></script>
<script src="/explorer-spa.js?v=29"></script>
</body>
</html>

View File

@@ -7,6 +7,7 @@ const checks = [
{ path: '/addresses', expect: ['Open An Address', 'Recently Active Addresses', 'Saved Watchlist'] },
{ path: '/tokens', expect: ['Find A Token', 'Common token searches', 'Tokens'] },
{ path: '/pools', expect: ['Canonical PMM routes', 'Pool operation shortcuts', 'Pools'] },
{ path: '/routes', expect: ['Live Route Decision Tree', 'Coverage sweep + priority route cards', 'Routes'] },
{ path: '/watchlist', expect: ['Saved Addresses', 'Watchlist', 'Export JSON'] },
{ path: '/search?q=cUSDT', expect: ['Search Results', 'Results for', 'Search'] },
{ path: '/blocks/1', expect: ['Loading block details', 'Block Details'] },