Added a component to render fetched data to include loading and error states. Added to all instances of useFetch
This commit is contained in:
parent
061388938c
commit
477e3faa6e
@ -6,11 +6,15 @@ import { Table, TableRow, TableCell } from '../table';
|
|||||||
|
|
||||||
interface BlockProps {
|
interface BlockProps {
|
||||||
block: BlockMeta;
|
block: BlockMeta;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BlockData = ({ block }: BlockProps) => {
|
export const BlockData = ({ block, className }: BlockProps) => {
|
||||||
return (
|
return (
|
||||||
<Table aria-label={`Data for block ${block.header?.height}`}>
|
<Table
|
||||||
|
aria-label={`Data for block ${block.header?.height}`}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
<TableRow dataTestId="block-row" modifier="background">
|
<TableRow dataTestId="block-row" modifier="background">
|
||||||
<TableCell
|
<TableCell
|
||||||
dataTestId="block-height"
|
dataTestId="block-height"
|
||||||
|
27
apps/explorer/src/app/components/render-fetched/index.tsx
Normal file
27
apps/explorer/src/app/components/render-fetched/index.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { StatusMessage } from '../status-message';
|
||||||
|
|
||||||
|
interface RenderFetchedProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
error: Error | undefined;
|
||||||
|
loading: boolean | undefined;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RenderFetched = ({
|
||||||
|
error,
|
||||||
|
loading,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
}: RenderFetchedProps) => {
|
||||||
|
if (loading) {
|
||||||
|
return <StatusMessage className={className}>Loading...</StatusMessage>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <StatusMessage className={className}>Error: {error}</StatusMessage>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
@ -7,6 +7,6 @@ interface StatusMessageProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const StatusMessage = ({ children, className }: StatusMessageProps) => {
|
export const StatusMessage = ({ children, className }: StatusMessageProps) => {
|
||||||
const classes = classnames('font-alpha', 'text-h4', 'mb-28', className);
|
const classes = classnames('font-alpha text-h4 mb-28', className);
|
||||||
return <h3 className={classes}>{children}</h3>;
|
return <h3 className={classes}>{children}</h3>;
|
||||||
};
|
};
|
||||||
|
@ -8,9 +8,12 @@ interface TxsProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TxsData = ({ data, className }: TxsProps) => {
|
export const BlockTxsData = ({ data, className }: TxsProps) => {
|
||||||
if (!data?.result) {
|
if (!data?.result) {
|
||||||
return <div className={className}>Awaiting block data</div>;
|
// Data for the block has already been fetched at this point, so no errors
|
||||||
|
// or loading to deal with. This is specifically the case
|
||||||
|
// where the data object is not undefined, but lacks a result.
|
||||||
|
return <div className={className}>No data</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -21,7 +24,7 @@ export const TxsData = ({ data, className }: TxsProps) => {
|
|||||||
{data.result?.block_metas?.map((block, index) => {
|
{data.result?.block_metas?.map((block, index) => {
|
||||||
return (
|
return (
|
||||||
<li key={index} data-testid="block-row">
|
<li key={index} data-testid="block-row">
|
||||||
<BlockData block={block} />
|
<BlockData block={block} className="mb-12" />
|
||||||
<TxsPerBlock blockHeight={block.header.height} />
|
<TxsPerBlock blockHeight={block.header.height} />
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
@ -1,4 +1,4 @@
|
|||||||
export { TxDetails } from './id/tx-details';
|
export { TxDetails } from './id/tx-details';
|
||||||
export { TxContent } from './id/tx-content';
|
export { TxContent } from './id/tx-content';
|
||||||
export { TxList } from './pending/tx-list';
|
export { TxList } from './pending/tx-list';
|
||||||
export { TxsData } from './home/txs-data';
|
export { BlockTxsData } from './home/block-txs-data';
|
||||||
|
@ -2,6 +2,7 @@ import useFetch from '../../../hooks/use-fetch';
|
|||||||
import { ChainExplorerTxResponse } from '../../../routes/types/chain-explorer-response';
|
import { ChainExplorerTxResponse } from '../../../routes/types/chain-explorer-response';
|
||||||
import { DATA_SOURCES } from '../../../config';
|
import { DATA_SOURCES } from '../../../config';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { RenderFetched } from '../../render-fetched';
|
||||||
import { TruncateInline } from '../../truncate/truncate';
|
import { TruncateInline } from '../../truncate/truncate';
|
||||||
|
|
||||||
interface TxsPerBlockProps {
|
interface TxsPerBlockProps {
|
||||||
@ -12,7 +13,7 @@ const truncateLength = 14;
|
|||||||
|
|
||||||
export const TxsPerBlock = ({ blockHeight }: TxsPerBlockProps) => {
|
export const TxsPerBlock = ({ blockHeight }: TxsPerBlockProps) => {
|
||||||
const {
|
const {
|
||||||
state: { data: decodedBlockData },
|
state: { data: decodedBlockData, loading, error },
|
||||||
} = useFetch<ChainExplorerTxResponse[]>(DATA_SOURCES.chainExplorerUrl, {
|
} = useFetch<ChainExplorerTxResponse[]>(DATA_SOURCES.chainExplorerUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
mode: 'cors',
|
mode: 'cors',
|
||||||
@ -27,44 +28,46 @@ export const TxsPerBlock = ({ blockHeight }: TxsPerBlockProps) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-x-auto whitespace-nowrap mb-28">
|
<RenderFetched error={error} loading={loading} className="text-body-large">
|
||||||
<table className="w-full">
|
<div className="overflow-x-auto whitespace-nowrap mb-28">
|
||||||
<thead>
|
<table className="w-full">
|
||||||
<tr className="font-mono">
|
<thead>
|
||||||
<td>Transaction</td>
|
<tr className="font-mono">
|
||||||
<td>From</td>
|
<td>Transaction</td>
|
||||||
<td>Type</td>
|
<td>From</td>
|
||||||
</tr>
|
<td>Type</td>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
{decodedBlockData &&
|
<tbody>
|
||||||
decodedBlockData.map(({ TxHash, PubKey, Type }, index) => {
|
{decodedBlockData &&
|
||||||
return (
|
decodedBlockData.map(({ TxHash, PubKey, Type }) => {
|
||||||
<tr key={TxHash}>
|
return (
|
||||||
<td>
|
<tr key={TxHash}>
|
||||||
<Link to={`/txs/${TxHash}`}>
|
<td>
|
||||||
|
<Link to={`/txs/${TxHash}`}>
|
||||||
|
<TruncateInline
|
||||||
|
text={TxHash}
|
||||||
|
startChars={truncateLength}
|
||||||
|
endChars={truncateLength}
|
||||||
|
className="text-vega-yellow font-mono"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
<TruncateInline
|
<TruncateInline
|
||||||
text={TxHash}
|
text={PubKey}
|
||||||
startChars={truncateLength}
|
startChars={truncateLength}
|
||||||
endChars={truncateLength}
|
endChars={truncateLength}
|
||||||
className="text-vega-yellow font-mono"
|
className="font-mono"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</td>
|
||||||
</td>
|
<td>{Type}</td>
|
||||||
<td>
|
</tr>
|
||||||
<TruncateInline
|
);
|
||||||
text={PubKey}
|
})}
|
||||||
startChars={truncateLength}
|
</tbody>
|
||||||
endChars={truncateLength}
|
</table>
|
||||||
className="font-mono"
|
</div>
|
||||||
/>
|
</RenderFetched>
|
||||||
</td>
|
|
||||||
<td>{Type}</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@ import { DATA_SOURCES } from '../../../config';
|
|||||||
import useFetch from '../../../hooks/use-fetch';
|
import useFetch from '../../../hooks/use-fetch';
|
||||||
import { TendermintBlockchainResponse } from '../tendermint-blockchain-response';
|
import { TendermintBlockchainResponse } from '../tendermint-blockchain-response';
|
||||||
import { RouteTitle } from '../../../components/route-title';
|
import { RouteTitle } from '../../../components/route-title';
|
||||||
import { StatusMessage } from '../../../components/status-message';
|
import { RenderFetched } from '../../../components/render-fetched';
|
||||||
import { BlocksData, BlocksRefetch } from '../../../components/blocks';
|
import { BlocksData, BlocksRefetch } from '../../../components/blocks';
|
||||||
import { JumpToBlock } from '../../../components/jump-to-block';
|
import { JumpToBlock } from '../../../components/jump-to-block';
|
||||||
|
|
||||||
@ -17,14 +17,12 @@ const Blocks = () => {
|
|||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<RouteTitle>Blocks</RouteTitle>
|
<RouteTitle>Blocks</RouteTitle>
|
||||||
{loading && <StatusMessage>Loading...</StatusMessage>}
|
<RenderFetched error={error} loading={loading}>
|
||||||
{error && <StatusMessage>Error: {error}</StatusMessage>}
|
|
||||||
{data && (
|
|
||||||
<>
|
<>
|
||||||
<BlocksRefetch refetch={refetch} />
|
<BlocksRefetch refetch={refetch} />
|
||||||
<BlocksData data={data} className="mb-28" />
|
<BlocksData data={data} className="mb-28" />
|
||||||
</>
|
</>
|
||||||
)}
|
</RenderFetched>
|
||||||
<JumpToBlock />
|
<JumpToBlock />
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
@ -3,12 +3,13 @@ import { TendermintBlockchainResponse } from '../../blocks/tendermint-blockchain
|
|||||||
import { DATA_SOURCES } from '../../../config';
|
import { DATA_SOURCES } from '../../../config';
|
||||||
import { RouteTitle } from '../../../components/route-title';
|
import { RouteTitle } from '../../../components/route-title';
|
||||||
import { BlocksRefetch } from '../../../components/blocks';
|
import { BlocksRefetch } from '../../../components/blocks';
|
||||||
import { TxsData } from '../../../components/txs';
|
import { RenderFetched } from '../../../components/render-fetched';
|
||||||
|
import { BlockTxsData } from '../../../components/txs';
|
||||||
import { JumpToBlock } from '../../../components/jump-to-block';
|
import { JumpToBlock } from '../../../components/jump-to-block';
|
||||||
|
|
||||||
const Txs = () => {
|
const Txs = () => {
|
||||||
const {
|
const {
|
||||||
state: { data },
|
state: { data, error, loading },
|
||||||
refetch,
|
refetch,
|
||||||
} = useFetch<TendermintBlockchainResponse>(
|
} = useFetch<TendermintBlockchainResponse>(
|
||||||
`${DATA_SOURCES.tendermintUrl}/blockchain`
|
`${DATA_SOURCES.tendermintUrl}/blockchain`
|
||||||
@ -17,8 +18,12 @@ const Txs = () => {
|
|||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<RouteTitle>Transactions</RouteTitle>
|
<RouteTitle>Transactions</RouteTitle>
|
||||||
<BlocksRefetch refetch={refetch} />
|
<RenderFetched error={error} loading={loading}>
|
||||||
<TxsData data={data} />
|
<>
|
||||||
|
<BlocksRefetch refetch={refetch} />
|
||||||
|
<BlockTxsData data={data} />
|
||||||
|
</>
|
||||||
|
</RenderFetched>
|
||||||
<JumpToBlock />
|
<JumpToBlock />
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user