Commit 22b24070 authored by tom's avatar tom

skeleton for block details

parent 52a6dbdc
import type { NextPage } from 'next'; import type { NextPage } from 'next';
import dynamic from 'next/dynamic';
import Head from 'next/head'; import Head from 'next/head';
import type { RoutedQuery } from 'nextjs-routes'; import type { RoutedQuery } from 'nextjs-routes';
import React from 'react'; import React from 'react';
import getSeo from 'lib/next/block/getSeo'; import getSeo from 'lib/next/block/getSeo';
import Block from 'ui/pages/Block';
import Page from 'ui/shared/Page/Page'; import Page from 'ui/shared/Page/Page';
const Block = dynamic(() => import('ui/pages/Block'), { ssr: false });
const BlockPage: NextPage<RoutedQuery<'/block/[height]'>> = ({ height }: RoutedQuery<'/block/[height]'>) => { const BlockPage: NextPage<RoutedQuery<'/block/[height]'>> = ({ height }: RoutedQuery<'/block/[height]'>) => {
const { title, description } = getSeo({ height }); const { title, description } = getSeo({ height });
return ( return (
......
import { Grid, GridItem, Text, Icon, Link, Box, Tooltip, useColorModeValue } from '@chakra-ui/react'; import { Grid, GridItem, Text, Icon, Link, Box, Tooltip, useColorModeValue, Skeleton } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import capitalize from 'lodash/capitalize'; import capitalize from 'lodash/capitalize';
...@@ -19,7 +19,6 @@ import dayjs from 'lib/date/dayjs'; ...@@ -19,7 +19,6 @@ import dayjs from 'lib/date/dayjs';
import { space } from 'lib/html-entities'; import { space } from 'lib/html-entities';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle'; import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import BlockDetailsSkeleton from 'ui/block/details/BlockDetailsSkeleton';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
...@@ -42,7 +41,7 @@ const BlockDetails = ({ query }: Props) => { ...@@ -42,7 +41,7 @@ const BlockDetails = ({ query }: Props) => {
const separatorColor = useColorModeValue('gray.200', 'gray.700'); const separatorColor = useColorModeValue('gray.200', 'gray.700');
const { data, isLoading, isError, error } = query; const { data, isPlaceholderData, isError, error } = query;
const handleCutClick = React.useCallback(() => { const handleCutClick = React.useCallback(() => {
setIsExpanded((flag) => !flag); setIsExpanded((flag) => !flag);
...@@ -63,10 +62,6 @@ const BlockDetails = ({ query }: Props) => { ...@@ -63,10 +62,6 @@ const BlockDetails = ({ query }: Props) => {
router.push({ pathname: '/block/[height]', query: { height: nextId } }, undefined); router.push({ pathname: '/block/[height]', query: { height: nextId } }, undefined);
}, [ data, router ]); }, [ data, router ]);
if (isLoading) {
return <BlockDetailsSkeleton/>;
}
if (isError) { if (isError) {
if (error?.status === 404) { if (error?.status === 404) {
throw Error('Block not found', { cause: error as unknown as Error }); throw Error('Block not found', { cause: error as unknown as Error });
...@@ -79,6 +74,10 @@ const BlockDetails = ({ query }: Props) => { ...@@ -79,6 +74,10 @@ const BlockDetails = ({ query }: Props) => {
return <DataFetchAlert/>; return <DataFetchAlert/>;
} }
if (!data) {
return null;
}
const sectionGap = ( const sectionGap = (
<GridItem <GridItem
colSpan={{ base: undefined, lg: 2 }} colSpan={{ base: undefined, lg: 2 }}
...@@ -92,13 +91,50 @@ const BlockDetails = ({ query }: Props) => { ...@@ -92,13 +91,50 @@ const BlockDetails = ({ query }: Props) => {
const validatorTitle = getNetworkValidatorTitle(); const validatorTitle = getNetworkValidatorTitle();
const rewardBreakDown = (() => {
if (appConfig.L2.isL2Network || totalReward.isEqualTo(ZERO) || txFees.isEqualTo(ZERO) || burntFees.isEqualTo(ZERO)) {
return null;
}
if (isPlaceholderData) {
return <Skeleton w="525px" h="20px"/>;
}
return (
<Text variant="secondary" whiteSpace="break-spaces">
<Tooltip label="Static block reward">
<span>{ staticReward.dividedBy(WEI).toFixed() }</span>
</Tooltip>
{ !txFees.isEqualTo(ZERO) && (
<>
{ space }+{ space }
<Tooltip label="Txn fees">
<span>{ txFees.dividedBy(WEI).toFixed() }</span>
</Tooltip>
</>
) }
{ !burntFees.isEqualTo(ZERO) && (
<>
{ space }-{ space }
<Tooltip label="Burnt fees">
<span>{ burntFees.dividedBy(WEI).toFixed() }</span>
</Tooltip>
</>
) }
</Text>
);
})();
return ( return (
<Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }} overflow="hidden"> <Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }} overflow="hidden">
<DetailsInfoItem <DetailsInfoItem
title={ `${ data.type === 'reorg' ? 'Reorg' : 'Block' } height` } title={ `${ data.type === 'reorg' ? 'Reorg' : 'Block' } height` }
hint="The block height of a particular block is defined as the number of blocks preceding it in the blockchain" hint="The block height of a particular block is defined as the number of blocks preceding it in the blockchain"
isLoading={ isPlaceholderData }
> >
{ data.height } <Skeleton isLoaded={ !isPlaceholderData }>
{ data.height }
</Skeleton>
{ data.height === 0 && <Text whiteSpace="pre"> - Genesis Block</Text> } { data.height === 0 && <Text whiteSpace="pre"> - Genesis Block</Text> }
<PrevNext <PrevNext
ml={ 6 } ml={ 6 }
...@@ -106,37 +142,52 @@ const BlockDetails = ({ query }: Props) => { ...@@ -106,37 +142,52 @@ const BlockDetails = ({ query }: Props) => {
prevLabel="View previous block" prevLabel="View previous block"
nextLabel="View next block" nextLabel="View next block"
isPrevDisabled={ data.height === 0 } isPrevDisabled={ data.height === 0 }
isLoading={ isPlaceholderData }
/> />
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Size" title="Size"
hint="Size of the block in bytes" hint="Size of the block in bytes"
isLoading={ isPlaceholderData }
> >
{ data.size.toLocaleString() } <Skeleton isLoaded={ !isPlaceholderData }>
{ data.size.toLocaleString() }
</Skeleton>
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Timestamp" title="Timestamp"
hint="Date & time at which block was produced." hint="Date & time at which block was produced."
isLoading={ isPlaceholderData }
> >
<Icon as={ clockIcon } boxSize={ 5 } color="gray.500"/> <Skeleton isLoaded={ !isPlaceholderData } boxSize={ 5 } borderRadius="full">
<Text ml={ 1 }>{ dayjs(data.timestamp).fromNow() }</Text> <Icon as={ clockIcon } boxSize={ 5 } color="gray.500"/>
</Skeleton>
<Skeleton isLoaded={ !isPlaceholderData } ml={ 1 }>
{ dayjs(data.timestamp).fromNow() }
</Skeleton>
<TextSeparator/> <TextSeparator/>
<Text whiteSpace="normal">{ dayjs(data.timestamp).format('LLLL') }</Text> <Skeleton isLoaded={ !isPlaceholderData } whiteSpace="normal">
{ dayjs(data.timestamp).format('LLLL') }
</Skeleton>
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Transactions" title="Transactions"
hint="The number of transactions in the block" hint="The number of transactions in the block"
isLoading={ isPlaceholderData }
> >
<LinkInternal href={ route({ pathname: '/block/[height]', query: { height: heightOrHash, tab: 'txs' } }) }> <Skeleton isLoaded={ !isPlaceholderData }>
{ data.tx_count } transaction{ data.tx_count === 1 ? '' : 's' } <LinkInternal href={ route({ pathname: '/block/[height]', query: { height: heightOrHash, tab: 'txs' } }) }>
</LinkInternal> { data.tx_count } transaction{ data.tx_count === 1 ? '' : 's' }
</LinkInternal>
</Skeleton>
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title={ appConfig.network.verificationType === 'validation' ? 'Validated by' : 'Mined by' } title={ appConfig.network.verificationType === 'validation' ? 'Validated by' : 'Mined by' }
hint="A block producer who successfully included the block onto the blockchain" hint="A block producer who successfully included the block onto the blockchain"
columnGap={ 1 } columnGap={ 1 }
isLoading={ isPlaceholderData }
> >
<AddressLink type="address" hash={ data.miner.hash }/> <AddressLink type="address" hash={ data.miner.hash } isLoading={ isPlaceholderData }/>
{ data.miner.name && <Text>{ `(${ capitalize(validatorTitle) }: ${ data.miner.name })` }</Text> } { data.miner.name && <Text>{ `(${ capitalize(validatorTitle) }: ${ data.miner.name })` }</Text> }
{ /* api doesn't return the block processing time yet */ } { /* api doesn't return the block processing time yet */ }
{ /* <Text>{ dayjs.duration(block.minedIn, 'second').humanize(true) }</Text> */ } { /* <Text>{ dayjs.duration(block.minedIn, 'second').humanize(true) }</Text> */ }
...@@ -149,31 +200,12 @@ const BlockDetails = ({ query }: Props) => { ...@@ -149,31 +200,12 @@ const BlockDetails = ({ query }: Props) => {
on top of the fees paid for all transactions in the block` on top of the fees paid for all transactions in the block`
} }
columnGap={ 1 } columnGap={ 1 }
isLoading={ isPlaceholderData }
> >
<Text>{ totalReward.dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }</Text> <Skeleton isLoaded={ !isPlaceholderData }>
{ (!txFees.isEqualTo(ZERO) || !burntFees.isEqualTo(ZERO)) && ( { totalReward.dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }
<Text variant="secondary" whiteSpace="break-spaces">( </Skeleton>
<Tooltip label="Static block reward"> { rewardBreakDown }
<span>{ staticReward.dividedBy(WEI).toFixed() }</span>
</Tooltip>
{ !txFees.isEqualTo(ZERO) && (
<>
{ space }+{ space }
<Tooltip label="Txn fees">
<span>{ txFees.dividedBy(WEI).toFixed() }</span>
</Tooltip>
</>
) }
{ !burntFees.isEqualTo(ZERO) && (
<>
{ space }-{ space }
<Tooltip label="Burnt fees">
<span>{ burntFees.dividedBy(WEI).toFixed() }</span>
</Tooltip>
</>
) }
)</Text>
) }
</DetailsInfoItem> </DetailsInfoItem>
) } ) }
{ data.rewards { data.rewards
...@@ -195,35 +227,49 @@ const BlockDetails = ({ query }: Props) => { ...@@ -195,35 +227,49 @@ const BlockDetails = ({ query }: Props) => {
<DetailsInfoItem <DetailsInfoItem
title="Gas used" title="Gas used"
hint="The total gas amount used in the block and its percentage of gas filled in the block" hint="The total gas amount used in the block and its percentage of gas filled in the block"
isLoading={ isPlaceholderData }
> >
<Text>{ BigNumber(data.gas_used || 0).toFormat() }</Text> <Skeleton isLoaded={ !isPlaceholderData }>
{ BigNumber(data.gas_used || 0).toFormat() }
</Skeleton>
<Utilization <Utilization
ml={ 4 } ml={ 4 }
colorScheme="gray" colorScheme="gray"
value={ BigNumber(data.gas_used || 0).dividedBy(BigNumber(data.gas_limit)).toNumber() } value={ BigNumber(data.gas_used || 0).dividedBy(BigNumber(data.gas_limit)).toNumber() }
isLoading={ isPlaceholderData }
/> />
{ data.gas_target_percentage && ( { data.gas_target_percentage && (
<> <>
<TextSeparator color={ separatorColor } mx={ 1 }/> <TextSeparator color={ separatorColor } mx={ 1 }/>
<GasUsedToTargetRatio value={ data.gas_target_percentage }/> <GasUsedToTargetRatio value={ data.gas_target_percentage } isLoading={ isPlaceholderData }/>
</> </>
) } ) }
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Gas limit" title="Gas limit"
hint="Total gas limit provided by all transactions in the block" hint="Total gas limit provided by all transactions in the block"
isLoading={ isPlaceholderData }
> >
<Text>{ BigNumber(data.gas_limit).toFormat() }</Text> <Skeleton isLoaded={ !isPlaceholderData }>
{ BigNumber(data.gas_limit).toFormat() }
</Skeleton>
</DetailsInfoItem> </DetailsInfoItem>
{ data.base_fee_per_gas && ( { data.base_fee_per_gas && (
<DetailsInfoItem <DetailsInfoItem
title="Base fee per gas" title="Base fee per gas"
hint="Minimum fee required per unit of gas. Fee adjusts based on network congestion" hint="Minimum fee required per unit of gas. Fee adjusts based on network congestion"
isLoading={ isPlaceholderData }
> >
<Text>{ BigNumber(data.base_fee_per_gas).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } </Text> { isPlaceholderData ? (
<Text variant="secondary" whiteSpace="pre"> <Skeleton isLoaded={ !isPlaceholderData } h="20px" maxW="380px" w="100%"/>
{ space }({ BigNumber(data.base_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() } Gwei) ) : (
</Text> <>
<Text>{ BigNumber(data.base_fee_per_gas).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } </Text>
<Text variant="secondary" whiteSpace="pre">
{ space }({ BigNumber(data.base_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() } Gwei)
</Text>
</>
) }
</DetailsInfoItem> </DetailsInfoItem>
) } ) }
<DetailsInfoItem <DetailsInfoItem
...@@ -233,15 +279,21 @@ const BlockDetails = ({ query }: Props) => { ...@@ -233,15 +279,21 @@ const BlockDetails = ({ query }: Props) => {
Equals Block Base Fee per Gas * Gas Used` Equals Block Base Fee per Gas * Gas Used`
} }
isLoading={ isPlaceholderData }
> >
<Icon as={ flameIcon } boxSize={ 5 } color="gray.500"/> <Skeleton isLoaded={ !isPlaceholderData } boxSize={ 5 }>
<Text ml={ 1 }>{ burntFees.dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }</Text> <Icon as={ flameIcon } boxSize={ 5 } color="gray.500"/>
</Skeleton>
<Skeleton isLoaded={ !isPlaceholderData } ml={ 1 }>
{ burntFees.dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }
</Skeleton>
{ !txFees.isEqualTo(ZERO) && ( { !txFees.isEqualTo(ZERO) && (
<Tooltip label="Burnt fees / Txn fees * 100%"> <Tooltip label="Burnt fees / Txn fees * 100%">
<Box> <Box>
<Utilization <Utilization
ml={ 4 } ml={ 4 }
value={ burntFees.dividedBy(txFees).toNumber() } value={ burntFees.dividedBy(txFees).toNumber() }
isLoading={ isPlaceholderData }
/> />
</Box> </Box>
</Tooltip> </Tooltip>
...@@ -251,8 +303,11 @@ const BlockDetails = ({ query }: Props) => { ...@@ -251,8 +303,11 @@ const BlockDetails = ({ query }: Props) => {
<DetailsInfoItem <DetailsInfoItem
title="Priority fee / Tip" title="Priority fee / Tip"
hint="User-defined tips sent to validator for transaction priority/inclusion" hint="User-defined tips sent to validator for transaction priority/inclusion"
isLoading={ isPlaceholderData }
> >
{ BigNumber(data.priority_fee).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } <Skeleton isLoaded={ !isPlaceholderData }>
{ BigNumber(data.priority_fee).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }
</Skeleton>
</DetailsInfoItem> </DetailsInfoItem>
) } ) }
{ /* api doesn't support extra data yet */ } { /* api doesn't support extra data yet */ }
...@@ -267,21 +322,21 @@ const BlockDetails = ({ query }: Props) => { ...@@ -267,21 +322,21 @@ const BlockDetails = ({ query }: Props) => {
{ /* CUT */ } { /* CUT */ }
<GridItem colSpan={{ base: undefined, lg: 2 }}> <GridItem colSpan={{ base: undefined, lg: 2 }}>
<Element name="BlockDetails__cutLink"> <Element name="BlockDetails__cutLink">
<Link <Skeleton isLoaded={ !isPlaceholderData } mt={ 6 } display="inline-block">
mt={ 6 } <Link
display="inline-block" fontSize="sm"
fontSize="sm" textDecorationLine="underline"
textDecorationLine="underline" textDecorationStyle="dashed"
textDecorationStyle="dashed" onClick={ handleCutClick }
onClick={ handleCutClick } >
> { isExpanded ? 'Hide details' : 'View details' }
{ isExpanded ? 'Hide details' : 'View details' } </Link>
</Link> </Skeleton>
</Element> </Element>
</GridItem> </GridItem>
{ /* ADDITIONAL INFO */ } { /* ADDITIONAL INFO */ }
{ isExpanded && ( { isExpanded && !isPlaceholderData && (
<> <>
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/> <GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>
......
import { Grid, GridItem, Skeleton } from '@chakra-ui/react';
import React from 'react';
import DetailsSkeletonRow from 'ui/shared/skeletons/DetailsSkeletonRow';
const BlockDetailsSkeleton = () => {
const sectionGap = (
<GridItem
colSpan={{ base: undefined, lg: 2 }}
mt={{ base: 2, lg: 3 }}
mb={{ base: 0, lg: 3 }}
borderBottom="1px solid"
borderColor="divider"
/>
);
return (
<Grid columnGap={ 8 } rowGap={{ base: 5, lg: 7 }} templateColumns={{ base: '1fr', lg: '210px 1fr' }} maxW="1000px">
<DetailsSkeletonRow w="25%"/>
<DetailsSkeletonRow w="25%"/>
<DetailsSkeletonRow w="65%"/>
<DetailsSkeletonRow w="25%"/>
<DetailsSkeletonRow/>
<DetailsSkeletonRow/>
{ sectionGap }
<DetailsSkeletonRow w="50%"/>
<DetailsSkeletonRow w="25%"/>
<DetailsSkeletonRow w="50%"/>
<DetailsSkeletonRow w="50%"/>
<DetailsSkeletonRow w="50%"/>
{ sectionGap }
<GridItem colSpan={{ base: undefined, lg: 2 }}>
<Skeleton h={ 5 } borderRadius="full" w="100px"/>
</GridItem>
</Grid>
);
};
export default BlockDetailsSkeleton;
...@@ -10,6 +10,7 @@ import { useAppContext } from 'lib/appContext'; ...@@ -10,6 +10,7 @@ import { useAppContext } from 'lib/appContext';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import useQueryWithPages from 'lib/hooks/useQueryWithPages'; import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import { BLOCK } from 'stubs/block';
import BlockDetails from 'ui/block/BlockDetails'; import BlockDetails from 'ui/block/BlockDetails';
import BlockWithdrawals from 'ui/block/BlockWithdrawals'; import BlockWithdrawals from 'ui/block/BlockWithdrawals';
import TextAd from 'ui/shared/ad/TextAd'; import TextAd from 'ui/shared/ad/TextAd';
...@@ -35,14 +36,17 @@ const BlockPageContent = () => { ...@@ -35,14 +36,17 @@ const BlockPageContent = () => {
const blockQuery = useApiQuery('block', { const blockQuery = useApiQuery('block', {
pathParams: { height }, pathParams: { height },
queryOptions: { enabled: Boolean(height) }, queryOptions: {
enabled: Boolean(height),
placeholderData: BLOCK,
},
}); });
const blockTxsQuery = useQueryWithPages({ const blockTxsQuery = useQueryWithPages({
resourceName: 'block_txs', resourceName: 'block_txs',
pathParams: { height }, pathParams: { height },
options: { options: {
enabled: Boolean(blockQuery.data?.height && tab === 'txs'), enabled: Boolean(!blockQuery.isPlaceholderData && blockQuery.data?.height && tab === 'txs'),
}, },
}); });
...@@ -50,7 +54,7 @@ const BlockPageContent = () => { ...@@ -50,7 +54,7 @@ const BlockPageContent = () => {
resourceName: 'block_withdrawals', resourceName: 'block_withdrawals',
pathParams: { height }, pathParams: { height },
options: { options: {
enabled: Boolean(blockQuery.data?.height && appConfig.beaconChain.hasBeaconChain && tab === 'withdrawals'), enabled: Boolean(!blockQuery.isPlaceholderData && blockQuery.data?.height && appConfig.beaconChain.hasBeaconChain && tab === 'withdrawals'),
}, },
}); });
......
import { Box, Icon, IconButton, chakra, Tooltip } from '@chakra-ui/react'; import { Box, Icon, IconButton, chakra, Tooltip, Flex, Skeleton } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import eastArrow from 'icons/arrows/east-mini.svg'; import eastArrow from 'icons/arrows/east-mini.svg';
...@@ -10,9 +10,10 @@ interface Props { ...@@ -10,9 +10,10 @@ interface Props {
nextLabel?: string; nextLabel?: string;
isPrevDisabled?: boolean; isPrevDisabled?: boolean;
isNextDisabled?: boolean; isNextDisabled?: boolean;
isLoading?: boolean;
} }
const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, isNextDisabled }: Props) => { const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, isNextDisabled, isLoading }: Props) => {
const handelPrevClick = React.useCallback(() => { const handelPrevClick = React.useCallback(() => {
onClick('prev'); onClick('prev');
}, [ onClick ]); }, [ onClick ]);
...@@ -21,6 +22,15 @@ const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, is ...@@ -21,6 +22,15 @@ const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, is
onClick('next'); onClick('next');
}, [ onClick ]); }, [ onClick ]);
if (isLoading) {
return (
<Flex columnGap="10px" className={ className }>
<Skeleton boxSize={ 6 } borderRadius="sm"/>
<Skeleton boxSize={ 6 } borderRadius="sm"/>
</Flex>
);
}
return ( return (
<Box className={ className }> <Box className={ className }>
<Tooltip label={ prevLabel }> <Tooltip label={ prevLabel }>
......
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