Commit bd9de9e9 authored by isstuev's avatar isstuev Committed by isstuev

batches statuses

parent 97fd4a12
......@@ -14,7 +14,7 @@ import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxStatus from 'ui/shared/TxStatus';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
type Props = InternalTransaction & { currentAddress: string; isLoading?: boolean };
......
......@@ -13,7 +13,7 @@ import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag';
import TxStatus from 'ui/shared/TxStatus';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
type Props = InternalTransaction & { currentAddress: string; isLoading?: boolean }
......
......@@ -17,9 +17,9 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxType from 'ui/txs/TxType';
......
......@@ -16,9 +16,9 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxType from 'ui/txs/TxType';
......
import { test as base, expect } from '@playwright/experimental-ct-react';
import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react';
import * as blockMock from 'mocks/blocks/block';
import * as statsMock from 'mocks/stats/index';
import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import * as socketServer from 'playwright/fixtures/socketServer';
import { txnBatchesData } from 'mocks/zkevmL2txnBatches/zkevmL2txnBatches';
import TestApp from 'playwright/TestApp';
import buildApiUrl from 'playwright/utils/buildApiUrl';
import * as configs from 'playwright/utils/configs';
import LatestBlocks from './LatestBlocks';
import LatestZkEvmL2Batches from './LatestZkEvmL2Batches';
const STATS_API_URL = buildApiUrl('homepage_stats');
const BLOCKS_API_URL = buildApiUrl('homepage_blocks');
export const test = base.extend<socketServer.SocketServerFixture>({
createSocket: socketServer.createSocket,
});
const BATCHES_API_URL = buildApiUrl('homepage_zkevm_l2_batches');
test('default view +@mobile +@dark-mode', async({ mount, page }) => {
await page.route(STATS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(statsMock.base),
}));
await page.route(BLOCKS_API_URL, (route) => route.fulfill({
await page.route(BATCHES_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify([
blockMock.base,
blockMock.base2,
]),
body: JSON.stringify(txnBatchesData),
}));
const component = await mount(
<TestApp>
<LatestBlocks/>
<LatestZkEvmL2Batches/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
const testL2 = test.extend({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context: contextWithEnvs(configs.featureEnvs.rollup) as any,
});
testL2('L2 view', async({ mount, page }) => {
await page.route(STATS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(statsMock.base),
}));
await page.route(BLOCKS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify([
blockMock.base,
blockMock.base2,
]),
}));
const component = await mount(
<TestApp>
<LatestBlocks/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
const testNoReward = test.extend({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context: contextWithEnvs(configs.viewsEnvs.block.hiddenFields) as any,
});
testNoReward('no reward view', async({ mount, page }) => {
await page.route(STATS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(statsMock.base),
}));
await page.route(BLOCKS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify([
blockMock.base,
blockMock.base2,
]),
}));
const component = await mount(
<TestApp>
<LatestBlocks/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
test('with long block height', async({ mount, page }) => {
await page.route(STATS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(statsMock.base),
}));
await page.route(BLOCKS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify([
{
...blockMock.base,
height: 123456789012345,
},
]),
}));
const component = await mount(
<TestApp>
<LatestBlocks/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
test.describe('socket', () => {
test.describe.configure({ mode: 'serial' });
test('new item', async({ mount, page, createSocket }) => {
await page.route(STATS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(statsMock.base),
}));
await page.route(BLOCKS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify([
blockMock.base,
blockMock.base2,
]),
}));
const component = await mount(
<TestApp withSocket>
<LatestBlocks/>
</TestApp>,
);
const socket = await createSocket();
const channel = await socketServer.joinChannel(socket, 'blocks:new_block');
socketServer.sendMessage(socket, channel, 'new_block', {
average_block_time: '6212.0',
block: {
...blockMock.base,
height: blockMock.base.height + 1,
timestamp: '2022-11-11T11:59:58Z',
},
});
await expect(component).toHaveScreenshot();
});
});
......@@ -13,7 +13,7 @@ import LatestZkevmL2BatchItem from './LatestZkevmL2BatchItem';
const LatestZkEvmL2Batches = () => {
const isMobile = useIsMobile();
const batchesMaxCount = isMobile ? 2 : 3;
const batchesMaxCount = isMobile ? 2 : 5;
const { data, isPlaceholderData, isError } = useApiQuery('homepage_zkevm_l2_batches', {
queryOptions: {
......@@ -33,6 +33,7 @@ const LatestZkEvmL2Batches = () => {
content = (
<>
<VStack spacing={ 3 } mb={ 4 } overflow="hidden" alignItems="stretch">
{ /* no socket so far */ }
{ /* <AnimatePresence initial={ false } > */ }
{ dataToShow.map(((batch, index) => (
<LatestZkevmL2BatchItem
......
import {
Box,
Flex,
Grid,
Skeleton,
} from '@chakra-ui/react';
import { motion } from 'framer-motion';
......@@ -13,6 +12,7 @@ import { route } from 'nextjs-routes';
import BlockTimestamp from 'ui/blocks/BlockTimestamp';
import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2';
import ZkEvmL2TxnBatchStatus from 'ui/shared/statusTag/ZkEvmL2TxnBatchStatus';
type Props = {
batch: ZkEvmL2TxnBatchesItem;
......@@ -53,12 +53,14 @@ const LatestZkevmL2BatchItem = ({ batch, isLoading }: Props) => {
ml={ 2 }
/>
</Flex>
<Grid gridGap={ 2 } templateColumns="auto minmax(0, 1fr)" fontSize="sm">
<Skeleton isLoaded={ !isLoading }>Txn</Skeleton>
<Skeleton isLoaded={ !isLoading } color="text_secondary"><span>{ batch.tx_count }</span></Skeleton>
<Skeleton isLoaded={ !isLoading }>Status</Skeleton>
<Skeleton isLoaded={ !isLoading } color="text_secondary"><span>{ batch.status }</span></Skeleton>
</Grid>
<Flex alignItems="center" justifyContent="space-between" w="100%" flexWrap="wrap">
<Flex alignItems="center">
<Skeleton isLoaded={ !isLoading } mr={ 2 }>Txn</Skeleton>
{ /* LINK!!! */ }
<Skeleton isLoaded={ !isLoading } color="text_secondary"><span>{ batch.tx_count }</span></Skeleton>
</Flex>
<ZkEvmL2TxnBatchStatus status={ batch.status } isLoading={ isLoading }/>
</Flex>
</Box>
);
};
......
import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react';
import TestApp from 'playwright/TestApp';
import StatusTag from './StatusTag';
test('ok status', async({ page, mount }) => {
await mount(
<TestApp>
<StatusTag type="ok" text="Test"/>
</TestApp>,
);
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 75, height: 30 } });
});
test('error status', async({ page, mount }) => {
await mount(
<TestApp>
<StatusTag type="error" text="Test"/>
</TestApp>,
);
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 75, height: 30 } });
});
test('pending status', async({ page, mount }) => {
await mount(
<TestApp>
<StatusTag type="pending" text="Test"/>
</TestApp>,
);
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 75, height: 30 } });
});
import { TagLabel, TagLeftIcon, Tooltip } from '@chakra-ui/react';
import React from 'react';
import type { Transaction } from 'types/api/transaction';
import errorIcon from 'icons/status/error.svg';
import pendingIcon from 'icons/status/pending.svg';
import successIcon from 'icons/status/success.svg';
import Tag from 'ui/shared/chakra/Tag';
export type StatusTagType = 'ok' | 'error' | 'pending';
export interface Props {
status: Transaction['status'];
type: 'ok' | 'error' | 'pending';
text: string;
errorText?: string | null;
isLoading?: boolean;
}
const TxStatus = ({ status, errorText, isLoading }: Props) => {
let label;
const StatusTag = ({ type, text, errorText, isLoading }: Props) => {
let icon;
let colorScheme;
switch (status) {
switch (type) {
case 'ok':
label = 'Success';
icon = successIcon;
colorScheme = 'green';
break;
case 'error':
label = 'Failed';
icon = errorIcon;
colorScheme = 'red';
break;
case null:
label = 'Pending';
case 'pending':
icon = pendingIcon;
// FIXME: it's not gray on mockups
// need to implement new color scheme or redefine colors here
......@@ -43,10 +40,10 @@ const TxStatus = ({ status, errorText, isLoading }: Props) => {
<Tooltip label={ errorText }>
<Tag colorScheme={ colorScheme } display="inline-flex" isLoading={ isLoading }>
<TagLeftIcon boxSize={ 2.5 } as={ icon }/>
<TagLabel>{ label }</TagLabel>
<TagLabel>{ text }</TagLabel>
</Tag>
</Tooltip>
);
};
export default TxStatus;
export default StatusTag;
import React from 'react';
import type { Transaction } from 'types/api/transaction';
import type { StatusTagType } from './StatusTag';
import StatusTag from './StatusTag';
export interface Props {
status: Transaction['status'];
errorText?: string | null;
isLoading?: boolean;
}
const TxStatus = ({ status, errorText, isLoading }: Props) => {
let text;
let type: StatusTagType;
switch (status) {
case 'ok':
text = 'Success';
type = 'ok';
break;
case 'error':
text = 'Failed';
type = 'error';
break;
case null:
text = 'Pending';
type = 'pending';
break;
}
return <StatusTag type={ type } text={ text } errorText={ errorText } isLoading={ isLoading }/>;
};
export default TxStatus;
import React from 'react';
import type { ZkEvmL2TxnBatchesItem } from 'types/api/zkEvml2TxnBatches';
import type { StatusTagType } from './StatusTag';
import StatusTag from './StatusTag';
export interface Props {
status: ZkEvmL2TxnBatchesItem['status'];
isLoading?: boolean;
}
const ZkEvmL2TxnBatchStatus = ({ status, isLoading }: Props) => {
let type: StatusTagType;
switch (status) {
case 'L1 Sequence Confirmed':
case 'Finalized':
type = 'ok';
break;
default:
type = 'pending';
break;
}
return <StatusTag type={ type } text={ status } isLoading={ isLoading }/>;
};
export default ZkEvmL2TxnBatchStatus;
......@@ -44,10 +44,11 @@ import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LogDecodedInputData from 'ui/shared/logs/LogDecodedInputData';
import RawInputData from 'ui/shared/RawInputData';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TextSeparator from 'ui/shared/TextSeparator';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxStatus from 'ui/shared/TxStatus';
import Utilization from 'ui/shared/Utilization/Utilization';
import VerificationSteps from 'ui/shared/verificationSteps/VerificationSteps';
import TxDetailsActions from 'ui/tx/details/TxDetailsActions';
import TxDetailsFeePerGas from 'ui/tx/details/TxDetailsFeePerGas';
import TxDetailsGasPrice from 'ui/tx/details/TxDetailsGasPrice';
......@@ -58,8 +59,6 @@ import TxAllowedPeekers from 'ui/tx/TxAllowedPeekers';
import TxSocketAlert from 'ui/tx/TxSocketAlert';
import useFetchTxInfo from 'ui/tx/useFetchTxInfo';
import VerificationSteps from './VerificationSteps';
const TxDetails = () => {
const { data, isPlaceholderData, isError, socketStatus, error } = useFetchTxInfo();
......
......@@ -10,7 +10,7 @@ import Icon from 'ui/shared/chakra/Icon';
import Tag from 'ui/shared/chakra/Tag';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxStatus from 'ui/shared/TxStatus';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
type Props = InternalTransaction & { isLoading?: boolean };
......
......@@ -19,9 +19,9 @@ import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxType from 'ui/txs/TxType';
......
......@@ -23,9 +23,9 @@ import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxType from './TxType';
......
......@@ -11,6 +11,7 @@ import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2';
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
import ZkEvmL2TxnBatchStatus from 'ui/shared/statusTag/ZkEvmL2TxnBatchStatus';
const feature = config.features.rollup;
......@@ -40,10 +41,7 @@ const ZkEvmTxnBatchesListItem = ({ item, isLoading }: Props) => {
<ListItemMobileGrid.Label isLoading={ isLoading }>Status</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<Skeleton isLoaded={ !isLoading }>
{ /* Not sertain how to display status */ }
{ item.status }
</Skeleton>
<ZkEvmL2TxnBatchStatus status={ status } isLoading={ isLoading }/>
</ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>Age</ListItemMobileGrid.Label>
......
......@@ -10,6 +10,7 @@ import dayjs from 'lib/date/dayjs';
import BlockEntityL2 from 'ui/shared/entities/block/BlockEntityL2';
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import LinkInternal from 'ui/shared/LinkInternal';
import ZkEvmL2TxnBatchStatus from 'ui/shared/statusTag/ZkEvmL2TxnBatchStatus';
const feature = config.features.rollup;
......@@ -35,9 +36,7 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => {
/>
</Td>
<Td>
<Skeleton isLoaded={ !isLoading }>
<span>{ item.status }</span>
</Skeleton>
<ZkEvmL2TxnBatchStatus status={ item.status } isLoading={ isLoading }/>
</Td>
<Td>
<Skeleton isLoaded={ !isLoading } color="text_secondary">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment