Public tags: protocol tag for transaction list (#3182)

Resolves #2976
This commit is contained in:
tom goriunov
2026-01-05 11:33:43 +01:00
committed by GitHub
parent 2997ca0ff9
commit 7ca07ae0af
17 changed files with 106 additions and 14 deletions
+19 -1
View File
@@ -1,9 +1,11 @@
/* eslint-disable max-len */
import type { AddressParam } from 'types/api/addressParams';
import type { Transaction } from 'types/api/transaction';
import * as addressMock from 'mocks/address/address';
import { publicTag, privateTag, watchlistName } from 'mocks/address/tag';
import * as interopMock from 'mocks/interop/interop';
import { protocolTag } from 'mocks/metadata/address';
import * as tokenTransferMock from 'mocks/tokens/tokenTransfer';
import * as decodedInputDataMock from 'mocks/txs/decodedInputData';
@@ -88,8 +90,24 @@ export const withWatchListNames: Transaction = {
} as Transaction['to'],
};
export const withProtocolTag: Transaction = {
...base,
hash: '0x62d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3194',
to: {
...(base.to as AddressParam),
metadata: {
tags: [ protocolTag ],
reputation: null,
},
private_tags: [],
watchlist_names: [],
public_tags: [],
},
};
export const withPendingUpdate: Transaction = {
...withWatchListNames,
...withProtocolTag,
hash: '0x62d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3133',
is_pending_update: true,
};
+48
View File
@@ -1,8 +1,12 @@
import { Box } from '@chakra-ui/react';
import React from 'react';
import type { AddressParam } from 'types/api/addressParams';
import * as txMock from 'mocks/txs/tx';
import * as socketServer from 'playwright/fixtures/socketServer';
import { test as base, expect, devices } from 'playwright/lib';
import * as pwConfig from 'playwright/utils/config';
import LatestTxs from './LatestTxs';
@@ -37,6 +41,50 @@ test('default view +@dark-mode', async({ render, mockApiResponse }) => {
await expect(component).toHaveScreenshot();
});
test.describe('small desktop', () => {
test.use({ viewport: pwConfig.viewport.md });
test('one tag', async({ render, mockApiResponse }) => {
await mockApiResponse('general:homepage_txs', [
{
...txMock.withProtocolTag,
to: {
...txMock.withProtocolTag.to,
metadata: {
tags: [ {
slug: 'aerodrome',
name: 'Very long protocol name that should be truncated',
tagType: 'protocol',
ordinal: 0,
meta: null,
} ],
reputation: null,
},
} as AddressParam,
},
]);
const component = await render(
<Box maxW="800px">
<LatestTxs/>
</Box>,
);
await expect(component).toHaveScreenshot();
});
test('two or more tags', async({ render, mockApiResponse }) => {
await mockApiResponse('general:homepage_txs', [
txMock.withWatchListNames,
]);
const component = await render(
<Box maxW="800px">
<LatestTxs/>
</Box>,
);
await expect(component).toHaveScreenshot();
});
});
test.describe('socket', () => {
test.describe.configure({ mode: 'serial' });
+17 -5
View File
@@ -13,6 +13,7 @@ import config from 'configs/app';
import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressFromTo from 'ui/shared/address/AddressFromTo';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import EntityTag from 'ui/shared/EntityTags/EntityTag';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TimeWithTooltip from 'ui/shared/time/TimeWithTooltip';
import TxFee from 'ui/shared/tx/TxFee';
@@ -30,15 +31,25 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
const dataTo = tx.to ? tx.to : tx.created_contract;
const columnNum = config.UI.views.tx.hiddenFields?.value && config.UI.views.tx.hiddenFields?.tx_fee ? 2 : 3;
const protocolTag = tx.to?.metadata?.tags?.find(tag => tag.tagType === 'protocol');
const tagsCount = [
1, // tx type
1, // tx status
...(tx.from?.watchlist_names || []),
...(tx.to?.watchlist_names || []),
protocolTag,
].filter(Boolean).length;
return (
<Grid
gridTemplateColumns={{
lg: columnNum === 2 ? '3fr minmax(auto, 180px)' : '3fr minmax(auto, 180px) 170px',
xl: columnNum === 2 ? '3fr minmax(auto, 250px)' : '3fr minmax(auto, 275px) 170px',
lg: columnNum === 2 ? '3fr minmax(auto, 200px)' : '3fr minmax(auto, 200px) 170px',
xl: columnNum === 2 ? '3fr minmax(auto, 270px)' : '3fr minmax(auto, 300px) 170px',
}}
gridGap={ 8 }
gridGap={ 3 }
width="100%"
minW="700px"
minW={ columnNum === 2 ? '700px' : '750px' }
borderBottom="1px solid"
borderColor="border.divider"
p={ 4 }
@@ -47,10 +58,11 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
<Flex overflow="hidden" w="100%">
<TxAdditionalInfo tx={ tx } isLoading={ isLoading } my="3px"/>
<Box ml={ 3 } w="calc(100% - 40px)">
<HStack flexWrap="wrap" my="3px">
<HStack flexWrap={ tagsCount <= 3 ? 'nowrap' : 'wrap' } my="3px">
<TxType types={ tx.transaction_types } isLoading={ isLoading }/>
<TxStatus status={ tx.status } errorText={ tx.status === 'error' ? tx.result : undefined } isLoading={ isLoading }/>
<TxWatchListTags tx={ tx } isLoading={ isLoading }/>
{ protocolTag && <EntityTag data={ protocolTag } isLoading={ isLoading } minW="0"/> }
</HStack>
<Flex
alignItems="center"
+5 -1
View File
@@ -13,6 +13,7 @@ import config from 'configs/app';
import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressFromTo from 'ui/shared/address/AddressFromTo';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import EntityTag from 'ui/shared/EntityTags/EntityTag';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TimeWithTooltip from 'ui/shared/time/TimeWithTooltip';
import TxFee from 'ui/shared/tx/TxFee';
@@ -29,6 +30,8 @@ type Props = {
const LatestTxsItem = ({ tx, isLoading }: Props) => {
const dataTo = tx.to ? tx.to : tx.created_contract;
const protocolTag = tx.to?.metadata?.tags?.find(tag => tag.tagType === 'protocol');
return (
<Box
width="100%"
@@ -38,10 +41,11 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
display={{ base: 'block', lg: 'none' }}
>
<Flex justifyContent="space-between">
<HStack flexWrap="wrap">
<HStack>
<TxType types={ tx.transaction_types } isLoading={ isLoading }/>
<TxStatus status={ tx.status } errorText={ tx.status === 'error' ? tx.result : undefined } isLoading={ isLoading }/>
<TxWatchListTags tx={ tx } isLoading={ isLoading }/>
{ protocolTag && <EntityTag data={ protocolTag } isLoading={ isLoading } minW="0"/> }
</HStack>
<TxAdditionalInfo tx={ tx } isMobile isLoading={ isLoading }/>
</Flex>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 198 KiB

+1 -1
View File
@@ -27,7 +27,7 @@ const TxWatchListTags = ({ tx, isLoading }: Props) => {
key={ tag.label }
loading={ isLoading }
truncated
maxW={{ base: '115px', lg: 'initial' }}
maxW={{ base: '115px', lg: '100%' }}
colorPalette="gray"
>
{ tag.display_name }
+4
View File
@@ -13,6 +13,7 @@ import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressFromTo from 'ui/shared/address/AddressFromTo';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import EntityTag from 'ui/shared/EntityTags/EntityTag';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TimeWithTooltip from 'ui/shared/time/TimeWithTooltip';
@@ -49,6 +50,8 @@ const TxsListItem = ({
}: Props) => {
const dataTo = tx.to ? tx.to : tx.created_contract;
const protocolTag = tx.to?.metadata?.tags?.find(tag => tag.tagType === 'protocol');
return (
<ListItemMobile display="block" width="100%" animation={ animation } key={ tx.hash }>
<Flex justifyContent="space-between" alignItems="flex-start" mt={ 4 }>
@@ -64,6 +67,7 @@ const TxsListItem = ({
}
<TxStatus status={ tx.status } errorText={ tx.status === 'error' ? tx.result : undefined } isLoading={ isLoading }/>
<TxWatchListTags tx={ tx } isLoading={ isLoading }/>
{ protocolTag && <EntityTag data={ protocolTag } isLoading={ isLoading }/> }
</HStack>
<TxAdditionalInfo tx={ tx } isMobile isLoading={ isLoading }/>
</Flex>
+12 -6
View File
@@ -12,6 +12,7 @@ import AddressFromTo from 'ui/shared/address/AddressFromTo';
import BlockPendingUpdateHint from 'ui/shared/block/BlockPendingUpdateHint';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import EntityTag from 'ui/shared/EntityTags/EntityTag';
import ChainIcon from 'ui/shared/externalChains/ChainIcon';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TimeWithTooltip from 'ui/shared/time/TimeWithTooltip';
@@ -48,6 +49,8 @@ const TxsTableItem = ({
}: Props) => {
const dataTo = tx.to ? tx.to : tx.created_contract;
const protocolTag = tx.to?.metadata?.tags?.find(tag => tag.tagType === 'protocol');
return (
<TableRow key={ tx.hash } animation={ animation }>
<TableCell textAlign="center">
@@ -77,7 +80,7 @@ const TxsTableItem = ({
</VStack>
</TableCell>
<TableCell>
<VStack alignItems="start">
<VStack alignItems="stretch">
{ translationIsLoading || translationData ? (
<TxTranslationType
txTypes={ tx.transaction_types }
@@ -92,11 +95,14 @@ const TxsTableItem = ({
</VStack>
</TableCell>
<TableCell whiteSpace="nowrap">
{ tx.method && (
<Badge colorPalette={ tx.method === 'Multicall' ? 'teal' : 'gray' } loading={ isLoading } truncated>
<span>{ tx.method }</span>
</Badge>
) }
<VStack alignItems="stretch">
{ tx.method && (
<Badge colorPalette={ tx.method === 'Multicall' ? 'teal' : 'gray' } loading={ isLoading } truncated>
<span>{ tx.method }</span>
</Badge>
) }
{ protocolTag && <EntityTag data={ protocolTag } isLoading={ isLoading }/> }
</VStack>
</TableCell>
{ showBlockInfo && (
<TableCell>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB