Feat/1682 fix api endpoints (#1690)
* chore(explorer): replace tendermint api with block explorer api for transaction related searches * feat(explorer): replace detect search type to be by process of elimination as temp measure * fix(explorer): fix broken tests
This commit is contained in:
parent
0b8c9c836c
commit
a7d100bce8
@ -89,8 +89,8 @@ describe('Detect Search', () => {
|
||||
expect(actual).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it("detectTypeByFetching should call fetch with hex query it's a transaction", async () => {
|
||||
const query = 'abc';
|
||||
it("detectTypeByFetching should call fetch with non-hex query it's a transaction", async () => {
|
||||
const query = '0xabc';
|
||||
const type = SearchTypes.Transaction;
|
||||
// @ts-ignore issue related to polyfill
|
||||
fetch.mockImplementation(
|
||||
@ -99,45 +99,21 @@ describe('Detect Search', () => {
|
||||
ok: true,
|
||||
json: () =>
|
||||
Promise.resolve({
|
||||
result: {
|
||||
tx: query,
|
||||
transaction: {
|
||||
hash: query,
|
||||
},
|
||||
}),
|
||||
})
|
||||
)
|
||||
);
|
||||
const result = await detectTypeByFetching(query, type);
|
||||
const result = await detectTypeByFetching(query);
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
`${DATA_SOURCES.tendermintUrl}/tx?hash=0x${query}`
|
||||
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(query)}`
|
||||
);
|
||||
expect(result).toBe(type);
|
||||
});
|
||||
|
||||
it("detectTypeByFetching should call fetch with non-hex query it's a party", async () => {
|
||||
const query = 'abc';
|
||||
const type = SearchTypes.Party;
|
||||
// @ts-ignore issue related to polyfill
|
||||
fetch.mockImplementation(
|
||||
jest.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () =>
|
||||
Promise.resolve({
|
||||
result: {
|
||||
txs: [query],
|
||||
},
|
||||
}),
|
||||
})
|
||||
)
|
||||
);
|
||||
const result = await detectTypeByFetching(query, type);
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
`${DATA_SOURCES.tendermintUrl}/tx_search?query="tx.submitter='${query}'"`
|
||||
);
|
||||
expect(result).toBe(type);
|
||||
});
|
||||
|
||||
it('detectTypeByFetching should return undefined if no matches', async () => {
|
||||
const query = 'abc';
|
||||
const type = SearchTypes.Party;
|
||||
// @ts-ignore issue related to polyfill
|
||||
@ -148,11 +124,8 @@ describe('Detect Search', () => {
|
||||
})
|
||||
)
|
||||
);
|
||||
const result = await detectTypeByFetching(query, type);
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
`${DATA_SOURCES.tendermintUrl}/tx_search?query="tx.submitter='${query}'"`
|
||||
);
|
||||
expect(result).toBe(undefined);
|
||||
const result = await detectTypeByFetching(query);
|
||||
expect(result).toBe(type);
|
||||
});
|
||||
|
||||
it('getSearchType should return party from fetch response', async () => {
|
||||
@ -163,13 +136,7 @@ describe('Detect Search', () => {
|
||||
fetch.mockImplementation(
|
||||
jest.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () =>
|
||||
Promise.resolve({
|
||||
result: {
|
||||
txs: [query],
|
||||
},
|
||||
}),
|
||||
ok: false,
|
||||
})
|
||||
)
|
||||
);
|
||||
@ -177,7 +144,7 @@ describe('Detect Search', () => {
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
it('getSearchType should return party from transaction response', async () => {
|
||||
it('getSearchType should return transaction from fetch response', async () => {
|
||||
const query =
|
||||
'4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
|
||||
const expected = SearchTypes.Transaction;
|
||||
@ -188,8 +155,8 @@ describe('Detect Search', () => {
|
||||
ok: true,
|
||||
json: () =>
|
||||
Promise.resolve({
|
||||
result: {
|
||||
tx: query,
|
||||
transaction: {
|
||||
hash: query,
|
||||
},
|
||||
}),
|
||||
})
|
||||
@ -200,17 +167,8 @@ describe('Detect Search', () => {
|
||||
});
|
||||
|
||||
it('getSearchType should return undefined from transaction response', async () => {
|
||||
const query =
|
||||
'0x4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
|
||||
const query = 'u';
|
||||
const expected = undefined;
|
||||
// @ts-ignore issue related to polyfill
|
||||
fetch.mockImplementation(
|
||||
jest.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: false,
|
||||
})
|
||||
)
|
||||
);
|
||||
const result = await getSearchType(query);
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { DATA_SOURCES } from '../../config';
|
||||
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
|
||||
|
||||
export enum SearchTypes {
|
||||
Transaction = 'transaction',
|
||||
@ -42,46 +43,88 @@ export const detectTypeFromQuery = (
|
||||
};
|
||||
|
||||
export const detectTypeByFetching = async (
|
||||
query: string,
|
||||
type: SearchTypes
|
||||
query: string
|
||||
): Promise<SearchTypes | undefined> => {
|
||||
const TYPES = [SearchTypes.Party, SearchTypes.Transaction];
|
||||
const hash = toNonHex(query);
|
||||
const request = await fetch(
|
||||
`${DATA_SOURCES.blockExplorerUrl}/transactions/${hash}`
|
||||
);
|
||||
|
||||
if (!TYPES.includes(type)) {
|
||||
throw new Error('Search type provided not recognised');
|
||||
}
|
||||
if (request?.ok) {
|
||||
const body: BlockExplorerTransaction = await request.json();
|
||||
|
||||
if (type === SearchTypes.Transaction) {
|
||||
const hash = toHex(query);
|
||||
const request = await fetch(
|
||||
`${DATA_SOURCES.tendermintUrl}/tx?hash=${hash}`
|
||||
);
|
||||
|
||||
if (request?.ok) {
|
||||
const body = await request.json();
|
||||
|
||||
if (body?.result?.tx) {
|
||||
return SearchTypes.Transaction;
|
||||
}
|
||||
}
|
||||
} else if (type === SearchTypes.Party) {
|
||||
const party = toNonHex(query);
|
||||
const request = await fetch(
|
||||
`${DATA_SOURCES.tendermintUrl}/tx_search?query="tx.submitter='${party}'"`
|
||||
);
|
||||
|
||||
if (request.ok) {
|
||||
const body = await request.json();
|
||||
|
||||
if (body?.result?.txs?.length) {
|
||||
return SearchTypes.Party;
|
||||
}
|
||||
if (body?.transaction) {
|
||||
return SearchTypes.Transaction;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return SearchTypes.Party;
|
||||
};
|
||||
|
||||
// Code commented out because the current solution to detect a hex is temporary (by process of elimination)
|
||||
// export const detectTypeByFetching = async (
|
||||
// query: string,
|
||||
// type: SearchTypes
|
||||
// ): Promise<SearchTypes | undefined> => {
|
||||
// const TYPES = [SearchTypes.Party, SearchTypes.Transaction];
|
||||
//
|
||||
// if (!TYPES.includes(type)) {
|
||||
// throw new Error('Search type provided not recognised');
|
||||
// }
|
||||
//
|
||||
// if (type === SearchTypes.Transaction) {
|
||||
// const hash = toNonHex(query);
|
||||
// const request = await fetch(
|
||||
// `${DATA_SOURCES.blockExplorerUrl}/transactions/${hash}`
|
||||
// );
|
||||
//
|
||||
// if (request?.ok) {
|
||||
// const body: BlockExplorerTransaction = await request.json();
|
||||
//
|
||||
// if (body?.transaction) {
|
||||
// return SearchTypes.Transaction;
|
||||
// }
|
||||
// }
|
||||
// } else if (type === SearchTypes.Party) {
|
||||
// const party = toNonHex(query);
|
||||
//
|
||||
// const request = await fetch(
|
||||
// `${DATA_SOURCES.blockExplorerUrl}/transactions?limit=1&filters[tx.submitter]=${party}`
|
||||
// );
|
||||
//
|
||||
// if (request.ok) {
|
||||
// const body: BlockExplorerTransactions = await request.json();
|
||||
//
|
||||
// if (body?.transactions?.length) {
|
||||
// return SearchTypes.Party;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return undefined;
|
||||
// };
|
||||
|
||||
// export const getSearchType = async (
|
||||
// query: string
|
||||
// ): Promise<SearchTypes | undefined> => {
|
||||
// const searchTypes = detectTypeFromQuery(query);
|
||||
// const hasResults = searchTypes?.length;
|
||||
//
|
||||
// if (hasResults) {
|
||||
// if (hasResults > 1) {
|
||||
// const promises = searchTypes.map((type) =>
|
||||
// detectTypeByFetching(query, type)
|
||||
// );
|
||||
// const results = await Promise.all(promises);
|
||||
// return results.find((result) => result !== undefined);
|
||||
// }
|
||||
//
|
||||
// return searchTypes[0];
|
||||
// }
|
||||
//
|
||||
// return undefined;
|
||||
// };
|
||||
|
||||
export const getSearchType = async (
|
||||
query: string
|
||||
): Promise<SearchTypes | undefined> => {
|
||||
@ -90,11 +133,7 @@ export const getSearchType = async (
|
||||
|
||||
if (hasResults) {
|
||||
if (hasResults > 1) {
|
||||
const promises = searchTypes.map((type) =>
|
||||
detectTypeByFetching(query, type)
|
||||
);
|
||||
const results = await Promise.all(promises);
|
||||
return results.find((type) => type !== undefined);
|
||||
return await detectTypeByFetching(query);
|
||||
}
|
||||
|
||||
return searchTypes[0];
|
||||
|
@ -22,32 +22,29 @@ export const Search = () => {
|
||||
const query = fields.search;
|
||||
|
||||
if (!query) {
|
||||
setError(new Error(t('Search query required')));
|
||||
} else {
|
||||
const result = await getSearchType(query);
|
||||
const urlAsHex = toHex(query);
|
||||
const unrecognisedError = new Error(
|
||||
t('Transaction type is not recognised')
|
||||
);
|
||||
|
||||
if (result) {
|
||||
switch (result) {
|
||||
case SearchTypes.Party:
|
||||
navigate(`${Routes.PARTIES}/${urlAsHex}`);
|
||||
break;
|
||||
case SearchTypes.Transaction:
|
||||
navigate(`${Routes.TX}/${urlAsHex}`);
|
||||
break;
|
||||
case SearchTypes.Block:
|
||||
navigate(`${Routes.BLOCKS}/${Number(query)}`);
|
||||
break;
|
||||
default:
|
||||
setError(unrecognisedError);
|
||||
}
|
||||
}
|
||||
|
||||
setError(unrecognisedError);
|
||||
return setError(new Error(t('Search query required')));
|
||||
}
|
||||
|
||||
const result = await getSearchType(query);
|
||||
const urlAsHex = toHex(query);
|
||||
const unrecognisedError = new Error(
|
||||
t('Transaction type is not recognised')
|
||||
);
|
||||
|
||||
if (result) {
|
||||
switch (result) {
|
||||
case SearchTypes.Party:
|
||||
return navigate(`${Routes.PARTIES}/${urlAsHex}`);
|
||||
case SearchTypes.Transaction:
|
||||
return navigate(`${Routes.TX}/${urlAsHex}`);
|
||||
case SearchTypes.Block:
|
||||
return navigate(`${Routes.BLOCKS}/${Number(query)}`);
|
||||
default:
|
||||
return setError(unrecognisedError);
|
||||
}
|
||||
}
|
||||
|
||||
return setError(unrecognisedError);
|
||||
},
|
||||
[navigate]
|
||||
);
|
||||
@ -61,22 +58,24 @@ export const Search = () => {
|
||||
{t('Search by block number or transaction hash')}
|
||||
</label>
|
||||
<div className="flex items-stretch gap-2">
|
||||
<Input
|
||||
{...register('search')}
|
||||
id="search"
|
||||
data-testid="search"
|
||||
className="text-white"
|
||||
hasError={Boolean(error?.message)}
|
||||
type="text"
|
||||
placeholder={t('Enter block number, party id or transaction hash')}
|
||||
/>
|
||||
{error?.message && (
|
||||
<div className="absolute top-[100%] flex-1 w-full">
|
||||
<InputError data-testid="search-error" intent="danger">
|
||||
{error.message}
|
||||
</InputError>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex grow relative">
|
||||
<Input
|
||||
{...register('search')}
|
||||
id="search"
|
||||
data-testid="search"
|
||||
className="text-white"
|
||||
hasError={Boolean(error?.message)}
|
||||
type="text"
|
||||
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">
|
||||
<InputError data-testid="search-error" intent="danger">
|
||||
{error.message}
|
||||
</InputError>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Button type="submit" size="sm" data-testid="search-button">
|
||||
{t('Search')}
|
||||
</Button>
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { TruncatedLink } from '../truncate/truncated-link';
|
||||
import { Routes } from '../../routes/route-names';
|
||||
import { TxOrderType } from './tx-order-type';
|
||||
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
|
||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
||||
import { toHex } from '../search/detect-search';
|
||||
|
||||
const TRUNCATE_LENGTH = 14;
|
||||
@ -13,7 +13,7 @@ export const TxsInfiniteListItem = ({
|
||||
type,
|
||||
block,
|
||||
index,
|
||||
}: Partial<BlockExplorerTransaction>) => {
|
||||
}: Partial<BlockExplorerTransactionResult>) => {
|
||||
if (
|
||||
!hash ||
|
||||
!submitter ||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { TxsInfiniteList } from './txs-infinite-list';
|
||||
import { render, screen, fireEvent, act } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
|
||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
||||
|
||||
const generateTxs = (number: number): BlockExplorerTransaction[] => {
|
||||
const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
|
||||
return Array.from(Array(number)).map((_) => ({
|
||||
block: '87901',
|
||||
index: 2,
|
||||
|
@ -3,19 +3,19 @@ import { FixedSizeList as List } from 'react-window';
|
||||
import InfiniteLoader from 'react-window-infinite-loader';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
|
||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
||||
|
||||
interface TxsInfiniteListProps {
|
||||
hasMoreTxs: boolean;
|
||||
areTxsLoading: boolean | undefined;
|
||||
txs: BlockExplorerTransaction[] | undefined;
|
||||
txs: BlockExplorerTransactionResult[] | undefined;
|
||||
loadMoreTxs: () => void;
|
||||
error: Error | undefined;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface ItemProps {
|
||||
index: BlockExplorerTransaction;
|
||||
index: BlockExplorerTransactionResult;
|
||||
style: React.CSSProperties;
|
||||
isLoading: boolean;
|
||||
error: Error | undefined;
|
||||
|
@ -13,12 +13,13 @@ import { SubHeading } from '../../../components/sub-heading';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { Panel } from '../../../components/panel';
|
||||
import { InfoPanel } from '../../../components/info-panel';
|
||||
import { toNonHex } from '../../../components/search/detect-search';
|
||||
import { DATA_SOURCES } from '../../../config';
|
||||
import type { TendermintSearchTransactionResponse } from '../tendermint-transaction-response';
|
||||
import type {
|
||||
PartyAssetsQuery,
|
||||
PartyAssetsQueryVariables,
|
||||
} from './__generated__/PartyAssetsQuery';
|
||||
import type { BlockExplorerTransactions } from '../../../routes/types/block-explorer-response';
|
||||
|
||||
const PARTY_ASSETS_QUERY = gql`
|
||||
query PartyAssetsQuery($partyId: ID!) {
|
||||
@ -57,13 +58,12 @@ const PARTY_ASSETS_QUERY = gql`
|
||||
|
||||
const Party = () => {
|
||||
const { party } = useParams<{ party: string }>();
|
||||
const partyId = party ? toNonHex(party) : '';
|
||||
|
||||
const {
|
||||
state: { data: partyData },
|
||||
} = useFetch<TendermintSearchTransactionResponse>(
|
||||
`${
|
||||
DATA_SOURCES.tendermintUrl
|
||||
}/tx_search?query="tx.submitter='${party?.replace('0x', '')}'"`
|
||||
} = useFetch<BlockExplorerTransactions>(
|
||||
`${DATA_SOURCES.blockExplorerUrl}/transactions?limit=1&filters[tx.submitter]=${partyId}`
|
||||
);
|
||||
|
||||
const { data } = useQuery<PartyAssetsQuery, PartyAssetsQueryVariables>(
|
||||
@ -71,7 +71,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 },
|
||||
skip: !party,
|
||||
}
|
||||
);
|
||||
|
@ -5,12 +5,12 @@ import { RouteTitle } from '../../../components/route-title';
|
||||
import { BlocksRefetch } from '../../../components/blocks';
|
||||
import { TxsInfiniteList } from '../../../components/txs';
|
||||
import type {
|
||||
BlockExplorerTransaction,
|
||||
BlockExplorerTransactionResult,
|
||||
BlockExplorerTransactions,
|
||||
} from '../../../routes/types/block-explorer-response';
|
||||
|
||||
interface TxsStateProps {
|
||||
txsData: BlockExplorerTransaction[];
|
||||
txsData: BlockExplorerTransactionResult[];
|
||||
hasMoreTxs: boolean;
|
||||
lastCursor: string;
|
||||
}
|
||||
|
@ -1,49 +1,43 @@
|
||||
import React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import type { TendermintTransactionResponse } from '../tendermint-transaction-response.d';
|
||||
import type { ChainExplorerTxResponse } from '../../types/chain-explorer-response';
|
||||
import { DATA_SOURCES } from '../../../config';
|
||||
import { RouteTitle } from '../../../components/route-title';
|
||||
import { RenderFetched } from '../../../components/render-fetched';
|
||||
import { TxContent } from './tx-content';
|
||||
import { TxDetails } from './tx-details';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import type { BlockExplorerTransaction } from '../../../routes/types/block-explorer-response';
|
||||
import { toNonHex } from '../../../components/search/detect-search';
|
||||
|
||||
const Tx = () => {
|
||||
const { txHash } = useParams<{ txHash: string }>();
|
||||
const hash = txHash ? toNonHex(txHash) : '';
|
||||
|
||||
const {
|
||||
state: { data: tTxData, loading: tTxLoading, error: tTxError },
|
||||
} = useFetch<TendermintTransactionResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/tx?hash=${txHash}`
|
||||
state: { data, loading: tTxLoading, error: tTxError },
|
||||
} = useFetch<BlockExplorerTransaction>(
|
||||
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(hash)}`
|
||||
);
|
||||
|
||||
const {
|
||||
state: { data: ceTxData, loading: ceTxLoading, error: ceTxError },
|
||||
} = useFetch<ChainExplorerTxResponse>(DATA_SOURCES.chainExplorerUrl, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
tx_hash: txHash,
|
||||
node_url: `${DATA_SOURCES.tendermintUrl}/`,
|
||||
}),
|
||||
});
|
||||
|
||||
return (
|
||||
<section>
|
||||
<RouteTitle>{t('Transaction details')}</RouteTitle>
|
||||
|
||||
<RenderFetched error={tTxError} loading={tTxLoading}>
|
||||
<TxDetails
|
||||
className="mb-28"
|
||||
txData={tTxData?.result}
|
||||
pubKey={ceTxData?.PubKey}
|
||||
/>
|
||||
</RenderFetched>
|
||||
<>
|
||||
<TxDetails
|
||||
className="mb-28"
|
||||
txData={data?.transaction}
|
||||
pubKey={data?.transaction.submitter}
|
||||
/>
|
||||
|
||||
<h2 className="text-2xl uppercase mb-4">{t('Transaction content')}</h2>
|
||||
<RenderFetched error={ceTxError} loading={ceTxLoading}>
|
||||
<TxContent data={ceTxData} />
|
||||
<h2 className="text-2xl uppercase mb-4">
|
||||
{t('Transaction content')}
|
||||
</h2>
|
||||
|
||||
<TxContent data={data?.transaction} />
|
||||
</>
|
||||
</RenderFetched>
|
||||
</section>
|
||||
);
|
||||
|
@ -8,14 +8,14 @@ import {
|
||||
TableRow,
|
||||
} from '../../../components/table';
|
||||
import { TxOrderType } from '../../../components/txs';
|
||||
import type { ChainExplorerTxResponse } from '../../types/chain-explorer-response';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
|
||||
interface TxContentProps {
|
||||
data: ChainExplorerTxResponse | undefined;
|
||||
data: BlockExplorerTransactionResult | undefined;
|
||||
}
|
||||
|
||||
export const TxContent = ({ data }: TxContentProps) => {
|
||||
if (!data?.Command) {
|
||||
if (!data?.command) {
|
||||
return (
|
||||
<StatusMessage>
|
||||
{t('Could not retrieve transaction content')}
|
||||
@ -31,13 +31,13 @@ export const TxContent = ({ data }: TxContentProps) => {
|
||||
{t('Type')}
|
||||
</TableHeader>
|
||||
<TableCell modifier="bordered">
|
||||
<TxOrderType orderType={data.Type} />
|
||||
<TxOrderType orderType={data.type} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableWithTbody>
|
||||
|
||||
<h3 className="font-mono mb-8">{t('Decoded transaction content')}</h3>
|
||||
<SyntaxHighlighter data={JSON.parse(data.Command)} />
|
||||
<SyntaxHighlighter data={data.command} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,33 +1,24 @@
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { truncateByChars } from '@vegaprotocol/react-helpers';
|
||||
import { TxDetails, txDetailsTruncateLength } from './tx-details';
|
||||
import type { Result } from '../tendermint-transaction-response.d';
|
||||
import { TxDetails } from './tx-details';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
|
||||
const pubKey = 'test';
|
||||
const hash = '7416753A30622A9E24A06F0172D6C33A95186B36806D96345C6DC5A23FA3F283';
|
||||
const height = '52987';
|
||||
const tx =
|
||||
'ClMIpeWjmKnn77FNEPedA5J9QhJAOGI3YjQzMWNlMmNhNzc4MWMzMTQ1M2IyYjc0MWYwMTJlNzQ1MzBhZDhjMDgzODVkMWQ1YjRiY2VkMTJiNDc1MhKTAQqAATM5NDFlNmExMzQ3MGVhNTlhNGExNmQzMjRiYzlkZjI5YWZkMzYxMDRiZjQ5MzEwZWMxM2ZiOTMxNTM2NGY3ZjU2ZTQyOTJmYTAyZDlhNTBlZDc0OWE0ZjExMzJiNjM2ZTZmMzQ3YzQ2NjdkYmM5OThmYzcyZjYzYzQxMzU4ZTAzEgx2ZWdhL2VkMjU1MTkYAYB9AtI+QDA5MzFhOGZkOGNjOTM1NDU4ZjQ3MGU0MzVhMDU0MTQzODdjZWE2ZjMyOWQ2NDhiZTg5NGZjZDQ0YmQ1MTdhMmI=';
|
||||
|
||||
const txData = {
|
||||
const txData: BlockExplorerTransactionResult = {
|
||||
hash,
|
||||
height,
|
||||
tx,
|
||||
block: height,
|
||||
index: 0,
|
||||
tx_result: {
|
||||
code: 0,
|
||||
data: null,
|
||||
log: '',
|
||||
info: '',
|
||||
events: [],
|
||||
gas_wanted: '0',
|
||||
gas_used: '0',
|
||||
codespace: '',
|
||||
},
|
||||
submitter: pubKey,
|
||||
code: 0,
|
||||
cursor: `${height}.0`,
|
||||
type: 'type',
|
||||
command: {},
|
||||
};
|
||||
|
||||
const renderComponent = (txData: Result) => (
|
||||
const renderComponent = (txData: BlockExplorerTransactionResult) => (
|
||||
<Router>
|
||||
<TxDetails txData={txData} pubKey={pubKey} />
|
||||
</Router>
|
||||
@ -49,15 +40,6 @@ describe('Transaction details', () => {
|
||||
expect(screen.getByText(height)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders the truncated tx text', () => {
|
||||
render(renderComponent(txData));
|
||||
expect(
|
||||
screen.getByText(
|
||||
truncateByChars(tx, txDetailsTruncateLength, txDetailsTruncateLength)
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders a copy button', () => {
|
||||
render(renderComponent(txData));
|
||||
expect(screen.getByTestId('copy-tx-to-clipboard')).toBeInTheDocument();
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { Routes } from '../../route-names';
|
||||
import { ButtonLink, CopyWithTooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { CopyWithTooltip, Icon } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
TableWithTbody,
|
||||
TableCell,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '../../../components/table';
|
||||
import { TruncateInline } from '../../../components/truncate/truncate';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { HighlightedLink } from '../../../components/highlighted-link';
|
||||
import type { Result } from '../tendermint-transaction-response.d';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import React from 'react';
|
||||
|
||||
interface TxDetailsProps {
|
||||
txData: Result | undefined;
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
pubKey: string | undefined;
|
||||
className?: string;
|
||||
}
|
||||
@ -21,7 +21,7 @@ export const txDetailsTruncateLength = 30;
|
||||
|
||||
export const TxDetails = ({ txData, pubKey, className }: TxDetailsProps) => {
|
||||
if (!txData) {
|
||||
return <>{t('Awaiting Tendermint transaction details')}</>;
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -30,6 +30,15 @@ export const TxDetails = ({ txData, pubKey, className }: TxDetailsProps) => {
|
||||
<TableCell>{t('Hash')}</TableCell>
|
||||
<TableCell modifier="bordered" data-testid="hash">
|
||||
{txData.hash}
|
||||
<CopyWithTooltip text={txData.hash}>
|
||||
<button
|
||||
title={t('Copy tx to clipboard')}
|
||||
data-testid="copy-tx-to-clipboard"
|
||||
className="underline"
|
||||
>
|
||||
<Icon name="duplicate" className="ml-2" />
|
||||
</button>
|
||||
</CopyWithTooltip>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
@ -44,31 +53,11 @@ export const TxDetails = ({ txData, pubKey, className }: TxDetailsProps) => {
|
||||
<TableCell>{t('Block')}</TableCell>
|
||||
<TableCell modifier="bordered" data-testid="block">
|
||||
<HighlightedLink
|
||||
to={`/${Routes.BLOCKS}/${txData.height}`}
|
||||
text={txData.height}
|
||||
to={`/${Routes.BLOCKS}/${txData.block}`}
|
||||
text={txData.block}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Encoded txn')}</TableCell>
|
||||
<TableCell
|
||||
modifier="bordered"
|
||||
data-testid="encoded-tnx"
|
||||
className="flex justify-between"
|
||||
>
|
||||
<TruncateInline
|
||||
text={txData.tx}
|
||||
startChars={txDetailsTruncateLength}
|
||||
endChars={txDetailsTruncateLength}
|
||||
/>
|
||||
<CopyWithTooltip text={txData.tx}>
|
||||
<ButtonLink
|
||||
title={t('Copy tx to clipboard')}
|
||||
data-testid="copy-tx-to-clipboard"
|
||||
/>
|
||||
</CopyWithTooltip>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableWithTbody>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
export interface BlockExplorerTransaction {
|
||||
export interface BlockExplorerTransactionResult {
|
||||
block: string;
|
||||
index: number;
|
||||
hash: string;
|
||||
@ -10,5 +10,9 @@ export interface BlockExplorerTransaction {
|
||||
}
|
||||
|
||||
export interface BlockExplorerTransactions {
|
||||
transactions: BlockExplorerTransaction[];
|
||||
transactions: BlockExplorerTransactionResult[];
|
||||
}
|
||||
|
||||
export interface BlockExplorerTransaction {
|
||||
transaction: BlockExplorerTransactionResult;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user