Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0a97c3fde | ||
|
|
4af2ad9a13 | ||
|
|
10f35a317b | ||
|
|
1d4ccf590d | ||
|
|
abd2768110 | ||
|
|
f474672d03 | ||
|
|
97d34fd660 | ||
|
|
7e5b9d58bb | ||
|
|
0636564a28 | ||
|
|
aee48cac31 | ||
|
|
a8463d1e32 | ||
|
|
56dd5062e1 | ||
|
|
9355f3b672 | ||
|
|
df757dc7a3 | ||
|
|
b8fa6ff783 | ||
|
|
198cbd98c0 | ||
|
|
98b244d1fc | ||
|
|
50e845c3ac | ||
|
|
4d94c0a8de | ||
|
|
1bd9fbbc36 | ||
|
|
87d15bbaa0 | ||
|
|
e44d205c7f | ||
|
|
ecf705ddb2 | ||
|
|
d4398a9e99 | ||
|
|
99db852687 | ||
|
|
582f9757f4 | ||
|
|
59f20f6d4d | ||
|
|
e8a3f9fdc7 | ||
|
|
64568777f5 | ||
|
|
37b03d884e | ||
|
|
58d91f231e | ||
|
|
36d8a773aa | ||
|
|
ca66dfc626 | ||
|
|
524a82cbf9 | ||
|
|
1af9bb900b | ||
|
|
719ffbbd05 | ||
|
|
3c88cf48ee | ||
|
|
19ea8ff25f | ||
|
|
3b76a95fbf | ||
|
|
8060e068a3 | ||
|
|
7cf3eac6f8 | ||
|
|
f415523240 | ||
|
|
2405d1d6e1 | ||
|
|
3233651178 | ||
|
|
3c8d735a1c | ||
|
|
3d2463c18d | ||
|
|
4da20fd502 | ||
|
|
41240ff640 | ||
|
|
97951cd6fb | ||
|
|
f311bedf5e | ||
|
|
5246b7bace | ||
|
|
b29ea07dfa | ||
|
|
a154ac1b2d | ||
|
|
86fd0d7fe6 | ||
|
|
e49fe6014c | ||
|
|
15398cc23f | ||
|
|
9a24d6437a | ||
|
|
5e3ea30046 | ||
|
|
f011bcb543 | ||
|
|
16937ecacf | ||
|
|
31116a9cd6 | ||
|
|
75a5c9649a | ||
|
|
9f0b3f0de6 | ||
|
|
3841fac411 | ||
|
|
d96322a525 | ||
|
|
0c238c4517 | ||
|
|
1f3b683ebc | ||
|
|
f2fdeeee44 | ||
|
|
2ae477260b | ||
|
|
7162ac1303 | ||
|
|
ccb23ca1a2 | ||
|
|
ad5d4801d1 | ||
|
|
28b819b995 | ||
|
|
6b2b502498 | ||
|
|
9aec3b9881 | ||
|
|
28dbdf2951 | ||
|
|
24a799a369 | ||
|
|
27fa8ebb9b | ||
|
|
48f9f32fe9 | ||
|
|
97ccc5cbd0 |
@@ -28,7 +28,7 @@ jobs:
|
||||
echo IS_MAINNET_RELEASE=false >> $GITHUB_ENV
|
||||
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
||||
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
||||
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
||||
echo IS_S3_RELASE=false >> $GITHUB_ENV
|
||||
|
||||
- name: Is PR
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
@@ -51,9 +51,9 @@ jobs:
|
||||
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is S3 Release
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' }}
|
||||
if: ${{ env.IS_IPFS_RELASE == 'false' && github.event_name == 'push' }}
|
||||
run: |
|
||||
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
||||
echo IS_S3_RELASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Set up QEMU
|
||||
id: quemu
|
||||
@@ -251,7 +251,7 @@ jobs:
|
||||
- name: Publish dist to s3
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
# s3 releases are not happening for trading on mainnet - it's IPFS
|
||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||
if: ${{ env.IS_S3_RELASE == 'true' }}
|
||||
with:
|
||||
args: --acl private --follow-symlinks --delete
|
||||
env:
|
||||
@@ -262,11 +262,11 @@ jobs:
|
||||
SOURCE_DIR: 'dist-result'
|
||||
|
||||
- name: Install aws CLI
|
||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||
if: ${{ env.IS_S3_RELASE == 'true' }}
|
||||
uses: unfor19/install-aws-cli-action@master
|
||||
|
||||
- name: Perform cache invalidation
|
||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||
if: ${{ env.IS_S3_RELASE == 'true' }}
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
|
||||
@@ -40,7 +40,7 @@ context.skip('Transactions page', function () {
|
||||
.first()
|
||||
.click({ force: true });
|
||||
} else {
|
||||
cy.log('Unable to find any transactions on page');
|
||||
cy.slack('Unable to find any transactions on page');
|
||||
cy.screenshot();
|
||||
}
|
||||
});
|
||||
@@ -78,7 +78,7 @@ context.skip('Transactions page', function () {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cy.log('Unable to find any transactions on page');
|
||||
cy.slack('Unable to find any transactions on page');
|
||||
cy.screenshot();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -137,7 +137,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||
headerName: t('Enactment date'),
|
||||
field: 'terms.enactmentDatetime',
|
||||
valueFormatter: ({
|
||||
valueFormatte: ({
|
||||
value,
|
||||
}: VegaValueFormatterParams<
|
||||
ProposalListFieldsFragment,
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export interface TxDetailsOrderIcebergDetailsProps {
|
||||
iceberg: components['schemas']['v1IcebergOpts'];
|
||||
size: components['schemas']['v1OrderSubmission']['size'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
.iceberg .sub {
|
||||
vertical-align: bottom;
|
||||
color: #954F01;
|
||||
}
|
||||
|
||||
.iceberg .sup {
|
||||
vertical-align: top;
|
||||
color: #515E1E;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Visualises the iceberg details of an order, showing the minimum visible size,
|
||||
* the full size and the peak size.
|
||||
*/
|
||||
export const TxOrderIcebergDetails = ({
|
||||
iceberg,
|
||||
size,
|
||||
}: TxDetailsOrderIcebergDetailsProps) => {
|
||||
return (
|
||||
<div
|
||||
className="inline-block iceberg bg-vega-blue-300 border-vega-blue-350 border-[1px] text-[70%] font-mono py-[2px] pl-2 pr-3 height-[1em] leading-[1em] cursor-pointer"
|
||||
style={{ clipPath: 'polygon(10% 0%, 100% 0%, 90% 100%, 0% 100%)' }}
|
||||
>
|
||||
<Tooltip description={t('Iceberg: Minimum visible size')}>
|
||||
<span className="align-bottom text-vega-orange-650">
|
||||
{iceberg.minimumVisibleSize || '-'}
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip description={t('Iceberg: Total size')}>
|
||||
<span className="text-sm text-vega-blue-600 mx-3">{size}</span>
|
||||
</Tooltip>
|
||||
<Tooltip description={t('Iceberg: Visible peak')}>
|
||||
<span className="align-top text-vega-yellow-600">
|
||||
{iceberg.peakSize || '-'}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -8,7 +8,6 @@ import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||
import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
|
||||
import Hash from '../../links/hash';
|
||||
import { TxOrderPeggedReferenceRow } from './order/tx-order-peg';
|
||||
import { TxOrderIcebergDetails } from './order/tx-order-iceberg';
|
||||
|
||||
interface TxDetailsOrderProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
@@ -33,8 +32,6 @@ export const TxDetailsOrder = ({
|
||||
const marketId = txData.command.orderSubmission.marketId || '-';
|
||||
const reference = txData.command.orderSubmission.peggedOrder;
|
||||
const side = txData.command.orderSubmission.side;
|
||||
const iceberg = txData.command.orderSubmission.icebergOpts;
|
||||
const size = txData.command.orderSubmission.size;
|
||||
|
||||
let deterministicId = '';
|
||||
|
||||
@@ -77,14 +74,6 @@ export const TxDetailsOrder = ({
|
||||
marketId={marketId}
|
||||
/>
|
||||
) : null}
|
||||
{iceberg ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Iceberg details')}</TableCell>
|
||||
<TableCell>
|
||||
<TxOrderIcebergDetails iceberg={iceberg} size={size} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
|
||||
{deterministicId.length > 0 ? (
|
||||
|
||||
@@ -166,7 +166,6 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
||||
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-250';
|
||||
|
||||
// This will get unwieldy and should probably produce a different colour of tag
|
||||
// Note that colours are currently arbitrary
|
||||
if (type === 'Chain Event' && !!command?.chainEvent) {
|
||||
type = getLabelForChainEvent(command.chainEvent);
|
||||
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
|
||||
@@ -178,9 +177,6 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
||||
type = getLabelForProposal(command.proposalSubmission);
|
||||
}
|
||||
colours = 'text-black bg-vega-yellow';
|
||||
} else if (type === 'Order' && command) {
|
||||
type = getLabelForOrderType(orderType, command);
|
||||
colours = 'text-white dark-text-white bg-vega-blue dark:bg-vega-blue';
|
||||
}
|
||||
|
||||
if (type === 'Vote on Proposal') {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { DATA_SOURCES } from '../../../config';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||
import type { TendermintBlocksResponse } from '../tendermint-blocks-response';
|
||||
import { RouteTitle } from '../../../components/route-title';
|
||||
import { TimeAgo } from '../../../components/time-ago';
|
||||
import {
|
||||
@@ -12,7 +14,7 @@ import { TxsPerBlock } from '../../../components/txs/txs-per-block';
|
||||
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { Routes } from '../../route-names';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useBlockInfo } from '@vegaprotocol/tendermint';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { NodeLink } from '../../../components/links';
|
||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||
import EmptyList from '../../../components/empty-list/empty-list';
|
||||
@@ -22,7 +24,10 @@ const Block = () => {
|
||||
useDocumentTitle(['Blocks', `Block #${block}`]);
|
||||
const {
|
||||
state: { data: blockData, loading, error },
|
||||
} = useBlockInfo(Number(block));
|
||||
} = useFetch<TendermintBlocksResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/block?height=${block}`,
|
||||
{ cache: 'force-cache' }
|
||||
);
|
||||
|
||||
return (
|
||||
<section>
|
||||
|
||||
@@ -18,10 +18,6 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
LC_ALL="en_US.UTF-8"
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@ NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_VEGA_REST_URL=http://localhost:3008/api/v2/
|
||||
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
|
||||
|
||||
@@ -13,6 +13,3 @@ NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.n00.devnet1.vega.xyz/api/v2/
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
|
||||
@@ -14,6 +14,3 @@ NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.vega.community/api/v2/
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
@@ -13,6 +13,3 @@ NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-mirror-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/
|
||||
|
||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||
|
||||
@@ -9,6 +9,3 @@ NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
@@ -14,6 +14,3 @@ NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
@@ -11,6 +11,3 @@ NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.
|
||||
@@ -18,10 +18,6 @@ import { VegaWallet } from '../vega-wallet';
|
||||
import { useLocation, useMatch } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
import { useTelemetryDialog } from '../telemetry-dialog/telemetry-dialog';
|
||||
import {
|
||||
ProtocolUpgradeCountdown,
|
||||
ProtocolUpgradeCountdownMode,
|
||||
} from '@vegaprotocol/proposals';
|
||||
|
||||
export const SettingsLink = () => {
|
||||
const { open, isOpen, close } = useTelemetryDialog();
|
||||
@@ -65,14 +61,7 @@ export const Nav = ({ theme }: Pick<NavigationProps, 'theme'>) => {
|
||||
appName="Governance"
|
||||
theme={theme}
|
||||
breakpoints={[458, 959]}
|
||||
actions={
|
||||
<>
|
||||
<SettingsLink />
|
||||
<ProtocolUpgradeCountdown
|
||||
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
actions={<SettingsLink />}
|
||||
>
|
||||
<NavigationList
|
||||
className="[.drawer-content_&]:border-b [.drawer-content_&]:border-b-vega-light-200 dark:[.drawer-content_&]:border-b-vega-dark-200 [.drawer-content_&]:pb-8 [.drawer-content_&]:mb-2"
|
||||
|
||||
@@ -4,11 +4,7 @@ import type { ReactNode } from 'react';
|
||||
import { AnnouncementBanner } from '@vegaprotocol/announcements';
|
||||
import { Nav } from '../nav';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import {
|
||||
ProtocolUpgradeCountdownMode,
|
||||
ProtocolUpgradeProposalNotification,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
|
||||
import React from 'react';
|
||||
|
||||
interface AppLayoutProps {
|
||||
children: ReactNode;
|
||||
@@ -35,23 +31,8 @@ export const AppLayout = ({ children }: AppLayoutProps) => {
|
||||
/>
|
||||
)}
|
||||
<Nav theme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
|
||||
<NotificationsContainer />
|
||||
</div>
|
||||
<div className={AppLayoutClasses}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const NotificationsContainer = () => {
|
||||
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
|
||||
return (
|
||||
<div data-testid="banners">
|
||||
<ProtocolUpgradeProposalNotification
|
||||
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
|
||||
/>
|
||||
{isReadOnly ? (
|
||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import React from 'react';
|
||||
|
||||
export interface TemplateSidebarProps {
|
||||
@@ -6,18 +8,24 @@ export interface TemplateSidebarProps {
|
||||
}
|
||||
|
||||
export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
||||
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
|
||||
return (
|
||||
<div className="w-full border-b border-neutral-700 lg:grid lg:grid-rows-[1fr] lg:grid-cols-[1fr_450px]">
|
||||
<main className="max-w-[100vw] col-start-1 p-4 overflow-auto">
|
||||
{children}
|
||||
</main>
|
||||
<aside className="col-start-2 row-start-1 row-span-2 hidden lg:block p-4 bg-banner bg-contain border-l border-neutral-700">
|
||||
{sidebar.map((Component, i) => (
|
||||
<section className="mb-4 last:mb-0" key={i}>
|
||||
{Component}
|
||||
</section>
|
||||
))}
|
||||
</aside>
|
||||
</div>
|
||||
<>
|
||||
{isReadOnly ? (
|
||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||
) : null}
|
||||
<div className="w-full border-b border-neutral-700 lg:grid lg:grid-rows-[1fr] lg:grid-cols-[1fr_450px]">
|
||||
<main className="max-w-[100vw] col-start-1 p-4 overflow-auto">
|
||||
{children}
|
||||
</main>
|
||||
<aside className="col-start-2 row-start-1 row-span-2 hidden lg:block p-4 bg-banner bg-contain border-l border-neutral-700">
|
||||
{sidebar.map((Component, i) => (
|
||||
<section className="mb-4 last:mb-0" key={i}>
|
||||
{Component}
|
||||
</section>
|
||||
))}
|
||||
</aside>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -837,7 +837,5 @@
|
||||
"RejectedProposals": "Rejected proposals",
|
||||
"networkGovernance": "Network governance",
|
||||
"networkUpgrades": "Network upgrades",
|
||||
"assetSpecification": "Asset specification",
|
||||
"Estimated time to upgrade": "Estimated time to upgrade",
|
||||
"Upgraded at": "Upgraded at"
|
||||
"assetSpecification": "Asset specification"
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import {
|
||||
orderByDate,
|
||||
orderByUpgradeBlockHeight,
|
||||
} from '../proposals/components/proposals-list/proposals-list';
|
||||
import { BigNumber } from '../../lib/bignumber';
|
||||
|
||||
const nodesToShow = 6;
|
||||
|
||||
@@ -249,8 +248,6 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
|
||||
|
||||
const activeNodes = removePaginationWrapper(
|
||||
validatorsData?.nodesConnection.edges
|
||||
).filter((node) =>
|
||||
new BigNumber(node.rankingScore.performanceScore).isGreaterThan(0)
|
||||
);
|
||||
|
||||
const trimmedActiveNodes = activeNodes?.slice(0, nodesToShow);
|
||||
|
||||
+8
-36
@@ -4,20 +4,16 @@ import { render } from '@testing-library/react';
|
||||
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
|
||||
import { ProtocolUpgradeProposalDetailInfo } from './protocol-upgrade-proposal-detail-info';
|
||||
|
||||
const PROPOSAL = {
|
||||
vegaReleaseTag: 'v0.1.234',
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
|
||||
upgradeBlockHeight: '12345',
|
||||
approvers: [],
|
||||
};
|
||||
|
||||
const renderComponent = (lastBlockHeight?: string, time?: string) =>
|
||||
const renderComponent = () =>
|
||||
render(
|
||||
<ProtocolUpgradeProposalDetailInfo
|
||||
proposal={PROPOSAL}
|
||||
lastBlockHeight={lastBlockHeight}
|
||||
time={time}
|
||||
proposal={{
|
||||
vegaReleaseTag: 'v0.1.234',
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
|
||||
upgradeBlockHeight: '12345',
|
||||
approvers: [],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -47,28 +43,4 @@ describe('ProtocolUpgradeProposalDetailInfo', () => {
|
||||
'v0.1.234'
|
||||
);
|
||||
});
|
||||
|
||||
it('should display estimated time if proposal is still pending', () => {
|
||||
const { getByTestId } = renderComponent('12', 'time');
|
||||
expect(getByTestId('protocol-upgrade-time-label')).toHaveTextContent(
|
||||
'Estimated time to upgrade'
|
||||
);
|
||||
expect(getByTestId('protocol-upgrade-time')).toHaveTextContent('time');
|
||||
});
|
||||
|
||||
it('should display upgraded at if proposal is done', () => {
|
||||
const { getByTestId } = renderComponent('123456', 'time');
|
||||
expect(getByTestId('protocol-upgrade-time-label')).toHaveTextContent(
|
||||
'Upgraded at'
|
||||
);
|
||||
expect(getByTestId('protocol-upgrade-time')).toHaveTextContent('time');
|
||||
});
|
||||
|
||||
it('should not display time if none provided', () => {
|
||||
const { queryByTestId } = renderComponent('123456', undefined);
|
||||
expect(
|
||||
queryByTestId('protocol-upgrade-time-label')
|
||||
).not.toBeInTheDocument();
|
||||
expect(queryByTestId('protocol-upgrade-time')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
+3
-30
@@ -5,33 +5,19 @@ import {
|
||||
RoundedWrapper,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { type ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
|
||||
|
||||
export interface ProtocolUpgradeProposalDetailInfoProps {
|
||||
proposal: ProtocolUpgradeProposalFieldsFragment;
|
||||
lastBlockHeight?: string;
|
||||
time?: string | ReactNode;
|
||||
}
|
||||
|
||||
export const ProtocolUpgradeProposalDetailInfo = ({
|
||||
proposal,
|
||||
lastBlockHeight,
|
||||
time,
|
||||
}: ProtocolUpgradeProposalDetailInfoProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const shouldShowUpgradeTime =
|
||||
![
|
||||
Types.ProtocolUpgradeProposalStatus
|
||||
.PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED,
|
||||
Types.ProtocolUpgradeProposalStatus
|
||||
.PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED,
|
||||
].includes(proposal.status) && time;
|
||||
|
||||
const pending = Number(proposal.upgradeBlockHeight) > Number(lastBlockHeight);
|
||||
|
||||
return (
|
||||
<div className="mb-10">
|
||||
<SubHeading title={t('proposal')} />
|
||||
@@ -43,26 +29,13 @@ export const ProtocolUpgradeProposalDetailInfo = ({
|
||||
<span data-testid="protocol-upgrade-block-height">
|
||||
{proposal.upgradeBlockHeight}{' '}
|
||||
{lastBlockHeight && (
|
||||
<span className="text-vega-light-300 dark:text-vega-dark-300">
|
||||
<>
|
||||
({t('currently')} {lastBlockHeight})
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
|
||||
{shouldShowUpgradeTime && (
|
||||
<KeyValueTableRow>
|
||||
<span
|
||||
data-testid="protocol-upgrade-time-label"
|
||||
className="uppercase"
|
||||
>
|
||||
{pending ? t('Estimated time to upgrade') : t('Upgraded at')}
|
||||
</span>
|
||||
|
||||
<span data-testid="protocol-upgrade-time">{time}</span>
|
||||
</KeyValueTableRow>
|
||||
)}
|
||||
|
||||
<KeyValueTableRow>
|
||||
<span className="uppercase">{t('state')}</span>
|
||||
|
||||
|
||||
+2
-38
@@ -1,23 +1,14 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
convertToCountdownString,
|
||||
formatDateWithLocalTimezone,
|
||||
removePaginationWrapper,
|
||||
stripFullStops,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { removePaginationWrapper, stripFullStops } from '@vegaprotocol/utils';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
import { ProtocolUpgradeProposal } from './protocol-upgrade-proposal';
|
||||
import { ProposalNotFound } from '../components/proposal-not-found';
|
||||
import { useNodesQuery } from '../../staking/home/__generated__/Nodes';
|
||||
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
||||
import {
|
||||
useProtocolUpgradeProposalsQuery,
|
||||
useTimeToUpgrade,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { useBlockInfo } from '@vegaprotocol/tendermint';
|
||||
import { useProtocolUpgradeProposalsQuery } from '@vegaprotocol/proposals';
|
||||
|
||||
export const ProtocolUpgradeProposalContainer = () => {
|
||||
const params = useParams<{ proposalReleaseTag: string }>();
|
||||
@@ -67,20 +58,6 @@ export const ProtocolUpgradeProposalContainer = () => {
|
||||
);
|
||||
}, [nodesData]);
|
||||
|
||||
const pending =
|
||||
Number(protocolUpgradeProposal?.upgradeBlockHeight) >
|
||||
Number(data?.lastBlockHeight);
|
||||
|
||||
const {
|
||||
state: { data: blockInfo },
|
||||
} = useBlockInfo(
|
||||
Number(protocolUpgradeProposal?.upgradeBlockHeight),
|
||||
!pending
|
||||
);
|
||||
const time = useTimeToUpgrade(
|
||||
Number(protocolUpgradeProposal?.upgradeBlockHeight)
|
||||
);
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
loading={loading || nodesLoading}
|
||||
@@ -92,19 +69,6 @@ export const ProtocolUpgradeProposalContainer = () => {
|
||||
proposal={protocolUpgradeProposal}
|
||||
lastBlockHeight={data?.lastBlockHeight}
|
||||
consensusValidators={consensusValidators}
|
||||
time={
|
||||
pending && time ? (
|
||||
convertToCountdownString(time, '0:00:00:00')
|
||||
) : blockInfo?.result ? (
|
||||
<span title={blockInfo.result.block.header.time}>
|
||||
{formatDateWithLocalTimezone(
|
||||
new Date(blockInfo.result.block.header.time)
|
||||
)}
|
||||
</span>
|
||||
) : (
|
||||
'-'
|
||||
)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<ProposalNotFound />
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { ProtocolUpgradeProposalDetailHeader } from '../components/protocol-upgrade-proposal-detail-header';
|
||||
import { ProtocolUpdateProposalDetailApprovals } from '../components/protocol-upgrade-proposal-detail-approvals';
|
||||
import { ProtocolUpgradeProposalDetailInfo } from '../components/protocol-upgrade-proposal-detail-info';
|
||||
import { getNormalisedVotingPower } from '../../staking/shared';
|
||||
import type { NodesFragmentFragment } from '../../staking/home/__generated__/Nodes';
|
||||
import { type ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
|
||||
import { useVegaRelease } from '@vegaprotocol/environment';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -14,7 +13,6 @@ export interface ProtocolUpgradeProposalProps {
|
||||
proposal: ProtocolUpgradeProposalFieldsFragment;
|
||||
consensusValidators: NodesFragmentFragment[] | null;
|
||||
lastBlockHeight?: string;
|
||||
time?: string | ReactNode;
|
||||
}
|
||||
|
||||
export const getConsensusApprovals = (
|
||||
@@ -46,7 +44,6 @@ export const ProtocolUpgradeProposal = ({
|
||||
proposal,
|
||||
lastBlockHeight,
|
||||
consensusValidators,
|
||||
time,
|
||||
}: ProtocolUpgradeProposalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const releaseInfo = useVegaRelease(proposal.vegaReleaseTag);
|
||||
@@ -76,7 +73,6 @@ export const ProtocolUpgradeProposal = ({
|
||||
<ProtocolUpgradeProposalDetailInfo
|
||||
proposal={proposal}
|
||||
lastBlockHeight={lastBlockHeight}
|
||||
time={time}
|
||||
/>
|
||||
|
||||
{consensusValidators && consensusApprovals && (
|
||||
|
||||
@@ -54,7 +54,7 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
|
||||
it('can deposit', function () {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
// 1001-DEPO-001
|
||||
// 1001-DEPO-002
|
||||
@@ -117,7 +117,7 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
it('can key to key transfers', function () {
|
||||
// 1003-TRAN-023
|
||||
// 1003-TRAN-006
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
cy.getByTestId(collateralTab).click();
|
||||
cy.getByTestId('open-transfer').click();
|
||||
@@ -344,7 +344,7 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
const ethWalletAddress = Cypress.env('ETHEREUM_WALLET_ADDRESS');
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId(toastCloseBtn, txTimeout).click();
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
@@ -431,7 +431,7 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
// 1001-DEPO-006
|
||||
// 1001-DEPO-007
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId(toastCloseBtn, txTimeout).click();
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
@@ -453,7 +453,7 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
// 1002-WITH-007
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('[data-testid="pathname-/portfolio"]', txTimeout).should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]', txTimeout).should('exist');
|
||||
cy.getByTestId(toastCloseBtn, txTimeout).click();
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
|
||||
@@ -351,6 +351,12 @@ describe('Closed markets', { tags: '@smoke' }, () => {
|
||||
)
|
||||
);
|
||||
|
||||
// 6001-MARK-017
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="realisedPNL"]')
|
||||
.should('have.text', '-');
|
||||
|
||||
// 6001-MARK-018
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
|
||||
cy.mockTradingPage();
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId('Deposits').click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('MetaMask');
|
||||
|
||||
@@ -106,7 +106,7 @@ describe('home', { tags: '@regression' }, () => {
|
||||
cy.visit('/');
|
||||
cy.wait('@Markets');
|
||||
|
||||
cy.get('[data-testid^="pathname-/markets/"]');
|
||||
cy.get('main[data-testid^="/markets/"]');
|
||||
|
||||
// the choose market overlay is no longer showing
|
||||
cy.contains('Loading...').should('not.exist');
|
||||
|
||||
@@ -37,23 +37,27 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
const data = [
|
||||
{
|
||||
code: 'SOLUSD',
|
||||
markPrice: '84.41',
|
||||
vol: '0.00',
|
||||
markPrice: 'XYZalpha84.41',
|
||||
change: '',
|
||||
vol: '24h vol0.00',
|
||||
},
|
||||
{
|
||||
code: 'ETHBTC.QM21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
markPrice: 'tBTC46,126.90058',
|
||||
change: '',
|
||||
vol: '24h vol0.00',
|
||||
},
|
||||
{
|
||||
code: 'BTCUSD.MF21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
markPrice: 'tDAI46,126.90058',
|
||||
change: '',
|
||||
vol: '24h vol0.00',
|
||||
},
|
||||
{
|
||||
code: 'AAPL.MF21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
markPrice: 'tUSDC46,126.90058',
|
||||
change: '',
|
||||
vol: '24h vol0.00',
|
||||
},
|
||||
];
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
@@ -65,12 +69,16 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
// 6001-MARK-022
|
||||
expect(item.find('h3').text()).equals(market.code);
|
||||
expect(
|
||||
item.find('[data-testid="market-selector-volume"]').text()
|
||||
item.find('[data-testid="market-selector-data-row"]').eq(0).text()
|
||||
).contains(market.vol);
|
||||
// 6001-MARK-024
|
||||
expect(
|
||||
item.find('[data-testid="market-selector-price"]').text()
|
||||
item.find('[data-testid="market-selector-data-row"]').eq(1).text()
|
||||
).contains(market.markPrice);
|
||||
// 6001-MARK-023
|
||||
expect(item.find('[data-testid="market-item-change"]').text()).equals(
|
||||
market.change
|
||||
);
|
||||
// 6001-MARK-025
|
||||
expect(item.find('[data-testid="sparkline-svg"]')).to.not.exist;
|
||||
});
|
||||
|
||||
@@ -101,14 +101,13 @@ describe('order book', { tags: '@smoke' }, () => {
|
||||
'1,000',
|
||||
'10,000',
|
||||
];
|
||||
cy.getByTestId(priceResolution).click();
|
||||
cy.get('[role="menu"]')
|
||||
.find('[role="menuitem"]')
|
||||
cy.getByTestId(priceResolution)
|
||||
.find('option')
|
||||
.each(($el, index) => {
|
||||
expect($el.text()).to.equal(resolutions[index]);
|
||||
});
|
||||
|
||||
cy.get('[role="menuitem"]').eq(4).click();
|
||||
cy.getByTestId(priceResolution).select('0.0');
|
||||
cy.getByTestId(resPrice).should('have.text', '99.0');
|
||||
cy.getByTestId(askPrice).should('not.exist');
|
||||
cy.getByTestId(bidPrice).should('not.exist');
|
||||
|
||||
@@ -14,12 +14,6 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
|
||||
cy.get('[data-testid="deal-ticket-form"]').then(($form) => {
|
||||
if (!$form.length) {
|
||||
cy.getByTestId('Order').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -59,12 +59,6 @@ describe(
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
|
||||
cy.get('[data-testid="deal-ticket-form"]').then(($form) => {
|
||||
if (!$form.length) {
|
||||
cy.getByTestId('Order').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should display info and button for deposit', () => {
|
||||
|
||||
@@ -37,7 +37,7 @@ describe('fills', { tags: '@regression' }, () => {
|
||||
|
||||
it('renders fills on portfolio page', () => {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId('Fills').click();
|
||||
validateFillsDisplayed();
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ describe('ethereum wallet', { tags: '@smoke', testIsolation: true }, () => {
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ describe(
|
||||
cy.visit('/#/portfolio');
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
});
|
||||
|
||||
it('can connect', () => {
|
||||
@@ -122,7 +122,7 @@ describe('connect vega wallet', { tags: '@smoke', testIsolation: true }, () => {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
});
|
||||
|
||||
it('can connect', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { selectAsset } from '../support/helpers';
|
||||
|
||||
// #region consts
|
||||
const amountField = 'input[name="amount"]';
|
||||
const amountShortName = 'input[name="amount"] + div + span.text-xs';
|
||||
const assetSelection = 'select-asset';
|
||||
@@ -26,6 +26,7 @@ const ASSET_SEPOLIA_TBTC = 2;
|
||||
const collateralTab = 'Collateral';
|
||||
const toastCloseBtn = 'toast-close';
|
||||
const toastContent = 'toast-content';
|
||||
// #endregion
|
||||
|
||||
describe('transfer fees', { tags: '@regression', testIsolation: true }, () => {
|
||||
beforeEach(() => {
|
||||
@@ -36,17 +37,17 @@ describe('transfer fees', { tags: '@regression', testIsolation: true }, () => {
|
||||
|
||||
cy.visit('/');
|
||||
|
||||
cy.wait('@Assets');
|
||||
cy.wait('@Accounts');
|
||||
|
||||
cy.mockVegaWalletTransaction();
|
||||
|
||||
// Only click if not already active otherwise sidebar will close
|
||||
cy.get('[data-testid="sidebar-content"]').then(($sidebarContent) => {
|
||||
if ($sidebarContent.find('h2').text() !== 'Transfer') {
|
||||
cy.get('[data-testid="sidebar"] [data-testid="Transfer"]').click();
|
||||
}
|
||||
});
|
||||
|
||||
cy.wait('@Assets');
|
||||
cy.wait('@Accounts');
|
||||
|
||||
cy.mockVegaWalletTransaction();
|
||||
});
|
||||
|
||||
it('transfer fees tooltips', () => {
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
import { matchFilter, lpAggregatedDataProvider } from '@vegaprotocol/liquidity';
|
||||
import {
|
||||
matchFilter,
|
||||
lpAggregatedDataProvider,
|
||||
useCheckLiquidityStatus,
|
||||
} from '@vegaprotocol/liquidity';
|
||||
import { tooltipMapping } from '@vegaprotocol/markets';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumberPercentage,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
} from '@vegaprotocol/network-parameters';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { Tab, Tabs } from '@vegaprotocol/ui-toolkit';
|
||||
import { Tab, Tabs, Indicator, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { memo, useEffect, useState } from 'react';
|
||||
|
||||
import { Header, HeaderStat, HeaderTitle } from '../../components/header';
|
||||
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { useMarket, useStaticMarketData } from '@vegaprotocol/markets';
|
||||
import { DocsLinks } from '@vegaprotocol/environment';
|
||||
import { LiquidityContainer } from '../../components/liquidity-container';
|
||||
|
||||
const enum LiquidityTabs {
|
||||
@@ -19,6 +38,92 @@ export const Liquidity = () => {
|
||||
return <LiquidityViewContainer marketId={marketId} />;
|
||||
};
|
||||
|
||||
const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
|
||||
const { data: market } = useMarket(marketId);
|
||||
const { data: marketData } = useStaticMarketData(marketId);
|
||||
const targetStake = marketData?.targetStake;
|
||||
const suppliedStake = marketData?.suppliedStake;
|
||||
const assetDecimalPlaces =
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0;
|
||||
const symbol =
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||
|
||||
const { params } = useNetworkParams([
|
||||
NetworkParams.market_liquidity_stakeToCcyVolume,
|
||||
NetworkParams.market_liquidity_targetstake_triggering_ratio,
|
||||
]);
|
||||
const triggeringRatio =
|
||||
params.market_liquidity_targetstake_triggering_ratio || '1';
|
||||
|
||||
const { percentage, status } = useCheckLiquidityStatus({
|
||||
suppliedStake: suppliedStake || 0,
|
||||
targetStake: targetStake || 0,
|
||||
triggeringRatio,
|
||||
});
|
||||
|
||||
return (
|
||||
<Header
|
||||
title={
|
||||
market?.tradableInstrument.instrument.code &&
|
||||
marketId && (
|
||||
<HeaderTitle>
|
||||
{market.tradableInstrument.instrument.code &&
|
||||
t(
|
||||
'%s liquidity provision',
|
||||
market.tradableInstrument.instrument.code
|
||||
)}
|
||||
</HeaderTitle>
|
||||
)
|
||||
}
|
||||
>
|
||||
<HeaderStat
|
||||
heading={t('Target stake')}
|
||||
description={tooltipMapping['targetStake']}
|
||||
testId="target-stake"
|
||||
>
|
||||
<div>
|
||||
{targetStake
|
||||
? `${addDecimalsFormatNumber(
|
||||
targetStake,
|
||||
assetDecimalPlaces ?? 0
|
||||
)} ${symbol}`
|
||||
: '-'}
|
||||
</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat
|
||||
heading={t('Supplied stake')}
|
||||
description={tooltipMapping['suppliedStake']}
|
||||
testId="supplied-stake"
|
||||
>
|
||||
<div>
|
||||
{suppliedStake
|
||||
? `${addDecimalsFormatNumber(
|
||||
suppliedStake,
|
||||
assetDecimalPlaces ?? 0
|
||||
)} ${symbol}`
|
||||
: '-'}
|
||||
</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Liquidity supplied')} testId="liquidity-supplied">
|
||||
<Indicator variant={status} /> {formatNumberPercentage(percentage, 2)}
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Market ID')} testId="liquidity-market-id">
|
||||
<div className="break-word">{marketId}</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Learn more')} testId="liquidity-learn-more">
|
||||
{DocsLinks ? (
|
||||
<ExternalLink href={DocsLinks.LIQUIDITY}>
|
||||
{t('Providing liquidity')}
|
||||
</ExternalLink>
|
||||
) : (
|
||||
(null as React.ReactNode)
|
||||
)}
|
||||
</HeaderStat>
|
||||
</Header>
|
||||
);
|
||||
});
|
||||
LiquidityViewHeader.displayName = 'LiquidityViewHeader';
|
||||
|
||||
export const LiquidityViewContainer = ({
|
||||
marketId,
|
||||
}: {
|
||||
@@ -49,29 +154,35 @@ export const LiquidityViewContainer = ({
|
||||
}, [data, pubKey]);
|
||||
|
||||
return (
|
||||
<div className="h-full p-1.5">
|
||||
<div className="h-full border border-default">
|
||||
<Tabs value={tab || LiquidityTabs.Active} onValueChange={setTab}>
|
||||
<Tab
|
||||
id={LiquidityTabs.MyLiquidityProvision}
|
||||
name={t('My liquidity provision')}
|
||||
hidden={!pubKey}
|
||||
>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ partyId: pubKey || undefined }}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Active} name={t('Active')}>
|
||||
<LiquidityContainer marketId={marketId} filter={{ active: true }} />
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ active: false }}
|
||||
/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
<div className="h-full grid grid-rows-[min-content_1fr]">
|
||||
<LiquidityViewHeader marketId={marketId} />
|
||||
<div className="p-1">
|
||||
<div className="h-full border border-default">
|
||||
<Tabs value={tab || LiquidityTabs.Active} onValueChange={setTab}>
|
||||
<Tab
|
||||
id={LiquidityTabs.MyLiquidityProvision}
|
||||
name={t('My liquidity provision')}
|
||||
hidden={!pubKey}
|
||||
>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ partyId: pubKey || undefined }}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Active} name={t('Active')}>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ active: true }}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ active: false }}
|
||||
/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
+29
-1
@@ -19,6 +19,7 @@ describe('AssetDropdown', () => {
|
||||
checkedAssets={[]}
|
||||
assets={assets}
|
||||
onSelect={mockOnSelect}
|
||||
onReset={jest.fn()}
|
||||
/>
|
||||
);
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
@@ -38,6 +39,7 @@ describe('AssetDropdown', () => {
|
||||
checkedAssets={[assets[0].id]}
|
||||
assets={assets}
|
||||
onSelect={mockOnSelect}
|
||||
onReset={jest.fn()}
|
||||
/>
|
||||
);
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
@@ -46,9 +48,35 @@ describe('AssetDropdown', () => {
|
||||
expect(mockOnSelect).toHaveBeenCalledWith(assets[0].id, false);
|
||||
});
|
||||
|
||||
it('can be reset clearing all assets', async () => {
|
||||
const mockOnSelect = jest.fn();
|
||||
const mockOnReset = jest.fn();
|
||||
render(
|
||||
<AssetDropdown
|
||||
checkedAssets={assets.map((a) => a.id)}
|
||||
assets={assets}
|
||||
onSelect={mockOnSelect}
|
||||
onReset={mockOnReset}
|
||||
/>
|
||||
);
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
const items = screen.getAllByRole('menuitemcheckbox');
|
||||
// all should be checked
|
||||
items.forEach((item) => {
|
||||
expect(item).toBeChecked();
|
||||
});
|
||||
await userEvent.click(screen.getByText('Reset'));
|
||||
expect(mockOnReset).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('doesnt render if no assets provided', async () => {
|
||||
const { container } = render(
|
||||
<AssetDropdown checkedAssets={[]} assets={[]} onSelect={jest.fn()} />
|
||||
<AssetDropdown
|
||||
checkedAssets={[]}
|
||||
assets={[]}
|
||||
onSelect={jest.fn()}
|
||||
onReset={jest.fn()}
|
||||
/>
|
||||
);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
+9
-9
@@ -3,10 +3,10 @@ import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuItemIndicator,
|
||||
DropdownMenuTrigger,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
DropdownMenuSeparator,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
type Assets = Array<{ id: string; symbol: string }>;
|
||||
@@ -15,10 +15,12 @@ export const AssetDropdown = ({
|
||||
assets,
|
||||
checkedAssets,
|
||||
onSelect,
|
||||
onReset,
|
||||
}: {
|
||||
assets: Assets | undefined;
|
||||
checkedAssets: string[];
|
||||
onSelect: (id: string, checked: boolean) => void;
|
||||
onReset: () => void;
|
||||
}) => {
|
||||
if (!assets?.length) {
|
||||
return null;
|
||||
@@ -33,6 +35,8 @@ export const AssetDropdown = ({
|
||||
}
|
||||
>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem onClick={onReset}>{t('Reset')}</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
{assets?.map((a) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
@@ -62,19 +66,15 @@ const TriggerText = ({
|
||||
assets: Assets;
|
||||
checkedAssets: string[];
|
||||
}) => {
|
||||
let text = t('Assets');
|
||||
let text = t('Asset');
|
||||
|
||||
if (checkedAssets.length === 1) {
|
||||
const assetId = checkedAssets[0];
|
||||
const asset = assets.find((a) => a.id === assetId);
|
||||
text = asset ? asset.symbol : t('Asset (1)');
|
||||
} else if (checkedAssets.length > 1) {
|
||||
text = t(`${checkedAssets.length} Assets`);
|
||||
text = t(`Asset (${checkedAssets.length})`);
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="flex justify-between items-center">
|
||||
{text} <VegaIcon name={VegaIconNames.CHEVRON_DOWN} />
|
||||
</span>
|
||||
);
|
||||
return <span className="px-1">{text}</span>;
|
||||
};
|
||||
+1
-1
@@ -169,7 +169,7 @@ describe('MarketSelectorItem', () => {
|
||||
// link renders and is styled
|
||||
expect(link).toHaveAttribute('href', '/markets/' + market.id);
|
||||
|
||||
expect(link).toHaveClass('bg-vega-clight-600');
|
||||
expect(link.parentNode).toHaveClass('bg-vega-light-100');
|
||||
|
||||
expect(screen.getByTitle('24h vol')).toHaveTextContent('0.00');
|
||||
expect(screen.getByTitle(symbol)).toHaveTextContent('-');
|
||||
+7
-7
@@ -79,7 +79,7 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-2/5" role="gridcell">
|
||||
<div className="w-1/4" role="gridcell">
|
||||
<h3 className="text-ellipsis whitespace-nowrap overflow-hidden">
|
||||
{market.tradableInstrument.instrument.code}
|
||||
</h3>
|
||||
@@ -90,25 +90,25 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="w-1/5 text-sm whitespace-nowrap text-ellipsis overflow-hidden"
|
||||
className="w-1/4 text-sm"
|
||||
title={instrument.product.settlementAsset.symbol}
|
||||
data-testid="market-selector-price"
|
||||
data-testid="market-selector-data-row"
|
||||
role="gridcell"
|
||||
>
|
||||
{price} {instrument.product.settlementAsset.symbol}
|
||||
</div>
|
||||
<div
|
||||
className="w-1/5 text-sm text-right whitespace-nowrap text-ellipsis overflow-hidden"
|
||||
className="w-1/4 text-sm text-right"
|
||||
title={t('24h vol')}
|
||||
data-testid="market-selector-volume"
|
||||
data-testid="market-selector-data-row"
|
||||
role="gridcell"
|
||||
>
|
||||
{volume}
|
||||
</div>
|
||||
<div className="w-1/5 flex justify-end" role="gridcell">
|
||||
<div className="w-1/4" role="gridcell">
|
||||
{oneDayCandles && (
|
||||
<Sparkline
|
||||
width={64}
|
||||
width={70}
|
||||
height={15}
|
||||
data={oneDayCandles.map((c) => Number(c.close))}
|
||||
/>
|
||||
+1
-1
@@ -240,7 +240,7 @@ describe('MarketSelector', () => {
|
||||
|
||||
await userEvent.click(screen.getByTestId('sort-trigger'));
|
||||
const options = screen.getAllByTestId(/sort-item/);
|
||||
expect(options.map((o) => o.textContent?.trim())).toEqual(
|
||||
expect(options.map((o) => o.textContent)).toEqual(
|
||||
Object.entries(Sort)
|
||||
.filter(([key]) => key !== Sort.None)
|
||||
.map(([key]) => SortTypeMapping[key as SortType])
|
||||
+30
-29
@@ -8,7 +8,7 @@ import {
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { useCallback, useState, useMemo, useRef } from 'react';
|
||||
import { useCallback, useState, useMemo } from 'react';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import { useMarketSelectorList } from './use-market-selector-list';
|
||||
import type { ProductType } from './product-selector';
|
||||
@@ -66,7 +66,20 @@ export const MarketSelector = ({
|
||||
placeholder={t('Search')}
|
||||
data-testid="search-term"
|
||||
className="w-full"
|
||||
prependElement={<VegaIcon name={VegaIconNames.SEARCH} />}
|
||||
appendElement={
|
||||
filter.searchTerm.length ? (
|
||||
<button
|
||||
onClick={() =>
|
||||
setFilter((curr) => ({ ...curr, searchTerm: '' }))
|
||||
}
|
||||
className="text-secondary"
|
||||
>
|
||||
<VegaIcon name={VegaIconNames.CROSS} />
|
||||
</button>
|
||||
) : (
|
||||
<span />
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<AssetDropdown
|
||||
@@ -96,6 +109,7 @@ export const MarketSelector = ({
|
||||
return curr;
|
||||
});
|
||||
}}
|
||||
onReset={() => setFilter((curr) => ({ ...curr, assets: [] }))}
|
||||
/>
|
||||
<SortDropdown
|
||||
currentSort={filter.sort}
|
||||
@@ -110,6 +124,7 @@ export const MarketSelector = ({
|
||||
};
|
||||
});
|
||||
}}
|
||||
onReset={() => setFilter((curr) => ({ ...curr, sort: Sort.None }))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -150,18 +165,9 @@ const MarketList = ({
|
||||
onSelect?: (marketId: string) => void;
|
||||
noItems: string;
|
||||
}) => {
|
||||
const itemSize = 45;
|
||||
const listRef = useRef<HTMLDivElement | null>(null);
|
||||
const rect = listRef.current?.getBoundingClientRect();
|
||||
// allow virtualized list to grow until it runs out of space
|
||||
const height = rect
|
||||
? Math.min(data.length * itemSize, window.innerHeight - rect.y)
|
||||
: 400;
|
||||
|
||||
if (error) {
|
||||
return <div>{error.message}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<TinyScroll>
|
||||
<div
|
||||
@@ -171,28 +177,25 @@ const MarketList = ({
|
||||
'p-2 mx-2 border-b border-default text-xs text-secondary'
|
||||
)}
|
||||
>
|
||||
<div className="w-2/5" role="columnheader">
|
||||
<div className="w-1/4" role="columnheader">
|
||||
{t('Name')}
|
||||
</div>
|
||||
<div className="w-1/5" role="columnheader">
|
||||
<div className="w-1/4" role="columnheader">
|
||||
{t('Price')}
|
||||
</div>
|
||||
<div className="w-1/5 text-right" role="columnheader">
|
||||
<div className="w-1/4 text-right" role="columnheader">
|
||||
{t('24h volume')}
|
||||
</div>
|
||||
<div className="w-1/5" role="columnheader" />
|
||||
</div>
|
||||
<div ref={listRef}>
|
||||
<List
|
||||
data={data}
|
||||
loading={loading}
|
||||
height={height}
|
||||
itemSize={itemSize}
|
||||
currentMarketId={currentMarketId}
|
||||
onSelect={onSelect}
|
||||
noItems={noItems}
|
||||
/>
|
||||
<div className="w-1/4" role="columnheader" />
|
||||
</div>
|
||||
<List
|
||||
data={data}
|
||||
loading={loading}
|
||||
height={400}
|
||||
currentMarketId={currentMarketId}
|
||||
onSelect={onSelect}
|
||||
noItems={noItems}
|
||||
/>
|
||||
</TinyScroll>
|
||||
);
|
||||
};
|
||||
@@ -223,14 +226,12 @@ const List = ({
|
||||
data,
|
||||
loading,
|
||||
height,
|
||||
itemSize,
|
||||
onSelect,
|
||||
noItems,
|
||||
currentMarketId,
|
||||
}: ListItemData & {
|
||||
loading: boolean;
|
||||
height: number;
|
||||
itemSize: number;
|
||||
noItems: string;
|
||||
}) => {
|
||||
const itemKey = useCallback(
|
||||
@@ -263,7 +264,7 @@ const List = ({
|
||||
className="vega-scrollbar"
|
||||
itemCount={data.length}
|
||||
itemData={itemData}
|
||||
itemSize={itemSize}
|
||||
itemSize={45}
|
||||
itemKey={itemKey}
|
||||
width="100%"
|
||||
height={height}
|
||||
@@ -2,9 +2,12 @@ import React, { useEffect, useMemo } from 'react';
|
||||
import { addDecimalsFormatNumber, titlefy } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import { useThrottledDataProvider } from '@vegaprotocol/data-provider';
|
||||
import {
|
||||
useDataProvider,
|
||||
useThrottledDataProvider,
|
||||
} from '@vegaprotocol/data-provider';
|
||||
import { AsyncRenderer, ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { marketDataProvider, useMarket } from '@vegaprotocol/markets';
|
||||
import { marketProvider, marketDataProvider } from '@vegaprotocol/markets';
|
||||
import { useGlobalStore, usePageTitleStore } from '../../stores';
|
||||
import { TradeGrid } from './trade-grid';
|
||||
import { TradePanels } from './trade-panels';
|
||||
@@ -67,7 +70,11 @@ export const MarketPage = () => {
|
||||
|
||||
const onSelect = useMarketClickHandler();
|
||||
|
||||
const { data, error, loading } = useMarket(marketId);
|
||||
const { data, error, loading } = useDataProvider({
|
||||
dataProvider: marketProvider,
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (data?.id && data.id !== lastMarketId) {
|
||||
|
||||
+10
-21
@@ -2,12 +2,12 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuItemIndicator,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuTrigger,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
DropdownMenuSeparator,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const Sort = {
|
||||
@@ -28,32 +28,22 @@ export const SortTypeMapping: {
|
||||
[Sort.New]: 'New markets',
|
||||
};
|
||||
|
||||
const SortIconMapping: {
|
||||
[key in SortType]: VegaIconNames;
|
||||
} = {
|
||||
[Sort.None]: null as unknown as VegaIconNames, // not shown in list
|
||||
[Sort.Gained]: VegaIconNames.TREND_UP,
|
||||
[Sort.Lost]: VegaIconNames.TREND_DOWN,
|
||||
[Sort.New]: VegaIconNames.STAR,
|
||||
};
|
||||
|
||||
export const SortDropdown = ({
|
||||
currentSort,
|
||||
onSelect,
|
||||
onReset,
|
||||
}: {
|
||||
currentSort: SortType;
|
||||
onSelect: (sort: SortType) => void;
|
||||
onReset: () => void;
|
||||
}) => {
|
||||
return (
|
||||
<DropdownMenu
|
||||
trigger={
|
||||
<DropdownMenuTrigger data-testid="sort-trigger">
|
||||
<span className="flex justify-between items-center">
|
||||
{currentSort === SortTypeMapping.None
|
||||
? t('Sort')
|
||||
: SortTypeMapping[currentSort]}{' '}
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} />
|
||||
</span>
|
||||
{currentSort === SortTypeMapping.None
|
||||
? t('Sort')
|
||||
: SortTypeMapping[currentSort]}
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
@@ -62,6 +52,8 @@ export const SortDropdown = ({
|
||||
value={currentSort}
|
||||
onValueChange={(value) => onSelect(value as SortType)}
|
||||
>
|
||||
<DropdownMenuItem onClick={onReset}>{t('Reset')}</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
{Object.keys(Sort)
|
||||
.filter((s) => s !== Sort.None)
|
||||
.map((key) => {
|
||||
@@ -72,10 +64,7 @@ export const SortDropdown = ({
|
||||
value={key}
|
||||
data-testid={`sort-item-${key}`}
|
||||
>
|
||||
<span className="flex gap-2">
|
||||
<VegaIcon name={SortIconMapping[key as SortType]} />{' '}
|
||||
{SortTypeMapping[key as SortType]}
|
||||
</span>
|
||||
{SortTypeMapping[key as SortType]}
|
||||
<DropdownMenuItemIndicator />
|
||||
</DropdownMenuRadioItem>
|
||||
);
|
||||
@@ -8,9 +8,16 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import { OracleBanner } from '@vegaprotocol/markets';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import { Filter } from '@vegaprotocol/orders';
|
||||
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
Popover,
|
||||
Tab,
|
||||
LocalStoragePersistTabs as Tabs,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
||||
import { Header, HeaderTitle } from '../../components/header';
|
||||
import {
|
||||
ResizableGrid,
|
||||
ResizableGridPanel,
|
||||
@@ -18,6 +25,8 @@ import {
|
||||
} from '../../components/resizable-grid';
|
||||
import { TradingViews } from './trade-views';
|
||||
import { MarketSuccessorBanner } from '../../components/market-banner';
|
||||
import { MarketSelector } from './market-selector';
|
||||
import { MarketHeaderStats } from './market-header-stats';
|
||||
interface TradeGridProps {
|
||||
market: Market | null;
|
||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||
@@ -154,16 +163,32 @@ MainGrid.displayName = 'MainGrid';
|
||||
export const TradeGrid = ({ market, pinnedAsset }: TradeGridProps) => {
|
||||
const wrapperClasses = classNames(
|
||||
'h-full grid',
|
||||
'grid-rows-[min-content_1fr]'
|
||||
'grid-rows-[min-content_min-content_1fr]'
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
<div>
|
||||
<Header
|
||||
title={
|
||||
<Popover
|
||||
trigger={
|
||||
<HeaderTitle>
|
||||
{market?.tradableInstrument.instrument.code}
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={14} />
|
||||
</HeaderTitle>
|
||||
}
|
||||
>
|
||||
<MarketSelector currentMarketId={market?.id} />
|
||||
</Popover>
|
||||
}
|
||||
>
|
||||
<MarketHeaderStats market={market} />
|
||||
</Header>
|
||||
<div className="bg-vega-green">
|
||||
<MarketSuccessorBanner market={market} />
|
||||
<OracleBanner marketId={market?.id || ''} />
|
||||
</div>
|
||||
<div className="min-h-0 p-0.5">
|
||||
<div className="min-h-0 py-0.5">
|
||||
<MainGrid marketId={market?.id || ''} pinnedAsset={pinnedAsset} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,11 +8,19 @@ import {
|
||||
import type { TradingView } from './trade-views';
|
||||
import { TradingViews } from './trade-views';
|
||||
import { memo, useState } from 'react';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
Popover,
|
||||
Splash,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { NO_MARKET } from './constants';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import classNames from 'classnames';
|
||||
import { Header, HeaderTitle } from '../../components/header';
|
||||
import { MarketSelector } from './market-selector';
|
||||
import { MarketSuccessorBanner } from '../../components/market-banner';
|
||||
import { MarketHeaderStats } from './market-header-stats';
|
||||
|
||||
interface TradePanelsProps {
|
||||
market: Market | null;
|
||||
@@ -62,7 +70,23 @@ export const TradePanels = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-full grid grid-rows-[min-content_1fr_min-content]">
|
||||
<div className="h-full grid grid-rows-[min-content_min-content_1fr_min-content]">
|
||||
<Header
|
||||
title={
|
||||
<Popover
|
||||
trigger={
|
||||
<HeaderTitle>
|
||||
{market?.tradableInstrument.instrument.code}
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} />
|
||||
</HeaderTitle>
|
||||
}
|
||||
>
|
||||
<MarketSelector currentMarketId={market?.id} />
|
||||
</Popover>
|
||||
}
|
||||
>
|
||||
<MarketHeaderStats market={market} />
|
||||
</Header>
|
||||
<div>
|
||||
<MarketSuccessorBanner market={market} />
|
||||
<OracleBanner marketId={market?.id || ''} />
|
||||
|
||||
@@ -3,9 +3,9 @@ import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { TradesContainer } from '@vegaprotocol/trades';
|
||||
import { DepthChartContainer } from '@vegaprotocol/market-depth';
|
||||
import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
|
||||
import { OrderbookContainer } from '@vegaprotocol/market-depth';
|
||||
import { Filter } from '@vegaprotocol/orders';
|
||||
import { NO_MARKET } from './constants';
|
||||
import { OrderbookContainer } from '../../components/orderbook-container';
|
||||
import { FillsContainer } from '../../components/fills-container';
|
||||
import { PositionsContainer } from '../../components/positions-container';
|
||||
import { AccountsContainer } from '../../components/accounts-container';
|
||||
|
||||
+2
-2
@@ -4,12 +4,12 @@ import {
|
||||
isMarketActive,
|
||||
useMarketSelectorList,
|
||||
} from './use-market-selector-list';
|
||||
import { Product } from '../../components/market-selector/product-selector';
|
||||
import { Product } from './product-selector';
|
||||
import { Sort } from './sort-dropdown';
|
||||
import { createMarketFragment } from '@vegaprotocol/mock';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import { useMarketList } from '@vegaprotocol/markets';
|
||||
import type { Filter } from '../../components/market-selector';
|
||||
import type { Filter } from './market-selector';
|
||||
import { subDays } from 'date-fns';
|
||||
|
||||
jest.mock('@vegaprotocol/markets');
|
||||
+1
-1
@@ -3,7 +3,7 @@ import orderBy from 'lodash/orderBy';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import { calcCandleVolume, useMarketList } from '@vegaprotocol/markets';
|
||||
import { priceChangePercentage } from '@vegaprotocol/utils';
|
||||
import type { Filter } from '../../components/market-selector/market-selector';
|
||||
import type { Filter } from './market-selector';
|
||||
import { Sort } from './sort-dropdown';
|
||||
|
||||
// Used for sort order and filter
|
||||
@@ -2,6 +2,7 @@ import { act, render, screen, within, waitFor } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Closed } from './closed';
|
||||
import { MarketStateMapping, PropertyKeyType } from '@vegaprotocol/types';
|
||||
import { PositionStatus } from '@vegaprotocol/types';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import { subDays } from 'date-fns';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
@@ -18,6 +19,11 @@ import {
|
||||
} from '@vegaprotocol/markets';
|
||||
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import type {
|
||||
PositionsQuery,
|
||||
PositionFieldsFragment,
|
||||
} from '@vegaprotocol/positions';
|
||||
import { PositionsDocument } from '@vegaprotocol/positions';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import {
|
||||
createMarketFragment,
|
||||
@@ -155,6 +161,45 @@ describe('Closed', () => {
|
||||
},
|
||||
};
|
||||
|
||||
// Create mock position
|
||||
const createPosition = (): PositionFieldsFragment => {
|
||||
return {
|
||||
__typename: 'Position' as const,
|
||||
realisedPNL: '1000',
|
||||
unrealisedPNL: '2000',
|
||||
openVolume: '3000',
|
||||
averageEntryPrice: '100',
|
||||
updatedAt: new Date().toISOString(),
|
||||
positionStatus: PositionStatus.POSITION_STATUS_UNSPECIFIED,
|
||||
lossSocializationAmount: '1000',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: marketId,
|
||||
},
|
||||
party: {
|
||||
__typename: 'Party',
|
||||
id: pubKey,
|
||||
},
|
||||
};
|
||||
};
|
||||
const position = createPosition();
|
||||
const positionsMock: MockedResponse<PositionsQuery> = {
|
||||
request: {
|
||||
query: PositionsDocument,
|
||||
variables: {
|
||||
partyIds: [pubKey],
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
positions: {
|
||||
__typename: 'PositionConnection',
|
||||
edges: [{ __typename: 'PositionEdge', node: position }],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
originalNow = Date.now;
|
||||
Date.now = jest.fn().mockReturnValue(mockNowTimestamp);
|
||||
@@ -169,7 +214,12 @@ describe('Closed', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider
|
||||
mocks={[marketsMock, marketsDataMock, oracleDataMock]}
|
||||
mocks={[
|
||||
marketsMock,
|
||||
marketsDataMock,
|
||||
positionsMock,
|
||||
oracleDataMock,
|
||||
]}
|
||||
>
|
||||
<VegaWalletContext.Provider
|
||||
value={{ pubKey } as VegaWalletContextShape}
|
||||
@@ -193,6 +243,7 @@ describe('Closed', () => {
|
||||
'Best offer',
|
||||
'Mark price',
|
||||
'Settlement price',
|
||||
'Realised PNL',
|
||||
'Settlement asset',
|
||||
'', // actions row
|
||||
];
|
||||
@@ -215,6 +266,7 @@ describe('Closed', () => {
|
||||
addDecimalsFormatNumber(marketsData!.markPrice, market.decimalPlaces),
|
||||
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
||||
addDecimalsFormatNumber(property.value, market.decimalPlaces),
|
||||
addDecimalsFormatNumber(position.realisedPNL, market.decimalPlaces),
|
||||
market.tradableInstrument.instrument.product.settlementAsset.symbol,
|
||||
'', // actions row
|
||||
];
|
||||
@@ -275,7 +327,12 @@ describe('Closed', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider
|
||||
mocks={[mixedMarketsMock, marketsDataMock, oracleDataMock]}
|
||||
mocks={[
|
||||
mixedMarketsMock,
|
||||
marketsDataMock,
|
||||
positionsMock,
|
||||
oracleDataMock,
|
||||
]}
|
||||
>
|
||||
<VegaWalletContext.Provider
|
||||
value={{ pubKey } as VegaWalletContextShape}
|
||||
@@ -362,7 +419,12 @@ describe('Closed', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider
|
||||
mocks={[mixedMarketsMock, marketsDataMock, oracleDataMock]}
|
||||
mocks={[
|
||||
mixedMarketsMock,
|
||||
marketsDataMock,
|
||||
positionsMock,
|
||||
oracleDataMock,
|
||||
]}
|
||||
>
|
||||
<VegaWalletContext.Provider
|
||||
value={{ pubKey } as VegaWalletContextShape}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
getMarketExpiryDate,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { usePositionsQuery } from '@vegaprotocol/positions';
|
||||
import type {
|
||||
DataSourceFilterFragment,
|
||||
MarketMaybeWithData,
|
||||
@@ -25,6 +26,7 @@ import {
|
||||
closedMarketsWithDataProvider,
|
||||
marketProvider,
|
||||
} from '@vegaprotocol/markets';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
import { SettlementDateCell } from './settlement-date-cell';
|
||||
@@ -51,18 +53,34 @@ interface Row {
|
||||
setlementDataSourceFilter: DataSourceFilterFragment | undefined;
|
||||
tradingTerminationOracleId: string;
|
||||
settlementAsset: SettlementAsset;
|
||||
realisedPNL: string | undefined;
|
||||
successorMarketID: string | undefined | null;
|
||||
}
|
||||
|
||||
export const Closed = () => {
|
||||
const { data: marketData, error } = useDataProvider({
|
||||
const { pubKey } = useVegaWallet();
|
||||
const {
|
||||
data: marketData,
|
||||
error,
|
||||
reload,
|
||||
} = useDataProvider({
|
||||
dataProvider: closedMarketsWithDataProvider,
|
||||
variables: undefined,
|
||||
});
|
||||
const { data: positionData } = usePositionsQuery({
|
||||
variables: {
|
||||
partyIds: pubKey ? [pubKey] : [],
|
||||
},
|
||||
skip: !pubKey,
|
||||
});
|
||||
|
||||
// find a position for each market and add the realised pnl to
|
||||
// a normalized object
|
||||
const rowData = compact(marketData).map((market) => {
|
||||
const position = positionData?.positions?.edges?.find((edge) => {
|
||||
return edge.node.market.id === market.id;
|
||||
});
|
||||
|
||||
const instrument = market.tradableInstrument.instrument;
|
||||
|
||||
const spec =
|
||||
@@ -97,6 +115,7 @@ export const Closed = () => {
|
||||
tradingTerminationOracleId:
|
||||
instrument.product.dataSourceSpecForTradingTermination.id,
|
||||
settlementAsset: instrument.product.settlementAsset,
|
||||
realisedPNL: position?.node.realisedPNL,
|
||||
successorMarketID: market.successorMarketID,
|
||||
};
|
||||
|
||||
@@ -104,7 +123,7 @@ export const Closed = () => {
|
||||
});
|
||||
return (
|
||||
<div className="h-full relative">
|
||||
<ClosedMarketsDataGrid rowData={rowData} error={error} />
|
||||
<ClosedMarketsDataGrid rowData={rowData} error={error} reload={reload} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -134,9 +153,11 @@ export const SuccessorMarketRenderer = ({
|
||||
const ClosedMarketsDataGrid = ({
|
||||
rowData,
|
||||
error,
|
||||
reload,
|
||||
}: {
|
||||
rowData: Row[];
|
||||
error: Error | undefined;
|
||||
reload: () => void;
|
||||
}) => {
|
||||
const openAssetDialog = useAssetDetailsDialogStore((store) => store.open);
|
||||
const colDefs = useMemo(() => {
|
||||
@@ -268,11 +289,25 @@ const ClosedMarketsDataGrid = ({
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
headerName: t('Realised PNL'),
|
||||
field: 'realisedPNL',
|
||||
cellClass: 'font-mono ag-right-aligned-cell',
|
||||
type: 'numericColumn',
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<Row, 'realisedPNL'>) => {
|
||||
if (!value || !data) return '-';
|
||||
return addDecimalsFormatNumber(value, data.decimalPlaces);
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: t('Settlement asset'),
|
||||
field: 'settlementAsset',
|
||||
cellRenderer: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<Row, 'settlementAsset'>) => (
|
||||
<button
|
||||
className="underline"
|
||||
|
||||
@@ -15,7 +15,7 @@ export const MarketsPage = () => {
|
||||
updateTitle(titlefy(['Markets']));
|
||||
}, [updateTitle]);
|
||||
return (
|
||||
<div className="h-full pt-0.5 pb-3 px-1.5">
|
||||
<div className="h-full pt-0.5 pb-3 px-1">
|
||||
<div className="h-full my-1 border border-default rounded-sm">
|
||||
<Tabs storageKey="console-markets">
|
||||
<Tab id="all-markets" name={t('All markets')}>
|
||||
|
||||
@@ -54,7 +54,7 @@ export const Portfolio = () => {
|
||||
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' });
|
||||
const wrapperClasses = 'p-0.5 h-full max-h-full flex flex-col';
|
||||
const wrapperClasses = 'py-0.5 h-full max-h-full flex flex-col';
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
<ResizableGrid vertical onChange={handleOnLayoutChange}>
|
||||
|
||||
@@ -12,17 +12,19 @@ export const Header = ({ title, children }: TradeMarketHeaderProps) => {
|
||||
'grid',
|
||||
'grid-rows-[min-content_min-content]',
|
||||
'xl:grid-cols-[min-content_1fr]',
|
||||
'border-b border-default',
|
||||
'lg:border-x border-b border-default',
|
||||
'bg-vega-clight-800 dark:bg-vega-cdark-800'
|
||||
);
|
||||
return (
|
||||
<header className={headerClasses}>
|
||||
<div className="flex flex-col justify-center items-start pl-3 lg:pl-4 pt-2 xl:pb-2 pb-0">
|
||||
{title}
|
||||
</div>
|
||||
<div data-testid="header-summary" className="min-w-0">
|
||||
<div className="px-3 lg:px-4 py-2 flex flex-nowrap gap-4 items-center text-xs overflow-x-auto">
|
||||
{children}
|
||||
<header className="lg:px-1">
|
||||
<div className={headerClasses}>
|
||||
<div className="flex flex-col justify-center items-start pl-3 lg:pl-4 pt-2 xl:pb-2 pb-0">
|
||||
{title}
|
||||
</div>
|
||||
<div data-testid="header-summary" className="min-w-0">
|
||||
<div className="px-3 lg:px-4 py-2 flex flex-nowrap gap-4 items-center text-xs overflow-x-auto">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { Outlet, Routes, Route } from 'react-router-dom';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import { Sidebar, SidebarContent, useSidebar } from '../sidebar';
|
||||
import classNames from 'classnames';
|
||||
import { Routes as AppRoutes } from '../../pages/client-router';
|
||||
import { MarketHeader } from '../market-header';
|
||||
import { LiquidityHeader } from '../liquidity-header';
|
||||
|
||||
export const LayoutWithSidebar = () => {
|
||||
const sidebarView = useSidebar((store) => store.view);
|
||||
@@ -11,35 +8,28 @@ export const LayoutWithSidebar = () => {
|
||||
|
||||
const gridClasses = classNames(
|
||||
'h-full relative z-0 grid',
|
||||
'grid-rows-[min-content_1fr]',
|
||||
'grid-cols-[1fr_45px]',
|
||||
'lg:grid-cols-[1fr_350px_45px]'
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={gridClasses}>
|
||||
<div className="col-span-full">
|
||||
<Routes>
|
||||
<Route path={AppRoutes.MARKET} element={<MarketHeader />} />
|
||||
<Route path={AppRoutes.LIQUIDITY} element={<LiquidityHeader />} />
|
||||
</Routes>
|
||||
</div>
|
||||
<main
|
||||
<section
|
||||
className={classNames('col-start-1 col-end-1', {
|
||||
'lg:col-end-3': !sidebarOpen,
|
||||
'hidden lg:block lg:col-end-2': sidebarOpen,
|
||||
})}
|
||||
>
|
||||
<Outlet />
|
||||
</main>
|
||||
<aside
|
||||
</section>
|
||||
<div
|
||||
// min-h-0 is needed as this element is part of a grid, we want the content to be scrollable, without it it will push the grid element taller
|
||||
className={classNames('col-start-1 lg:col-start-2 min-h-0', {
|
||||
hidden: !sidebarOpen,
|
||||
})}
|
||||
>
|
||||
<SidebarContent />
|
||||
</aside>
|
||||
</div>
|
||||
<div className="col-start-2 lg:col-start-3 bg-vega-clight-800 dark:bg-vega-cdark-800 border-l border-default">
|
||||
<Sidebar />
|
||||
</div>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './liquidity-header';
|
||||
@@ -1,107 +0,0 @@
|
||||
import {
|
||||
tooltipMapping,
|
||||
useMarket,
|
||||
useStaticMarketData,
|
||||
} from '@vegaprotocol/markets';
|
||||
import { Header, HeaderStat, HeaderTitle } from '../header';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumberPercentage,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { ExternalLink, Indicator } from '@vegaprotocol/ui-toolkit';
|
||||
import { DocsLinks } from '@vegaprotocol/environment';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
} from '@vegaprotocol/network-parameters';
|
||||
import { useCheckLiquidityStatus } from '@vegaprotocol/liquidity';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
export const LiquidityHeader = () => {
|
||||
const { marketId } = useParams();
|
||||
const { data: market } = useMarket(marketId);
|
||||
const { data: marketData } = useStaticMarketData(marketId);
|
||||
const targetStake = marketData?.targetStake;
|
||||
const suppliedStake = marketData?.suppliedStake;
|
||||
const assetDecimalPlaces =
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0;
|
||||
const symbol =
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||
|
||||
const { params } = useNetworkParams([
|
||||
NetworkParams.market_liquidity_stakeToCcyVolume,
|
||||
NetworkParams.market_liquidity_targetstake_triggering_ratio,
|
||||
]);
|
||||
const triggeringRatio =
|
||||
params.market_liquidity_targetstake_triggering_ratio || '1';
|
||||
|
||||
const { percentage, status } = useCheckLiquidityStatus({
|
||||
suppliedStake: suppliedStake || 0,
|
||||
targetStake: targetStake || 0,
|
||||
triggeringRatio,
|
||||
});
|
||||
|
||||
console.log(market);
|
||||
|
||||
return (
|
||||
<Header
|
||||
title={
|
||||
market?.tradableInstrument.instrument.code &&
|
||||
marketId && (
|
||||
<HeaderTitle>
|
||||
{market.tradableInstrument.instrument.code &&
|
||||
t(
|
||||
'%s liquidity provision',
|
||||
market.tradableInstrument.instrument.code
|
||||
)}
|
||||
</HeaderTitle>
|
||||
)
|
||||
}
|
||||
>
|
||||
<HeaderStat
|
||||
heading={t('Target stake')}
|
||||
description={tooltipMapping['targetStake']}
|
||||
testId="target-stake"
|
||||
>
|
||||
<div>
|
||||
{targetStake
|
||||
? `${addDecimalsFormatNumber(
|
||||
targetStake,
|
||||
assetDecimalPlaces ?? 0
|
||||
)} ${symbol}`
|
||||
: '-'}
|
||||
</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat
|
||||
heading={t('Supplied stake')}
|
||||
description={tooltipMapping['suppliedStake']}
|
||||
testId="supplied-stake"
|
||||
>
|
||||
<div>
|
||||
{suppliedStake
|
||||
? `${addDecimalsFormatNumber(
|
||||
suppliedStake,
|
||||
assetDecimalPlaces ?? 0
|
||||
)} ${symbol}`
|
||||
: '-'}
|
||||
</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Liquidity supplied')} testId="liquidity-supplied">
|
||||
<Indicator variant={status} /> {formatNumberPercentage(percentage, 2)}
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Market ID')} testId="liquidity-market-id">
|
||||
<div className="break-word">{marketId}</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Learn more')} testId="liquidity-learn-more">
|
||||
{DocsLinks ? (
|
||||
<ExternalLink href={DocsLinks.LIQUIDITY}>
|
||||
{t('Providing liquidity')}
|
||||
</ExternalLink>
|
||||
) : (
|
||||
(null as React.ReactNode)
|
||||
)}
|
||||
</HeaderStat>
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export * from './market-header';
|
||||
@@ -1,33 +0,0 @@
|
||||
import { Popover, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import { Header, HeaderTitle } from '../header';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { MarketSelector } from '../../components/market-selector/market-selector';
|
||||
import { MarketHeaderStats } from '../../client-pages/market/market-header-stats';
|
||||
import { useMarket } from '@vegaprotocol/markets';
|
||||
|
||||
export const MarketHeader = () => {
|
||||
const { marketId } = useParams();
|
||||
const { data } = useMarket(marketId);
|
||||
|
||||
if (!data) return null;
|
||||
|
||||
return (
|
||||
<Header
|
||||
title={
|
||||
<Popover
|
||||
trigger={
|
||||
<HeaderTitle>
|
||||
{data.tradableInstrument.instrument.code}
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={14} />
|
||||
</HeaderTitle>
|
||||
}
|
||||
alignOffset={-10}
|
||||
>
|
||||
<MarketSelector currentMarketId={marketId} />
|
||||
</Popover>
|
||||
}
|
||||
>
|
||||
<MarketHeaderStats market={data} />
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './market-selector';
|
||||
export * from './market-selector-item';
|
||||
@@ -16,7 +16,7 @@ export const NodeHealthContainer = () => {
|
||||
<Tooltip
|
||||
description={
|
||||
<div
|
||||
className="flex flex-col gap-2 p-2 text-sm"
|
||||
className="flex flex-col gap-2 p-4 text-sm"
|
||||
data-testid="node-health"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -37,9 +37,8 @@ export const NodeHealthContainer = () => {
|
||||
</div>
|
||||
}
|
||||
align="end"
|
||||
side="left"
|
||||
sideOffset={18}
|
||||
arrow={false}
|
||||
side="right"
|
||||
sideOffset={10}
|
||||
>
|
||||
<button
|
||||
className="flex justify-center items-center p-2 rounded hover:bg-vega-light-200 hover:dark:bg-vega-dark-200"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './orderbook-container';
|
||||
@@ -1,23 +0,0 @@
|
||||
import { OrderbookManager } from '@vegaprotocol/market-depth';
|
||||
import { useCreateOrderStore } from '@vegaprotocol/orders';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
|
||||
export const OrderbookContainer = ({ marketId }: { marketId: string }) => {
|
||||
const useOrderStoreRef = useCreateOrderStore();
|
||||
const updateOrder = useOrderStoreRef((store) => store.update);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
return (
|
||||
<OrderbookManager
|
||||
marketId={marketId}
|
||||
onClick={({ price, size }) => {
|
||||
if (price) {
|
||||
updateOrder(marketId, { price });
|
||||
}
|
||||
if (size) {
|
||||
updateOrder(marketId, { size });
|
||||
}
|
||||
setView({ type: ViewType.Order });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -20,7 +20,6 @@ export interface TooltipProps {
|
||||
side?: 'top' | 'right' | 'bottom' | 'left';
|
||||
sideOffset?: number;
|
||||
delayDuration?: number;
|
||||
arrow?: boolean;
|
||||
}
|
||||
|
||||
// Conditionally rendered tooltip if description content is provided.
|
||||
@@ -32,7 +31,6 @@ export const Tooltip = ({
|
||||
align = 'start',
|
||||
side = 'bottom',
|
||||
delayDuration = 200,
|
||||
arrow = true,
|
||||
}: TooltipProps) =>
|
||||
description ? (
|
||||
<Provider delayDuration={delayDuration} skipDelayDuration={100}>
|
||||
@@ -55,13 +53,11 @@ export const Tooltip = ({
|
||||
<div className="relative z-0" data-testid="tooltip-content">
|
||||
{description}
|
||||
</div>
|
||||
{arrow && (
|
||||
<Arrow
|
||||
width={16}
|
||||
height={8}
|
||||
className="fill-vega-clight-500 dark:fill-vega-cdark-500"
|
||||
/>
|
||||
)}
|
||||
<Arrow
|
||||
width={16}
|
||||
height={8}
|
||||
className="fill-vega-clight-500 dark:fill-vega-cdark-500"
|
||||
/>
|
||||
</Content>
|
||||
</Portal>
|
||||
)}
|
||||
|
||||
@@ -95,9 +95,9 @@ function AppBody({ Component }: AppProps) {
|
||||
<ViewingBanner />
|
||||
<UpgradeBanner showVersionChange={true} />
|
||||
</div>
|
||||
<div data-testid={`pathname-${location.pathname}`}>
|
||||
<main data-testid={location.pathname}>
|
||||
<Component />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<DialogsContainer />
|
||||
<ToastsManager />
|
||||
|
||||
@@ -61,18 +61,18 @@ html.dark {
|
||||
html [data-theme='dark'],
|
||||
html [data-theme='light'] {
|
||||
/* sell candles only use stroke as the candle is solid (without border) */
|
||||
--pennant-color-sell-stroke: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-sell-stroke: theme('colors.market.red.500');
|
||||
|
||||
/* studies */
|
||||
--pennant-color-eldar-ray-bear-power: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-eldar-ray-bull-power: theme(colors.market.green.600);
|
||||
--pennant-color-eldar-ray-bear-power: theme('colors.market.red.500');
|
||||
--pennant-color-eldar-ray-bull-power: theme('colors.market.green.600');
|
||||
|
||||
--pennant-color-macd-divergence-buy: theme(colors.market.green.600);
|
||||
--pennant-color-macd-divergence-sell: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-macd-signal: theme(colors.vega.blue.DEFAULT);
|
||||
--pennant-color-macd-macd: theme(colors.vega.yellow.500);
|
||||
--pennant-color-macd-divergence-buy: theme('colors.market.green.600');
|
||||
--pennant-color-macd-divergence-sell: theme('colors.market.red.500');
|
||||
--pennant-color-macd-signal: theme('colors.vega.blue.500');
|
||||
--pennant-color-macd-macd: theme('colors.vega.yellow.500');
|
||||
|
||||
--pennant-color-volume-sell: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-volume-sell: theme('colors.market.red.500');
|
||||
}
|
||||
|
||||
html [data-theme='light'] {
|
||||
@@ -80,20 +80,20 @@ html [data-theme='light'] {
|
||||
--pennant-background-surface-color: theme(colors.vega.clight.900);
|
||||
|
||||
/* candles */
|
||||
--pennant-color-buy-fill: theme(colors.market.green.DEFAULT);
|
||||
--pennant-color-buy-fill: theme(colors.market.green.500);
|
||||
--pennant-color-buy-stroke: theme(colors.market.green.600);
|
||||
|
||||
/* sell uses stroke for fill and stroke */
|
||||
--pennant-color-sell-stroke: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-sell-stroke: theme(colors.market.red.500);
|
||||
|
||||
/* depth chart */
|
||||
--pennant-color-depth-buy-fill: theme(colors.market.green.DEFAULT);
|
||||
--pennant-color-depth-buy-fill: theme(colors.market.green.500);
|
||||
--pennant-color-depth-buy-stroke: theme(colors.market.green.600);
|
||||
--pennant-color-depth-sell-fill: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-depth-sell-stroke: theme(colors.market.red.650);
|
||||
--pennant-color-depth-sell-fill: theme(colors.market.red.500);
|
||||
--pennant-color-depth-sell-stroke: theme(colors.market.red.600);
|
||||
|
||||
--pennant-color-volume-buy: theme(colors.market.green.300);
|
||||
--pennant-color-volume-sell: theme(colors.market.red.300);
|
||||
--pennant-color-volume-buy: theme(colors.market.green.400);
|
||||
--pennant-color-volume-sell: theme(colors.market.red.400);
|
||||
}
|
||||
|
||||
html [data-theme='dark'] {
|
||||
@@ -102,19 +102,19 @@ html [data-theme='dark'] {
|
||||
|
||||
/* candles */
|
||||
--pennant-color-buy-fill: theme(colors.market.green.600);
|
||||
--pennant-color-buy-stroke: theme(colors.market.green.DEFAULT);
|
||||
--pennant-color-buy-stroke: theme(colors.market.green.500);
|
||||
|
||||
/* sell uses stroke for fill and stroke */
|
||||
--pennant-color-sell-stroke: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-sell-stroke: theme(colors.market.red.500);
|
||||
|
||||
/* depth chart */
|
||||
--pennant-color-depth-buy-fill: theme(colors.market.green.600);
|
||||
--pennant-color-depth-buy-stroke: theme(colors.market.green.DEFAULT);
|
||||
--pennant-color-depth-sell-fill: theme(colors.market.red.650);
|
||||
--pennant-color-depth-sell-stroke: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-depth-buy-stroke: theme(colors.market.green.500);
|
||||
--pennant-color-depth-sell-fill: theme(colors.market.red.600);
|
||||
--pennant-color-depth-sell-stroke: theme(colors.market.red.500);
|
||||
|
||||
--pennant-color-volume-buy: theme(colors.market.green.600);
|
||||
--pennant-color-volume-sell: theme(colors.market.red.650);
|
||||
--pennant-color-volume-sell: theme(colors.market.red.600);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@ import { addMockGQLCommand } from './lib/mock-gql';
|
||||
import { addMockSubscription } from './lib/mock-ws';
|
||||
import { addMockWalletCommand } from './lib/mock-rest';
|
||||
import { addMockWeb3ProviderCommand } from './lib/commands/mock-web3-provider';
|
||||
import { addSlackCommand } from './lib/commands/slack';
|
||||
import { addHighlightLog } from './lib/commands/highlight-log';
|
||||
import { addGetAssets } from './lib/commands/get-assets';
|
||||
import { addVegaWalletReceiveFaucetedAsset } from './lib/commands/vega-wallet-receive-fauceted-asset';
|
||||
@@ -25,6 +26,7 @@ import { addVegaWalletTopUpRewardsPool } from './lib/commands/vega-wallet-top-up
|
||||
import { addAssociateTokensToVegaWallet } from './lib/commands/associate-tokens-to-vega-wallet';
|
||||
|
||||
addGetTestIdcommand();
|
||||
addSlackCommand();
|
||||
addMockGQLCommand();
|
||||
addMockSubscription();
|
||||
addMockWalletCommand();
|
||||
@@ -57,14 +59,7 @@ export { aliasGQLQuery } from './lib/mock-gql';
|
||||
export { aliasWalletQuery } from './lib/mock-rest';
|
||||
export * from './lib/utils';
|
||||
|
||||
Cypress.on('uncaught:exception', (err) => {
|
||||
if (
|
||||
err.message.includes('ResizeObserver loop limit exceeded') ||
|
||||
err.message.includes(
|
||||
'ResizeObserver loop completed with undelivered notifications'
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
Cypress.on(
|
||||
'uncaught:exception',
|
||||
(err) => !err.message.includes('ResizeObserver loop limit exceeded')
|
||||
);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface Chainable<Subject> {
|
||||
slack(message: string): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function addSlackCommand() {
|
||||
// @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command
|
||||
Cypress.Commands.add('slack', (message) => {
|
||||
const text = `${message}: ${JSON.stringify(Cypress.spec)}`;
|
||||
|
||||
cy.log('NOTIFYING SLACK');
|
||||
|
||||
const webhook = Cypress.env('SLACK_WEBHOOK');
|
||||
|
||||
if (!webhook) {
|
||||
return;
|
||||
}
|
||||
|
||||
cy.request('POST', webhook, {
|
||||
text,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -35,9 +35,7 @@ export const ZeroBalanceError = ({
|
||||
}
|
||||
buttonProps={{
|
||||
text: t(`Make a deposit`),
|
||||
action: () => {
|
||||
onDeposit(asset.id);
|
||||
},
|
||||
action: () => onDeposit(asset.id),
|
||||
dataTestId: 'deal-ticket-deposit-dialog-button',
|
||||
size: 'small',
|
||||
}}
|
||||
|
||||
@@ -10,7 +10,7 @@ export const DealTicketButton = ({ side }: Props) => {
|
||||
const buttonClasses = classNames(
|
||||
'px-10 py-2 uppercase rounded-md text-white w-full',
|
||||
{
|
||||
'bg-market-red': side === Side.SIDE_SELL,
|
||||
'bg-market-red-500': side === Side.SIDE_SELL,
|
||||
'bg-market-green-550': side === Side.SIDE_BUY,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -270,8 +270,8 @@ export const DealTicket = ({
|
||||
return (
|
||||
<form
|
||||
onSubmit={isReadOnly ? undefined : handleSubmit(onSubmit)}
|
||||
className="p-4"
|
||||
noValidate
|
||||
data-testid="deal-ticket-form"
|
||||
>
|
||||
<Controller
|
||||
name="type"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import { AsyncRendererInline } from '@vegaprotocol/ui-toolkit';
|
||||
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { DepositManager } from './deposit-manager';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { enabledAssetsProvider } from '@vegaprotocol/assets';
|
||||
|
||||
@@ -15,14 +16,18 @@ export const DepositContainer = ({ assetId }: { assetId?: string }) => {
|
||||
});
|
||||
|
||||
return (
|
||||
<AsyncRendererInline data={data} loading={loading} error={error}>
|
||||
{data && data.length && (
|
||||
<AsyncRenderer data={data} loading={loading} error={error}>
|
||||
{data && data.length ? (
|
||||
<DepositManager
|
||||
assetId={assetId}
|
||||
assets={data}
|
||||
isFaucetable={VEGA_ENV !== Networks.MAINNET}
|
||||
/>
|
||||
) : (
|
||||
<Splash>
|
||||
<p>{t('No assets on this network')}</p>
|
||||
</Splash>
|
||||
)}
|
||||
</AsyncRendererInline>
|
||||
</AsyncRenderer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -90,6 +90,7 @@ export const DepositForm = ({
|
||||
const [approveNotificationIntent, setApproveNotificationIntent] =
|
||||
useState<Intent>(Intent.Warning);
|
||||
const [persistedDeposit] = usePersistentDeposit(selectedAsset?.id);
|
||||
console.log('deposit-form', account);
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
|
||||
@@ -359,14 +359,6 @@ function compileEnvVars() {
|
||||
),
|
||||
APP_VERSION: windowOrDefault('APP_VERSION', process.env['NX_APP_VERSION']),
|
||||
SENTRY_DSN: windowOrDefault('SENTRY_DSN', process.env['NX_SENTRY_DSN']),
|
||||
TENDERMINT_URL: windowOrDefault(
|
||||
'NX_TENDERMINT_URL',
|
||||
process.env['NX_TENDERMINT_URL']
|
||||
),
|
||||
TENDERMINT_WEBSOCKET_URL: windowOrDefault(
|
||||
'NX_TENDERMINT_WEBSOCKET_URL',
|
||||
process.env['NX_TENDERMINT_WEBSOCKET_URL']
|
||||
),
|
||||
};
|
||||
|
||||
return env;
|
||||
|
||||
@@ -54,8 +54,6 @@ const schemaObject = {
|
||||
VEGA_INCIDENT_URL: z.optional(z.string()),
|
||||
APP_VERSION: z.optional(z.string()),
|
||||
SENTRY_DSN: z.optional(z.string()),
|
||||
TENDERMINT_URL: z.optional(z.string()),
|
||||
TENDERMINT_WEBSOCKET_URL: z.optional(z.string()),
|
||||
};
|
||||
|
||||
// combine schema above with custom rule to ensure either
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from './__generated__/MarketDepth';
|
||||
export * from './depth-chart';
|
||||
export * from './market-depth-provider';
|
||||
export * from './orderbook-container';
|
||||
export * from './orderbook-data';
|
||||
export * from './orderbook-manager';
|
||||
export * from './orderbook-row';
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { OrderbookManager } from './orderbook-manager';
|
||||
|
||||
export const OrderbookContainer = ({ marketId }: { marketId: string }) => (
|
||||
<OrderbookManager marketId={marketId} />
|
||||
);
|
||||
@@ -9,6 +9,7 @@ import type {
|
||||
MarketDepthUpdateSubscription,
|
||||
PriceLevelFieldsFragment,
|
||||
} from './__generated__/MarketDepth';
|
||||
import { useCreateOrderStore } from '@vegaprotocol/orders';
|
||||
|
||||
export type OrderbookData = {
|
||||
asks: PriceLevelFieldsFragment[];
|
||||
@@ -17,13 +18,9 @@ export type OrderbookData = {
|
||||
|
||||
interface OrderbookManagerProps {
|
||||
marketId: string;
|
||||
onClick?: (args: { price?: string; size?: string }) => void;
|
||||
}
|
||||
|
||||
export const OrderbookManager = ({
|
||||
marketId,
|
||||
onClick,
|
||||
}: OrderbookManagerProps) => {
|
||||
export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
|
||||
const variables = { marketId };
|
||||
|
||||
const { data, error, loading, reload } = useDataProvider<
|
||||
@@ -53,6 +50,8 @@ export const OrderbookManager = ({
|
||||
dataProvider: marketDataProvider,
|
||||
variables,
|
||||
});
|
||||
const useOrderStoreRef = useCreateOrderStore();
|
||||
const updateOrder = useOrderStoreRef((store) => store.update);
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
@@ -67,7 +66,14 @@ export const OrderbookManager = ({
|
||||
decimalPlaces={market?.decimalPlaces ?? 0}
|
||||
positionDecimalPlaces={market?.positionDecimalPlaces ?? 0}
|
||||
assetSymbol={market?.tradableInstrument.instrument.product.quoteName}
|
||||
onClick={onClick}
|
||||
onClick={({ price, size }) => {
|
||||
if (price) {
|
||||
updateOrder(marketId, { price });
|
||||
}
|
||||
if (size) {
|
||||
updateOrder(marketId, { size });
|
||||
}
|
||||
}}
|
||||
midPrice={marketData?.midPrice}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
|
||||
@@ -13,12 +13,8 @@ interface OrderbookRowProps {
|
||||
price: string;
|
||||
onClick?: (args: { price?: string; size?: string }) => void;
|
||||
type: VolumeType;
|
||||
width: number;
|
||||
}
|
||||
|
||||
const HIDE_VOL_WIDTH = 150;
|
||||
const HIDE_CUMULATIVE_VOL_WIDTH = 220;
|
||||
|
||||
const CumulationBar = ({
|
||||
cumulativeValue = 0,
|
||||
type,
|
||||
@@ -30,7 +26,7 @@ const CumulationBar = ({
|
||||
<div
|
||||
data-testid={`${VolumeType.bid === type ? 'bid' : 'ask'}-bar`}
|
||||
className={classNames(
|
||||
'absolute top-0 left-0 h-full',
|
||||
'absolute top-0 left-0 h-full transition-all',
|
||||
type === VolumeType.bid
|
||||
? 'bg-market-green-300 dark:bg-market-green/50'
|
||||
: 'bg-market-red-300 dark:bg-market-red/30'
|
||||
@@ -94,18 +90,12 @@ export const OrderbookRow = React.memo(
|
||||
price,
|
||||
onClick,
|
||||
type,
|
||||
width,
|
||||
}: OrderbookRowProps) => {
|
||||
const txtId = type === VolumeType.bid ? 'bid' : 'ask';
|
||||
const cols =
|
||||
width >= HIDE_CUMULATIVE_VOL_WIDTH ? 3 : width >= HIDE_VOL_WIDTH ? 2 : 1;
|
||||
return (
|
||||
<div className="relative pr-1">
|
||||
<div className="relative">
|
||||
<CumulationBar cumulativeValue={cumulativeRelativeValue} type={type} />
|
||||
<div
|
||||
data-testid={`${txtId}-rows-container`}
|
||||
className={classNames('grid gap-1 text-right', `grid-cols-${cols}`)}
|
||||
>
|
||||
<div className="grid gap-1 text-right grid-cols-3">
|
||||
<PriceCell
|
||||
testId={`price-${price}`}
|
||||
value={BigInt(price)}
|
||||
@@ -119,37 +109,33 @@ export const OrderbookRow = React.memo(
|
||||
: 'text-market-green-600 dark:text-market-green'
|
||||
}
|
||||
/>
|
||||
{width >= HIDE_VOL_WIDTH && (
|
||||
<PriceCell
|
||||
testId={`${txtId}-vol-${price}`}
|
||||
onClick={(value) =>
|
||||
onClick &&
|
||||
value &&
|
||||
onClick({
|
||||
size: addDecimal(value, positionDecimalPlaces),
|
||||
})
|
||||
}
|
||||
value={value}
|
||||
valueFormatted={addDecimalsFixedFormatNumber(
|
||||
value,
|
||||
positionDecimalPlaces
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{width >= HIDE_CUMULATIVE_VOL_WIDTH && (
|
||||
<CumulativeVol
|
||||
testId={`cumulative-vol-${price}`}
|
||||
onClick={() =>
|
||||
onClick &&
|
||||
cumulativeValue &&
|
||||
onClick({
|
||||
size: addDecimal(cumulativeValue, positionDecimalPlaces),
|
||||
})
|
||||
}
|
||||
positionDecimalPlaces={positionDecimalPlaces}
|
||||
cumulativeValue={cumulativeValue}
|
||||
/>
|
||||
)}
|
||||
<PriceCell
|
||||
testId={`${txtId}-vol-${price}`}
|
||||
onClick={(value) =>
|
||||
onClick &&
|
||||
value &&
|
||||
onClick({
|
||||
size: addDecimal(value, positionDecimalPlaces),
|
||||
})
|
||||
}
|
||||
value={value}
|
||||
valueFormatted={addDecimalsFixedFormatNumber(
|
||||
value,
|
||||
positionDecimalPlaces
|
||||
)}
|
||||
/>
|
||||
<CumulativeVol
|
||||
testId={`cumulative-vol-${price}`}
|
||||
onClick={() =>
|
||||
onClick &&
|
||||
cumulativeValue &&
|
||||
onClick({
|
||||
size: addDecimal(cumulativeValue, positionDecimalPlaces),
|
||||
})
|
||||
}
|
||||
positionDecimalPlaces={positionDecimalPlaces}
|
||||
cumulativeValue={cumulativeValue}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { render, waitFor, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { render, fireEvent, waitFor, screen } from '@testing-library/react';
|
||||
import { generateMockData, VolumeType } from './orderbook-data';
|
||||
import { Orderbook } from './orderbook';
|
||||
import * as orderbookData from './orderbook-data';
|
||||
@@ -34,7 +33,6 @@ describe('Orderbook', () => {
|
||||
const decimalPlaces = 3;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockOffsetSize(800, 768);
|
||||
});
|
||||
it('markPrice should be in the middle', async () => {
|
||||
@@ -71,17 +69,12 @@ describe('Orderbook', () => {
|
||||
await screen.findByTestId(`middle-mark-price-${params.midPrice}`)
|
||||
).toBeInTheDocument();
|
||||
// Before resolution change the price is 122.934
|
||||
await userEvent.click(await screen.getByTestId('price-122901'));
|
||||
await fireEvent.click(await screen.getByTestId('price-122901'));
|
||||
expect(onClickSpy).toBeCalledWith({ price: '122.901' });
|
||||
|
||||
await userEvent.click(screen.getByTestId('resolution'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getAllByRole('menuitem')[1]);
|
||||
|
||||
const resolutionSelect = screen.getByTestId(
|
||||
'resolution'
|
||||
) as HTMLSelectElement;
|
||||
await fireEvent.change(resolutionSelect, { target: { value: '10' } });
|
||||
expect(orderbookData.compactRows).toHaveBeenCalledWith(
|
||||
mockedData.bids,
|
||||
VolumeType.bid,
|
||||
@@ -92,88 +85,7 @@ describe('Orderbook', () => {
|
||||
VolumeType.ask,
|
||||
10
|
||||
);
|
||||
await userEvent.click(await screen.getByTestId('price-12294'));
|
||||
await fireEvent.click(await screen.getByTestId('price-12294'));
|
||||
expect(onClickSpy).toBeCalledWith({ price: '122.94' });
|
||||
});
|
||||
|
||||
it('plus - minus buttons should change resolution', async () => {
|
||||
const onClickSpy = jest.fn();
|
||||
jest.spyOn(orderbookData, 'compactRows');
|
||||
const mockedData = generateMockData(params);
|
||||
render(
|
||||
<Orderbook
|
||||
decimalPlaces={decimalPlaces}
|
||||
positionDecimalPlaces={0}
|
||||
onClick={onClickSpy}
|
||||
{...mockedData}
|
||||
assetSymbol="USD"
|
||||
/>
|
||||
);
|
||||
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
||||
1
|
||||
);
|
||||
expect(screen.getByTestId('minus-button')).toBeDisabled();
|
||||
userEvent.click(screen.getByTestId('plus-button'));
|
||||
await waitFor(() => {
|
||||
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
||||
10
|
||||
);
|
||||
});
|
||||
expect(screen.getByTestId('minus-button')).not.toBeDisabled();
|
||||
userEvent.click(screen.getByTestId('minus-button'));
|
||||
await waitFor(() => {
|
||||
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
||||
1
|
||||
);
|
||||
});
|
||||
expect(screen.getByTestId('minus-button')).toBeDisabled();
|
||||
await userEvent.click(screen.getByTestId('resolution'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
});
|
||||
await userEvent.click(screen.getAllByRole('menuitem')[5]);
|
||||
await waitFor(() => {
|
||||
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
|
||||
100000
|
||||
);
|
||||
});
|
||||
expect(screen.getByTestId('plus-button')).toBeDisabled();
|
||||
});
|
||||
|
||||
it('two columns', () => {
|
||||
mockOffsetSize(200, 768);
|
||||
const onClickSpy = jest.fn();
|
||||
const mockedData = generateMockData(params);
|
||||
render(
|
||||
<Orderbook
|
||||
decimalPlaces={decimalPlaces}
|
||||
positionDecimalPlaces={0}
|
||||
onClick={onClickSpy}
|
||||
{...mockedData}
|
||||
assetSymbol="USD"
|
||||
/>
|
||||
);
|
||||
screen.getAllByTestId('bid-rows-container').forEach((item) => {
|
||||
expect(item).toHaveClass('grid-cols-2');
|
||||
});
|
||||
});
|
||||
|
||||
it('one column', () => {
|
||||
mockOffsetSize(140, 768);
|
||||
const onClickSpy = jest.fn();
|
||||
const mockedData = generateMockData(params);
|
||||
render(
|
||||
<Orderbook
|
||||
decimalPlaces={decimalPlaces}
|
||||
positionDecimalPlaces={0}
|
||||
onClick={onClickSpy}
|
||||
{...mockedData}
|
||||
assetSymbol="USD"
|
||||
/>
|
||||
);
|
||||
screen.getAllByTestId('ask-rows-container').forEach((item) => {
|
||||
expect(item).toHaveClass('grid-cols-1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import ReactVirtualizedAutoSizer from 'react-virtualized-auto-sizer';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumberFixed,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { usePrevious } from '@vegaprotocol/react-helpers';
|
||||
import { OrderbookRow } from './orderbook-row';
|
||||
import type { OrderbookRowData } from './orderbook-data';
|
||||
import { compactRows, VolumeType } from './orderbook-data';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
Splash,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import { useState } from 'react';
|
||||
import type { PriceLevelFieldsFragment } from './__generated__/MarketDepth';
|
||||
|
||||
// Sets row height, will be used to calculate number of rows that can be
|
||||
@@ -27,19 +19,6 @@ export const rowHeight = 17;
|
||||
const rowGap = 1;
|
||||
const midHeight = 30;
|
||||
|
||||
type PriceChange = 'up' | 'down' | 'none';
|
||||
|
||||
const PRICE_CHANGE_ICON_MAP: Readonly<Record<PriceChange, VegaIconNames>> = {
|
||||
up: VegaIconNames.ARROW_UP,
|
||||
down: VegaIconNames.ARROW_DOWN,
|
||||
none: VegaIconNames.BULLET,
|
||||
};
|
||||
const PRICE_CHANGE_CLASS_MAP: Readonly<Record<PriceChange, string>> = {
|
||||
up: 'text-market-green-600 dark:text-market-green',
|
||||
down: 'text-market-red dark:text-market-red',
|
||||
none: 'text-vega-blue-500',
|
||||
};
|
||||
|
||||
const OrderbookTable = ({
|
||||
rows,
|
||||
resolution,
|
||||
@@ -47,7 +26,6 @@ const OrderbookTable = ({
|
||||
decimalPlaces,
|
||||
positionDecimalPlaces,
|
||||
onClick,
|
||||
width,
|
||||
}: {
|
||||
rows: OrderbookRowData[];
|
||||
resolution: number;
|
||||
@@ -55,7 +33,6 @@ const OrderbookTable = ({
|
||||
positionDecimalPlaces: number;
|
||||
type: VolumeType;
|
||||
onClick?: (args: { price?: string; size?: string }) => void;
|
||||
width: number;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
@@ -82,7 +59,6 @@ const OrderbookTable = ({
|
||||
cumulativeValue={data.cumulativeVol.value}
|
||||
cumulativeRelativeValue={data.cumulativeVol.relativeValue}
|
||||
type={type}
|
||||
width={width}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -123,50 +99,12 @@ export const Orderbook = ({
|
||||
const groupedBids = useMemo(() => {
|
||||
return compactRows(bids, VolumeType.bid, resolution);
|
||||
}, [bids, resolution]);
|
||||
const [isOpen, setOpen] = useState(false);
|
||||
const previousMidPrice = usePrevious(midPrice);
|
||||
const priceChangeRef = useRef<'up' | 'down' | 'none'>('none');
|
||||
if (midPrice && previousMidPrice !== midPrice) {
|
||||
priceChangeRef.current =
|
||||
(previousMidPrice || '') > midPrice ? 'down' : 'up';
|
||||
}
|
||||
|
||||
const priceChangeIcon = (
|
||||
<span
|
||||
className={classNames(PRICE_CHANGE_CLASS_MAP[priceChangeRef.current])}
|
||||
>
|
||||
<VegaIcon name={PRICE_CHANGE_ICON_MAP[priceChangeRef.current]} />
|
||||
</span>
|
||||
);
|
||||
|
||||
const formatResolution = (r: number) => {
|
||||
return formatNumberFixed(
|
||||
Math.log10(r) - decimalPlaces > 0
|
||||
? Math.pow(10, Math.log10(r) - decimalPlaces)
|
||||
: 0,
|
||||
decimalPlaces - Math.log10(r)
|
||||
);
|
||||
};
|
||||
|
||||
const increaseResolution = () => {
|
||||
const index = resolutions.indexOf(resolution);
|
||||
if (index < resolutions.length - 1) {
|
||||
setResolution(resolutions[index + 1]);
|
||||
}
|
||||
};
|
||||
|
||||
const decreaseResolution = () => {
|
||||
const index = resolutions.indexOf(resolution);
|
||||
if (index > 0) {
|
||||
setResolution(resolutions[index - 1]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-full text-xs grid grid-rows-[1fr_min-content]">
|
||||
<div>
|
||||
<ReactVirtualizedAutoSizer>
|
||||
{({ width, height }) => {
|
||||
<ReactVirtualizedAutoSizer disableWidth>
|
||||
{({ height }) => {
|
||||
const limit = Math.max(
|
||||
1,
|
||||
Math.floor((height - midHeight) / 2 / (rowHeight + rowGap))
|
||||
@@ -178,7 +116,6 @@ export const Orderbook = ({
|
||||
className="overflow-hidden grid"
|
||||
data-testid="orderbook-grid-element"
|
||||
style={{
|
||||
width: width + 'px',
|
||||
height: height + 'px',
|
||||
gridTemplateRows: `1fr ${midHeight}px 1fr`, // cannot use tailwind here as tailwind will not parse a class string with interpolation
|
||||
}}
|
||||
@@ -192,7 +129,6 @@ export const Orderbook = ({
|
||||
decimalPlaces={decimalPlaces}
|
||||
positionDecimalPlaces={positionDecimalPlaces}
|
||||
onClick={onClick}
|
||||
width={width}
|
||||
/>
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
{midPrice && (
|
||||
@@ -204,7 +140,6 @@ export const Orderbook = ({
|
||||
{addDecimalsFormatNumber(midPrice, decimalPlaces)}
|
||||
</span>
|
||||
<span className="text-base">{assetSymbol}</span>
|
||||
{priceChangeIcon}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -215,7 +150,6 @@ export const Orderbook = ({
|
||||
decimalPlaces={decimalPlaces}
|
||||
positionDecimalPlaces={positionDecimalPlaces}
|
||||
onClick={onClick}
|
||||
width={width}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
@@ -228,59 +162,26 @@ export const Orderbook = ({
|
||||
}}
|
||||
</ReactVirtualizedAutoSizer>
|
||||
</div>
|
||||
<div className="border-t border-default flex">
|
||||
<button
|
||||
onClick={increaseResolution}
|
||||
disabled={resolutions.indexOf(resolution) >= resolutions.length - 1}
|
||||
className="flex items-center border-r border-default px-2 cursor-pointer"
|
||||
data-testid="plus-button"
|
||||
<div className="border-t border-default bg-vega-clight-700 dark:bg-vega-cdark-700">
|
||||
<select
|
||||
onChange={(e) => {
|
||||
setResolution(Number(e.currentTarget.value));
|
||||
}}
|
||||
value={resolution}
|
||||
className="block bg-transparent font-mono text-right"
|
||||
data-testid="resolution"
|
||||
>
|
||||
<VegaIcon size={12} name={VegaIconNames.PLUS} />
|
||||
</button>
|
||||
<DropdownMenu
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => setOpen(open)}
|
||||
trigger={
|
||||
<DropdownMenuTrigger
|
||||
data-testid="resolution"
|
||||
className="flex justify-between px-1 items-center"
|
||||
style={{
|
||||
width: `${
|
||||
Math.max.apply(
|
||||
null,
|
||||
resolutions.map((item) => formatResolution(item).length)
|
||||
) + 3
|
||||
}ch`,
|
||||
}}
|
||||
>
|
||||
<VegaIcon
|
||||
size={12}
|
||||
name={
|
||||
isOpen ? VegaIconNames.CHEVRON_UP : VegaIconNames.CHEVRON_DOWN
|
||||
}
|
||||
/>
|
||||
<div className="text-xs text-left">
|
||||
{formatResolution(resolution)}
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
<DropdownMenuContent align="start">
|
||||
{resolutions.map((r) => (
|
||||
<DropdownMenuItem key={r} onClick={() => setResolution(r)}>
|
||||
{formatResolution(r)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<button
|
||||
onClick={decreaseResolution}
|
||||
disabled={resolutions.indexOf(resolution) <= 0}
|
||||
className="flex items-center border-x border-default px-2 cursor-pointer"
|
||||
data-testid="minus-button"
|
||||
>
|
||||
<VegaIcon size={12} name={VegaIconNames.MINUS} />
|
||||
</button>
|
||||
{resolutions.map((r) => (
|
||||
<option key={r} value={r}>
|
||||
{formatNumberFixed(
|
||||
Math.log10(r) - decimalPlaces > 0
|
||||
? Math.pow(10, Math.log10(r) - decimalPlaces)
|
||||
: 0,
|
||||
decimalPlaces - Math.log10(r)
|
||||
)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -168,6 +168,7 @@ export const MarketInfoDocument = gql`
|
||||
}
|
||||
}
|
||||
}
|
||||
parentMarketID
|
||||
}
|
||||
}
|
||||
${DataSourceFragmentDoc}`;
|
||||
|
||||
@@ -82,7 +82,6 @@ export const marketProvider = makeDerivedDataProvider<
|
||||
);
|
||||
|
||||
export const useMarket = (marketId?: string) => {
|
||||
console.log(marketId);
|
||||
const variables = useMemo(() => ({ marketId: marketId || '' }), [marketId]);
|
||||
return useDataProvider({
|
||||
dataProvider: marketProvider,
|
||||
|
||||
@@ -6,7 +6,6 @@ import type { Position } from './positions-data-providers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { PositionStatus, PositionStatusMapping } from '@vegaprotocol/types';
|
||||
import type { ICellRendererParams } from 'ag-grid-community';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
|
||||
jest.mock('./liquidation-price', () => ({
|
||||
LiquidationPrice: () => (
|
||||
@@ -20,7 +19,7 @@ const singleRow: Position = {
|
||||
assetSymbol: 'BTC',
|
||||
averageEntryPrice: '133',
|
||||
currentLeverage: 1.1,
|
||||
decimals: 2, // this is settlementAsset.decimals
|
||||
decimals: 2,
|
||||
quantum: '0.1',
|
||||
lossSocializationAmount: '0',
|
||||
marginAccountBalance: '12345600',
|
||||
@@ -178,23 +177,12 @@ it('displays allocated margin', async () => {
|
||||
});
|
||||
|
||||
it('displays realised and unrealised PNL', async () => {
|
||||
// pnl cells should be rendered with asset dps
|
||||
const expectedRealised = addDecimalsFormatNumber(
|
||||
singleRow.realisedPNL,
|
||||
singleRow.decimals
|
||||
);
|
||||
const expectedUnrealised = addDecimalsFormatNumber(
|
||||
singleRow.unrealisedPNL,
|
||||
singleRow.decimals
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
render(<PositionsTable rowData={singleRowData} isReadOnly={false} />);
|
||||
});
|
||||
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
expect(cells[9].textContent).toEqual(expectedRealised);
|
||||
expect(cells[10].textContent).toEqual(expectedUnrealised);
|
||||
expect(cells[9].textContent).toEqual('12.3');
|
||||
expect(cells[10].textContent).toEqual('45.6');
|
||||
});
|
||||
|
||||
it('displays close button', async () => {
|
||||
|
||||
@@ -365,14 +365,20 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
valueGetter: ({ data }: VegaValueGetterParams<Position>) => {
|
||||
return !data
|
||||
? undefined
|
||||
: toBigNum(data.realisedPNL, data.decimals).toNumber();
|
||||
: toBigNum(
|
||||
data.realisedPNL,
|
||||
data.marketDecimalPlaces
|
||||
).toNumber();
|
||||
},
|
||||
valueFormatter: ({
|
||||
data,
|
||||
}: VegaValueFormatterParams<Position, 'realisedPNL'>) => {
|
||||
return !data
|
||||
? ''
|
||||
: addDecimalsFormatNumber(data.realisedPNL, data.decimals);
|
||||
: addDecimalsFormatNumber(
|
||||
data.realisedPNL,
|
||||
data.marketDecimalPlaces
|
||||
);
|
||||
},
|
||||
headerTooltip: t(
|
||||
'Profit or loss is realised whenever your position is reduced to zero and the margin is released back to your collateral balance. P&L excludes any fees paid.'
|
||||
@@ -390,14 +396,20 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
valueGetter: ({ data }: VegaValueGetterParams<Position>) => {
|
||||
return !data
|
||||
? undefined
|
||||
: toBigNum(data.unrealisedPNL, data.decimals).toNumber();
|
||||
: toBigNum(
|
||||
data.unrealisedPNL,
|
||||
data.marketDecimalPlaces
|
||||
).toNumber();
|
||||
},
|
||||
valueFormatter: ({
|
||||
data,
|
||||
}: VegaValueFormatterParams<Position, 'unrealisedPNL'>) =>
|
||||
!data
|
||||
? ''
|
||||
: addDecimalsFormatNumber(data.unrealisedPNL, data.decimals),
|
||||
: addDecimalsFormatNumber(
|
||||
data.unrealisedPNL,
|
||||
data.marketDecimalPlaces
|
||||
),
|
||||
headerTooltip: t(
|
||||
'Unrealised profit is the current profit on your open position. Margin is still allocated to your position.'
|
||||
),
|
||||
|
||||
@@ -44,10 +44,7 @@ export const ProtocolUpgradeProposalNotification = ({
|
||||
case ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING:
|
||||
countdown =
|
||||
time !== undefined ? (
|
||||
<span
|
||||
title={t('estimated time to protocol upgrade')}
|
||||
className="text-vega-orange-500"
|
||||
>
|
||||
<span className="text-vega-orange-500">
|
||||
{convertToCountdownString(time, '0:00:00:00')}
|
||||
</span>
|
||||
) : (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useReducer, useRef } from 'react';
|
||||
|
||||
export interface State<T> {
|
||||
interface State<T> {
|
||||
data?: T;
|
||||
error?: Error;
|
||||
loading?: boolean;
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
# tendermint
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test tendermint` to execute the unit tests via [Jest](https://jestjs.io).
|
||||
@@ -1,11 +0,0 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'tendermint',
|
||||
preset: '../../jest.preset.js',
|
||||
transform: {
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
||||
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/tendermint',
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "tendermint",
|
||||
"version": "0.0.1"
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"name": "tendermint",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/tendermint/src",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"lint": {
|
||||
"executor": "@nx/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["libs/tendermint/**/*.{ts,tsx,js,jsx}"]
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nx/rollup:rollup",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/libs/tendermint",
|
||||
"tsConfig": "libs/tendermint/tsconfig.lib.json",
|
||||
"project": "libs/tendermint/package.json",
|
||||
"entryFile": "libs/tendermint/src/index.ts",
|
||||
"external": ["react", "react-dom", "react/jsx-runtime"],
|
||||
"rollupConfig": "@nx/react/plugins/bundle-rollup",
|
||||
"compiler": "babel",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "libs/tendermint/README.md",
|
||||
"input": ".",
|
||||
"output": "."
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "libs/tendermint/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"ci": true,
|
||||
"codeCoverage": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './lib/use-block-info';
|
||||
export * from './types';
|
||||
@@ -1,20 +0,0 @@
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import type { TendermintBlockResponse } from '../types';
|
||||
|
||||
export const useBlockInfo = (blockHeight?: number, canFetch = true) => {
|
||||
const { TENDERMINT_URL } = useEnvironment();
|
||||
|
||||
const url = `${TENDERMINT_URL}/block?height=${blockHeight}`;
|
||||
const canFetchData = Boolean(
|
||||
TENDERMINT_URL && blockHeight && !isNaN(blockHeight) && canFetch
|
||||
);
|
||||
|
||||
const { state, refetch } = useFetch<TendermintBlockResponse>(
|
||||
url,
|
||||
{ cache: 'force-cache' },
|
||||
canFetchData
|
||||
);
|
||||
|
||||
return { state, refetch };
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
export type TendermintBlockResponse = {
|
||||
jsonrpc: string;
|
||||
id: number;
|
||||
result: {
|
||||
block_id: Id;
|
||||
block: Block;
|
||||
};
|
||||
};
|
||||
|
||||
type Id = {
|
||||
hash: string;
|
||||
parts: {
|
||||
total: number;
|
||||
hash: string;
|
||||
};
|
||||
};
|
||||
|
||||
type Header = {
|
||||
version: {
|
||||
block: string;
|
||||
};
|
||||
chain_id: string;
|
||||
height: string;
|
||||
time: string;
|
||||
last_block_id: Id;
|
||||
last_commit_hash: string;
|
||||
data_hash: string;
|
||||
validators_hash: string;
|
||||
next_validators_hash: string;
|
||||
consensus_hash: string;
|
||||
app_hash: string;
|
||||
last_results_hash: string;
|
||||
evidence_hash: string;
|
||||
proposer_address: string;
|
||||
};
|
||||
|
||||
type Block = {
|
||||
header: Header;
|
||||
data: {
|
||||
txs: string[];
|
||||
};
|
||||
evidence: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
evidence: any[];
|
||||
};
|
||||
last_commit: {
|
||||
height: string;
|
||||
round: number;
|
||||
block_id: Id;
|
||||
signatures: {
|
||||
block_id_flag: number;
|
||||
validator_address: string;
|
||||
timestamp: string;
|
||||
signature: string;
|
||||
}[];
|
||||
};
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": false,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../tsconfig.base.json"
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"types": ["node"]
|
||||
},
|
||||
"files": [
|
||||
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
|
||||
"../../node_modules/@nx/react/typings/image.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.test.jsx"
|
||||
],
|
||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user