You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ExplorerPage/ExplorerDashboard in apps/ui/src/routes/explorer.tsx renders PageHero with live set (line 67) and a 6-tile KPI grid (totalExtrinsics, totalBlocks, totalEvents, totalFees, totalTips, successRate, lines 267–301) sourced entirely from chainActivityQuery/chainFeesQuery/chainCallsQuery/chainSignersQuery — all daily-aggregated over the 7d/30d window toggle. There is no chain-head tip: nothing on the page shows the current block number or how fresh it is. blocksQuery (apps/ui/src/lib/metagraphed/queries.ts) already fetches /api/v1/blocks newest-first and the Block type (apps/ui/src/lib/metagraphed/types.ts) already carries block_number: number and observed_at?: string — blocks.index.tsx renders exactly this pair today via #{formatNumber(b.block_number)} + <TimeAgo at={b.observed_at} />, so the raw data and the rendering primitive both already exist, they're just not surfaced on the explorer page.
Requirement
Add a compact live-tip band to the explorer page's hero showing the current chain head (#<block_number>) and its recency (<N> ago), fetched from /api/v1/blocks with limit: 1, sitting alongside — not replacing — the existing daily-aggregate KPI grid.
Deliverable
File to change: apps/ui/src/routes/explorer.tsx (confirmed at this path; ExplorerPage/PageHero call at lines 62–87, ExplorerDashboard at lines 225–520).
Anchor: the PageHero invocation inside ExplorerPage (lines 65–71). Add a useQuery(blocksQuery({ limit: 1 })) (or useSuspenseQuery, matching the rest of the page's suspense-first style) and render its single row as a small band — block number formatted with the existing formatNumber helper (already imported, line 22) and elapsed time via the existing <TimeAgo at={...} /> component (apps/ui/src/components/metagraphed/time-ago.tsx), following the same block_number/observed_at pairing already used in blocks.index.tsx. Import blocksQuery and Block alongside the other imports from @/lib/metagraphed/queries / @/lib/metagraphed/types (both already imported for other query/types in this file).
Add /api/v1/blocks to the ApiSourceFooter's paths array (lines 77–84) — confirmed absent from that array today, and it's now a real data dependency of the page.
What "done" looks like: on load, the explorer hero shows something like "head #123456 · 4s ago" (title format matches the issue's own title pattern, head #NNNN · N ago) without disturbing the existing 7d/30d window toggle or the 6-tile KPI grid below it. A null/loading block (cold poller, no rows yet) must render an honest empty/placeholder state, not a crash or a fabricated value — the same defensive style already used elsewhere on this page (e.g. successRate == null ? "—" : ..., line 298).
apps/ui/src/routes/explorer.tsx is the only route file changed, and it renders a live chain-head band (block number + relative time) inside/adjacent to the existing PageHero
The band is sourced from blocksQuery({ limit: 1 }) (or equivalent direct fetch against /api/v1/blocks), not fabricated or derived from the daily-aggregate queries already on the page
Block number is formatted with formatNumber and elapsed time with TimeAgo (or an equivalent already-reviewed relative-time renderer), consistent with blocks.index.tsx's existing block_number/observed_at pairing
/api/v1/blocks is added to the ApiSourceFooterpaths array in this file
The existing 7d/30d window toggle and 6-tile KPI grid (ExplorerDashboard) render unchanged — the new band is additive
A cold/empty block response (no rows yet) renders a defensive placeholder, not a crash or a fake block number
PR description includes a before/after screenshot table per the repo's UI-PR rule (this is a visual change to apps/ui/)
Do not modify the existing daily-aggregate KPI tiles, the window toggle, the call-mix section, or any other part of ExplorerDashboard beyond adding the new band and the one ApiSourceFooter path
No backend/schema changes — /api/v1/blocks and the Block type already expose everything this needs
Size
Size: S — keep this PR small (aim for ≤10 files / ≤1000 LOC).
Context
ExplorerPage/ExplorerDashboardinapps/ui/src/routes/explorer.tsxrendersPageHerowithliveset (line 67) and a 6-tile KPI grid (totalExtrinsics,totalBlocks,totalEvents,totalFees,totalTips,successRate, lines 267–301) sourced entirely fromchainActivityQuery/chainFeesQuery/chainCallsQuery/chainSignersQuery— all daily-aggregated over the7d/30dwindow toggle. There is no chain-head tip: nothing on the page shows the current block number or how fresh it is.blocksQuery(apps/ui/src/lib/metagraphed/queries.ts) already fetches/api/v1/blocksnewest-first and theBlocktype (apps/ui/src/lib/metagraphed/types.ts) already carriesblock_number: numberandobserved_at?: string—blocks.index.tsxrenders exactly this pair today via#{formatNumber(b.block_number)}+<TimeAgo at={b.observed_at} />, so the raw data and the rendering primitive both already exist, they're just not surfaced on the explorer page.Requirement
Add a compact live-tip band to the explorer page's hero showing the current chain head (
#<block_number>) and its recency (<N> ago), fetched from/api/v1/blockswithlimit: 1, sitting alongside — not replacing — the existing daily-aggregate KPI grid.Deliverable
apps/ui/src/routes/explorer.tsx(confirmed at this path;ExplorerPage/PageHerocall at lines 62–87,ExplorerDashboardat lines 225–520).PageHeroinvocation insideExplorerPage(lines 65–71). Add auseQuery(blocksQuery({ limit: 1 }))(oruseSuspenseQuery, matching the rest of the page's suspense-first style) and render its single row as a small band — block number formatted with the existingformatNumberhelper (already imported, line 22) and elapsed time via the existing<TimeAgo at={...} />component (apps/ui/src/components/metagraphed/time-ago.tsx), following the sameblock_number/observed_atpairing already used inblocks.index.tsx. ImportblocksQueryandBlockalongside the other imports from@/lib/metagraphed/queries/@/lib/metagraphed/types(both already imported for other query/types in this file)./api/v1/blocksto theApiSourceFooter'spathsarray (lines 77–84) — confirmed absent from that array today, and it's now a real data dependency of the page.head #NNNN · N ago) without disturbing the existing 7d/30d window toggle or the 6-tile KPI grid below it. A null/loading block (cold poller, no rows yet) must render an honest empty/placeholder state, not a crash or a fabricated value — the same defensive style already used elsewhere on this page (e.g.successRate == null ? "—" : ..., line 298).index.tsx/HomeHero) — implement independently, they touch different files. Add reusable FreshnessBadge ("as of / N ago" + realtime-vs-daily tier) component #3370 (FreshnessBadgecomponent) and Add a polling auto-refresh hook for the latest block / freshness (refetchInterval) #3371 (pollingrefetchIntervalhook) are both listed as foundational/unblocking in the parent tracker (🎨 Wave 3 — Frontend explorer enrichment (LIVE — 219 issues filed) #2542) but neither exists in the repo yet (nofreshness-badge.tsx, nouse-poll/use-refreshhook file —refetchIntervalis still only inlined ad hoc inhealth.tsx/status.tsx, confirming the parent tracker's own description). Do not block on them: ship this PR using the existingTimeAgocomponent for the "N ago" text and a plainuseQuery/useSuspenseQuery(optionally with an inlinerefetchInterval, matching thehealth.tsxprecedent) for now; swap inFreshnessBadge/the shared polling hook in a later PR once those land.Acceptance criteria
apps/ui/src/routes/explorer.tsxis the only route file changed, and it renders a live chain-head band (block number + relative time) inside/adjacent to the existingPageHeroblocksQuery({ limit: 1 })(or equivalent direct fetch against/api/v1/blocks), not fabricated or derived from the daily-aggregate queries already on the pageformatNumberand elapsed time withTimeAgo(or an equivalent already-reviewed relative-time renderer), consistent withblocks.index.tsx's existingblock_number/observed_atpairing/api/v1/blocksis added to theApiSourceFooterpathsarray in this fileExplorerDashboard) render unchanged — the new band is additiveapps/ui/)Non-goals
FreshnessBadge(Add reusable FreshnessBadge ("as of / N ago" + realtime-vs-daily tier) component #3370) or the shared polling/refetchIntervalhook (Add a polling auto-refresh hook for the latest block / freshness (refetchInterval) #3371) in this PR — reference/reuse them later once they land, don't gate this issue on themapps/ui/src/routes/index.tsx/HomeHero— that's the separate twin issue Add a live-tip hero band to index.tsx (head #NNNN · N ago) #3372ExplorerDashboardbeyond adding the new band and the oneApiSourceFooterpath/api/v1/blocksand theBlocktype already expose everything this needsSize
Size: S — keep this PR small (aim for ≤10 files / ≤1000 LOC).
Part of #2542.