fix(explorer): improve search errors (#2327)
* feat(explorer): clearer errors on parties and txs
This commit is contained in:
parent
9f1a1d7a1b
commit
0a11831ab0
@ -7,6 +7,7 @@ interface RenderFetchedProps {
|
||||
error: Error | undefined;
|
||||
loading: boolean | undefined;
|
||||
className?: string;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
export const RenderFetched = ({
|
||||
@ -14,6 +15,7 @@ export const RenderFetched = ({
|
||||
loading,
|
||||
children,
|
||||
className,
|
||||
errorMessage = t('Error retrieving data'),
|
||||
}: RenderFetchedProps) => {
|
||||
if (loading) {
|
||||
return (
|
||||
@ -22,11 +24,7 @@ export const RenderFetched = ({
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<StatusMessage className={className}>
|
||||
{t('Error retrieving data')}
|
||||
</StatusMessage>
|
||||
);
|
||||
return <StatusMessage className={className}>{errorMessage}</StatusMessage>;
|
||||
}
|
||||
|
||||
return children;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { Button, Input, InputError } from '@vegaprotocol/ui-toolkit';
|
||||
import { useForm } from 'react-hook-form';
|
||||
@ -69,7 +69,7 @@ export const Search = () => {
|
||||
placeholder={t('Enter block number, party id or transaction hash')}
|
||||
/>
|
||||
{error?.message && (
|
||||
<div className="bg-white border border-t-0 border-accent absolute top-[100%] flex-1 w-full pb-2 px-2 rounded-b">
|
||||
<div className="bg-white border border-t-0 border-accent absolute top-[100%] flex-1 w-full pb-2 px-2 rounded-b text-black">
|
||||
<InputError data-testid="search-error" intent="danger">
|
||||
{error.message}
|
||||
</InputError>
|
||||
|
@ -31,7 +31,7 @@ export const TxDetailsOrder = ({
|
||||
|
||||
let deterministicId = '';
|
||||
|
||||
const sig = txData.signature.value as string;
|
||||
const sig = txData?.signature?.value;
|
||||
if (sig) {
|
||||
deterministicId = txSignatureToDeterministicId(sig);
|
||||
}
|
||||
|
@ -6,13 +6,15 @@ import { TxOrderType } from './tx-order-type';
|
||||
import { Table, TableRow, TableCell } from '../table';
|
||||
import { t, useFetch } from '@vegaprotocol/react-helpers';
|
||||
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
|
||||
import isNumber from 'lodash/isNumber';
|
||||
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
|
||||
|
||||
interface TxsPerBlockProps {
|
||||
blockHeight: string;
|
||||
txCount: number;
|
||||
}
|
||||
|
||||
const truncateLength = 14;
|
||||
const truncateLength = 5;
|
||||
|
||||
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||
// TODO after https://github.com/vegaprotocol/vega/pull/6958/files is merged and deployed, use filter
|
||||
@ -22,8 +24,9 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||
} = useFetch<BlockExplorerTransactions>(
|
||||
`${
|
||||
DATA_SOURCES.blockExplorerUrl
|
||||
}/transactions/before=${blockHeight.toString()}.0&limit=${txCount}`
|
||||
}/transactions?before=${blockHeight.toString()}.0&limit=${txCount}`
|
||||
);
|
||||
|
||||
return (
|
||||
<RenderFetched error={error} loading={loading} className="text-body-large">
|
||||
{data && data.transactions.length > 0 ? (
|
||||
@ -34,38 +37,54 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||
<td>{t('Transaction')}</td>
|
||||
<td>{t('From')}</td>
|
||||
<td>{t('Type')}</td>
|
||||
<td>{t('Status')}</td>
|
||||
</TableRow>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.transactions.map(({ hash, submitter, type, command }) => {
|
||||
return (
|
||||
<TableRow
|
||||
modifier="bordered"
|
||||
key={hash}
|
||||
data-testid="transaction-row"
|
||||
>
|
||||
<TableCell modifier="bordered" className="pr-12">
|
||||
<TruncatedLink
|
||||
to={`/${Routes.TX}/${hash}`}
|
||||
text={hash}
|
||||
startChars={truncateLength}
|
||||
endChars={truncateLength}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell modifier="bordered" className="pr-12">
|
||||
<TruncatedLink
|
||||
to={`/${Routes.PARTIES}/${submitter}`}
|
||||
text={submitter}
|
||||
startChars={truncateLength}
|
||||
endChars={truncateLength}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell modifier="bordered">
|
||||
<TxOrderType orderType={type} command={command} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
{data.transactions.map(
|
||||
({ hash, submitter, type, command, code }) => {
|
||||
return (
|
||||
<TableRow
|
||||
modifier="bordered"
|
||||
key={hash}
|
||||
data-testid="transaction-row"
|
||||
>
|
||||
<TableCell
|
||||
modifier="bordered"
|
||||
className="pr-12 font-mono"
|
||||
>
|
||||
<TruncatedLink
|
||||
to={`/${Routes.TX}/${hash}`}
|
||||
text={hash}
|
||||
startChars={truncateLength}
|
||||
endChars={truncateLength}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
modifier="bordered"
|
||||
className="pr-12 font-mono"
|
||||
>
|
||||
<TruncatedLink
|
||||
to={`/${Routes.PARTIES}/${submitter}`}
|
||||
text={submitter}
|
||||
startChars={truncateLength}
|
||||
endChars={truncateLength}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell modifier="bordered">
|
||||
<TxOrderType orderType={type} command={command} />
|
||||
</TableCell>
|
||||
<TableCell modifier="bordered" className="text">
|
||||
{isNumber(code) ? (
|
||||
<ChainResponseCode code={code} hideLabel={true} />
|
||||
) : (
|
||||
code
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</tbody>
|
||||
</Table>
|
||||
</div>
|
||||
|
@ -0,0 +1,27 @@
|
||||
import { remove0x, t } from '@vegaprotocol/react-helpers';
|
||||
import type { ApolloError } from '@apollo/client';
|
||||
|
||||
export function isValidPartyId(rawId: string) {
|
||||
const id = (rawId = remove0x(rawId));
|
||||
return id.length === 64;
|
||||
}
|
||||
|
||||
type PartyIdErrorProps = {
|
||||
id: string;
|
||||
error: ApolloError;
|
||||
};
|
||||
|
||||
const PartyIdError = ({ id, error }: PartyIdErrorProps) => {
|
||||
const end = isValidPartyId(id)
|
||||
? t('No accounts or transactions found for: ')
|
||||
: 'Invalid party id: ';
|
||||
return (
|
||||
<section>
|
||||
<p>
|
||||
{end} <code>{id}</code>
|
||||
</p>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default PartyIdError;
|
@ -15,6 +15,7 @@ import { PageHeader } from '../../../components/page-header';
|
||||
import { useExplorerPartyAssetsQuery } from './__generated__/party-assets';
|
||||
import type { Schema } from '@vegaprotocol/types';
|
||||
import get from 'lodash/get';
|
||||
import PartyIdError from './error/party-id-error';
|
||||
|
||||
const accountTypeString: Record<Schema.AccountType, string> = {
|
||||
ACCOUNT_TYPE_BOND: t('Bond'),
|
||||
@ -46,14 +47,14 @@ const Party = () => {
|
||||
filters,
|
||||
});
|
||||
|
||||
const { data } = useExplorerPartyAssetsQuery({
|
||||
const partyRes = useExplorerPartyAssetsQuery({
|
||||
// Don't cache data for this query, party information can move quite quickly
|
||||
fetchPolicy: 'network-only',
|
||||
variables: { partyId: partyId },
|
||||
skip: !party,
|
||||
});
|
||||
|
||||
const p = data?.partiesConnection?.edges[0].node;
|
||||
const p = partyRes.data?.partiesConnection?.edges[0].node;
|
||||
|
||||
const header = p?.id ? (
|
||||
<PageHeader
|
||||
@ -133,7 +134,10 @@ const Party = () => {
|
||||
>
|
||||
{t('Party')}
|
||||
</h1>
|
||||
{data ? (
|
||||
{partyRes.error ? (
|
||||
<PartyIdError id={partyId} error={partyRes.error} />
|
||||
) : null}
|
||||
{partyRes.data ? (
|
||||
<>
|
||||
{header}
|
||||
<SubHeading>{t('Asset data')}</SubHeading>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { remove0x, useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { DATA_SOURCES } from '../../../config';
|
||||
import { RenderFetched } from '../../../components/render-fetched';
|
||||
import { TxDetails } from './tx-details';
|
||||
@ -14,13 +14,20 @@ import { Icon } from '@vegaprotocol/ui-toolkit';
|
||||
const Tx = () => {
|
||||
const { txHash } = useParams<{ txHash: string }>();
|
||||
const hash = txHash ? toNonHex(txHash) : '';
|
||||
let errorMessage: string | undefined = undefined;
|
||||
|
||||
const {
|
||||
state: { data, loading: tTxLoading, error: tTxError },
|
||||
state: { data, loading, error },
|
||||
} = useFetch<BlockExplorerTransaction>(
|
||||
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(hash)}`
|
||||
);
|
||||
|
||||
if (error) {
|
||||
if (remove0x(hash).length !== 64) {
|
||||
errorMessage = 'Invalid transaction hash';
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Link
|
||||
@ -41,7 +48,11 @@ const Tx = () => {
|
||||
className="mb-5"
|
||||
/>
|
||||
|
||||
<RenderFetched error={tTxError} loading={tTxLoading}>
|
||||
<RenderFetched
|
||||
error={error}
|
||||
loading={loading}
|
||||
errorMessage={errorMessage}
|
||||
>
|
||||
<TxDetails
|
||||
className="mb-28"
|
||||
txData={data?.transaction}
|
||||
|
Loading…
Reference in New Issue
Block a user