add signers mobile view
@@ -32,4 +32,7 @@ export const ARBITRUM_L2_TXN_BATCH: ArbitrumL2TxnBatch = {
|
||||
before_acc: '0x2ed7c4985eb778d76ec400a43805e7feecc8c2afcdb492dbe5caf227de6d37bc',
|
||||
start_block: 1245209,
|
||||
end_block: 1245490,
|
||||
data_availability: {
|
||||
batch_data_container: 'in_blob4844',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -51,7 +51,7 @@ export type ArbitrumL2TxnBatchesResponse = {
|
||||
} | null;
|
||||
}
|
||||
|
||||
type BatchDataAvailability = {
|
||||
export type ArbitrumL2TxnBatchDAAnytrust = {
|
||||
batch_data_container: 'in_anytrust';
|
||||
bls_signature: string;
|
||||
data_hash: string;
|
||||
@@ -61,7 +61,9 @@ type BatchDataAvailability = {
|
||||
trusted: boolean;
|
||||
proof?: string;
|
||||
}>;
|
||||
} | {
|
||||
}
|
||||
|
||||
export type ArbitrumL2TxnBatchDataAvailability = ArbitrumL2TxnBatchDAAnytrust | {
|
||||
batch_data_container: Exclude<BatchDataContainer, 'in_anytrust'>;
|
||||
}
|
||||
|
||||
@@ -73,7 +75,7 @@ export type ArbitrumL2TxnBatch = {
|
||||
start_block: number;
|
||||
number: number;
|
||||
transactions_count: number;
|
||||
data_availability: BatchDataAvailability;
|
||||
data_availability: ArbitrumL2TxnBatchDataAvailability;
|
||||
}
|
||||
|
||||
export type ArbitrumL2BatchTxs = {
|
||||
|
||||
@@ -24,6 +24,13 @@ test('base view', async({ render, mockApiResponse }) => {
|
||||
await expect(component).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test('with anytrust DA', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('arbitrum_l2_txn_batch', batchDataAnytrust, { pathParams: { number: batchNumber } });
|
||||
const component = await render(<ArbitrumL2TxnBatch/>, { hooksConfig });
|
||||
await component.getByText('Show data availability info').click();
|
||||
await expect(component).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test.describe('mobile', () => {
|
||||
test.use({ viewport: devices['iPhone 13 Pro'].viewport });
|
||||
test('base view', async({ render, mockApiResponse }) => {
|
||||
@@ -31,11 +38,11 @@ test.describe('mobile', () => {
|
||||
const component = await render(<ArbitrumL2TxnBatch/>, { hooksConfig });
|
||||
await expect(component).toHaveScreenshot();
|
||||
});
|
||||
});
|
||||
|
||||
test('with anytrust DA', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('arbitrum_l2_txn_batch', batchDataAnytrust, { pathParams: { number: batchNumber } });
|
||||
const component = await render(<ArbitrumL2TxnBatch/>, { hooksConfig });
|
||||
await component.getByText('Show data availability info').click();
|
||||
await expect(component).toHaveScreenshot();
|
||||
test('with anytrust DA', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('arbitrum_l2_txn_batch', batchDataAnytrust, { pathParams: { number: batchNumber } });
|
||||
const component = await render(<ArbitrumL2TxnBatch/>, { hooksConfig });
|
||||
await component.getByText('Show data availability info').click();
|
||||
await expect(component).toHaveScreenshot();
|
||||
});
|
||||
});
|
||||
|
||||
|
After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 56 KiB |
@@ -1,4 +1,4 @@
|
||||
import { Grid, GridItem, Link, Text, Flex, Box, Skeleton, useColorModeValue } from '@chakra-ui/react';
|
||||
import { Grid, GridItem, Link, Skeleton } from '@chakra-ui/react';
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
@@ -9,7 +9,6 @@ import type { ArbitrumL2TxnBatch } from 'types/api/arbitrumL2';
|
||||
import { route } from 'nextjs-routes';
|
||||
|
||||
import type { ResourceError } from 'lib/api/resources';
|
||||
import dayjs from 'lib/date/dayjs';
|
||||
import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
|
||||
import isCustomAppError from 'ui/shared/AppError/isCustomAppError';
|
||||
import ArbitrumL2TxnBatchDA from 'ui/shared/batch/ArbitrumL2TxnBatchDA';
|
||||
@@ -19,12 +18,11 @@ import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
|
||||
import DetailsTimestamp from 'ui/shared/DetailsTimestamp';
|
||||
import BlockEntityL1 from 'ui/shared/entities/block/BlockEntityL1';
|
||||
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
|
||||
import HashStringShorten from 'ui/shared/HashStringShorten';
|
||||
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
import LinkInternal from 'ui/shared/links/LinkInternal';
|
||||
import PrevNext from 'ui/shared/PrevNext';
|
||||
import TextSeparator from 'ui/shared/TextSeparator';
|
||||
|
||||
import ArbitrumL2TxnBatchDetailsDA from './ArbitrumL2TxnBatchDetailsDA';
|
||||
interface Props {
|
||||
query: UseQueryResult<ArbitrumL2TxnBatch, ResourceError>;
|
||||
}
|
||||
@@ -54,8 +52,6 @@ const ArbitrumL2TxnBatchDetails = ({ query }: Props) => {
|
||||
router.push({ pathname: '/batches/[number]', query: { number: nextId } }, undefined);
|
||||
}, [ data, router ]);
|
||||
|
||||
const signersBg = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
|
||||
|
||||
if (isError) {
|
||||
if (isCustomAppError(error)) {
|
||||
throwOnResourceLoadError({ isError, error });
|
||||
@@ -227,83 +223,7 @@ const ArbitrumL2TxnBatchDetails = ({ query }: Props) => {
|
||||
<>
|
||||
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>
|
||||
|
||||
<DetailsInfoItem.Label
|
||||
isLoading={ isPlaceholderData }
|
||||
hint="Aggregated BLS signature of AnyTrust committee members"
|
||||
>
|
||||
Signature
|
||||
</DetailsInfoItem.Label>
|
||||
<DetailsInfoItem.Value wordBreak="break-all" whiteSpace="break-spaces">
|
||||
{ data.data_availability.bls_signature }
|
||||
</DetailsInfoItem.Value>
|
||||
|
||||
<DetailsInfoItem.Label
|
||||
isLoading={ isPlaceholderData }
|
||||
hint="The hash of the data blob stored by the AnyTrust committee"
|
||||
>
|
||||
Data hash
|
||||
</DetailsInfoItem.Label>
|
||||
<DetailsInfoItem.Value>
|
||||
{ data.data_availability.data_hash }
|
||||
<CopyToClipboard text={ data.data_availability.data_hash } ml={ 2 }/>
|
||||
</DetailsInfoItem.Value>
|
||||
|
||||
<DetailsInfoItem.Label
|
||||
isLoading={ isPlaceholderData }
|
||||
hint="Expiration timeout for the data blob"
|
||||
>
|
||||
Timeout
|
||||
</DetailsInfoItem.Label>
|
||||
<DetailsInfoItem.Value>
|
||||
{ dayjs(data.data_availability.timeout) < dayjs() ?
|
||||
<DetailsTimestamp timestamp={ data.data_availability.timeout }/> :
|
||||
(
|
||||
<>
|
||||
<Text>{ dayjs(data.data_availability.timeout).format('llll') }</Text>
|
||||
<TextSeparator color="gray.500"/>
|
||||
<Text color="red.500">{ dayjs(data.data_availability.timeout).diff(dayjs(), 'day') } days left</Text>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</DetailsInfoItem.Value>
|
||||
|
||||
<DetailsInfoItem.Label
|
||||
isLoading={ isPlaceholderData }
|
||||
hint="Members of AnyTrust committee"
|
||||
>
|
||||
Signers
|
||||
</DetailsInfoItem.Label>
|
||||
<DetailsInfoItem.Value overflowX="scroll">
|
||||
<Grid
|
||||
templateColumns="1fr auto auto"
|
||||
gap={ 5 }
|
||||
backgroundColor={ signersBg }
|
||||
padding={ 4 }
|
||||
borderRadius="md"
|
||||
minW="600px"
|
||||
>
|
||||
<Text fontWeight={ 600 }>Key</Text>
|
||||
<Text fontWeight={ 600 }>Trusted</Text>
|
||||
<Text fontWeight={ 600 }>Proof</Text>
|
||||
{ data.data_availability.signers.map(signer => (
|
||||
<>
|
||||
<Flex justifyContent="space-between">
|
||||
<Text wordBreak="break-all" whiteSpace="break-spaces">{ signer.key }</Text>
|
||||
<CopyToClipboard text={ signer.key } ml={ 2 }/>
|
||||
</Flex>
|
||||
<Box justifySelf="center">
|
||||
{ signer.trusted ? <IconSvg name="check" boxSize={ 6 }/> : <IconSvg name="cross" boxSize={ 6 }/> }
|
||||
</Box>
|
||||
{ signer.proof ? (
|
||||
<Flex>
|
||||
<HashStringShorten hash={ signer.proof }/>
|
||||
<CopyToClipboard text={ signer.proof } ml={ 2 }/>
|
||||
</Flex>
|
||||
) : '-' }
|
||||
</>
|
||||
)) }
|
||||
</Grid>
|
||||
</DetailsInfoItem.Value>
|
||||
<ArbitrumL2TxnBatchDetailsDA dataAvailability={ data.data_availability }/>
|
||||
</>
|
||||
) }
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
import { Grid, Text, Flex, Box, useColorModeValue, Show, Hide, VStack } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { ArbitrumL2TxnBatchDAAnytrust } from 'types/api/arbitrumL2';
|
||||
|
||||
import dayjs from 'lib/date/dayjs';
|
||||
import CopyToClipboard from 'ui/shared/CopyToClipboard';
|
||||
import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
|
||||
import DetailsTimestamp from 'ui/shared/DetailsTimestamp';
|
||||
import HashStringShorten from 'ui/shared/HashStringShorten';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
import TextSeparator from 'ui/shared/TextSeparator';
|
||||
|
||||
type Props = {
|
||||
dataAvailability: ArbitrumL2TxnBatchDAAnytrust;
|
||||
}
|
||||
|
||||
const ArbitrumL2TxnBatchDetailsDA = ({ dataAvailability }: Props) => {
|
||||
const signersBg = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
|
||||
|
||||
return (
|
||||
<>
|
||||
<DetailsInfoItem.Label
|
||||
hint="Aggregated BLS signature of AnyTrust committee members"
|
||||
>
|
||||
Signature
|
||||
</DetailsInfoItem.Label><DetailsInfoItem.Value wordBreak="break-all" whiteSpace="break-spaces">
|
||||
{ dataAvailability.bls_signature }
|
||||
</DetailsInfoItem.Value><DetailsInfoItem.Label
|
||||
hint="The hash of the data blob stored by the AnyTrust committee"
|
||||
>
|
||||
Data hash
|
||||
</DetailsInfoItem.Label><DetailsInfoItem.Value>
|
||||
{ dataAvailability.data_hash }
|
||||
<CopyToClipboard text={ dataAvailability.data_hash } ml={ 2 }/>
|
||||
</DetailsInfoItem.Value><DetailsInfoItem.Label
|
||||
hint="Expiration timeout for the data blob"
|
||||
>
|
||||
Timeout
|
||||
</DetailsInfoItem.Label><DetailsInfoItem.Value>
|
||||
{ dayjs(dataAvailability.timeout) < dayjs() ?
|
||||
<DetailsTimestamp timestamp={ dataAvailability.timeout }/> :
|
||||
(
|
||||
<>
|
||||
<Text>{ dayjs(dataAvailability.timeout).format('llll') }</Text>
|
||||
<TextSeparator color="gray.500"/>
|
||||
<Text color="red.500">{ dayjs(dataAvailability.timeout).diff(dayjs(), 'day') } days left</Text>
|
||||
</>
|
||||
) }
|
||||
</DetailsInfoItem.Value>
|
||||
<DetailsInfoItem.Label
|
||||
hint="Members of AnyTrust committee"
|
||||
>
|
||||
Signers
|
||||
</DetailsInfoItem.Label>
|
||||
<DetailsInfoItem.Value overflowX="scroll" fontSize="sm">
|
||||
<Show above="lg" ssr={ false }>
|
||||
<Grid
|
||||
templateColumns="1fr auto auto"
|
||||
gap={ 5 }
|
||||
backgroundColor={ signersBg }
|
||||
padding={ 4 }
|
||||
borderRadius="md"
|
||||
minW="600px"
|
||||
>
|
||||
<Text fontWeight={ 600 }>Key</Text>
|
||||
<Text fontWeight={ 600 }>Trusted</Text>
|
||||
<Text fontWeight={ 600 }>Proof</Text>
|
||||
{ dataAvailability.signers.map(signer => (
|
||||
<>
|
||||
<Flex justifyContent="space-between">
|
||||
<Text wordBreak="break-all" whiteSpace="break-spaces">{ signer.key }</Text>
|
||||
<CopyToClipboard text={ signer.key } ml={ 2 }/>
|
||||
</Flex>
|
||||
<Box justifySelf="center">
|
||||
{ signer.trusted ? <IconSvg name="check" boxSize={ 6 }/> : <IconSvg name="cross" boxSize={ 6 }/> }
|
||||
</Box>
|
||||
{ signer.proof ? (
|
||||
<Flex>
|
||||
<HashStringShorten hash={ signer.proof }/>
|
||||
<CopyToClipboard text={ signer.proof } ml={ 2 }/>
|
||||
</Flex>
|
||||
) : '-' }
|
||||
</>
|
||||
)) }
|
||||
</Grid>
|
||||
</Show>
|
||||
|
||||
<Hide above="lg" ssr={ false }>
|
||||
<Box backgroundColor={ signersBg } borderRadius="md">
|
||||
{ dataAvailability.signers.map(signer => (
|
||||
<VStack padding={ 4 } key={ signer.key } gap={ 2 }>
|
||||
<Flex w="100%" justifyContent="space-between">
|
||||
<Text fontWeight={ 600 }>Key</Text>
|
||||
<CopyToClipboard text={ signer.key }/>
|
||||
</Flex>
|
||||
<Text wordBreak="break-all" whiteSpace="break-spaces">{ signer.key }</Text>
|
||||
<Flex w="100%" alignItems="center">
|
||||
<Flex alignItems="center" w="50%">
|
||||
<Text fontWeight={ 600 } mr={ 2 }>Trusted</Text>
|
||||
{ signer.trusted ? <IconSvg name="check" boxSize={ 6 }/> : <IconSvg name="cross" boxSize={ 6 }/> }
|
||||
</Flex>
|
||||
<Flex alignItems="center" w="50%">
|
||||
<Text fontWeight={ 600 } mr={ 2 }>Proof</Text>
|
||||
{ signer.proof ? (
|
||||
<Flex>
|
||||
<HashStringShorten hash={ signer.proof }/>
|
||||
<CopyToClipboard text={ signer.proof } ml={ 2 }/>
|
||||
</Flex>
|
||||
) : '-' }
|
||||
</Flex>
|
||||
</Flex>
|
||||
</VStack>
|
||||
)) }
|
||||
</Box>
|
||||
</Hide>
|
||||
</DetailsInfoItem.Value>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ArbitrumL2TxnBatchDetailsDA;
|
||||