From 5abb6118986dd94ca2bb7aec17b8f62e3e2ae9c0 Mon Sep 17 00:00:00 2001 From: Jordan Gensler Date: Tue, 28 Mar 2023 10:08:06 -0700 Subject: [PATCH] [explorer] Update transaction to use new block terminology (#9958) ## Description This makes some changes to the explorer to use new terminology. ## Test Plan Tests should still pass --- .../src/components/Activity/index.tsx | 18 ++++++-- .../src/components/HomeMetrics/index.tsx | 4 +- .../src/components/Table/TableFooter.tsx | 4 +- .../FunctionExecutionResult.tsx | 4 +- .../transactions/TransactionsForAddress.tsx | 16 ++++++-- .../components/transactions/TxCardUtils.tsx | 6 +-- .../src/components/transactions/index.tsx | 11 ++--- .../pages/address-result/AddressResult.tsx | 2 +- .../pages/checkpoints/CheckpointsTable.tsx | 1 + apps/explorer/src/pages/index.tsx | 20 +++++---- .../src/pages/object-result/views/PkgView.tsx | 2 +- .../pages/object-result/views/TokenView.tsx | 4 +- .../Transactions.tsx => recent/index.tsx} | 13 ++++-- .../src/pages/searcherror/SearchError.tsx | 41 ------------------- .../{Command.tsx => Transaction.tsx} | 30 ++++++-------- .../{Commands.tsx => Transactions.tsx} | 14 +++---- .../programmable-transaction-view/index.tsx | 14 ++----- apps/explorer/src/ui/InternalLink.tsx | 2 +- apps/explorer/src/ui/PageHeader.tsx | 8 +++- apps/explorer/tests/search.spec.ts | 2 +- apps/explorer/tests/transaction.spec.ts | 6 +-- .../app/components/explorer-link/Explorer.ts | 2 +- 22 files changed, 102 insertions(+), 122 deletions(-) rename apps/explorer/src/pages/{transactions/Transactions.tsx => recent/index.tsx} (60%) delete mode 100644 apps/explorer/src/pages/searcherror/SearchError.tsx rename apps/explorer/src/pages/transaction-result/programmable-transaction-view/{Command.tsx => Transaction.tsx} (70%) rename apps/explorer/src/pages/transaction-result/programmable-transaction-view/{Commands.tsx => Transactions.tsx} (55%) diff --git a/apps/explorer/src/components/Activity/index.tsx b/apps/explorer/src/components/Activity/index.tsx index 70b71cb7ee6c2..f0199d264b94b 100644 --- a/apps/explorer/src/components/Activity/index.tsx +++ b/apps/explorer/src/components/Activity/index.tsx @@ -11,6 +11,7 @@ import { PlayPause } from '~/ui/PlayPause'; import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '~/ui/Tabs'; type Props = { + initialTab?: string | null; initialLimit: number; disablePagination?: boolean; }; @@ -19,7 +20,14 @@ const AUTO_REFRESH_ID = 'auto-refresh'; const REFETCH_INTERVAL_SECONDS = 10; const REFETCH_INTERVAL = REFETCH_INTERVAL_SECONDS * 1000; -export function Activity({ initialLimit, disablePagination }: Props) { +export function Activity({ + initialTab, + initialLimit, + disablePagination, +}: Props) { + const [selectedIndex, setSelectedIndex] = useState( + initialTab === 'checkpoints' ? 1 : 0 + ); const [paused, setPaused] = useState(false); const handlePauseChange = () => { @@ -39,10 +47,14 @@ export function Activity({ initialLimit, disablePagination }: Props) { return (
- +
- Transactions + Transaction Blocks Checkpoints diff --git a/apps/explorer/src/components/HomeMetrics/index.tsx b/apps/explorer/src/components/HomeMetrics/index.tsx index e1fd3f0f483b8..57be9bcd79cc6 100644 --- a/apps/explorer/src/components/HomeMetrics/index.tsx +++ b/apps/explorer/src/components/HomeMetrics/index.tsx @@ -101,8 +101,8 @@ export function HomeMetrics() { {formatAmount(countsData?.objects)} {formatAmount(countsData?.transactions)} diff --git a/apps/explorer/src/components/Table/TableFooter.tsx b/apps/explorer/src/components/Table/TableFooter.tsx index 0d573647fdfc2..ed12b69282856 100644 --- a/apps/explorer/src/components/Table/TableFooter.tsx +++ b/apps/explorer/src/components/Table/TableFooter.tsx @@ -20,6 +20,7 @@ interface Props { data?: PaginationResponse; limit: number; onLimitChange(value: number): void; + href: string; } export function TableFooter({ @@ -30,12 +31,13 @@ export function TableFooter({ count, limit, onLimitChange, + href, }: Props) { return (
{disablePagination ? ( <> - }> + }> More {label} diff --git a/apps/explorer/src/components/module/module-functions-interaction/FunctionExecutionResult.tsx b/apps/explorer/src/components/module/module-functions-interaction/FunctionExecutionResult.tsx index aeeddddc63ad0..0c5fa2463ddb0 100644 --- a/apps/explorer/src/components/module/module-functions-interaction/FunctionExecutionResult.tsx +++ b/apps/explorer/src/components/module/module-functions-interaction/FunctionExecutionResult.tsx @@ -48,13 +48,13 @@ export function FunctionExecutionResult({ >
(b.timestampMs ?? 0) - (a.timestampMs ?? 0) - ); + const inserted = new Map(); + const uniqueList: SuiTransactionBlockResponse[] = []; + + [...results[0].data, ...results[1].data] + .sort((a, b) => (b.timestampMs ?? 0) - (a.timestampMs ?? 0)) + .forEach((txb) => { + if (inserted.get(txb.digest)) return; + uniqueList.push(txb); + inserted.set(txb.digest, true); + }); + + return uniqueList; } ); diff --git a/apps/explorer/src/components/transactions/TxCardUtils.tsx b/apps/explorer/src/components/transactions/TxCardUtils.tsx index 86452a9c301ef..52c7b1b4e5a9a 100644 --- a/apps/explorer/src/components/transactions/TxCardUtils.tsx +++ b/apps/explorer/src/components/transactions/TxCardUtils.tsx @@ -91,7 +91,7 @@ export const genTableDataFromTxData = ( ), - transactionId: ( + digest: ( , diff --git a/apps/explorer/src/components/transactions/index.tsx b/apps/explorer/src/components/transactions/index.tsx index 68c91be678783..4f23e5a5e6d34 100644 --- a/apps/explorer/src/components/transactions/index.tsx +++ b/apps/explorer/src/components/transactions/index.tsx @@ -82,26 +82,21 @@ export function Transactions({ )}
diff --git a/apps/explorer/src/pages/address-result/AddressResult.tsx b/apps/explorer/src/pages/address-result/AddressResult.tsx index 4c9ca715d608f..20b067b60eff5 100644 --- a/apps/explorer/src/pages/address-result/AddressResult.tsx +++ b/apps/explorer/src/pages/address-result/AddressResult.tsx @@ -31,7 +31,7 @@ function AddressResult() {
- Transactions + Transaction Blocks
diff --git a/apps/explorer/src/pages/checkpoints/CheckpointsTable.tsx b/apps/explorer/src/pages/checkpoints/CheckpointsTable.tsx index d066af7568c0e..7d018b9f96c29 100644 --- a/apps/explorer/src/pages/checkpoints/CheckpointsTable.tsx +++ b/apps/explorer/src/pages/checkpoints/CheckpointsTable.tsx @@ -138,6 +138,7 @@ export function CheckpointsTable({ onLimitChange={setLimit} pagination={pagination} disablePagination={disablePagination} + href="/recent?tab=checkpoints" />
diff --git a/apps/explorer/src/pages/index.tsx b/apps/explorer/src/pages/index.tsx index f3f4cd2a06694..3d6a465d84be6 100644 --- a/apps/explorer/src/pages/index.tsx +++ b/apps/explorer/src/pages/index.tsx @@ -14,9 +14,8 @@ import CheckpointDetail from './checkpoints/CheckpointDetail'; import EpochDetail from './epochs/EpochDetail'; import Home from './home/Home'; import { ObjectResult } from './object-result/ObjectResult'; -import SearchError from './searcherror/SearchError'; +import { Recent } from './recent'; import TransactionResult from './transaction-result/TransactionResult'; -import Transactions from './transactions/Transactions'; import { ValidatorDetails } from './validator/ValidatorDetails'; import { ValidatorPageResult } from './validators/Validators'; @@ -36,25 +35,32 @@ export const router = sentryCreateBrowserRouter([ element: , children: [ { path: '/', element: }, - { path: 'transactions', element: }, + { path: 'recent', element: }, { path: 'object/:id', element: }, { path: 'checkpoint/:id', element: }, { path: 'epoch/current', element: }, - { path: 'transaction/:id', element: }, + { path: 'txblock/:id', element: }, { path: 'address/:id', element: }, { path: 'validators', element: }, { path: 'validator/:id', element: }, - { path: 'error/:category/:id', element: }, ], }, - // Support legacy plural routes: + { + path: '/transactions', + element: , + }, + // Support legacy routes: { path: '/objects/:id', element: , }, + { + path: '/transaction/:id', + element: , + }, { path: '/transactions/:id', - element: , + element: , }, { path: '/addresses/:id', diff --git a/apps/explorer/src/pages/object-result/views/PkgView.tsx b/apps/explorer/src/pages/object-result/views/PkgView.tsx index 4631f2e3c4440..e27f303685085 100644 --- a/apps/explorer/src/pages/object-result/views/PkgView.tsx +++ b/apps/explorer/src/pages/object-result/views/PkgView.tsx @@ -106,7 +106,7 @@ function PkgView({ data }: { data: DataType }) {
-

Transactions

+

Transaction Blocks

- +
-

Transactions

+

Transaction Blocks

diff --git a/apps/explorer/src/pages/transactions/Transactions.tsx b/apps/explorer/src/pages/recent/index.tsx similarity index 60% rename from apps/explorer/src/pages/transactions/Transactions.tsx rename to apps/explorer/src/pages/recent/index.tsx index f63978aafc65a..d948460a77587 100644 --- a/apps/explorer/src/pages/transactions/Transactions.tsx +++ b/apps/explorer/src/pages/recent/index.tsx @@ -4,9 +4,13 @@ import { Activity } from '../../components/Activity'; import { ErrorBoundary } from '../../components/error-boundary/ErrorBoundary'; +import { useSearchParamsMerged } from '~/ui/utils/LinkWithQuery'; + const TRANSACTIONS_LIMIT = 20; -function Transactions() { +export function Recent() { + const [searchParams] = useSearchParamsMerged(); + return (
- +
); } - -export default Transactions; diff --git a/apps/explorer/src/pages/searcherror/SearchError.tsx b/apps/explorer/src/pages/searcherror/SearchError.tsx deleted file mode 100644 index 023980473534b..0000000000000 --- a/apps/explorer/src/pages/searcherror/SearchError.tsx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import { useParams } from 'react-router-dom'; - -import { Banner } from '~/ui/Banner'; - -const addressErrEnd = - 'must be a hex string encoding 20 bytes, with or without the "0x" prefix.'; - -function SearchError() { - const { category } = useParams(); - - let msg = 'unknown'; - switch (category) { - case 'transactions': - // TODO - generate expected length errors from source of truth in Rust - msg = 'transaction id must be a base64 string encoding 32 bytes'; - break; - case 'objects': - msg = `object id ${addressErrEnd}`; - break; - case 'addresses': - msg = `address ${addressErrEnd}`; - break; - case 'all': - msg = - 'Search terms currently supported are transaction IDs (32 byte base58/base64), object IDs (20 byte hex), and addresses (20 byte hex)'; - break; - case 'missing': - msg = 'Data on the following query could not be found'; - } - - return ( - - {msg} - - ); -} - -export default SearchError; diff --git a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Command.tsx b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transaction.tsx similarity index 70% rename from apps/explorer/src/pages/transaction-result/programmable-transaction-view/Command.tsx rename to apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transaction.tsx index 9f3aa10487bd5..be02f138ed7d3 100644 --- a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Command.tsx +++ b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transaction.tsx @@ -12,12 +12,12 @@ import { flattenSuiArguments } from './utils'; import { ObjectLink } from '~/ui/InternalLink'; -export interface CommandProps { +export interface TransactionProps { type: string; data: T; } -function CommandContent({ +function TransactionContent({ type, children, }: { @@ -26,17 +26,11 @@ function CommandContent({ }) { return ( <> -
+
{type}
{children && ( -
+
{children}
)} @@ -47,15 +41,15 @@ function CommandContent({ function ArrayArgument({ type, data, -}: CommandProps<(SuiArgument | SuiArgument[])[] | undefined>) { +}: TransactionProps<(SuiArgument | SuiArgument[])[] | undefined>) { return ( - + {data && <>({flattenSuiArguments(data)})} - + ); } -function MoveCall({ type, data }: CommandProps) { +function MoveCall({ type, data }: TransactionProps) { const { module, package: movePackage, @@ -64,7 +58,7 @@ function MoveCall({ type, data }: CommandProps) { type_arguments: typeArgs, } = data; return ( - + (package: , module:{' '} ) { , function: {func} {args && <>, arguments: [{flattenSuiArguments(args!)}]} {typeArgs && <>, type_arguments: {typeArgs}}) - + ); } -export function Command({ +export function Transaction({ type, data, -}: CommandProps< +}: TransactionProps< (SuiArgument | SuiArgument[])[] | MoveCallSuiTransaction | SuiMovePackage >) { if (type === 'MoveCall') { diff --git a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Commands.tsx b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transactions.tsx similarity index 55% rename from apps/explorer/src/pages/transaction-result/programmable-transaction-view/Commands.tsx rename to apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transactions.tsx index 577b47a1d0cfb..c18ed599107be 100644 --- a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Commands.tsx +++ b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/Transactions.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { type SuiTransaction } from '@mysten/sui.js'; -import { Command } from './Command'; +import { Transaction } from './Transaction'; import { TableHeader } from '~/ui/TableHeader'; @@ -10,23 +10,21 @@ interface Props { transactions: SuiTransaction[]; } -export function Commands({ transactions }: Props) { +export function Transactions({ transactions }: Props) { if (!transactions?.length) { return null; } return ( <> - Commands + Transactions
    - {transactions.map((command, index) => { - const commandName = Object.keys(command)[0]; - const commandData = - command[commandName as keyof typeof command]; + {transactions.map((transaction, index) => { + const [[type, data]] = Object.entries(transaction); return (
  • - +
  • ); })} diff --git a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/index.tsx b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/index.tsx index 1a03c1204eed2..6157f72770815 100644 --- a/apps/explorer/src/pages/transaction-result/programmable-transaction-view/index.tsx +++ b/apps/explorer/src/pages/transaction-result/programmable-transaction-view/index.tsx @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import { type ProgrammableTransaction } from '@mysten/sui.js'; -import { Commands } from './Commands'; import { Inputs } from './Inputs'; +import { Transactions } from './Transactions'; interface Props { transaction: ProgrammableTransaction; @@ -12,18 +12,12 @@ interface Props { export function ProgrammableTransactionView({ transaction }: Props) { return ( <> -
    +
    -
    - +
    +
    ); diff --git a/apps/explorer/src/ui/InternalLink.tsx b/apps/explorer/src/ui/InternalLink.tsx index 3a8507fc892bd..25cd2ecd8c8f1 100644 --- a/apps/explorer/src/ui/InternalLink.tsx +++ b/apps/explorer/src/ui/InternalLink.tsx @@ -39,7 +39,7 @@ export const CheckpointSequenceLink = createInternalLink( export const AddressLink = createInternalLink('address', 'address'); export const ObjectLink = createInternalLink('object', 'objectId'); export const TransactionLink = createInternalLink( - 'transaction', + 'txblock', 'digest', formatDigest ); diff --git a/apps/explorer/src/ui/PageHeader.tsx b/apps/explorer/src/ui/PageHeader.tsx index 88d1773a52f90..5141c9913ad63 100644 --- a/apps/explorer/src/ui/PageHeader.tsx +++ b/apps/explorer/src/ui/PageHeader.tsx @@ -23,7 +23,11 @@ export interface PageHeaderProps { status?: 'success' | 'failure'; } -const TYPE_TO_ICON: Record = { +const TYPE_TO_COPY: Partial> = { + Transaction: 'Transaction Block', +}; + +const TYPE_TO_ICON: Record = { Transaction: CallIcon, Checkpoint: Flag16, Object: Nft16, @@ -51,7 +55,7 @@ export function PageHeader({ title, subtitle, type, status }: PageHeaderProps) {
    {Icon && } - {type} + {type in TYPE_TO_COPY ? TYPE_TO_COPY[type] : type}
    diff --git a/apps/explorer/tests/search.spec.ts b/apps/explorer/tests/search.spec.ts index 8d9d1d2a6559f..c1a144a910c66 100644 --- a/apps/explorer/tests/search.spec.ts +++ b/apps/explorer/tests/search.spec.ts @@ -37,5 +37,5 @@ test('can search for transaction', async ({ page }) => { const txid = getTransactionDigest(tx); await page.goto('/'); await search(page, txid); - await expect(page).toHaveURL(`/transaction/${txid}`); + await expect(page).toHaveURL(`/txblock/${txid}`); }); diff --git a/apps/explorer/tests/transaction.spec.ts b/apps/explorer/tests/transaction.spec.ts index 87221a4cc9aa7..e34934f52c440 100644 --- a/apps/explorer/tests/transaction.spec.ts +++ b/apps/explorer/tests/transaction.spec.ts @@ -1,15 +1,15 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +import { getTransactionDigest } from '@mysten/sui.js'; import { expect, test } from '@playwright/test'; import { faucet, split_coin } from './utils/localnet'; -import { getTransactionDigest } from '@mysten/sui.js'; test('displays the transaction timestamp', async ({ page }) => { const address = await faucet(); const tx = await split_coin(address); const txid = getTransactionDigest(tx); - await page.goto(`/transaction/${txid}`); + await page.goto(`/txblock/${txid}`); await expect( page.getByTestId('transaction-timestamp').locator('div').nth(1) ).not.toBeEmpty(); @@ -19,6 +19,6 @@ test('displays gas breakdown', async ({ page }) => { const address = await faucet(); const tx = await split_coin(address); const txid = getTransactionDigest(tx); - await page.goto(`/transaction/${txid}`); + await page.goto(`/txblock/${txid}`); await expect(page.getByTestId('gas-breakdown')).toBeVisible(); }); diff --git a/apps/wallet/src/ui/app/components/explorer-link/Explorer.ts b/apps/wallet/src/ui/app/components/explorer-link/Explorer.ts index 8066f72f56946..c2b2433a945d0 100644 --- a/apps/wallet/src/ui/app/components/explorer-link/Explorer.ts +++ b/apps/wallet/src/ui/app/components/explorer-link/Explorer.ts @@ -44,7 +44,7 @@ export function getTransactionUrl( customRPC: string ) { return getExplorerUrl( - `/transaction/${encodeURIComponent(txDigest)}`, + `/txblock/${encodeURIComponent(txDigest)}`, apiEnv, customRPC );