From 6a71e18b9a3413a9109fbb8e7cb46d9da3a6f21f Mon Sep 17 00:00:00 2001 From: Andrew Davis <1709934+Savid@users.noreply.github.com> Date: Thu, 28 May 2026 09:35:48 +1000 Subject: [PATCH] feat(validators): move report tool to validators index Promote the validator report tool from /ethereum/validators/report to the section index at /ethereum/validators, and remove the now-redundant Validators subsection from the sidebar. - Render IndexPage (the report tool) at the validators index route, carrying over the indices/from/to search param schema - Delete the standalone report route and the card-based LandingPage that previously linked to it (and to a non-existent battle page) - Update IndexPage useSearch/navigate references to target the index route instead of /report - Drop the Validators nav array, its filter memo, and both mobile and desktop subsection blocks from the Sidebar - Regenerate routeTree.gen.ts Co-Authored-By: Claude Opus 4.7 (1M context) --- src/components/Layout/Sidebar/Sidebar.tsx | 29 ---------- src/pages/ethereum/validators/IndexPage.tsx | 4 +- src/pages/ethereum/validators/LandingPage.tsx | 57 ------------------- src/pages/ethereum/validators/index.ts | 1 - src/routeTree.gen.ts | 22 ------- src/routes/ethereum/validators/index.tsx | 12 +++- src/routes/ethereum/validators/report.tsx | 52 ----------------- 7 files changed, 12 insertions(+), 165 deletions(-) delete mode 100644 src/pages/ethereum/validators/LandingPage.tsx delete mode 100644 src/routes/ethereum/validators/report.tsx diff --git a/src/components/Layout/Sidebar/Sidebar.tsx b/src/components/Layout/Sidebar/Sidebar.tsx index 2b1545e1e..51c80cea5 100644 --- a/src/components/Layout/Sidebar/Sidebar.tsx +++ b/src/components/Layout/Sidebar/Sidebar.tsx @@ -165,10 +165,6 @@ const ethereumConsensusPages: NavItem[] = [ { name: 'Forks', to: '/ethereum/forks', icon: SignalIcon }, ]; -const ethereumValidatorsPages: NavItem[] = [ - { name: 'Report', to: '/ethereum/validators/report', icon: DocumentTextIcon }, -]; - const ethereumDataAvailabilityPages: NavItem[] = [ { name: 'Custody', to: '/ethereum/data-availability/custody', icon: CircleStackIcon }, { name: 'Probes', to: '/ethereum/data-availability/probes', icon: MagnifyingGlassIcon }, @@ -292,11 +288,6 @@ export function Sidebar({ sidebarOpen, setSidebarOpen, collapsed, setCollapsed } [config?.features, currentNetwork?.name] ); - const filteredEthereumValidatorsPages = useMemo( - () => ethereumValidatorsPages.filter(page => isPageEnabled(page.to, config?.features, currentNetwork?.name)), - [config?.features, currentNetwork?.name] - ); - const filteredXatuPages = useMemo( () => xatuPages.filter(page => isPageEnabled(page.to, config?.features, currentNetwork?.name)), [config?.features, currentNetwork?.name] @@ -356,16 +347,6 @@ export function Sidebar({ sidebarOpen, setSidebarOpen, collapsed, setCollapsed } )} - {filteredEthereumValidatorsPages.length > 0 && ( -
- -
- {filteredEthereumValidatorsPages.map(page => ( - - ))} -
-
- )} @@ -487,16 +468,6 @@ export function Sidebar({ sidebarOpen, setSidebarOpen, collapsed, setCollapsed } )} - {filteredEthereumValidatorsPages.length > 0 && ( -
- -
- {filteredEthereumValidatorsPages.map(page => ( - - ))} -
-
- )} diff --git a/src/pages/ethereum/validators/IndexPage.tsx b/src/pages/ethereum/validators/IndexPage.tsx index 360aafa72..5cccb4211 100644 --- a/src/pages/ethereum/validators/IndexPage.tsx +++ b/src/pages/ethereum/validators/IndexPage.tsx @@ -56,7 +56,7 @@ function tagsFromUrl(indices?: string): string[] { */ export function IndexPage(): JSX.Element { const navigate = useNavigate(); - const search = useSearch({ from: '/ethereum/validators/report' }) as ValidatorsSearch; + const search = useSearch({ from: '/ethereum/validators/' }) as ValidatorsSearch; // Initialize state from URL params or defaults const defaultRange = getDefaultTimeRange(); @@ -117,7 +117,7 @@ export function IndexPage(): JSX.Element { (tagList: string[], from: number, to: number) => { const indices = tagList.join(','); void navigate({ - to: '/ethereum/validators/report', + to: '/ethereum/validators', search: { indices: indices || undefined, from: from || undefined, diff --git a/src/pages/ethereum/validators/LandingPage.tsx b/src/pages/ethereum/validators/LandingPage.tsx deleted file mode 100644 index 41860a58d..000000000 --- a/src/pages/ethereum/validators/LandingPage.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import type { JSX } from 'react'; -import { Link } from '@tanstack/react-router'; -import { DocumentTextIcon, BoltIcon } from '@heroicons/react/24/outline'; -import { Container } from '@/components/Layout/Container'; -import { Header } from '@/components/Layout/Header'; -import { Card } from '@/components/Layout/Card'; - -interface ValidatorPageCard { - name: string; - description: string; - path: string; - icon: typeof DocumentTextIcon; -} - -const validatorPages: ValidatorPageCard[] = [ - { - name: 'Report', - description: - 'Analyze validator performance including attestation correctness, sync committee participation, and balance history.', - path: '/ethereum/validators/report', - icon: DocumentTextIcon, - }, - { - name: 'Battle', - description: 'Compare validators head-to-head across key performance metrics to see how they stack up.', - path: '/ethereum/validators/battle', - icon: BoltIcon, - }, -]; - -/** Landing page for the validators section */ -export function LandingPage(): JSX.Element { - return ( - -
- -
- {validatorPages.map(page => { - const Icon = page.icon; - return ( - - -
-
- -

{page.name}

-
-

{page.description}

-
-
- - ); - })} -
- - ); -} diff --git a/src/pages/ethereum/validators/index.ts b/src/pages/ethereum/validators/index.ts index 46871637e..b36af7308 100644 --- a/src/pages/ethereum/validators/index.ts +++ b/src/pages/ethereum/validators/index.ts @@ -1,2 +1 @@ export { IndexPage } from './IndexPage'; -export { LandingPage } from './LandingPage'; diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 7318c274e..7361d2b96 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -42,7 +42,6 @@ import { Route as EthereumEpochsIndexRouteImport } from './routes/ethereum/epoch import { Route as EthereumEntitiesIndexRouteImport } from './routes/ethereum/entities/index' import { Route as EthereumContractsIndexRouteImport } from './routes/ethereum/contracts/index' import { Route as XatuContributorsIdRouteImport } from './routes/xatu/contributors/$id' -import { Route as EthereumValidatorsReportRouteImport } from './routes/ethereum/validators/report' import { Route as EthereumSlotsSlotRouteImport } from './routes/ethereum/slots/$slot' import { Route as EthereumForksForkRouteImport } from './routes/ethereum/forks/$fork' import { Route as EthereumExecutionTimingsRouteImport } from './routes/ethereum/execution/timings' @@ -239,12 +238,6 @@ const XatuContributorsIdRoute = XatuContributorsIdRouteImport.update({ path: '/$id', getParentRoute: () => XatuContributorsRoute, } as any) -const EthereumValidatorsReportRoute = - EthereumValidatorsReportRouteImport.update({ - id: '/report', - path: '/report', - getParentRoute: () => EthereumValidatorsRoute, - } as any) const EthereumSlotsSlotRoute = EthereumSlotsSlotRouteImport.update({ id: '/$slot', path: '/$slot', @@ -433,7 +426,6 @@ export interface FileRoutesByFullPath { '/ethereum/execution/timings': typeof EthereumExecutionTimingsRouteWithChildren '/ethereum/forks/$fork': typeof EthereumForksForkRoute '/ethereum/slots/$slot': typeof EthereumSlotsSlotRoute - '/ethereum/validators/report': typeof EthereumValidatorsReportRoute '/xatu/contributors/$id': typeof XatuContributorsIdRoute '/ethereum/contracts/': typeof EthereumContractsIndexRoute '/ethereum/entities/': typeof EthereumEntitiesIndexRoute @@ -481,7 +473,6 @@ export interface FileRoutesByTo { '/ethereum/execution/state-growth': typeof EthereumExecutionStateGrowthRoute '/ethereum/forks/$fork': typeof EthereumForksForkRoute '/ethereum/slots/$slot': typeof EthereumSlotsSlotRoute - '/ethereum/validators/report': typeof EthereumValidatorsReportRoute '/xatu/contributors/$id': typeof XatuContributorsIdRoute '/ethereum/contracts': typeof EthereumContractsIndexRoute '/ethereum/entities': typeof EthereumEntitiesIndexRoute @@ -543,7 +534,6 @@ export interface FileRoutesById { '/ethereum/execution/timings': typeof EthereumExecutionTimingsRouteWithChildren '/ethereum/forks/$fork': typeof EthereumForksForkRoute '/ethereum/slots/$slot': typeof EthereumSlotsSlotRoute - '/ethereum/validators/report': typeof EthereumValidatorsReportRoute '/xatu/contributors/$id': typeof XatuContributorsIdRoute '/ethereum/contracts/': typeof EthereumContractsIndexRoute '/ethereum/entities/': typeof EthereumEntitiesIndexRoute @@ -606,7 +596,6 @@ export interface FileRouteTypes { | '/ethereum/execution/timings' | '/ethereum/forks/$fork' | '/ethereum/slots/$slot' - | '/ethereum/validators/report' | '/xatu/contributors/$id' | '/ethereum/contracts/' | '/ethereum/entities/' @@ -654,7 +643,6 @@ export interface FileRouteTypes { | '/ethereum/execution/state-growth' | '/ethereum/forks/$fork' | '/ethereum/slots/$slot' - | '/ethereum/validators/report' | '/xatu/contributors/$id' | '/ethereum/contracts' | '/ethereum/entities' @@ -715,7 +703,6 @@ export interface FileRouteTypes { | '/ethereum/execution/timings' | '/ethereum/forks/$fork' | '/ethereum/slots/$slot' - | '/ethereum/validators/report' | '/xatu/contributors/$id' | '/ethereum/contracts/' | '/ethereum/entities/' @@ -981,13 +968,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof XatuContributorsIdRouteImport parentRoute: typeof XatuContributorsRoute } - '/ethereum/validators/report': { - id: '/ethereum/validators/report' - path: '/report' - fullPath: '/ethereum/validators/report' - preLoaderRoute: typeof EthereumValidatorsReportRouteImport - parentRoute: typeof EthereumValidatorsRoute - } '/ethereum/slots/$slot': { id: '/ethereum/slots/$slot' path: '/$slot' @@ -1371,12 +1351,10 @@ const EthereumSlotsRouteWithChildren = EthereumSlotsRoute._addFileChildren( ) interface EthereumValidatorsRouteChildren { - EthereumValidatorsReportRoute: typeof EthereumValidatorsReportRoute EthereumValidatorsIndexRoute: typeof EthereumValidatorsIndexRoute } const EthereumValidatorsRouteChildren: EthereumValidatorsRouteChildren = { - EthereumValidatorsReportRoute: EthereumValidatorsReportRoute, EthereumValidatorsIndexRoute: EthereumValidatorsIndexRoute, } diff --git a/src/routes/ethereum/validators/index.tsx b/src/routes/ethereum/validators/index.tsx index 2f00cdf08..55dcc1f64 100644 --- a/src/routes/ethereum/validators/index.tsx +++ b/src/routes/ethereum/validators/index.tsx @@ -1,8 +1,16 @@ import { createFileRoute } from '@tanstack/react-router'; -import { LandingPage } from '@/pages/ethereum/validators'; +import { z } from 'zod'; +import { IndexPage } from '@/pages/ethereum/validators'; + +const validatorsSearchSchema = z.object({ + indices: z.string().optional(), + from: z.coerce.number().optional(), + to: z.coerce.number().optional(), +}); export const Route = createFileRoute('/ethereum/validators/')({ - component: LandingPage, + component: IndexPage, + validateSearch: validatorsSearchSchema, beforeLoad: () => ({ getBreadcrumb: () => ({ show: false }), }), diff --git a/src/routes/ethereum/validators/report.tsx b/src/routes/ethereum/validators/report.tsx deleted file mode 100644 index 492e2b7f9..000000000 --- a/src/routes/ethereum/validators/report.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router'; -import { z } from 'zod'; -import { IndexPage } from '@/pages/ethereum/validators'; - -const validatorsSearchSchema = z.object({ - indices: z.string().optional(), - from: z.coerce.number().optional(), - to: z.coerce.number().optional(), -}); - -export const Route = createFileRoute('/ethereum/validators/report')({ - component: IndexPage, - validateSearch: validatorsSearchSchema, - beforeLoad: () => ({ - getBreadcrumb: () => ({ label: 'Report' }), - }), - head: () => ({ - meta: [ - { - title: `Validator Report | ${import.meta.env.VITE_BASE_TITLE}`, - }, - { - name: 'description', - content: - 'Analyze Ethereum validator performance including attestation correctness, sync committee participation, and balance history.', - }, - { property: 'og:url', content: `${import.meta.env.VITE_BASE_URL}/ethereum/validators/report` }, - { property: 'og:type', content: 'website' }, - { property: 'og:title', content: `Validator Report | ${import.meta.env.VITE_BASE_TITLE}` }, - { - property: 'og:description', - content: - 'Analyze Ethereum validator performance including attestation correctness, sync committee participation, and balance history.', - }, - { - property: 'og:image', - content: `${import.meta.env.VITE_BASE_URL}/images/ethereum/validators.png`, - }, - { name: 'twitter:url', content: `${import.meta.env.VITE_BASE_URL}/ethereum/validators/report` }, - { name: 'twitter:title', content: `Validator Report | ${import.meta.env.VITE_BASE_TITLE}` }, - { - name: 'twitter:description', - content: - 'Analyze Ethereum validator performance including attestation correctness, sync committee participation, and balance history.', - }, - { - name: 'twitter:image', - content: `${import.meta.env.VITE_BASE_URL}/images/ethereum/validators.png`, - }, - ], - }), -});