Files
observer/web/src/components/SectionNav.tsx
T
grenadeandClaude Opus 5 6b45004907
deploy / build (push) Successful in 7m46s
deploy / deploy-web (push) Successful in 5s
deploy / deploy-api (push) Successful in 15s
feat: the call index — declared surface against actual use
Every explorer shows what happened on a chain. None shows the difference
between what a chain can do and what it has done, because none holds the
runtime's declared surface next to the activity. We already hold both, so this
is a join rather than new indexing.

    quantus    v152   6 of 58 dispatchables used
    heisenberg v148   6 of 58 — and a different six

The gap is the interesting half. ReversibleTransfers, TechReferenda, Vesting
and Preimage are shipped, documented and untouched; "this chain has governance
nobody has used" is a different statement from "this chain has no governance",
and only one of them appears on a list of what happened. Unused calls keep their
signature and their docs, both read from the chain rather than a source tree,
and are dimmed rather than hidden.

Two chains on the same runtime family diverging is the other thing it surfaces:
mainnet has exercised the wormhole batch verifiers and nothing else, while
Heisenberg has a whole multisig lifecycle and no wormhole traffic.

`/:chain/call/:pallet/:call` is the feed behind a row — who dispatched it, with
what arguments, and whether it worked. Nothing is written per call type: the
arguments render through the same `Payload` as everything else, so a pallet
added next year gets a row on the index when the runtime declares it and a
working page the moment somebody uses it.

`BlockExtrinsic` gained `height` and `at`, which are redundant on a block's own
page and the entire point on a feed where every row is a different block.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jp6a8EDar9ueEhAxzep4V5
2026-09-10 07:44:29 +03:00

67 lines
2.0 KiB
TypeScript

/**
* The site's sections.
*
* Every route this site has was reachable only by already knowing an address —
* a block hash, a preimage, an SS58 string, a spec_version. That is fine for a
* link somebody sent you and useless for finding out the pages exist at all.
* This is the answer to "what else is here".
*
* The standings are the first entry because they are the front page, and there
* is no "Miners" beside them for the same reason: the standings already are the
* index of miners, and a second page listing the same rows under a different
* address would be two answers to one question.
*/
import { Link } from 'react-router-dom'
import type { Window as WindowName } from '../api/generated/Window'
import { href, type Route, SECTIONS } from '../lib/routes'
export function SectionNav({
chain,
route,
window: windowName,
}: {
chain: string | null
route: Route
/** Carried into the standings link so leaving a section and coming back does
* not silently reset the span someone chose. */
window: WindowName
}) {
if (!chain) return null
// The standings are current when nothing else is: no panel open, no index.
const onStandings =
route.index === null &&
route.block === null &&
route.miner === null &&
route.account === null &&
route.runtime === null &&
route.call === null
return (
<nav className="sections" aria-label="Section">
<Link
to={href({ chain, window: windowName })}
className="section-link"
aria-current={onStandings ? 'page' : undefined}
>
Standings
</Link>
{SECTIONS.map((s) => (
<Link
key={s.id}
to={href({ chain, index: s.id })}
className="section-link"
// A call's own page belongs to the Calls section, so the nav marks
// it there rather than nowhere.
aria-current={
route.index === s.id || (s.id === 'call' && route.call !== null) ? 'page' : undefined
}
>
{s.label}
</Link>
))}
</nav>
)
}