- Block |
+ Block |
Size, bytes |
{ !config.UI.views.block.hiddenFields?.miner &&
{ capitalize(getNetworkValidatorTitle()) } | }
diff --git a/ui/blocks/BlocksTableItem.tsx b/ui/blocks/BlocksTableItem.tsx
index 8ded36820f..80af501a61 100644
--- a/ui/blocks/BlocksTableItem.tsx
+++ b/ui/blocks/BlocksTableItem.tsx
@@ -44,6 +44,11 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement }: Props) => {
>
+ { data.celo?.is_epoch_block && (
+
+
+
+ ) }
{
) }
+ { statsQueryResult.data?.celo && (
+
+ Current epoch:
+ #{ statsQueryResult.data.celo.epoch_number }
+
+ ) }
{ content }
diff --git a/ui/home/LatestBlocksItem.tsx b/ui/home/LatestBlocksItem.tsx
index 72b428d93c..54419c2e0d 100644
--- a/ui/home/LatestBlocksItem.tsx
+++ b/ui/home/LatestBlocksItem.tsx
@@ -3,6 +3,7 @@ import {
Flex,
Grid,
Skeleton,
+ Tooltip,
} from '@chakra-ui/react';
import { motion } from 'framer-motion';
import React from 'react';
@@ -14,6 +15,7 @@ import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
+import IconSvg from 'ui/shared/IconSvg';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
type Props = {
@@ -46,6 +48,11 @@ const LatestBlocksItem = ({ block, isLoading }: Props) => {
fontWeight={ 500 }
mr="auto"
/>
+ { block.celo?.is_epoch_block && (
+
+
+
+ ) }
{
value: `${ BigNumber(data.rootstock_locked_btc).div(WEI).dp(0).toFormat() } RBTC`,
isLoading,
},
+ data.celo && {
+ icon: 'hourglass' as const,
+ label: 'Current epoch',
+ value: `#${ data.celo.epoch_number }`,
+ isLoading,
+ },
].filter(Boolean);
return (
diff --git a/ui/pages/Block.tsx b/ui/pages/Block.tsx
index 29cd7f2e8e..573f58e5d5 100644
--- a/ui/pages/Block.tsx
+++ b/ui/pages/Block.tsx
@@ -1,4 +1,4 @@
-import { chakra, Skeleton } from '@chakra-ui/react';
+import { chakra, Skeleton, Tooltip } from '@chakra-ui/react';
import capitalize from 'lodash/capitalize';
import { useRouter } from 'next/router';
import React from 'react';
@@ -14,6 +14,7 @@ import useIsMobile from 'lib/hooks/useIsMobile';
import getNetworkValidationActionText from 'lib/networks/getNetworkValidationActionText';
import getQueryParamString from 'lib/router/getQueryParamString';
import BlockDetails from 'ui/block/BlockDetails';
+import BlockEpochRewards from 'ui/block/BlockEpochRewards';
import BlockWithdrawals from 'ui/block/BlockWithdrawals';
import useBlockBlobTxsQuery from 'ui/block/useBlockBlobTxsQuery';
import useBlockQuery from 'ui/block/useBlockQuery';
@@ -21,6 +22,7 @@ import useBlockTxsQuery from 'ui/block/useBlockTxsQuery';
import useBlockWithdrawalsQuery from 'ui/block/useBlockWithdrawalsQuery';
import TextAd from 'ui/shared/ad/TextAd';
import ServiceDegradationWarning from 'ui/shared/alerts/ServiceDegradationWarning';
+import Tag from 'ui/shared/chakra/Tag';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import NetworkExplorers from 'ui/shared/NetworkExplorers';
import PageTitle from 'ui/shared/Page/PageTitle';
@@ -94,7 +96,12 @@ const BlockPageContent = () => {
>
),
} : null,
- ].filter(Boolean)), [ blockBlobTxsQuery, blockQuery, blockTxsQuery, blockWithdrawalsQuery, hasPagination ]);
+ blockQuery.data?.celo?.is_epoch_block ? {
+ id: 'epoch_rewards',
+ title: 'Epoch rewards',
+ component: ,
+ } : null,
+ ].filter(Boolean)), [ blockBlobTxsQuery, blockQuery, blockTxsQuery, blockWithdrawalsQuery, hasPagination, heightOrHash ]);
let pagination;
if (tab === 'txs') {
@@ -139,6 +146,25 @@ const BlockPageContent = () => {
return `Block #${ blockQuery.data?.height }`;
}
})();
+ const contentAfter = (() => {
+ if (!blockQuery.data?.celo) {
+ return null;
+ }
+
+ if (!blockQuery.data.celo.is_epoch_block) {
+ return (
+
+ Epoch #{ blockQuery.data.celo.epoch_number }
+
+ );
+ }
+
+ return (
+
+ Finalized epoch #{ blockQuery.data.celo.epoch_number }
+
+ );
+ })();
const titleSecondRow = (
<>
{ !config.UI.views.block.hiddenFields?.miner && (
@@ -166,6 +192,7 @@ const BlockPageContent = () => {
diff --git a/ui/pages/__screenshots__/Blocks.pw.tsx_dark-color-mode_base-view-dark-mode-1.png b/ui/pages/__screenshots__/Blocks.pw.tsx_dark-color-mode_base-view-dark-mode-1.png
index 0b0e83ab7c..692b38d152 100644
Binary files a/ui/pages/__screenshots__/Blocks.pw.tsx_dark-color-mode_base-view-dark-mode-1.png and b/ui/pages/__screenshots__/Blocks.pw.tsx_dark-color-mode_base-view-dark-mode-1.png differ
diff --git a/ui/pages/__screenshots__/Blocks.pw.tsx_default_base-view-dark-mode-1.png b/ui/pages/__screenshots__/Blocks.pw.tsx_default_base-view-dark-mode-1.png
index f323f61a1c..dbe834000d 100644
Binary files a/ui/pages/__screenshots__/Blocks.pw.tsx_default_base-view-dark-mode-1.png and b/ui/pages/__screenshots__/Blocks.pw.tsx_default_base-view-dark-mode-1.png differ
diff --git a/ui/pages/__screenshots__/Blocks.pw.tsx_default_hidden-fields-1.png b/ui/pages/__screenshots__/Blocks.pw.tsx_default_hidden-fields-1.png
index 4db3cd98f2..510e3019c5 100644
Binary files a/ui/pages/__screenshots__/Blocks.pw.tsx_default_hidden-fields-1.png and b/ui/pages/__screenshots__/Blocks.pw.tsx_default_hidden-fields-1.png differ
diff --git a/ui/pages/__screenshots__/Blocks.pw.tsx_default_new-item-from-socket-1.png b/ui/pages/__screenshots__/Blocks.pw.tsx_default_new-item-from-socket-1.png
index 6e23cda129..d2fa2ec9c8 100644
Binary files a/ui/pages/__screenshots__/Blocks.pw.tsx_default_new-item-from-socket-1.png and b/ui/pages/__screenshots__/Blocks.pw.tsx_default_new-item-from-socket-1.png differ
diff --git a/ui/pages/__screenshots__/Blocks.pw.tsx_default_socket-error-1.png b/ui/pages/__screenshots__/Blocks.pw.tsx_default_socket-error-1.png
index 1c3da310ea..ccd7bde953 100644
Binary files a/ui/pages/__screenshots__/Blocks.pw.tsx_default_socket-error-1.png and b/ui/pages/__screenshots__/Blocks.pw.tsx_default_socket-error-1.png differ
diff --git a/ui/shared/DetailsInfoItem.tsx b/ui/shared/DetailsInfoItem.tsx
index 20982f6f3b..bae00ec3ad 100644
--- a/ui/shared/DetailsInfoItem.tsx
+++ b/ui/shared/DetailsInfoItem.tsx
@@ -3,6 +3,7 @@ import React from 'react';
import * as ContainerWithScrollY from 'ui/shared/ContainerWithScrollY';
import Hint from 'ui/shared/Hint';
+import HintPopover from 'ui/shared/HintPopover';
const LabelScrollText = () => (
@@ -11,15 +12,16 @@ const LabelScrollText = () => (
);
interface LabelProps {
- hint?: string;
+ hint?: React.ReactNode;
children: React.ReactNode;
isLoading?: boolean;
className?: string;
id?: string;
hasScroll?: boolean;
+ type?: 'tooltip' | 'popover';
}
-const Label = chakra(({ hint, children, isLoading, id, className, hasScroll }: LabelProps) => {
+const Label = chakra(({ hint, children, isLoading, id, className, hasScroll, type }: LabelProps) => {
return (
- { hint && }
+ { hint && (type === 'popover' ?
+ :
+ ) }
{ children }
{ hasScroll && }
diff --git a/ui/shared/HintPopover.tsx b/ui/shared/HintPopover.tsx
new file mode 100644
index 0000000000..7dde21f4fa
--- /dev/null
+++ b/ui/shared/HintPopover.tsx
@@ -0,0 +1,57 @@
+import type {
+ PopoverBodyProps,
+ PopoverContentProps,
+ PopoverProps } from '@chakra-ui/react';
+import {
+ Skeleton,
+ DarkMode,
+ PopoverArrow,
+ PopoverBody,
+ PopoverContent,
+ PopoverTrigger,
+ Portal,
+ chakra,
+ useColorModeValue,
+} from '@chakra-ui/react';
+import React from 'react';
+
+import Popover from 'ui/shared/chakra/Popover';
+
+import IconSvg from './IconSvg';
+
+interface Props {
+ label: React.ReactNode;
+ className?: string;
+ isLoading?: boolean;
+ popoverProps?: Partial;
+ popoverContentProps?: Partial;
+ popoverBodyProps?: Partial;
+}
+
+const HintPopover = ({ label, isLoading, className, popoverProps, popoverContentProps, popoverBodyProps }: Props) => {
+ const bgColor = useColorModeValue('gray.700', 'gray.900');
+
+ if (isLoading) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+ { label }
+
+
+
+
+
+ );
+};
+
+export default React.memo(chakra(HintPopover));
diff --git a/ui/tx/details/TxDetailsTokenTransfer.tsx b/ui/shared/TokenTransferSnippet/TokenTransferSnippet.tsx
similarity index 66%
rename from ui/tx/details/TxDetailsTokenTransfer.tsx
rename to ui/shared/TokenTransferSnippet/TokenTransferSnippet.tsx
index 5c5762b184..1fde813b2f 100644
--- a/ui/tx/details/TxDetailsTokenTransfer.tsx
+++ b/ui/shared/TokenTransferSnippet/TokenTransferSnippet.tsx
@@ -1,8 +1,8 @@
-import { Flex } from '@chakra-ui/react';
+import { Flex, Skeleton } from '@chakra-ui/react';
import React from 'react';
import type {
- TokenTransfer as TTokenTransfer,
+ TokenTransfer,
Erc20TotalPayload,
Erc721TotalPayload,
Erc1155TotalPayload,
@@ -10,27 +10,34 @@ import type {
} from 'types/api/tokenTransfer';
import AddressFromTo from 'ui/shared/address/AddressFromTo';
-import NftTokenTransferSnippet from 'ui/tx/NftTokenTransferSnippet';
-import FtTokenTransferSnippet from '../FtTokenTransferSnippet';
+import TokenTransferSnippetFiat from './TokenTransferSnippetFiat';
+import TokenTransferSnippetNft from './TokenTransferSnippetNft';
interface Props {
- data: TTokenTransfer;
+ data: TokenTransfer;
+ noAddressIcons?: boolean;
+ isLoading?: boolean;
}
-const TxDetailsTokenTransfer = ({ data }: Props) => {
+const TokenTransferSnippet = ({ data, isLoading, noAddressIcons = true }: Props) => {
const content = (() => {
+
+ if (isLoading) {
+ return ;
+ }
+
switch (data.token.type) {
case 'ERC-20': {
const total = data.total as Erc20TotalPayload;
- return ;
+ return ;
}
case 'ERC-721': {
const total = data.total as Erc721TotalPayload;
return (
- {
case 'ERC-1155': {
const total = data.total as Erc1155TotalPayload;
return (
- {
if (total.token_id !== null) {
return (
- {
return null;
}
- return ;
+ return ;
}
}
}
@@ -86,12 +93,13 @@ const TxDetailsTokenTransfer = ({ data }: Props) => {
from={ data.from }
to={ data.to }
truncation="constant"
- noIcon
+ noIcon={ noAddressIcons }
fontWeight="500"
+ isLoading={ isLoading }
/>
{ content }
);
};
-export default React.memo(TxDetailsTokenTransfer);
+export default React.memo(TokenTransferSnippet);
diff --git a/ui/tx/FtTokenTransferSnippet.tsx b/ui/shared/TokenTransferSnippet/TokenTransferSnippetFiat.tsx
similarity index 100%
rename from ui/tx/FtTokenTransferSnippet.tsx
rename to ui/shared/TokenTransferSnippet/TokenTransferSnippetFiat.tsx
diff --git a/ui/tx/NftTokenTransferSnippet.tsx b/ui/shared/TokenTransferSnippet/TokenTransferSnippetNft.tsx
similarity index 100%
rename from ui/tx/NftTokenTransferSnippet.tsx
rename to ui/shared/TokenTransferSnippet/TokenTransferSnippetNft.tsx
diff --git a/ui/shared/entities/address/AddressEntityContentProxy.tsx b/ui/shared/entities/address/AddressEntityContentProxy.tsx
index 066c8e5448..66fbb4146f 100644
--- a/ui/shared/entities/address/AddressEntityContentProxy.tsx
+++ b/ui/shared/entities/address/AddressEntityContentProxy.tsx
@@ -33,6 +33,7 @@ const AddressEntityContentProxy = (props: ContentProps) => {
{ ...props }
truncation={ nameTag || implementationName || props.address.name ? 'tail' : props.truncation }
text={ nameTag || implementationName || props.address.name || props.address.hash }
+ isTooltipDisabled
/>
diff --git a/ui/shared/entities/base/components.tsx b/ui/shared/entities/base/components.tsx
index f86ec7a798..67a96e33d5 100644
--- a/ui/shared/entities/base/components.tsx
+++ b/ui/shared/entities/base/components.tsx
@@ -113,9 +113,10 @@ const Icon = ({ isLoading, iconSize, noIcon, name, color, borderRadius }: IconBa
export interface ContentBaseProps extends Pick {
asProp?: As;
text: string;
+ isTooltipDisabled?: boolean;
}
-const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dynamic', tailLength }: ContentBaseProps) => {
+const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dynamic', tailLength, isTooltipDisabled }: ContentBaseProps) => {
const children = (() => {
switch (truncation) {
@@ -125,6 +126,7 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna
hash={ text }
as={ asProp }
type="long"
+ isTooltipDisabled={ isTooltipDisabled }
/>
);
case 'constant':
@@ -132,6 +134,7 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna
);
case 'dynamic':
@@ -140,6 +143,7 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna
hash={ text }
as={ asProp }
tailLength={ tailLength }
+ isTooltipDisabled={ isTooltipDisabled }
/>
);
case 'tail':
diff --git a/ui/shared/pagination/useLazyLoadedList.tsx b/ui/shared/pagination/useLazyLoadedList.tsx
new file mode 100644
index 0000000000..f53125c1d6
--- /dev/null
+++ b/ui/shared/pagination/useLazyLoadedList.tsx
@@ -0,0 +1,45 @@
+import type { InfiniteData, UseInfiniteQueryResult } from '@tanstack/react-query';
+import React from 'react';
+import { useInView } from 'react-intersection-observer';
+
+import type { PaginatedResources, ResourceError, ResourcePayload } from 'lib/api/resources';
+import type { Params as ApiInfiniteQueryParams } from 'lib/api/useApiInfiniteQuery';
+import useApiInfiniteQuery from 'lib/api/useApiInfiniteQuery';
+
+interface Params extends ApiInfiniteQueryParams {
+ rootRef: React.RefObject;
+}
+
+interface ReturnType {
+ cutRef: (node?: Element | null) => void;
+ query: UseInfiniteQueryResult>, ResourceError>;
+}
+
+export default function useLazyLoadedList({
+ rootRef,
+ resourceName,
+ queryOptions,
+ pathParams,
+}: Params): ReturnType {
+ const query = useApiInfiniteQuery({
+ resourceName,
+ pathParams,
+ queryOptions,
+ });
+
+ const { ref, inView } = useInView({
+ root: rootRef.current,
+ triggerOnce: false,
+ skip: queryOptions?.enabled === false || query.isFetchingNextPage || !query.hasNextPage,
+ });
+
+ React.useEffect(() => {
+ if (inView) {
+ query.fetchNextPage();
+ }
+ // should run only on inView state change
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [ inView ]);
+
+ return { cutRef: ref, query };
+}
diff --git a/ui/sol2uml/Sol2UmlDiagram.tsx b/ui/sol2uml/Sol2UmlDiagram.tsx
index 9ba28ad7b1..8af184211f 100644
--- a/ui/sol2uml/Sol2UmlDiagram.tsx
+++ b/ui/sol2uml/Sol2UmlDiagram.tsx
@@ -45,8 +45,8 @@ const Sol2UmlDiagram = ({ addressHash }: Props) => {
sources: composeSources(contractQuery.data),
},
},
- queryKey: [ 'visualize_sol2uml', addressHash ],
queryOptions: {
+ queryKey: [ 'visualize_sol2uml', addressHash ],
enabled: Boolean(contractQuery.data),
refetchOnMount: false,
},
diff --git a/ui/tx/details/TxDetailsTokenTransfers.tsx b/ui/tx/details/TxDetailsTokenTransfers.tsx
index c9cc9673c5..d8e57c8450 100644
--- a/ui/tx/details/TxDetailsTokenTransfers.tsx
+++ b/ui/tx/details/TxDetailsTokenTransfers.tsx
@@ -8,8 +8,7 @@ import { route } from 'nextjs-routes';
import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal';
-
-import TxDetailsTokenTransfer from './TxDetailsTokenTransfer';
+import TokenTransferSnippet from 'ui/shared/TokenTransferSnippet/TokenTransferSnippet';
interface Props {
data: Array;
@@ -54,7 +53,7 @@ const TxDetailsTokenTransfers = ({ data, txHash, isOverflow }: Props) => {
w="100%"
overflow="hidden"
>
- { items.map((item, index) => ) }
+ { items.map((item, index) => ) }
|