Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- ## [[2.3.1](https://github.com/multiversx/mx-explorer-dapp/pull/199)] - 2025-10-29

- [Updated Account Token Value display constrains](https://github.com/multiversx/mx-explorer-dapp/pull/198)
- [Transaction Preview Button](https://github.com/multiversx/mx-explorer-dapp/pull/198)
- [Removed FormatDisplayValue Whitespace](https://github.com/multiversx/mx-explorer-dapp/pull/197)

- ## [[2.3.0](https://github.com/multiversx/mx-explorer-dapp/pull/196)] - 2025-10-20
Expand Down
8 changes: 0 additions & 8 deletions cypress/e2e/Dashbboard/Dashboard.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@ import {
describe('Dashboard', () => {
beforeEach(() => {
cy.visit('/');
cy.apiIntercept(ApiMethodsEnum.GET, ApiEndpointsEnum.blocks);
cy.apiIntercept(ApiMethodsEnum.GET, ApiEndpointsEnum.transactions);
cy.apiIntercept(ApiMethodsEnum.GET, ApiEndpointsEnum.stats);
});

it('should successfully return the API responses', () => {
cy.verifyApiResponse(ApiEndpointsEnum.blocks, (xhr) => {
expect(xhr?.response?.body).to.have.lengthOf(25);
});
cy.verifyApiResponse(ApiEndpointsEnum.transactions, (xhr) => {
expect(xhr?.response?.body).to.have.lengthOf(25);
});
cy.verifyApiResponse(ApiEndpointsEnum.stats, (xhr) => {
expect(xhr?.response?.body?.accounts).to.be.at.least(3200);
expect(xhr?.response?.body?.scResults).to.be.at.least(48177);
Expand Down
1 change: 1 addition & 0 deletions cypress/e2e/Transactions/Transactions.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ describe('Transactions', () => {

it('should properly display the table', () => {
const tableHead = [
'',
'Txn Hash',
'Age',
'Shard',
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "mx-explorer-dapp",
"description": "MultiversX Blockchain Explorer",
"version": "2.3.0",
"version": "2.3.1",
"author": "MultiversX",
"license": "GPL-3.0-or-later",
"repository": "multiversx/mx-explorer-dapp",
Expand All @@ -16,8 +16,8 @@
"@fortawesome/free-regular-svg-icons": "6.7.2",
"@fortawesome/free-solid-svg-icons": "6.7.2",
"@fortawesome/react-fontawesome": "0.2.0",
"@multiversx/sdk-core": "15.2.1",
"@multiversx/sdk-dapp": "5.2.9",
"@multiversx/sdk-core": "15.3.0",
"@multiversx/sdk-dapp": "5.2.13",
"@multiversx/sdk-dapp-sc-explorer": "0.0.6-beta.1",
"@multiversx/sdk-dapp-ui": "0.0.36",
"@multiversx/sdk-dapp-utils": "3.0.2",
Expand Down
3 changes: 2 additions & 1 deletion src/appConstants/general.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export const MAX_DISPLAY_TX_DATA_LENGTH = 1_000_000;
export const MAX_DISPLAY_ZERO_DECIMALS = 5;
export const MAX_ACOUNT_TOKENS_BALANCE = 1000;

export const LOW_LIQUIDITY_DISPLAY_TRESHOLD = 1_000_000;
export const LOW_LIQUIDITY_DISPLAY_TRESHOLD = 100_000;
export const LOW_LIQUIDITY_MIN_LIQUIDITY_THRESHHOLD = 200;
export const LOW_LIQUIDITY_MARKET_CAP_DISPLAY_TRESHOLD = 10_000_000;

export const AUCTION_LIST_MAX_NODES = 3000;
Expand Down
1 change: 1 addition & 0 deletions src/assets/scss/components/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
@import '../../../components/PauseRefreshButton/pauseRefreshButton.styles';
@import '../../../components/PercentageBar/percentageBar.styles.scss';
@import '../../../components/PercentageLed/percentageLed.styles.scss';
@import '../../../components/PreviewPanel/previewPanel.styles.scss';
@import '../../../components/ProgressRing/progressRing.styles.scss';
@import '../../../components/ProvidersTable/providersTable.styles.scss';
@import '../../../components/PulsatingLed/pulsatingLed.styles.scss';
Expand Down
6 changes: 3 additions & 3 deletions src/components/BlocksTable/BlocksTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
import { formatSize } from 'helpers';
import { useIsSovereign } from 'hooks';
import { blocksSelector } from 'redux/selectors';
import { pauseRefresh, resumeRefresh } from 'redux/slices/blocks';
import { pauseBlocksRefresh, resumeBlocksRefresh } from 'redux/slices/blocks';
import { UIBlockType, WithClassnameType } from 'types';

import { FailedBlocks } from './components/FailedBlocks';
Expand Down Expand Up @@ -87,8 +87,8 @@ export const BlocksTable = ({
<th className='d-flex align-item-center justify-content-between'>
Leader{' '}
<PauseRefreshButton
pauseRefresh={pauseRefresh}
resumeRefresh={resumeRefresh}
pauseRefresh={pauseBlocksRefresh}
resumeRefresh={resumeBlocksRefresh}
isRefreshPaused={isRefreshPaused}
/>
</th>
Expand Down
6 changes: 3 additions & 3 deletions src/components/EventsTable/components/EventsTableHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from 'components';
import { useIsSovereign } from 'hooks';
import { eventsSelector } from 'redux/selectors';
import { pauseRefresh, resumeRefresh } from 'redux/slices/events';
import { pauseEventsRefresh, resumeEventsRefresh } from 'redux/slices';
import { TransactionFiltersEnum, WithClassnameType } from 'types';

export interface EventsTableHeaderUIType extends WithClassnameType {
Expand Down Expand Up @@ -42,8 +42,8 @@ export const EventsTableHeader = ({
Identifier <IdentifierColumnFilters />
</div>
<PauseRefreshButton
pauseRefresh={pauseRefresh}
resumeRefresh={resumeRefresh}
pauseRefresh={pauseEventsRefresh}
resumeRefresh={resumeEventsRefresh}
isRefreshPaused={isRefreshPaused}
/>
</th>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export const NodeQualification = ({
<Overlay title='Dropped'>
<FontAwesomeIcon
icon={faScissors}
className='text-red-400 icon-dropped'
className='text-red-400 icon-small'
/>
</Overlay>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import { useRef, useState } from 'react';
import classNames from 'classnames';
import { OverlayTrigger, Popover } from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';

import { Loader } from 'components';
import { PreviewPanelWrapper } from 'components';
import { useAdapter } from 'hooks';

import { nodesOverviewSelector } from 'redux/selectors';
import { addNodeDetails } from 'redux/slices';
import {
IndexedNodeStatusPreviewType,
WithClassnameType,
NodeType
} from 'types';
import { IndexedNodeStatusPreviewType, WithClassnameType } from 'types';

import { NodePanel } from '../NodePanel';

Expand All @@ -21,71 +15,26 @@ export interface NodeCellUIType extends WithClassnameType {
}

export const NodeCell = ({ node, className }: NodeCellUIType) => {
const ref = useRef(null);
const dispatch = useDispatch();
const { bls, status, isInDangerZone, auctionQualified } = node;
const { nodeDetails: stateNodeSetails } = useSelector(nodesOverviewSelector);
const { getNode } = useAdapter();

const [show, setShow] = useState(false);
const [dataReady, setDataReady] = useState<boolean | undefined>();
const [nodeDetails, setNodeDetails] = useState<NodeType | undefined>();
const currentNode = stateNodeSetails?.[bls];

const fetchNodeDetails = (bls: string) => {
if (bls) {
if (stateNodeSetails?.[bls]) {
setNodeDetails(stateNodeSetails[bls]);
setDataReady(true);
return;
return (
<PreviewPanelWrapper
hash={bls}
fetchData={() => getNode(bls)}
cachedPreviews={stateNodeSetails ?? {}}
preview={
currentNode && <NodePanel node={currentNode} index={node.index} />
}

getNode(bls).then(({ data, success }) => {
setNodeDetails(data);
onApiData={(data) => {
dispatch(addNodeDetails({ nodeDetails: data }));
setDataReady(data && success);
});
}
};

const handleOnMouseEnter = () => {
setShow(true);
};
const handleOnMouseLeave = () => {
setShow(false);
};

return (
<OverlayTrigger
key='popover'
trigger={['click', 'hover']}
placement='top'
delay={{ show: 100, hide: 400 }}
rootClose
onToggle={(show) => {
if (show) {
fetchNodeDetails(bls);
}
}}
show={show}
overlay={
<Popover
id='popover-positioned-bottom'
className='node-panel-wrapper'
onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave}
>
{dataReady && nodeDetails ? (
<NodePanel node={nodeDetails} index={node.index} />
) : (
<Loader className='px-5' />
)}
</Popover>
}
>
<div
ref={ref}
onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave}
className={classNames(
'node-cell cursor-context',
status,
Expand All @@ -97,6 +46,6 @@ export const NodeCell = ({ node, className }: NodeCellUIType) => {
)}
aria-description={`${bls}: ${status}`}
></div>
</OverlayTrigger>
</PreviewPanelWrapper>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const NodePanel = ({
<span>Node</span>
<NodeOnlineState node={node} />
</div>
<div className='node-bls d-flex align-items-center gap-2'>
<div className='preview-small preview-hash d-flex align-items-center gap-2'>
<NodeChangingShardIcon node={node} />
<NodeIssueIcon node={node} />
<Trim text={node.bls} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import {
NodeQualification,
NodeRating,
NodeStatus,
PreviewPanelCard,
ShardLink
} from 'components';
import { useIsSovereign } from 'hooks';
import { nodesOverviewSelector } from 'redux/selectors';
import { NodeType, NodeStatusEnum } from 'types';

import { PanelCard } from './PanelCard';
import { TimeRemainingPanelCard } from './TimeRemainingPanelCard';

export const NodePanelCards = ({
Expand All @@ -26,49 +26,50 @@ export const NodePanelCards = ({
const { nodes } = useSelector(nodesOverviewSelector);

return (
<dl className='node-panel-cards'>
<PanelCard title='Name'>
<dl className='preview-panel-cards'>
<PreviewPanelCard title='Name'>
{node.name ? (
<div className='truncate-item-lg' title={node.name}>
{node.name}
</div>
) : (
<span className='text-neutral-400'>N/A</span>
)}
</PanelCard>
<PanelCard title='Version'>
</PreviewPanelCard>
<PreviewPanelCard title='Version'>
{node.version ? node.version : 'N/A'}
</PanelCard>
<PanelCard title={isSovereign ? 'Chain' : 'Shard'}>
</PreviewPanelCard>
<PreviewPanelCard title={isSovereign ? 'Chain' : 'Shard'}>
<ShardLink shard={node.shard} />
</PanelCard>
<PanelCard title='Rating'>
</PreviewPanelCard>
<PreviewPanelCard title='Rating'>
<NodeRating node={node} />
</PanelCard>
<PanelCard title='Status' featured>
</PreviewPanelCard>
<PreviewPanelCard title='Status' featured>
<NodeStatus node={node} />
</PanelCard>
</PreviewPanelCard>
{node.status === NodeStatusEnum.auction ? (
<PanelCard
<PreviewPanelCard
title='Auction Status'
className={classNames({
'border danger-zone': node.auctionQualified && node.isInDangerZone
'border border-warning':
node.auctionQualified && node.isInDangerZone
})}
featured
>
<NodeQualification node={node} showLed={node.auctionQualified} />
</PanelCard>
</PreviewPanelCard>
) : (
<>
{index !== undefined && (
<PanelCard title='List Index' featured>
<PreviewPanelCard title='List Index' featured>
<span className='text-neutral-200'>{index}</span> of{' '}
{nodes.length}
</PanelCard>
</PreviewPanelCard>
)}
</>
)}
<PanelCard
<PreviewPanelCard
title={
node.status === NodeStatusEnum.auction
? 'Qualified Stake'
Expand All @@ -77,7 +78,7 @@ export const NodePanelCards = ({
featured
>
<NodeLockedStake node={node} showLabel={false} />
</PanelCard>
</PreviewPanelCard>
<TimeRemainingPanelCard node={node} />
</dl>
);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { ELLIPSIS } from 'appConstants';
import { PreviewPanelCard } from 'components';
import { formatBigNumber } from 'helpers';
import { useGetEpochRemainingTime } from 'hooks';

import { NodeType, NodeStatusEnum } from 'types';

import { PanelCard } from './PanelCard';

export const TimeRemainingPanelCard = ({ node }: { node: NodeType }) => {
const { epoch, remainingTime, isStatsFetched } = useGetEpochRemainingTime();
const [days, hours, minutes, seconds] = remainingTime;
Expand All @@ -22,7 +21,7 @@ export const TimeRemainingPanelCard = ({ node }: { node: NodeType }) => {
};

return (
<PanelCard
<PreviewPanelCard
title={getRemainingTimeTitle()}
className='text-primary'
featured
Expand All @@ -41,6 +40,6 @@ export const TimeRemainingPanelCard = ({ node }: { node: NodeType }) => {
) : (
ELLIPSIS
)}
</PanelCard>
</PreviewPanelCard>
);
};
Loading
Loading