Created unstyled block explorer blocks page, with new refresh method from useFetch, and a 'navigate to' component
This commit is contained in:
parent
e467344a4d
commit
f88661e422
47
apps/explorer/src/app/components/blocks/home/blocksTable.tsx
Normal file
47
apps/explorer/src/app/components/blocks/home/blocksTable.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { TendermintBlockchainResponse } from '../../../routes/blocks/tendermint-blockchain-response';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { SecondsAgo } from '../../seconds-ago';
|
||||
|
||||
interface BlocksProps {
|
||||
data: TendermintBlockchainResponse | undefined;
|
||||
showExpanded?: boolean;
|
||||
}
|
||||
|
||||
export const BlocksTable = ({ data }: BlocksProps) => {
|
||||
if (!data?.result) {
|
||||
return <>Awaiting block data</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<table>
|
||||
<tbody>
|
||||
{data.result?.block_metas?.map((block) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<Link to={`/blocks/${block.header?.height}`}>
|
||||
{block.header?.height}
|
||||
</Link>
|
||||
</td>
|
||||
<td>
|
||||
{block.num_txs === '1'
|
||||
? '1 transaction'
|
||||
: `${block.num_txs} transactions`}
|
||||
</td>
|
||||
{block.header?.proposer_address && (
|
||||
<td>
|
||||
<Link to={`/validators/${block.header.proposer_address}`}>
|
||||
{block.header.proposer_address}
|
||||
</Link>
|
||||
</td>
|
||||
)}
|
||||
<td>
|
||||
<SecondsAgo date={block.header?.time} />
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
1
apps/explorer/src/app/components/blocks/index.tsx
Normal file
1
apps/explorer/src/app/components/blocks/index.tsx
Normal file
@ -0,0 +1 @@
|
||||
export { BlocksTable } from './home/blocksTable';
|
27
apps/explorer/src/app/components/jump-to-block/index.tsx
Normal file
27
apps/explorer/src/app/components/jump-to-block/index.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export const JumpToBlock = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleSubmit = (e: React.SyntheticEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
const target = e.target as typeof e.target & {
|
||||
blockNumber: { value: number };
|
||||
};
|
||||
|
||||
const blockNumber = target.blockNumber.value;
|
||||
|
||||
if (blockNumber) {
|
||||
navigate(`/blocks/${blockNumber}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input type={'tel'} name={'blockNumber'} placeholder={'Block number'} />
|
||||
<input type={'submit'} value={'Go'} />
|
||||
</form>
|
||||
);
|
||||
};
|
28
apps/explorer/src/app/components/seconds-ago/index.tsx
Normal file
28
apps/explorer/src/app/components/seconds-ago/index.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
interface SecondsAgoProps {
|
||||
date: string;
|
||||
}
|
||||
|
||||
export const SecondsAgo = ({ date }: SecondsAgoProps) => {
|
||||
const [now, setNow] = useState(Date.now());
|
||||
|
||||
useEffect(() => {
|
||||
const int = setInterval(() => {
|
||||
setNow(Date.now());
|
||||
}, 500);
|
||||
return () => clearInterval(int);
|
||||
}, [setNow]);
|
||||
|
||||
if (!date) {
|
||||
return <>Date unknown</>;
|
||||
}
|
||||
|
||||
const timeAgoInSeconds = Math.floor((now - new Date(date).getTime()) / 1000);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{timeAgoInSeconds === 1 ? '1 second' : `${timeAgoInSeconds} seconds`} ago
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,7 +1,13 @@
|
||||
import { TendermintUnconfirmedTransactionsResponse } from '../../../routes/txs/tendermint-unconfirmed-transactions-response.d';
|
||||
|
||||
interface TxsProps {
|
||||
data: string | undefined;
|
||||
data: TendermintUnconfirmedTransactionsResponse | undefined;
|
||||
}
|
||||
|
||||
export const Txs = ({ data }: TxsProps) => {
|
||||
return <>Blah</>;
|
||||
export const TxList = ({ data }: TxsProps) => {
|
||||
if (!data) {
|
||||
return <div>Awaiting transactions</div>;
|
||||
}
|
||||
|
||||
return <div>{JSON.stringify(data, null, ' ')}</div>;
|
||||
};
|
||||
|
@ -0,0 +1,37 @@
|
||||
import { Codeblock } from '../../codeblock';
|
||||
import { ChainExplorerTxResponse } from '../../../routes/types/chain-explorer-response';
|
||||
|
||||
interface TxContentProps {
|
||||
data: ChainExplorerTxResponse | undefined;
|
||||
}
|
||||
|
||||
export const TxContent = ({ data }: TxContentProps) => {
|
||||
if (!data?.Command) {
|
||||
return <>Awaiting decoded transaction data</>;
|
||||
}
|
||||
|
||||
const Command = JSON.parse(data.Command);
|
||||
|
||||
const displayCode = `{
|
||||
"market": "${Command.marketId}",
|
||||
"type": "${Command.type}",
|
||||
"side": "${Command.side}",
|
||||
"size": "${Command.size}",
|
||||
}`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Type</td>
|
||||
<td>{data.Type}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Decoded transaction content</h3>
|
||||
<Codeblock code={displayCode} language={'javascript'} />
|
||||
</>
|
||||
);
|
||||
};
|
@ -0,0 +1,48 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Routes } from '../../../routes/router-config';
|
||||
import { Result } from '../../../routes/txs/tendermint-transaction-response.d';
|
||||
|
||||
interface TxDetailsProps {
|
||||
txData: Result | undefined;
|
||||
pubKey: string | undefined;
|
||||
}
|
||||
|
||||
export const TxDetails = ({ txData, pubKey }: TxDetailsProps) => {
|
||||
if (!txData) {
|
||||
return <>Awaiting Tendermint transaction details</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Hash</td>
|
||||
<td>{txData.hash}</td>
|
||||
</tr>
|
||||
{pubKey ? (
|
||||
<tr>
|
||||
<td>Submitted by</td>
|
||||
<td>
|
||||
<Link to={`/${Routes.PARTIES}/${pubKey}`}>{pubKey}</Link>
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<tr>
|
||||
<td>Submitted by</td>
|
||||
<td>Awaiting decoded transaction data</td>
|
||||
</tr>
|
||||
)}
|
||||
{txData.height ? (
|
||||
<tr>
|
||||
<td>Block</td>
|
||||
<td>{txData.height}</td>
|
||||
</tr>
|
||||
) : null}
|
||||
<tr>
|
||||
<td>Encoded tnx</td>
|
||||
<td>{txData.tx}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
@ -1,85 +1,3 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Routes } from '../../routes/router-config';
|
||||
import { Codeblock } from '../codeblock';
|
||||
import { ChainExplorerTxResponse } from '../../routes/types/chain-explorer-response';
|
||||
import { Result } from '../../routes/txs/tendermint-transaction-response.d';
|
||||
|
||||
interface TxDetailsProps {
|
||||
txData: Result | undefined;
|
||||
pubKey: string | undefined;
|
||||
}
|
||||
|
||||
interface TxContentProps {
|
||||
data: ChainExplorerTxResponse | undefined;
|
||||
}
|
||||
|
||||
export const TxDetails = ({ txData, pubKey }: TxDetailsProps) => {
|
||||
if (!txData) {
|
||||
return <>Awaiting Tendermint transaction details</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Hash</td>
|
||||
<td>{txData.hash}</td>
|
||||
</tr>
|
||||
{pubKey ? (
|
||||
<tr>
|
||||
<td>Submitted by</td>
|
||||
<td>
|
||||
<Link to={`/${Routes.PARTIES}/${pubKey}`}>{pubKey}</Link>
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<tr>
|
||||
<td>Submitted by</td>
|
||||
<td>Awaiting decoded transaction data</td>
|
||||
</tr>
|
||||
)}
|
||||
{txData.height ? (
|
||||
<tr>
|
||||
<td>Block</td>
|
||||
<td>{txData.height}</td>
|
||||
</tr>
|
||||
) : null}
|
||||
<tr>
|
||||
<td>Encoded tnx</td>
|
||||
<td>{txData.tx}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
export const TxContent = ({ data }: TxContentProps) => {
|
||||
if (!data?.Command) {
|
||||
return <>Awaiting decoded transaction data</>;
|
||||
}
|
||||
|
||||
const Command = JSON.parse(data.Command);
|
||||
|
||||
const displayCode = `{
|
||||
"market": "${Command.marketId}",
|
||||
"type": "${Command.type}",
|
||||
"side": "${Command.side}",
|
||||
"size": "${Command.size}",
|
||||
}`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Type</td>
|
||||
<td>{data.Type}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Decoded transaction content</h3>
|
||||
<Codeblock code={displayCode} language={'javascript'} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
export { TxDetails } from './id/txDetails';
|
||||
export { TxContent } from './id/txContent';
|
||||
export { TxList } from './home/txList';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useEffect, useReducer, useRef } from "react";
|
||||
import { useCallback, useEffect, useReducer, useRef } from 'react';
|
||||
|
||||
interface State<T> {
|
||||
data?: T;
|
||||
@ -7,9 +7,9 @@ interface State<T> {
|
||||
}
|
||||
|
||||
enum ActionType {
|
||||
LOADING = "LOADING",
|
||||
ERROR = "ERROR",
|
||||
FETCHED = "FETCHED",
|
||||
LOADING = 'LOADING',
|
||||
ERROR = 'ERROR',
|
||||
FETCHED = 'FETCHED',
|
||||
}
|
||||
|
||||
// discriminated union type
|
||||
@ -18,7 +18,10 @@ type Action<T> =
|
||||
| { type: ActionType.FETCHED; payload: T }
|
||||
| { type: ActionType.ERROR; error: Error };
|
||||
|
||||
function useFetch<T = unknown>(url?: string, options?: RequestInit): State<T> {
|
||||
function useFetch<T = unknown>(
|
||||
url?: string,
|
||||
options?: RequestInit
|
||||
): { state: State<T>; refetch: () => void } {
|
||||
// Used to prevent state update if the component is unmounted
|
||||
const cancelRequest = useRef<boolean>(false);
|
||||
|
||||
@ -41,9 +44,7 @@ function useFetch<T = unknown>(url?: string, options?: RequestInit): State<T> {
|
||||
};
|
||||
|
||||
const [state, dispatch] = useReducer(fetchReducer, initialState);
|
||||
|
||||
useEffect(() => {
|
||||
// Do nothing if the url is not given
|
||||
const fetchCallback = useCallback(() => {
|
||||
if (!url) return;
|
||||
|
||||
const fetchData = async () => {
|
||||
@ -56,8 +57,8 @@ function useFetch<T = unknown>(url?: string, options?: RequestInit): State<T> {
|
||||
}
|
||||
|
||||
const data = (await response.json()) as T;
|
||||
if ("error" in data) {
|
||||
// @ts-ignore
|
||||
if ('error' in data) {
|
||||
// @ts-ignore - data.error
|
||||
throw new Error(data.error);
|
||||
}
|
||||
if (cancelRequest.current) return;
|
||||
@ -72,15 +73,23 @@ function useFetch<T = unknown>(url?: string, options?: RequestInit): State<T> {
|
||||
|
||||
void fetchData();
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [url]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchCallback();
|
||||
// Use the cleanup function for avoiding a possibly...
|
||||
// ...state update after the component was unmounted
|
||||
return () => {
|
||||
cancelRequest.current = true;
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [url]);
|
||||
// Do nothing if the url is not given
|
||||
}, [fetchCallback]);
|
||||
|
||||
return state;
|
||||
return {
|
||||
state,
|
||||
refetch: fetchCallback,
|
||||
};
|
||||
}
|
||||
|
||||
export default useFetch;
|
||||
|
@ -1,40 +1,27 @@
|
||||
import { DATA_SOURCES } from '../../../config';
|
||||
import useFetch from '../../../hooks/use-fetch';
|
||||
import { NewBlockMessage } from '../tendermint-new-block';
|
||||
import { TendermintBlockchainResponse } from '../tendermint-blockchain-response';
|
||||
import { useTendermintWebsocket } from '../../../hooks/use-tendermint-websocket';
|
||||
|
||||
const MAX_BLOCKS = 10;
|
||||
import { BlocksTable } from '../../../components/blocks';
|
||||
import { JumpToBlock } from '../../../components/jump-to-block';
|
||||
|
||||
const Blocks = () => {
|
||||
const { messages: blocks } = useTendermintWebsocket<NewBlockMessage>(
|
||||
{
|
||||
query: "tm.event = 'NewBlock'",
|
||||
},
|
||||
MAX_BLOCKS
|
||||
);
|
||||
const { data } = useFetch<TendermintBlockchainResponse>(
|
||||
const {
|
||||
state: { data },
|
||||
refetch,
|
||||
} = useFetch<TendermintBlockchainResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/blockchain`
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<section>
|
||||
<h1>Blocks</h1>
|
||||
<h2>Blocks from blockchain</h2>
|
||||
{`${DATA_SOURCES.tendermintUrl}/blockchain`}
|
||||
<br />
|
||||
<div>Height: {data?.result?.last_height || 0}</div>
|
||||
<br />
|
||||
<div>
|
||||
<br />
|
||||
<pre>{JSON.stringify(data, null, ' ')}</pre>
|
||||
</div>
|
||||
<h2>Blocks streamed in</h2>
|
||||
<div>
|
||||
<br />
|
||||
<pre>{JSON.stringify(blocks, null, ' ')}</pre>
|
||||
</div>
|
||||
<button onClick={() => refetch()}>Refresh to see latest blocks</button>
|
||||
<BlocksTable data={data} />
|
||||
</section>
|
||||
|
||||
<JumpToBlock />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -7,22 +7,24 @@ import { TendermintBlocksResponse } from '../tendermint-blocks-response';
|
||||
|
||||
const Block = () => {
|
||||
const { block } = useParams<{ block: string }>();
|
||||
const { data: decodedBlockData } = useFetch<ChainExplorerTxResponse[]>(
|
||||
DATA_SOURCES.chainExplorerUrl,
|
||||
{
|
||||
const {
|
||||
state: { data: decodedBlockData },
|
||||
} = useFetch<ChainExplorerTxResponse[]>(DATA_SOURCES.chainExplorerUrl, {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
block_height: parseInt(block!),
|
||||
node_url: `${DATA_SOURCES.tendermintUrl}/`,
|
||||
}),
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const { data: blockData } = useFetch<TendermintBlocksResponse>(
|
||||
const {
|
||||
state: { data: blockData },
|
||||
} = useFetch<TendermintBlocksResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/block?height=${block}`
|
||||
);
|
||||
|
||||
|
@ -4,7 +4,9 @@ import useFetch from '../../hooks/use-fetch';
|
||||
import { TendermintGenesisResponse } from './tendermint-genesis-response';
|
||||
|
||||
const Genesis = () => {
|
||||
const { data: genesis } = useFetch<TendermintGenesisResponse>(
|
||||
const {
|
||||
state: { data: genesis },
|
||||
} = useFetch<TendermintGenesisResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/genesis`
|
||||
);
|
||||
if (!genesis?.result.genesis) return null;
|
||||
|
@ -3,7 +3,7 @@
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AccountType } from './../../../../../__generated__/globalTypes';
|
||||
import { AccountType } from '../../../../../__generated__/globalTypes';
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: PartyAssetsQuery
|
||||
@ -123,5 +123,5 @@ export interface PartyAssetsQuery {
|
||||
}
|
||||
|
||||
export interface PartyAssetsQueryVariables {
|
||||
partyId: string;
|
||||
partyId: string | undefined;
|
||||
}
|
||||
|
@ -47,7 +47,9 @@ const PARTY_ASSETS_QUERY = gql`
|
||||
|
||||
const Party = () => {
|
||||
const { party } = useParams<{ party: string }>();
|
||||
const { data: partyData } = useFetch<TendermintSearchTransactionResponse>(
|
||||
const {
|
||||
state: { data: partyData },
|
||||
} = useFetch<TendermintSearchTransactionResponse>(
|
||||
`${DATA_SOURCES.tendermintWebsocketUrl}/tx_search?query="tx.submitter=%27${party}%27"`
|
||||
);
|
||||
|
||||
@ -56,7 +58,7 @@ const Party = () => {
|
||||
{
|
||||
// Don't cache data for this query, party information can move quite quickly
|
||||
fetchPolicy: 'network-only',
|
||||
variables: { partyId: party!.replace('0x', '') },
|
||||
variables: { partyId: party?.replace('0x', '') },
|
||||
skip: !party,
|
||||
}
|
||||
);
|
||||
|
@ -1,25 +1,26 @@
|
||||
import React from "react";
|
||||
import { DATA_SOURCES } from "../../../config";
|
||||
import useFetch from "../../../hooks/use-fetch";
|
||||
import { TendermintUnconfirmedTransactionsResponse } from "../tendermint-unconfirmed-transactions-response.d";
|
||||
import React from 'react';
|
||||
import { DATA_SOURCES } from '../../../config';
|
||||
import useFetch from '../../../hooks/use-fetch';
|
||||
import { TendermintUnconfirmedTransactionsResponse } from '../tendermint-unconfirmed-transactions-response.d';
|
||||
import { TxList } from '../../../components/txs';
|
||||
|
||||
const Txs = () => {
|
||||
const { data: unconfirmedTransactions } =
|
||||
useFetch<TendermintUnconfirmedTransactionsResponse>(
|
||||
const {
|
||||
state: { data: unconfirmedTransactions },
|
||||
} = useFetch<TendermintUnconfirmedTransactionsResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/unconfirmed_txs`
|
||||
);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1>Tx</h1>
|
||||
<h2>Unconfirmed transactions</h2>
|
||||
<h1>Unconfirmed transactions</h1>
|
||||
https://lb.testnet.vega.xyz/tm/unconfirmed_txs
|
||||
<br />
|
||||
<div>Number: {unconfirmedTransactions?.result?.n_txs || 0}</div>
|
||||
<br />
|
||||
<div>
|
||||
<br />
|
||||
{JSON.stringify(unconfirmedTransactions, null, " ")}
|
||||
<TxList data={unconfirmedTransactions} />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
@ -4,23 +4,24 @@ import { DATA_SOURCES } from '../../../config';
|
||||
import useFetch from '../../../hooks/use-fetch';
|
||||
import { ChainExplorerTxResponse } from '../../types/chain-explorer-response';
|
||||
import { TendermintTransactionResponse } from '../tendermint-transaction-response.d';
|
||||
import { TxDetails, TxContent } from '../../../components/transaction';
|
||||
import { TxDetails, TxContent } from '../../../components/txs';
|
||||
|
||||
const Tx = () => {
|
||||
const { txHash } = useParams<{ txHash: string }>();
|
||||
const { data: transactionData } = useFetch<TendermintTransactionResponse>(
|
||||
const {
|
||||
state: { data: transactionData },
|
||||
} = useFetch<TendermintTransactionResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/tx?hash=${txHash}`
|
||||
);
|
||||
const { data: decodedData } = useFetch<ChainExplorerTxResponse>(
|
||||
DATA_SOURCES.chainExplorerUrl,
|
||||
{
|
||||
const {
|
||||
state: { data: decodedData },
|
||||
} = useFetch<ChainExplorerTxResponse>(DATA_SOURCES.chainExplorerUrl, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
tx_hash: txHash,
|
||||
node_url: `${DATA_SOURCES.tendermintUrl}/`,
|
||||
}),
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<section>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { gql, useQuery } from "@apollo/client";
|
||||
import React from "react";
|
||||
import { DATA_SOURCES } from "../../config";
|
||||
import useFetch from "../../hooks/use-fetch";
|
||||
import { TendermintValidatorsResponse } from "./tendermint-validator-response";
|
||||
import { NodesQuery } from "./__generated__/NodesQuery";
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import React from 'react';
|
||||
import { DATA_SOURCES } from '../../config';
|
||||
import useFetch from '../../hooks/use-fetch';
|
||||
import { TendermintValidatorsResponse } from './tendermint-validator-response';
|
||||
import { NodesQuery } from './__generated__/NodesQuery';
|
||||
|
||||
const NODES_QUERY = gql`
|
||||
query NodesQuery {
|
||||
@ -34,7 +34,9 @@ const NODES_QUERY = gql`
|
||||
`;
|
||||
|
||||
const Validators = () => {
|
||||
const { data: validators } = useFetch<TendermintValidatorsResponse>(
|
||||
const {
|
||||
state: { data: validators },
|
||||
} = useFetch<TendermintValidatorsResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/validators`
|
||||
);
|
||||
const { data } = useQuery<NodesQuery>(NODES_QUERY);
|
||||
@ -43,9 +45,9 @@ const Validators = () => {
|
||||
<section>
|
||||
<h1>Validators</h1>
|
||||
<h2>Tendermint data</h2>
|
||||
<pre>{JSON.stringify(validators, null, " ")}</pre>
|
||||
<pre>{JSON.stringify(validators, null, ' ')}</pre>
|
||||
<h2>Vega data</h2>
|
||||
<pre>{JSON.stringify(data, null, " ")}</pre>
|
||||
<pre>{JSON.stringify(data, null, ' ')}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user