Skip to content

Commit 83687a4

Browse files
committed
Add VerifiersTable component and integrate into CCIP directory pages
1 parent ddf4936 commit 83687a4

File tree

4 files changed

+332
-0
lines changed

4 files changed

+332
-0
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import Address from "~/components/AddressReact.tsx"
2+
import "./Table.css"
3+
import { Environment, Verifier, getVerifierTypeDisplay } from "~/config/data/ccip/index.ts"
4+
import TableSearchInput from "./TableSearchInput.tsx"
5+
import { useState } from "react"
6+
import {
7+
getExplorerAddressUrl,
8+
fallbackVerifierIconUrl,
9+
getChainIcon,
10+
getTitle,
11+
directoryToSupportedChain,
12+
getExplorer,
13+
getChainTypeAndFamily,
14+
} from "~/features/utils/index.ts"
15+
16+
interface VerifiersTableProps {
17+
verifiers: Verifier[]
18+
}
19+
20+
function VerifiersTable({ verifiers }: VerifiersTableProps) {
21+
const [search, setSearch] = useState("")
22+
23+
// Transform verifiers data to include network information
24+
console.log("VerifiersTable verifiers:", verifiers)
25+
const verifiersWithNetworkInfo = verifiers.map((verifier) => {
26+
const supportedChain = directoryToSupportedChain(verifier.network)
27+
const networkName = getTitle(supportedChain) || verifier.network
28+
const networkLogo = getChainIcon(supportedChain) || ""
29+
const explorer = getExplorer(supportedChain)
30+
const { chainType } = getChainTypeAndFamily(supportedChain)
31+
32+
return {
33+
...verifier,
34+
networkName,
35+
networkLogo,
36+
supportedChain,
37+
explorer,
38+
chainType,
39+
}
40+
})
41+
42+
const filteredVerifiers = verifiersWithNetworkInfo.filter(
43+
(verifier) =>
44+
verifier.name.toLowerCase().includes(search.toLowerCase()) ||
45+
verifier.networkName.toLowerCase().includes(search.toLowerCase()) ||
46+
verifier.address.toLowerCase().includes(search.toLowerCase()) ||
47+
getVerifierTypeDisplay(verifier.type).toLowerCase().includes(search.toLowerCase())
48+
)
49+
50+
return (
51+
<>
52+
<div className="ccip-table__filters">
53+
<div className="ccip-table__filters-title">
54+
Verifiers <span>({verifiers.length})</span>
55+
</div>
56+
<TableSearchInput search={search} setSearch={setSearch} />
57+
</div>
58+
<div className="ccip-table__wrapper">
59+
<table className="ccip-table">
60+
<thead>
61+
<tr>
62+
<th>Verifier</th>
63+
<th>Network</th>
64+
<th>Verifier address</th>
65+
<th>Verifier type</th>
66+
</tr>
67+
</thead>
68+
<tbody>
69+
{filteredVerifiers.map((verifier, index) => (
70+
<tr key={`${verifier.network}-${verifier.address}`}>
71+
<td>
72+
<div className="ccip-table__network-name">
73+
<span className="ccip-table__logoContainer">
74+
<img
75+
src={verifier.logo}
76+
alt={`${verifier.name} verifier logo`}
77+
className="ccip-table__logo"
78+
onError={({ currentTarget }) => {
79+
currentTarget.onerror = null // prevents looping
80+
currentTarget.src = fallbackVerifierIconUrl
81+
}}
82+
/>
83+
</span>
84+
{verifier.name}
85+
</div>
86+
</td>
87+
<td>
88+
<div className="ccip-table__network-name">
89+
<span className="ccip-table__logoContainer">
90+
<img
91+
src={verifier.networkLogo}
92+
alt={`${verifier.networkName} blockchain logo`}
93+
className="ccip-table__logo"
94+
onError={({ currentTarget }) => {
95+
currentTarget.onerror = null // prevents looping
96+
currentTarget.src = fallbackVerifierIconUrl
97+
}}
98+
/>
99+
</span>
100+
{verifier.networkName}
101+
</div>
102+
</td>
103+
<td data-clipboard-type="verifier-address">
104+
<Address
105+
contractUrl={
106+
verifier.explorer
107+
? getExplorerAddressUrl(verifier.explorer, verifier.chainType)(verifier.address)
108+
: ""
109+
}
110+
address={verifier.address}
111+
endLength={4}
112+
/>
113+
</td>
114+
<td>{getVerifierTypeDisplay(verifier.type)}</td>
115+
</tr>
116+
))}
117+
</tbody>
118+
</table>
119+
<div className="ccip-table__notFound">{filteredVerifiers.length === 0 && <>No verifiers found</>}</div>
120+
</div>
121+
</>
122+
)
123+
}
124+
125+
export default VerifiersTable
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
---
2+
import CcipDirectoryLayout from "~/layouts/CcipDirectoryLayout.astro"
3+
import { getEntry, render } from "astro:content"
4+
import { getAllNetworks, getAllVerifiers, getSearchLanes, Version, Environment } from "~/config/data/ccip"
5+
import Table from "~/components/CCIP/Tables/VerifiersTable"
6+
import { getAllUniqueVerifiers } from "~/config/data/ccip/data.ts"
7+
import { DOCS_BASE_URL } from "~/utils/structuredData"
8+
import Breadcrumb from "~/components/CCIP/Breadcrumb/Breadcrumb"
9+
import Search from "~/components/CCIP/Search/Search"
10+
11+
interface Props {
12+
environment: Environment
13+
}
14+
15+
const { environment } = Astro.props as Props
16+
17+
const entry = await getEntry("ccip", "index")
18+
if (!entry) {
19+
throw new Error('Could not find "ccip/index" doc. Check src/content/ccip/index.mdx!')
20+
}
21+
22+
const { headings } = await render(entry)
23+
24+
const networks = getAllNetworks({ filter: environment })
25+
26+
const allVerifiers = getAllVerifiers({
27+
environment,
28+
version: Version.V1_2_0,
29+
})
30+
31+
const uniqueVerifiers = getAllUniqueVerifiers({
32+
environment,
33+
version: Version.V1_2_0,
34+
})
35+
36+
const searchLanes = getSearchLanes({ environment })
37+
38+
// Generate dynamic metadata for verifiers page
39+
const environmentText = environment === Environment.Mainnet ? "Mainnet" : "Testnet"
40+
const verifiersMetadata = {
41+
title: `CCIP Verifiers - ${environmentText} Networks`,
42+
description: `View all CCIP verifiers across ${environmentText} networks. Explore ${allVerifiers.length} verifiers, their addresses, types, and supported networks for cross-chain verification.`,
43+
image: "/assets/product-logos/ccip-logo.svg",
44+
excerpt: `CCIP verifiers ${environmentText.toLowerCase()} networks addresses types committee api cross-chain verification blockchain interoperability`,
45+
}
46+
47+
// Generate structured data for verifiers page
48+
const currentPath = new URL(Astro.request.url).pathname
49+
const canonicalForJsonLd = `${DOCS_BASE_URL}${currentPath}`
50+
---
51+
52+
<CcipDirectoryLayout
53+
frontmatter={{
54+
title: verifiersMetadata.title,
55+
section: "ccip",
56+
metadata: {
57+
description: verifiersMetadata.description,
58+
image: verifiersMetadata.image,
59+
excerpt: verifiersMetadata.excerpt,
60+
},
61+
}}
62+
{headings}
63+
environment={environment}
64+
pageTitleOverride={verifiersMetadata.title}
65+
metadataOverride={{
66+
description: verifiersMetadata.description,
67+
image: verifiersMetadata.image,
68+
excerpt: verifiersMetadata.excerpt,
69+
}}
70+
>
71+
<section class="ccip-chain-hero">
72+
<div class="ccip-chain-hero__content">
73+
<div class="ccip-chain-hero__top">
74+
<Breadcrumb
75+
items={[
76+
{
77+
name: "CCIP Directory",
78+
url: `/ccip/directory/${environment}`,
79+
},
80+
{
81+
name: "Verifiers",
82+
url: `/ccip/directory/${environment}/verifiers`,
83+
},
84+
]}
85+
/>
86+
<div class="ccip-chain-hero__chainSearch">
87+
<Search
88+
chains={networks}
89+
tokens={uniqueVerifiers.map((verifier) => ({
90+
id: verifier.id,
91+
totalNetworks: verifier.totalNetworks,
92+
logo: verifier.logo,
93+
}))}
94+
small
95+
environment={environment}
96+
lanes={searchLanes}
97+
client:load
98+
/>
99+
</div>
100+
</div>
101+
</div>
102+
</section>
103+
104+
<section class="layout">
105+
<div>
106+
<Table client:load verifiers={allVerifiers} />
107+
</div>
108+
</section>
109+
</CcipDirectoryLayout>
110+
111+
<style scoped="false">
112+
.ccip-chain-hero {
113+
background: var(--gray-50);
114+
border-bottom: 1px solid var(--gray-200);
115+
}
116+
117+
.ccip-chain-hero__content {
118+
max-width: 1500px;
119+
margin: 0 auto;
120+
padding: var(--space-6x);
121+
}
122+
123+
.ccip-chain-hero__top {
124+
display: flex;
125+
justify-content: space-between;
126+
align-items: center;
127+
gap: var(--space-4x);
128+
}
129+
130+
.ccip-chain-hero__chainSearch {
131+
flex-shrink: 0;
132+
}
133+
134+
@media (max-width: 768px) {
135+
.ccip-chain-hero__top {
136+
flex-direction: column;
137+
align-items: stretch;
138+
gap: var(--space-3x);
139+
}
140+
}
141+
142+
@media (min-width: 992px) {
143+
.ccip-chain-hero__content {
144+
padding: var(--space-10x) var(--space-8x);
145+
}
146+
}
147+
148+
.layout {
149+
margin: 0 auto;
150+
padding: var(--space-6x);
151+
}
152+
153+
.layout h2 {
154+
color: var(--gray-900);
155+
font-size: 22px;
156+
line-height: var(--space-10x);
157+
padding-bottom: var(--space-4x);
158+
border-bottom: 1px solid var(--gray-200);
159+
margin-bottom: var(--space-6x);
160+
}
161+
162+
.layout h2 span {
163+
color: var(--gray-400);
164+
font-weight: 600;
165+
letter-spacing: 0.5px;
166+
}
167+
168+
.networks__grid {
169+
display: grid;
170+
grid-template-columns: 1fr;
171+
gap: var(--space-8x);
172+
}
173+
174+
.tokens__grid {
175+
display: grid;
176+
grid-template-columns: 1fr 1fr;
177+
gap: var(--space-8x);
178+
}
179+
180+
@media (min-width: 50em) {
181+
.layout {
182+
max-width: 1500px;
183+
}
184+
}
185+
186+
@media (min-width: 992px) {
187+
.layout {
188+
padding: var(--space-10x) var(--space-8x);
189+
}
190+
}
191+
</style>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
import Verifiers from "~/components/CCIP/Verifiers/Verifiers.astro"
3+
import { Environment } from "~/config/data/ccip"
4+
5+
export const prerender = true
6+
---
7+
8+
<Verifiers environment={Environment.Mainnet} />
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
import Verifiers from "~/components/CCIP/Verifiers/Verifiers.astro"
3+
import { Environment } from "~/config/data/ccip"
4+
5+
export const prerender = true
6+
---
7+
8+
<Verifiers environment={Environment.Testnet} />

0 commit comments

Comments
 (0)