Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd1bd3447c | ||
|
|
03fbba6f81 | ||
|
|
e81a536a0d |
@@ -1,52 +1,143 @@
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumberPercentage,
|
||||
getMarketExpiryDateFormatted,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { MarketInfoWithData } from '@vegaprotocol/market-info';
|
||||
import { LiquidityInfoPanel } from '@vegaprotocol/market-info';
|
||||
import { LiquidityMonitoringParametersInfoPanel } from '@vegaprotocol/market-info';
|
||||
import {
|
||||
InstrumentInfoPanel,
|
||||
KeyDetailsInfoPanel,
|
||||
LiquidityPriceRangeInfoPanel,
|
||||
MetadataInfoPanel,
|
||||
OracleInfoPanel,
|
||||
RiskFactorsInfoPanel,
|
||||
RiskModelInfoPanel,
|
||||
RiskParametersInfoPanel,
|
||||
SettlementAssetInfoPanel,
|
||||
} from '@vegaprotocol/market-info';
|
||||
import { MarketInfoTable } from '@vegaprotocol/market-info';
|
||||
import {
|
||||
MarketStateMapping,
|
||||
MarketTradingModeMapping,
|
||||
} from '@vegaprotocol/types';
|
||||
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useMemo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
const quoteUnit = market?.tradableInstrument.instrument.product.quoteName;
|
||||
const assetId = useMemo(
|
||||
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
|
||||
[market]
|
||||
);
|
||||
const { data: asset } = useAssetDataProvider(assetId ?? '');
|
||||
|
||||
if (!market) return null;
|
||||
|
||||
const keyDetails = {
|
||||
decimalPlaces: market.decimalPlaces,
|
||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
||||
tradingMode: market.tradingMode,
|
||||
state: MarketStateMapping[market.state],
|
||||
};
|
||||
const assetDecimals =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
||||
|
||||
const liquidityPriceRange = formatNumberPercentage(
|
||||
new BigNumber(market.lpPriceRange).times(100)
|
||||
);
|
||||
|
||||
const panels = [
|
||||
{
|
||||
title: t('Key details'),
|
||||
content: <KeyDetailsInfoPanel noBorder={false} market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={{
|
||||
name: market.tradableInstrument.instrument.name,
|
||||
marketID: market.id,
|
||||
tradingMode:
|
||||
keyDetails.tradingMode &&
|
||||
MarketTradingModeMapping[keyDetails.tradingMode],
|
||||
marketDecimalPlaces: market.decimalPlaces,
|
||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
||||
settlementAssetDecimalPlaces: assetDecimals,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Instrument'),
|
||||
content: <InstrumentInfoPanel noBorder={false} market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={{
|
||||
marketName: market.tradableInstrument.instrument.name,
|
||||
code: market.tradableInstrument.instrument.code,
|
||||
productType:
|
||||
market.tradableInstrument.instrument.product.__typename,
|
||||
...market.tradableInstrument.instrument.product,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Settlement asset'),
|
||||
content: <SettlementAssetInfoPanel market={market} noBorder={false} />,
|
||||
content: asset ? (
|
||||
<AssetDetailsTable
|
||||
asset={asset}
|
||||
inline={true}
|
||||
noBorder={false}
|
||||
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
|
||||
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
|
||||
/>
|
||||
) : (
|
||||
<Splash>{t('No data')}</Splash>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Metadata'),
|
||||
content: <MetadataInfoPanel noBorder={false} market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={{
|
||||
expiryDate: getMarketExpiryDateFormatted(
|
||||
market.tradableInstrument.instrument.metadata.tags
|
||||
),
|
||||
...market.tradableInstrument.instrument.metadata.tags
|
||||
?.map((tag) => {
|
||||
const [key, value] = tag.split(':');
|
||||
return { [key]: value };
|
||||
})
|
||||
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Risk model'),
|
||||
content: <RiskModelInfoPanel noBorder={false} market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={market.tradableInstrument.riskModel}
|
||||
unformatted={true}
|
||||
omits={[]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Risk parameters'),
|
||||
content: <RiskParametersInfoPanel noBorder={false} market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={market.tradableInstrument.riskModel.params}
|
||||
unformatted={true}
|
||||
omits={[]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Risk factors'),
|
||||
content: <RiskFactorsInfoPanel noBorder={false} market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={market.riskFactors}
|
||||
unformatted={true}
|
||||
omits={['market', '__typename']}
|
||||
/>
|
||||
),
|
||||
},
|
||||
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||
(trigger, i) => ({
|
||||
@@ -67,10 +158,7 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={{ referencePrice: trigger.referencePrice }}
|
||||
decimalPlaces={
|
||||
market.tradableInstrument.instrument.product.settlementAsset
|
||||
.decimals
|
||||
}
|
||||
decimalPlaces={assetDecimals}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
@@ -78,26 +166,64 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
{
|
||||
title: t('Liquidity monitoring parameters'),
|
||||
content: (
|
||||
<LiquidityMonitoringParametersInfoPanel
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
market={market}
|
||||
data={{
|
||||
triggeringRatio:
|
||||
market.liquidityMonitoringParameters.triggeringRatio,
|
||||
...market.liquidityMonitoringParameters.targetStakeParameters,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Liquidity'),
|
||||
content: <LiquidityInfoPanel market={market} noBorder={false} />,
|
||||
},
|
||||
{
|
||||
title: t('Liquidity price range'),
|
||||
content: (
|
||||
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
|
||||
<>
|
||||
<p className="text-xs mb-4">
|
||||
{`For liquidity orders to count towards a commitment, they must be
|
||||
within the liquidity monitoring bounds.`}
|
||||
</p>
|
||||
<p className="text-xs mb-4">
|
||||
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
|
||||
price.`}
|
||||
</p>
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={{
|
||||
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
|
||||
lowestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.minus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
highestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.plus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
}}
|
||||
></MarketInfoTable>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel noBorder={false} market={market}>
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={
|
||||
market.tradableInstrument.instrument.product.dataSourceSpecBinding
|
||||
}
|
||||
>
|
||||
<Link
|
||||
className="text-xs hover:underline"
|
||||
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData.id}`}
|
||||
@@ -110,7 +236,7 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
>
|
||||
{t('View termination oracle specification')}
|
||||
</Link>
|
||||
</OracleInfoPanel>
|
||||
</MarketInfoTable>
|
||||
),
|
||||
},
|
||||
];
|
||||
@@ -118,7 +244,7 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
return (
|
||||
<>
|
||||
{panels.map((p) => (
|
||||
<div key={p.title} className="mb-3">
|
||||
<div className="mb-3">
|
||||
<h2 className="font-alpha calt text-xl">{p.title}</h2>
|
||||
{p.content}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { StatusMessage } from '../status-message';
|
||||
|
||||
interface RenderFetchedProps {
|
||||
@@ -8,7 +7,6 @@ interface RenderFetchedProps {
|
||||
loading: boolean | undefined;
|
||||
className?: string;
|
||||
errorMessage?: string;
|
||||
refetch?: () => void;
|
||||
}
|
||||
|
||||
export const RenderFetched = ({
|
||||
@@ -17,7 +15,6 @@ export const RenderFetched = ({
|
||||
children,
|
||||
className,
|
||||
errorMessage = t('Error retrieving data'),
|
||||
refetch,
|
||||
}: RenderFetchedProps) => {
|
||||
if (loading) {
|
||||
return (
|
||||
@@ -26,20 +23,7 @@ export const RenderFetched = ({
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<>
|
||||
<StatusMessage className={className}>{errorMessage}</StatusMessage>
|
||||
{refetch && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
refetch();
|
||||
}}
|
||||
>
|
||||
{t('Try again')}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
return <StatusMessage className={className}>{errorMessage}</StatusMessage>;
|
||||
}
|
||||
|
||||
return children;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||
import compact from 'lodash/compact';
|
||||
import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
|
||||
import { marketInfoWithDataProvider } from '@vegaprotocol/market-info';
|
||||
import { marketInfoProvider } from '@vegaprotocol/market-info';
|
||||
import { PageTitle } from '../../components/page-helpers/page-title';
|
||||
|
||||
export const MarketPage = () => {
|
||||
@@ -17,7 +17,7 @@ export const MarketPage = () => {
|
||||
const { marketId } = useParams<{ marketId: string }>();
|
||||
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: marketInfoWithDataProvider,
|
||||
dataProvider: marketInfoProvider,
|
||||
skipUpdates: true,
|
||||
variables: {
|
||||
marketId: marketId || '',
|
||||
|
||||
@@ -22,7 +22,6 @@ const Tx = () => {
|
||||
|
||||
const {
|
||||
state: { data, loading, error },
|
||||
refetch,
|
||||
} = useFetch<BlockExplorerTransaction>(
|
||||
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(hash)}`
|
||||
);
|
||||
@@ -57,7 +56,6 @@ const Tx = () => {
|
||||
error={error}
|
||||
loading={loading}
|
||||
errorMessage={errorMessage}
|
||||
refetch={refetch}
|
||||
>
|
||||
<TxDetails
|
||||
className="mb-28"
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"tranche_id": 54,
|
||||
"tranche_start": "2023-04-06T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-06T00:00:00.000Z",
|
||||
"total_added": "1584",
|
||||
"total_added": "1050",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1584",
|
||||
"locked_amount": "1050",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "111",
|
||||
@@ -26,26 +26,6 @@
|
||||
"amount": "33",
|
||||
"user": "0x0bBf7580e036eA5D69ABe679CC90117EeC2e3dc1",
|
||||
"tx": "0x591046ca7581e17fc9b6a99bca457d7abe411c8ef8445259a0954128b71b93fa"
|
||||
},
|
||||
{
|
||||
"amount": "177",
|
||||
"user": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
|
||||
"tx": "0x67855754e5b66b548c11d1c5377c8b7786d107d6064902318ba11dd6eb33b8d0"
|
||||
},
|
||||
{
|
||||
"amount": "111",
|
||||
"user": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
|
||||
"tx": "0x99aeaedef27b5fb693485f4e21d434e343b30fa100945a4ff65386de8801c87e"
|
||||
},
|
||||
{
|
||||
"amount": "114",
|
||||
"user": "0x8D416A61bCccf4E6aF5598302BC4e41f97401652",
|
||||
"tx": "0x09d7342bca4e0fdc9f5a40e18e402b0328991d0df5da17b834c67b149e270808"
|
||||
},
|
||||
{
|
||||
"amount": "132",
|
||||
"user": "0x9E53F72210479BF46aE7ABF77c48B0d611b3c3dB",
|
||||
"tx": "0xcb0f255003872ac506798efa97744868e11ceab2f2f03d96da605d8674f783f6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
@@ -109,66 +89,6 @@
|
||||
"total_tokens": "33",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "33"
|
||||
},
|
||||
{
|
||||
"address": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "177",
|
||||
"user": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
|
||||
"tranche_id": 54,
|
||||
"tx": "0x67855754e5b66b548c11d1c5377c8b7786d107d6064902318ba11dd6eb33b8d0"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "177",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "177"
|
||||
},
|
||||
{
|
||||
"address": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "111",
|
||||
"user": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
|
||||
"tranche_id": 54,
|
||||
"tx": "0x99aeaedef27b5fb693485f4e21d434e343b30fa100945a4ff65386de8801c87e"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "111",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "111"
|
||||
},
|
||||
{
|
||||
"address": "0x8D416A61bCccf4E6aF5598302BC4e41f97401652",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "114",
|
||||
"user": "0x8D416A61bCccf4E6aF5598302BC4e41f97401652",
|
||||
"tranche_id": 54,
|
||||
"tx": "0x09d7342bca4e0fdc9f5a40e18e402b0328991d0df5da17b834c67b149e270808"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "114",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "114"
|
||||
},
|
||||
{
|
||||
"address": "0x9E53F72210479BF46aE7ABF77c48B0d611b3c3dB",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "132",
|
||||
"user": "0x9E53F72210479BF46aE7ABF77c48B0d611b3c3dB",
|
||||
"tranche_id": 54,
|
||||
"tx": "0xcb0f255003872ac506798efa97744868e11ceab2f2f03d96da605d8674f783f6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "132",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "132"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -277,7 +197,7 @@
|
||||
"tranche_end": "2023-04-06T00:00:00.000Z",
|
||||
"total_added": "14099",
|
||||
"total_removed": "22.78816420236",
|
||||
"locked_amount": "9775.8699107676210698",
|
||||
"locked_amount": "10229.9446714456392499",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "30",
|
||||
@@ -2970,7 +2890,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "86666.297",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "62802.0961944541744214653",
|
||||
"locked_amount": "63039.1561083784903416105",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "86666.297",
|
||||
@@ -3036,7 +2956,7 @@
|
||||
"tranche_end": "2023-06-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1064.48587581400075",
|
||||
"locked_amount": "1078.200040700040825",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
@@ -3157,7 +3077,7 @@
|
||||
"tranche_end": "2023-09-01T00:00:00.000Z",
|
||||
"total_added": "17500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "16120.4076401469395",
|
||||
"locked_amount": "16215.3633252818025",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "12500",
|
||||
@@ -3424,7 +3344,7 @@
|
||||
"tranche_end": "2023-08-01T00:00:00.000Z",
|
||||
"total_added": "37500",
|
||||
"total_removed": "3992.79801615",
|
||||
"locked_amount": "28693.62674570288625",
|
||||
"locked_amount": "28900.47575199508875",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -3667,7 +3587,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "62744.797183739481485052",
|
||||
"locked_amount": "62981.64081032036146416",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@@ -3733,7 +3653,7 @@
|
||||
"tranche_end": "2023-09-03T00:00:00.000Z",
|
||||
"total_added": "62600",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "29412.49367706747522",
|
||||
"locked_amount": "29583.72460679858138",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10000",
|
||||
@@ -3926,7 +3846,7 @@
|
||||
"tranche_end": "2023-09-17T00:00:00.000Z",
|
||||
"total_added": "5000",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2541.021530948757",
|
||||
"locked_amount": "2554.6981227803145",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "5000",
|
||||
@@ -4137,7 +4057,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "97499.58",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "4769.0027179179875744514",
|
||||
"locked_amount": "5001.324252612036335169",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "97499.58",
|
||||
@@ -4170,7 +4090,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "135173.4239508",
|
||||
"total_removed": "98230.390980249184455396",
|
||||
"locked_amount": "6518.4033814222176646361931672",
|
||||
"locked_amount": "6835.94681070926191948628655",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "135173.4239508",
|
||||
@@ -4216,7 +4136,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "32499.86",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2006.2370871562641268176",
|
||||
"locked_amount": "2103.9707448237409406114",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "32499.86",
|
||||
@@ -4249,7 +4169,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "10833.29",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "653.010703805487814995",
|
||||
"locked_amount": "684.8220609912854297203",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10833.29",
|
||||
@@ -4282,7 +4202,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "22749.93",
|
||||
"total_removed": "4720.860935375",
|
||||
"locked_amount": "2441.0998581315436582191",
|
||||
"locked_amount": "2560.0178162303665144245",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "6500",
|
||||
@@ -4434,7 +4354,7 @@
|
||||
"tranche_end": "2023-05-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "5529.83377455",
|
||||
"locked_amount": "5779.71195902394075",
|
||||
"locked_amount": "5903.82136279926225",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -4797,7 +4717,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "928642.9598472029154",
|
||||
"locked_amount": "417188.6231006399309246128",
|
||||
"locked_amount": "422494.9448277827874971314",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@@ -6108,7 +6028,7 @@
|
||||
"tranche_start": "2021-09-05T00:00:00.000Z",
|
||||
"tranche_end": "2022-09-30T00:00:00.000Z",
|
||||
"total_added": "60916.66666633337",
|
||||
"total_removed": "39354.939349357864974364",
|
||||
"total_removed": "39088.634764730198755268",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -6208,11 +6128,6 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "266.304584627666219096",
|
||||
"user": "0x832cfD8fD4a1791b5eF5BD18a677beb7731Aa18E",
|
||||
"tx": "0x98f1e1e3dd3a0ef2fe25ccb9e7222b29c1a5136b52255a1b492b330adbfc6b66"
|
||||
},
|
||||
{
|
||||
"amount": "3395.631843574",
|
||||
"user": "0xa0fF757077B5D796259582b2b9Db99c906277007",
|
||||
@@ -6727,12 +6642,6 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "266.304584627666219096",
|
||||
"user": "0x832cfD8fD4a1791b5eF5BD18a677beb7731Aa18E",
|
||||
"tranche_id": 13,
|
||||
"tx": "0x98f1e1e3dd3a0ef2fe25ccb9e7222b29c1a5136b52255a1b492b330adbfc6b66"
|
||||
},
|
||||
{
|
||||
"amount": "279.862130034666196311",
|
||||
"user": "0x832cfD8fD4a1791b5eF5BD18a677beb7731Aa18E",
|
||||
@@ -6777,8 +6686,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "1983.33333333333",
|
||||
"withdrawn_tokens": "1983.33333333333",
|
||||
"remaining_tokens": "0"
|
||||
"withdrawn_tokens": "1717.028748705663780904",
|
||||
"remaining_tokens": "266.304584627666219096"
|
||||
},
|
||||
{
|
||||
"address": "0x883aD562D0a83569dA00DdF88C96C348519c0030",
|
||||
@@ -10240,7 +10149,7 @@
|
||||
"tranche_start": "2021-09-03T00:00:00.000Z",
|
||||
"tranche_end": "2022-09-03T00:00:00.000Z",
|
||||
"total_added": "56798.000000000000000003",
|
||||
"total_removed": "48097.21518131551",
|
||||
"total_removed": "44482.21518131551",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -20765,21 +20674,6 @@
|
||||
"user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
|
||||
"tx": "0xc1d1e0a03a5ace0a8c61f58c81a407867a2d3195d2249df11d2eb630949d4ea2"
|
||||
},
|
||||
{
|
||||
"amount": "1925",
|
||||
"user": "0xA260d0f8070b2A85B3C00ADb1f0046f20ca85AAa",
|
||||
"tx": "0xd2190b942a3b15e97692b9007c71b2cf3b887aaff782a73b23b9dfa7369b9c84"
|
||||
},
|
||||
{
|
||||
"amount": "1690",
|
||||
"user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
"tx": "0x3e3247a9cf87d30ca8436606fe8f0cc01cba11fbd798a5aff4f8a7bbf3247af5"
|
||||
},
|
||||
{
|
||||
"amount": "0",
|
||||
"user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
"tx": "0x11c2f143f1fccec8d746a0760ada1f4abf9fbce7ee76835a8da17bcfc4d2c7f5"
|
||||
},
|
||||
{
|
||||
"amount": "130",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
@@ -23558,17 +23452,10 @@
|
||||
"tx": "0x62b105e7c569b195b3a3625869c62e4cd307fbda5b0c1e5931a857e376ef6c09"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "1925",
|
||||
"user": "0xA260d0f8070b2A85B3C00ADb1f0046f20ca85AAa",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xd2190b942a3b15e97692b9007c71b2cf3b887aaff782a73b23b9dfa7369b9c84"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "1925",
|
||||
"withdrawn_tokens": "1925",
|
||||
"remaining_tokens": "0"
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "1925"
|
||||
},
|
||||
{
|
||||
"address": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
|
||||
@@ -32399,23 +32286,10 @@
|
||||
"tx": "0x248d34bdf3224997d3f0e2cd55f75e1b13937591a64cff99abf513bada6da087"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "1690",
|
||||
"user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x3e3247a9cf87d30ca8436606fe8f0cc01cba11fbd798a5aff4f8a7bbf3247af5"
|
||||
},
|
||||
{
|
||||
"amount": "0",
|
||||
"user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x11c2f143f1fccec8d746a0760ada1f4abf9fbce7ee76835a8da17bcfc4d2c7f5"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "1690",
|
||||
"withdrawn_tokens": "1690",
|
||||
"remaining_tokens": "0"
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "1690"
|
||||
},
|
||||
{
|
||||
"address": "0xfeDf4b4406B3126744047be05A013570b09DC0cC",
|
||||
@@ -38296,7 +38170,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "700133.348465855088393",
|
||||
"locked_amount": "665574.988783539092352126032",
|
||||
"locked_amount": "673728.95781315364925259848",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@@ -39678,7 +39552,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15870102.715470999700000001",
|
||||
"total_removed": "803126.94523812819680452",
|
||||
"locked_amount": "7659773.76186853928704096963886072002784536",
|
||||
"locked_amount": "7688687.2125127014185007375133475697864288",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@@ -45805,7 +45679,7 @@
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "5735873.982235800798313006",
|
||||
"locked_amount": "1350009.002549479199448998084455602",
|
||||
"locked_amount": "1376701.715570043445104453407840739",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@@ -53149,7 +53023,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "5778205.3912159303",
|
||||
"total_removed": "3362269.76579626473241024",
|
||||
"locked_amount": "216493.318153589487100687138655917",
|
||||
"locked_amount": "227039.77050419898661023179041578",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "552496.6455",
|
||||
@@ -55254,8 +55128,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "37672.6965943910685",
|
||||
"locked_amount": "105464.16156158729024788626382548",
|
||||
"total_removed": "36243.9702435650685",
|
||||
"locked_amount": "106756.20456440379208495091730084",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
@@ -61874,46 +61748,6 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "154.812094114",
|
||||
"user": "0x27e2254A2A8c9c9D1321E5Fe64cAD88e7A4f0ba7",
|
||||
"tx": "0x15c4a1943b6b69bc70687ce0530764aed11f2f0ca54f0095e557fc543ba771c0"
|
||||
},
|
||||
{
|
||||
"amount": "154.817421358",
|
||||
"user": "0x33f011bfc2Aa2231632E6ACa93751287Ff5f0A02",
|
||||
"tx": "0x1ae3216da90cba90edb671024763f142f168b665995cd7522668e6dae7fdb74b"
|
||||
},
|
||||
{
|
||||
"amount": "154.817497462",
|
||||
"user": "0xEC207aED6bABDAd28792aB260B7e09C5E586C068",
|
||||
"tx": "0xb2848359058b782cc1125b7cf6ac590146b3b1fa672431df6e5011c69eedb08a"
|
||||
},
|
||||
{
|
||||
"amount": "154.826858192",
|
||||
"user": "0x1bE37051e42C96b33ee3f87ba8c5b25C96A67912",
|
||||
"tx": "0x9ed5223b260f1854dbfd3e4f0dbdf22f0e8c0542a94f4fd8320f2da70210d5d3"
|
||||
},
|
||||
{
|
||||
"amount": "154.826934296",
|
||||
"user": "0x560cB4F0e1643f884a54f07589Fc5AC44bcA14d2",
|
||||
"tx": "0x2ef496b522943ec63787c26b66bff0a75a20c3ff939abffaddf8fb7e512e56b0"
|
||||
},
|
||||
{
|
||||
"amount": "309.708054284",
|
||||
"user": "0xAc5bd5a3890B12B0da7cF1Ad846F6b8b260B60CC",
|
||||
"tx": "0x0217cf9cf1bc6f7cb36d51c5531e8f857b0c4982debfcdcda652f116fe01f80b"
|
||||
},
|
||||
{
|
||||
"amount": "309.878526128",
|
||||
"user": "0x1010101036EA85caAC4BB82D953f26cAf14a9Ebc",
|
||||
"tx": "0xd6774c065c0e886d82445f16909e9dec106e3c6714cad682ed4102470403aace"
|
||||
},
|
||||
{
|
||||
"amount": "35.038964992",
|
||||
"user": "0x046717d8914087EB6890dFdF78ebD0f1343F15F6",
|
||||
"tx": "0xa90a66881bf15cc988e22cebc0b0fa29e6421ddda8480c13b32dc3ca0a784ea1"
|
||||
},
|
||||
{
|
||||
"amount": "129.867928716",
|
||||
"user": "0x09996E1a67c371400bD5f52DF841f77B1741eB9d",
|
||||
@@ -67211,17 +67045,10 @@
|
||||
"tx": "0x5f6fbdcd43bd83bf0d7a4beb3a2c7d4aa493ef5e4c0c6eeb6a4eb6a0ae4df05e"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "309.708054284",
|
||||
"user": "0xAc5bd5a3890B12B0da7cF1Ad846F6b8b260B60CC",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x0217cf9cf1bc6f7cb36d51c5531e8f857b0c4982debfcdcda652f116fe01f80b"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "400",
|
||||
"withdrawn_tokens": "309.708054284",
|
||||
"remaining_tokens": "90.291945716"
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "400"
|
||||
},
|
||||
{
|
||||
"address": "0x71bA18Cb18d7Cd338CF6E911882E717A8dEf8041",
|
||||
@@ -70209,17 +70036,10 @@
|
||||
"tx": "0xc7dd4c2b995cc486fcd8b7892cd79f8fb393ada004dc68cf66ec82d99b35763c"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "309.878526128",
|
||||
"user": "0x1010101036EA85caAC4BB82D953f26cAf14a9Ebc",
|
||||
"tranche_id": 5,
|
||||
"tx": "0xd6774c065c0e886d82445f16909e9dec106e3c6714cad682ed4102470403aace"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "400",
|
||||
"withdrawn_tokens": "309.878526128",
|
||||
"remaining_tokens": "90.121473872"
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "400"
|
||||
},
|
||||
{
|
||||
"address": "0x64D50eceEC4D3428d4Ea43365A3335Cb7CBCA3fD",
|
||||
@@ -77160,12 +76980,6 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "35.038964992",
|
||||
"user": "0x046717d8914087EB6890dFdF78ebD0f1343F15F6",
|
||||
"tranche_id": 5,
|
||||
"tx": "0xa90a66881bf15cc988e22cebc0b0fa29e6421ddda8480c13b32dc3ca0a784ea1"
|
||||
},
|
||||
{
|
||||
"amount": "84.425145866",
|
||||
"user": "0x046717d8914087EB6890dFdF78ebD0f1343F15F6",
|
||||
@@ -77180,8 +76994,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "155.282109334",
|
||||
"remaining_tokens": "44.717890666"
|
||||
"withdrawn_tokens": "120.243144342",
|
||||
"remaining_tokens": "79.756855658"
|
||||
},
|
||||
{
|
||||
"address": "0x8847EBaaf29A18396e49191602f8d8D141b98aa7",
|
||||
@@ -78814,17 +78628,10 @@
|
||||
"tx": "0xd23813c30e93f3867eaa257b7aef7052a050b1ee1c1a90102a3f40c5d989fe82"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "154.812094114",
|
||||
"user": "0x27e2254A2A8c9c9D1321E5Fe64cAD88e7A4f0ba7",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x15c4a1943b6b69bc70687ce0530764aed11f2f0ca54f0095e557fc543ba771c0"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "154.812094114",
|
||||
"remaining_tokens": "45.187905886"
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "200"
|
||||
},
|
||||
{
|
||||
"address": "0x1bE37051e42C96b33ee3f87ba8c5b25C96A67912",
|
||||
@@ -78836,17 +78643,10 @@
|
||||
"tx": "0xd23813c30e93f3867eaa257b7aef7052a050b1ee1c1a90102a3f40c5d989fe82"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "154.826858192",
|
||||
"user": "0x1bE37051e42C96b33ee3f87ba8c5b25C96A67912",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x9ed5223b260f1854dbfd3e4f0dbdf22f0e8c0542a94f4fd8320f2da70210d5d3"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "154.826858192",
|
||||
"remaining_tokens": "45.173141808"
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "200"
|
||||
},
|
||||
{
|
||||
"address": "0xB4a0DfC4F2Ee7b32ba8947882A7b25877eE1C829",
|
||||
@@ -82238,17 +82038,10 @@
|
||||
"tx": "0xc8541da6a57f410b6faba47a5e5184bae700193b7bd042914fffc562114d92f5"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "154.826934296",
|
||||
"user": "0x560cB4F0e1643f884a54f07589Fc5AC44bcA14d2",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x2ef496b522943ec63787c26b66bff0a75a20c3ff939abffaddf8fb7e512e56b0"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "154.826934296",
|
||||
"remaining_tokens": "45.173065704"
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "200"
|
||||
},
|
||||
{
|
||||
"address": "0xb2Fb11d69DC52B76fa1Bb06Af05d4fF016cA2836",
|
||||
@@ -82282,17 +82075,10 @@
|
||||
"tx": "0xc8541da6a57f410b6faba47a5e5184bae700193b7bd042914fffc562114d92f5"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "154.817421358",
|
||||
"user": "0x33f011bfc2Aa2231632E6ACa93751287Ff5f0A02",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x1ae3216da90cba90edb671024763f142f168b665995cd7522668e6dae7fdb74b"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "154.817421358",
|
||||
"remaining_tokens": "45.182578642"
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "200"
|
||||
},
|
||||
{
|
||||
"address": "0x43242cB46516471Dd1e45bB749347aa6ab914330",
|
||||
@@ -82319,17 +82105,10 @@
|
||||
"tx": "0xc8541da6a57f410b6faba47a5e5184bae700193b7bd042914fffc562114d92f5"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "154.817497462",
|
||||
"user": "0xEC207aED6bABDAd28792aB260B7e09C5E586C068",
|
||||
"tranche_id": 5,
|
||||
"tx": "0xb2848359058b782cc1125b7cf6ac590146b3b1fa672431df6e5011c69eedb08a"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "154.817497462",
|
||||
"remaining_tokens": "45.182502538"
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "200"
|
||||
},
|
||||
{
|
||||
"address": "0x08D639bF499BbFd76D050A597A2E2FAE1A7bd6E4",
|
||||
|
||||
@@ -7,10 +7,6 @@ const externalLink = 'external-link';
|
||||
const accordionContent = 'accordion-content';
|
||||
|
||||
describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
});
|
||||
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
|
||||
@@ -25,8 +25,7 @@ export const DepositsContainer = () => {
|
||||
<div className="h-full relative">
|
||||
<DepositsTable
|
||||
rowData={data || []}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
noRowsOverlayComponent={() => null}
|
||||
ref={gridRef}
|
||||
{...bottomPlaceholderProps}
|
||||
/>
|
||||
|
||||
@@ -24,8 +24,7 @@ export const WithdrawalsContainer = () => {
|
||||
<WithdrawalsTable
|
||||
data-testid="withdrawals-history"
|
||||
rowData={data}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
noRowsOverlayComponent={() => null}
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<AsyncRenderer
|
||||
|
||||
@@ -1,30 +1,20 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { NodeHealth, NodeUrl, HealthIndicator } from './footer';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
jest.mock('@vegaprotocol/environment', () => ({
|
||||
...jest.requireActual('@vegaprotocol/environment'),
|
||||
useEnvironment: jest
|
||||
.fn()
|
||||
.mockImplementation(() => ({ VEGA_URL: 'https://vega-url.wtf' })),
|
||||
}));
|
||||
|
||||
const mockSetNodeSwitcher = jest.fn();
|
||||
jest.mock('../../stores', () => ({
|
||||
...jest.requireActual('../../stores'),
|
||||
useGlobalStore: () => mockSetNodeSwitcher,
|
||||
}));
|
||||
|
||||
describe('NodeHealth', () => {
|
||||
it('controls the node switcher dialog', async () => {
|
||||
render(<NodeHealth />, { wrapper: MockedProvider });
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
const mockOnClick = jest.fn();
|
||||
render(
|
||||
<NodeHealth
|
||||
onClick={mockOnClick}
|
||||
url={'https://api.n99.somenetwork.vega.xyz'}
|
||||
blockHeight={100}
|
||||
blockDiff={0}
|
||||
/>
|
||||
);
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
expect(mockSetNodeSwitcher).toHaveBeenCalled();
|
||||
expect(mockOnClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,22 +31,14 @@ describe('NodeUrl', () => {
|
||||
|
||||
describe('HealthIndicator', () => {
|
||||
const cases = [
|
||||
{
|
||||
intent: Intent.Success,
|
||||
text: 'Operational',
|
||||
classname: 'bg-vega-green-550',
|
||||
},
|
||||
{
|
||||
intent: Intent.Warning,
|
||||
text: '5 Blocks behind',
|
||||
classname: 'bg-warning',
|
||||
},
|
||||
{ intent: Intent.Danger, text: 'Non operational', classname: 'bg-danger' },
|
||||
{ diff: 0, classname: 'bg-vega-green-550', text: 'Operational' },
|
||||
{ diff: 5, classname: 'bg-warning', text: '5 Blocks behind' },
|
||||
{ diff: null, classname: 'bg-danger', text: 'Non operational' },
|
||||
];
|
||||
it.each(cases)(
|
||||
'renders correct text and indicator color for $diff block difference',
|
||||
(elem) => {
|
||||
render(<HealthIndicator text={elem.text} intent={elem.intent} />);
|
||||
render(<HealthIndicator blockDiff={elem.diff} />);
|
||||
expect(screen.getByTestId('indicator')).toHaveClass(elem.classname);
|
||||
expect(screen.getByText(elem.text)).toBeInTheDocument();
|
||||
}
|
||||
|
||||
@@ -1,45 +1,60 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useEnvironment, useNodeHealth } from '@vegaprotocol/environment';
|
||||
import { useNavigatorOnline } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { Indicator } from '@vegaprotocol/ui-toolkit';
|
||||
import { Indicator, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<footer className="px-4 py-1 text-xs border-t border-default text-vega-light-300 dark:text-vega-dark-300 lg:fixed bottom-0 left-0 border-r bg-white dark:bg-black">
|
||||
{/* Pull left to align with top nav, due to button padding */}
|
||||
<div className="-ml-2">
|
||||
<NodeHealth />
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export const NodeHealth = () => {
|
||||
const { VEGA_URL } = useEnvironment();
|
||||
const setNodeSwitcher = useGlobalStore(
|
||||
(store) => (open: boolean) => store.update({ nodeSwitcherDialog: open })
|
||||
);
|
||||
const { datanodeBlockHeight, text, intent } = useNodeHealth();
|
||||
const onClick = useCallback(() => {
|
||||
setNodeSwitcher(true);
|
||||
}, [setNodeSwitcher]);
|
||||
return VEGA_URL ? (
|
||||
const { blockDiff, datanodeBlockHeight } = useNodeHealth();
|
||||
|
||||
return (
|
||||
<footer className="px-4 py-1 text-xs border-t border-default text-vega-light-300 dark:text-vega-dark-300 lg:fixed bottom-0 left-0 border-r bg-white dark:bg-black">
|
||||
{/* Pull left to align with top nav, due to button padding */}
|
||||
<div className="-ml-2">
|
||||
{VEGA_URL && (
|
||||
<NodeHealth
|
||||
url={VEGA_URL}
|
||||
blockHeight={datanodeBlockHeight}
|
||||
blockDiff={blockDiff}
|
||||
onClick={() => setNodeSwitcher(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
interface NodeHealthProps {
|
||||
url: string;
|
||||
blockHeight: number | undefined;
|
||||
blockDiff: number | null;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const NodeHealth = ({
|
||||
url,
|
||||
blockHeight,
|
||||
blockDiff,
|
||||
onClick,
|
||||
}: NodeHealthProps) => {
|
||||
return (
|
||||
<FooterButton onClick={onClick} data-testid="node-health">
|
||||
<FooterButtonPart>
|
||||
<HealthIndicator text={text} intent={intent} />
|
||||
<HealthIndicator blockDiff={blockDiff} />
|
||||
</FooterButtonPart>
|
||||
<FooterButtonPart>
|
||||
<NodeUrl url={VEGA_URL} />
|
||||
<NodeUrl url={url} />
|
||||
</FooterButtonPart>
|
||||
<FooterButtonPart>
|
||||
<span title={t('Block height')}>{datanodeBlockHeight}</span>
|
||||
<span title={t('Block height')}>{blockHeight}</span>
|
||||
</FooterButtonPart>
|
||||
</FooterButton>
|
||||
) : null;
|
||||
);
|
||||
};
|
||||
|
||||
interface NodeUrlProps {
|
||||
@@ -54,11 +69,31 @@ export const NodeUrl = ({ url }: NodeUrlProps) => {
|
||||
};
|
||||
|
||||
interface HealthIndicatorProps {
|
||||
text: string;
|
||||
intent: Intent;
|
||||
blockDiff: number | null;
|
||||
}
|
||||
|
||||
export const HealthIndicator = ({ text, intent }: HealthIndicatorProps) => {
|
||||
// How many blocks behind the most advanced block that is
|
||||
// deemed acceptable for "Good" status
|
||||
const BLOCK_THRESHOLD = 3;
|
||||
|
||||
export const HealthIndicator = ({ blockDiff }: HealthIndicatorProps) => {
|
||||
const online = useNavigatorOnline();
|
||||
|
||||
let intent = Intent.Success;
|
||||
let text = 'Operational';
|
||||
|
||||
if (!online) {
|
||||
text = t('Offline');
|
||||
intent = Intent.Danger;
|
||||
} else if (blockDiff === null) {
|
||||
// Block height query failed and null was returned
|
||||
text = t('Non operational');
|
||||
intent = Intent.Danger;
|
||||
} else if (blockDiff >= BLOCK_THRESHOLD) {
|
||||
text = t(`${blockDiff} Blocks behind`);
|
||||
intent = Intent.Warning;
|
||||
}
|
||||
|
||||
return (
|
||||
<span title={t('Node health')}>
|
||||
<Indicator variant={intent} />
|
||||
|
||||
@@ -15,29 +15,51 @@ jest.mock('@vegaprotocol/react-helpers', () => ({
|
||||
}));
|
||||
|
||||
describe('AccountManager', () => {
|
||||
describe('when rerender', () => {
|
||||
beforeEach(() => {
|
||||
mockedUseDataProvider
|
||||
.mockImplementationOnce((args) => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
})
|
||||
.mockImplementationOnce((args) => {
|
||||
return {
|
||||
data: [
|
||||
{ asset: { id: 'a1' }, party: { id: 't1' } },
|
||||
{ asset: { id: 'a2' }, party: { id: 't2' } },
|
||||
],
|
||||
};
|
||||
});
|
||||
});
|
||||
beforeEach(() => {
|
||||
mockedUseDataProvider
|
||||
.mockImplementationOnce((args) => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
})
|
||||
.mockImplementationOnce((args) => {
|
||||
return {
|
||||
data: [
|
||||
{ asset: { id: 'a1' }, party: { id: 't1' } },
|
||||
{ asset: { id: 'a2' }, party: { id: 't2' } },
|
||||
],
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
it('change partyId should reload data provider', async () => {
|
||||
const { rerender } = render(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[0][0].variables.partyId
|
||||
).toEqual('partyOne');
|
||||
await act(() => {
|
||||
rerender(
|
||||
<AccountManager
|
||||
partyId="partyTwo"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[1][0].variables.partyId
|
||||
).toEqual('partyTwo');
|
||||
});
|
||||
|
||||
it('change partyId should reload data provider', async () => {
|
||||
it('update method should return proper result', async () => {
|
||||
let rerenderer: (ui: React.ReactElement) => void;
|
||||
await act(() => {
|
||||
const { rerender } = render(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
@@ -45,67 +67,13 @@ describe('AccountManager', () => {
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[0][0].variables
|
||||
.partyId
|
||||
).toEqual('partyOne');
|
||||
await act(() => {
|
||||
rerender(
|
||||
<AccountManager
|
||||
partyId="partyTwo"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(
|
||||
(helpers.useDataProvider as jest.Mock).mock.calls[1][0].variables
|
||||
.partyId
|
||||
).toEqual('partyTwo');
|
||||
rerenderer = rerender;
|
||||
});
|
||||
|
||||
it('update method should return proper result', async () => {
|
||||
let rerenderer: (ui: React.ReactElement) => void;
|
||||
await act(() => {
|
||||
const { rerender } = render(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
rerenderer = rerender;
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('No accounts')).toBeInTheDocument();
|
||||
});
|
||||
await act(() => {
|
||||
rerenderer(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
isReadOnly={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const container = document.querySelector('.ag-center-cols-container');
|
||||
await waitFor(() => {
|
||||
expect(container).toBeInTheDocument();
|
||||
});
|
||||
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('splash loading should be displayed', async () => {
|
||||
mockedUseDataProvider.mockImplementation((args) => {
|
||||
return {
|
||||
loading: true,
|
||||
data: null,
|
||||
};
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('No accounts')).toBeInTheDocument();
|
||||
});
|
||||
await act(() => {
|
||||
render(
|
||||
rerenderer(
|
||||
<AccountManager
|
||||
partyId="partyOne"
|
||||
onClickAsset={jest.fn}
|
||||
@@ -113,15 +81,11 @@ describe('AccountManager', () => {
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const container = document.querySelector('.ag-center-cols-container');
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText(
|
||||
(content, element) =>
|
||||
Boolean(
|
||||
element?.className.endsWith('flex items-center justify-center')
|
||||
) && content.startsWith('Loading')
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
expect(container).toBeInTheDocument();
|
||||
});
|
||||
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,8 +60,7 @@ export const AccountManager = ({
|
||||
onClickDeposit={onClickDeposit}
|
||||
onClickWithdraw={onClickWithdraw}
|
||||
isReadOnly={isReadOnly}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
noRowsOverlayComponent={() => null}
|
||||
pinnedAsset={pinnedAsset}
|
||||
getRowHeight={getRowHeight}
|
||||
{...bottomPlaceholderProps}
|
||||
|
||||
@@ -59,19 +59,13 @@ export function createClient({
|
||||
const timestamp = r?.headers.get('x-block-timestamp');
|
||||
if (blockHeight && timestamp) {
|
||||
const state = useHeaderStore.getState();
|
||||
const urlState = state[r.url];
|
||||
if (
|
||||
!urlState?.blockHeight ||
|
||||
urlState.blockHeight !== blockHeight
|
||||
) {
|
||||
useHeaderStore.setState({
|
||||
...state,
|
||||
[r.url]: {
|
||||
blockHeight: Number(blockHeight),
|
||||
timestamp: new Date(Number(timestamp.slice(0, -6))),
|
||||
},
|
||||
});
|
||||
}
|
||||
useHeaderStore.setState({
|
||||
...state,
|
||||
[r.url]: {
|
||||
blockHeight: Number(blockHeight),
|
||||
timestamp: new Date(Number(timestamp.slice(0, -6))),
|
||||
},
|
||||
});
|
||||
}
|
||||
return response;
|
||||
});
|
||||
|
||||
@@ -5,7 +5,6 @@ import { MockedProvider } from '@apollo/react-testing';
|
||||
import type { StatisticsQuery } from '../utils/__generated__/Node';
|
||||
import { StatisticsDocument } from '../utils/__generated__/Node';
|
||||
import { useHeaderStore } from '@vegaprotocol/apollo-client';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
const vegaUrl = 'https://foo.bar.com';
|
||||
|
||||
@@ -56,24 +55,9 @@ function setup(
|
||||
|
||||
describe('useNodeHealth', () => {
|
||||
it.each([
|
||||
{
|
||||
core: 1,
|
||||
node: 1,
|
||||
expectedText: 'Operational',
|
||||
expectedIntent: Intent.Success,
|
||||
},
|
||||
{
|
||||
core: 1,
|
||||
node: 5,
|
||||
expectedText: 'Operational',
|
||||
expectedIntent: Intent.Success,
|
||||
},
|
||||
{
|
||||
core: 10,
|
||||
node: 5,
|
||||
expectedText: '5 Blocks behind',
|
||||
expectedIntent: Intent.Warning,
|
||||
},
|
||||
{ core: 1, node: 1, expected: 0 },
|
||||
{ core: 1, node: 5, expected: -4 },
|
||||
{ core: 10, node: 5, expected: 5 },
|
||||
])(
|
||||
'provides difference core block $core and node block $node',
|
||||
async (cases) => {
|
||||
@@ -81,12 +65,12 @@ describe('useNodeHealth', () => {
|
||||
blockHeight: cases.node,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
expect(result.current.text).toEqual('Non operational');
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.blockDiff).toEqual(null);
|
||||
expect(result.current.coreBlockHeight).toEqual(undefined);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(cases.node);
|
||||
await waitFor(() => {
|
||||
expect(result.current.text).toEqual(cases.expectedText);
|
||||
expect(result.current.intent).toEqual(cases.expectedIntent);
|
||||
expect(result.current.blockDiff).toEqual(cases.expected);
|
||||
expect(result.current.coreBlockHeight).toEqual(cases.core);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(cases.node);
|
||||
});
|
||||
}
|
||||
@@ -106,64 +90,25 @@ describe('useNodeHealth', () => {
|
||||
blockHeight: 1,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
expect(result.current.text).toEqual('Non operational');
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.blockDiff).toEqual(null);
|
||||
expect(result.current.coreBlockHeight).toEqual(undefined);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(1);
|
||||
await waitFor(() => {
|
||||
expect(result.current.text).toEqual('Non operational');
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.blockDiff).toEqual(null);
|
||||
expect(result.current.coreBlockHeight).toEqual(undefined);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 0 if no headers are found (waits until stats query resolves)', async () => {
|
||||
const { result } = setup(createStatsMock(1), undefined);
|
||||
expect(result.current.text).toEqual('Non operational');
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.blockDiff).toEqual(null);
|
||||
expect(result.current.coreBlockHeight).toEqual(undefined);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(undefined);
|
||||
await waitFor(() => {
|
||||
expect(result.current.text).toEqual('Operational');
|
||||
expect(result.current.intent).toEqual(Intent.Success);
|
||||
expect(result.current.blockDiff).toEqual(0);
|
||||
expect(result.current.coreBlockHeight).toEqual(1);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
it('Warning latency', async () => {
|
||||
const now = 1678800900087;
|
||||
const headerTimestamp = now - 4000;
|
||||
const dateNow = new Date(now);
|
||||
const dateHeaderTimestamp = new Date(headerTimestamp);
|
||||
jest.useFakeTimers().setSystemTime(dateNow);
|
||||
|
||||
const { result } = setup(createStatsMock(2), {
|
||||
blockHeight: 2,
|
||||
timestamp: dateHeaderTimestamp,
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(result.current.text).toEqual('Warning delay ( >3 sec): 4.05 sec');
|
||||
expect(result.current.intent).toEqual(Intent.Warning);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('Erroneous latency', async () => {
|
||||
const now = 1678800900087;
|
||||
const headerTimestamp = now - 11000;
|
||||
const dateNow = new Date(now);
|
||||
const dateHeaderTimestamp = new Date(headerTimestamp);
|
||||
jest.useFakeTimers().setSystemTime(dateNow);
|
||||
|
||||
const { result } = setup(createStatsMock(2), {
|
||||
blockHeight: 2,
|
||||
timestamp: dateHeaderTimestamp,
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(result.current.text).toEqual(
|
||||
'Erroneous latency ( >10 sec): 11.05 sec'
|
||||
);
|
||||
expect(result.current.intent).toEqual(Intent.Danger);
|
||||
expect(result.current.datanodeBlockHeight).toEqual(2);
|
||||
});
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,35 +2,30 @@ import { useEffect, useMemo } from 'react';
|
||||
import { useStatisticsQuery } from '../utils/__generated__/Node';
|
||||
import { useHeaderStore } from '@vegaprotocol/apollo-client';
|
||||
import { useEnvironment } from './use-environment';
|
||||
import { useNavigatorOnline } from '@vegaprotocol/react-helpers';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { fromNanoSeconds } from '@vegaprotocol/utils';
|
||||
|
||||
const POLL_INTERVAL = 1000;
|
||||
const BLOCK_THRESHOLD = 3;
|
||||
const ERROR_LATENCY = 10000;
|
||||
const WARNING_LATENCY = 3000;
|
||||
|
||||
export const useNodeHealth = () => {
|
||||
const online = useNavigatorOnline();
|
||||
const url = useEnvironment((store) => store.VEGA_URL);
|
||||
const headerStore = useHeaderStore();
|
||||
const headers = url ? headerStore[url] : undefined;
|
||||
const { data, error, startPolling, stopPolling } = useStatisticsQuery({
|
||||
fetchPolicy: 'no-cache',
|
||||
});
|
||||
const { data, error, loading, startPolling, stopPolling } =
|
||||
useStatisticsQuery({
|
||||
fetchPolicy: 'no-cache',
|
||||
});
|
||||
|
||||
const blockDiff = useMemo(() => {
|
||||
if (!data?.statistics.blockHeight) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!headers?.blockHeight) {
|
||||
if (!headers) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Number(data.statistics.blockHeight) - headers.blockHeight;
|
||||
}, [data?.statistics.blockHeight, headers?.blockHeight]);
|
||||
}, [data, headers]);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
@@ -43,43 +38,17 @@ export const useNodeHealth = () => {
|
||||
}
|
||||
}, [error, startPolling, stopPolling]);
|
||||
|
||||
const blockUpdateMsLatency = headers?.timestamp
|
||||
? Date.now() - headers.timestamp.getTime()
|
||||
: 0;
|
||||
|
||||
const [text, intent] = useMemo(() => {
|
||||
let intent = Intent.Success;
|
||||
let text = 'Operational';
|
||||
|
||||
if (!online) {
|
||||
text = t('Offline');
|
||||
intent = Intent.Danger;
|
||||
} else if (blockDiff === null) {
|
||||
// Block height query failed and null was returned
|
||||
text = t('Non operational');
|
||||
intent = Intent.Danger;
|
||||
} else if (blockUpdateMsLatency > ERROR_LATENCY) {
|
||||
text = t('Erroneous latency ( >%s sec): %s sec', [
|
||||
(ERROR_LATENCY / 1000).toString(),
|
||||
(blockUpdateMsLatency / 1000).toFixed(2),
|
||||
]);
|
||||
intent = Intent.Danger;
|
||||
} else if (blockDiff >= BLOCK_THRESHOLD) {
|
||||
text = t(`%s Blocks behind`, String(blockDiff));
|
||||
intent = Intent.Warning;
|
||||
} else if (blockUpdateMsLatency > WARNING_LATENCY) {
|
||||
text = t('Warning delay ( >%s sec): %s sec', [
|
||||
(WARNING_LATENCY / 1000).toString(),
|
||||
(blockUpdateMsLatency / 1000).toFixed(2),
|
||||
]);
|
||||
intent = Intent.Warning;
|
||||
}
|
||||
return [text, intent];
|
||||
}, [online, blockDiff, blockUpdateMsLatency]);
|
||||
|
||||
return {
|
||||
error,
|
||||
loading,
|
||||
coreBlockHeight: data?.statistics
|
||||
? Number(data.statistics.blockHeight)
|
||||
: undefined,
|
||||
coreVegaTime: data?.statistics
|
||||
? fromNanoSeconds(data?.statistics.vegaTime)
|
||||
: undefined,
|
||||
datanodeBlockHeight: headers?.blockHeight,
|
||||
text,
|
||||
intent,
|
||||
datanodeVegaTime: headers?.timestamp,
|
||||
blockDiff,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,4 +3,3 @@ export * from './info-market';
|
||||
export * from './tooltip-mapping';
|
||||
export * from './__generated__/MarketInfo';
|
||||
export * from './market-info-data-provider';
|
||||
export * from './market-info-panels';
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { removePaginationWrapper, TokenLinks } from '@vegaprotocol/utils';
|
||||
import {
|
||||
totalFeesPercentage,
|
||||
calcCandleVolume,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
formatNumberPercentage,
|
||||
removePaginationWrapper,
|
||||
TokenLinks,
|
||||
getMarketExpiryDateFormatted,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider, useYesterday } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
@@ -10,31 +22,15 @@ import {
|
||||
Link as UILink,
|
||||
Splash,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useMemo } from 'react';
|
||||
import { generatePath, Link } from 'react-router-dom';
|
||||
|
||||
import { MarketInfoTable } from './info-key-value-table';
|
||||
import { marketInfoWithDataAndCandlesProvider } from './market-info-data-provider';
|
||||
|
||||
import type { MarketInfoWithDataAndCandles } from './market-info-data-provider';
|
||||
import { MarketProposalNotification } from '@vegaprotocol/proposals';
|
||||
import {
|
||||
CurrentFeesInfoPanel,
|
||||
InstrumentInfoPanel,
|
||||
InsurancePoolInfoPanel,
|
||||
KeyDetailsInfoPanel,
|
||||
LiquidityInfoPanel,
|
||||
LiquidityMonitoringParametersInfoPanel,
|
||||
LiquidityPriceRangeInfoPanel,
|
||||
MarketPriceInfoPanel,
|
||||
MarketVolumeInfoPanel,
|
||||
MetadataInfoPanel,
|
||||
OracleInfoPanel,
|
||||
PriceMonitoringBoundsInfoPanel,
|
||||
RiskFactorsInfoPanel,
|
||||
RiskModelInfoPanel,
|
||||
RiskParametersInfoPanel,
|
||||
SettlementAssetInfoPanel,
|
||||
} from './market-info-panels';
|
||||
|
||||
export interface InfoProps {
|
||||
market: MarketInfoWithDataAndCandles;
|
||||
@@ -84,6 +80,15 @@ export const MarketInfoContainer = ({
|
||||
export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
const { VEGA_TOKEN_URL, VEGA_EXPLORER_URL } = useEnvironment();
|
||||
const headerClassName = 'uppercase text-lg';
|
||||
const assetSymbol =
|
||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||
const quoteUnit =
|
||||
market?.tradableInstrument.instrument.product?.quoteName || '';
|
||||
const assetId = useMemo(
|
||||
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
|
||||
[market]
|
||||
);
|
||||
const { data: asset } = useAssetDataProvider(assetId ?? '');
|
||||
|
||||
if (!market) return null;
|
||||
|
||||
@@ -91,75 +96,272 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
market.accountsConnection?.edges
|
||||
);
|
||||
|
||||
const last24hourVolume = market.candles && calcCandleVolume(market.candles);
|
||||
|
||||
const marketDataPanels = [
|
||||
{
|
||||
title: t('Current fees'),
|
||||
content: <CurrentFeesInfoPanel market={market} />,
|
||||
content: (
|
||||
<>
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
...market.fees.factors,
|
||||
totalFees: totalFeesPercentage(market.fees.factors),
|
||||
}}
|
||||
asPercentage={true}
|
||||
/>
|
||||
<p className="text-xs">
|
||||
{t(
|
||||
'All fees are paid by price takers and are a % of the trade notional value. Fees are not paid during auction uncrossing.'
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Market price'),
|
||||
content: <MarketPriceInfoPanel market={market} />,
|
||||
content: (
|
||||
<>
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
markPrice: market.data?.markPrice,
|
||||
bestBidPrice: market.data?.bestBidPrice,
|
||||
bestOfferPrice: market.data?.bestOfferPrice,
|
||||
quoteUnit: market.tradableInstrument.instrument.product.quoteName,
|
||||
}}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
/>
|
||||
<p className="text-xs mt-4">
|
||||
{t(
|
||||
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
|
||||
[assetSymbol, quoteUnit]
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Market volume'),
|
||||
content: <MarketVolumeInfoPanel market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
'24hourVolume':
|
||||
last24hourVolume && last24hourVolume !== '0'
|
||||
? addDecimalsFormatNumber(
|
||||
last24hourVolume,
|
||||
market.positionDecimalPlaces
|
||||
)
|
||||
: '-',
|
||||
openInterest: market.data?.openInterest,
|
||||
bestBidVolume: market.data?.bestBidVolume,
|
||||
bestOfferVolume: market.data?.bestOfferVolume,
|
||||
bestStaticBidVolume: market.data?.bestStaticBidVolume,
|
||||
bestStaticOfferVolume: market.data?.bestStaticOfferVolume,
|
||||
}}
|
||||
decimalPlaces={market.positionDecimalPlaces}
|
||||
/>
|
||||
),
|
||||
},
|
||||
...marketAccounts
|
||||
.filter((a) => a.type === Schema.AccountType.ACCOUNT_TYPE_INSURANCE)
|
||||
.map((a) => ({
|
||||
title: t(`Insurance pool`),
|
||||
content: <InsurancePoolInfoPanel market={market} account={a} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
balance: a.balance,
|
||||
}}
|
||||
assetSymbol={assetSymbol}
|
||||
decimalPlaces={
|
||||
market.tradableInstrument.instrument.product.settlementAsset
|
||||
.decimals
|
||||
}
|
||||
/>
|
||||
),
|
||||
})),
|
||||
];
|
||||
|
||||
const keyDetails = {
|
||||
decimalPlaces: market.decimalPlaces,
|
||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
||||
tradingMode: market.tradingMode,
|
||||
state: Schema.MarketStateMapping[market.state],
|
||||
};
|
||||
|
||||
const assetDecimals =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
||||
|
||||
const liquidityPriceRange = formatNumberPercentage(
|
||||
new BigNumber(market.lpPriceRange).times(100)
|
||||
);
|
||||
|
||||
const marketSpecPanels = [
|
||||
{
|
||||
title: t('Key details'),
|
||||
content: <KeyDetailsInfoPanel market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
name: market.tradableInstrument.instrument.name,
|
||||
marketID: market.id,
|
||||
tradingMode:
|
||||
keyDetails.tradingMode &&
|
||||
Schema.MarketTradingModeMapping[keyDetails.tradingMode],
|
||||
marketDecimalPlaces: market.decimalPlaces,
|
||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
||||
settlementAssetDecimalPlaces: assetDecimals,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Instrument'),
|
||||
content: <InstrumentInfoPanel market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
marketName: market.tradableInstrument.instrument.name,
|
||||
code: market.tradableInstrument.instrument.code,
|
||||
productType:
|
||||
market.tradableInstrument.instrument.product.__typename,
|
||||
...market.tradableInstrument.instrument.product,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Settlement asset'),
|
||||
content: <SettlementAssetInfoPanel market={market} />,
|
||||
content: asset ? (
|
||||
<>
|
||||
<AssetDetailsTable
|
||||
asset={asset}
|
||||
inline={true}
|
||||
noBorder={true}
|
||||
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
|
||||
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
|
||||
/>
|
||||
<p className="text-xs mt-4">
|
||||
{t(
|
||||
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
|
||||
[assetSymbol, quoteUnit]
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
<Splash>{t('No data')}</Splash>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Metadata'),
|
||||
content: <MetadataInfoPanel market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
expiryDate: getMarketExpiryDateFormatted(
|
||||
market.tradableInstrument.instrument.metadata.tags
|
||||
),
|
||||
...market.tradableInstrument.instrument.metadata.tags
|
||||
?.map((tag) => {
|
||||
const [key, value] = tag.split(':');
|
||||
return { [key]: value };
|
||||
})
|
||||
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Risk model'),
|
||||
content: <RiskModelInfoPanel market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
data={market.tradableInstrument.riskModel}
|
||||
unformatted={true}
|
||||
omits={[]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Risk parameters'),
|
||||
content: <RiskParametersInfoPanel market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
data={market.tradableInstrument.riskModel.params}
|
||||
unformatted={true}
|
||||
omits={[]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Risk factors'),
|
||||
content: <RiskFactorsInfoPanel market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
data={market.riskFactors}
|
||||
unformatted={true}
|
||||
omits={['market', '__typename']}
|
||||
/>
|
||||
),
|
||||
},
|
||||
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||
(_, triggerIndex) => ({
|
||||
title: t(`Price monitoring bounds ${triggerIndex + 1}`),
|
||||
content: (
|
||||
<PriceMonitoringBoundsInfoPanel
|
||||
market={market}
|
||||
triggerIndex={triggerIndex}
|
||||
/>
|
||||
),
|
||||
})
|
||||
(trigger, i) => {
|
||||
const bounds = market.data?.priceMonitoringBounds?.[i];
|
||||
return {
|
||||
title: t(`Price monitoring bounds ${i + 1}`),
|
||||
content: (
|
||||
<div className="text-xs">
|
||||
<div className="grid grid-cols-2 text-xs mb-4">
|
||||
<p className="col-span-1">
|
||||
{t('%s probability price bounds', [
|
||||
formatNumberPercentage(
|
||||
new BigNumber(trigger.probability).times(100)
|
||||
),
|
||||
])}
|
||||
</p>
|
||||
<p className="col-span-1 text-right">
|
||||
{t('Within %s seconds', [formatNumber(trigger.horizonSecs)])}
|
||||
</p>
|
||||
</div>
|
||||
<div className="pl-2 pb-0 text-xs border-l-2">
|
||||
{bounds && (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
highestPrice: bounds.maxValidPrice,
|
||||
lowestPrice: bounds.minValidPrice,
|
||||
}}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
assetSymbol={quoteUnit}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<p className="mt-4">
|
||||
{t('Results in %s seconds auction if breached', [
|
||||
trigger.auctionExtensionSecs.toString(),
|
||||
])}
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
}
|
||||
),
|
||||
{
|
||||
title: t('Liquidity monitoring parameters'),
|
||||
content: <LiquidityMonitoringParametersInfoPanel market={market} />,
|
||||
content: (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
triggeringRatio:
|
||||
market.liquidityMonitoringParameters.triggeringRatio,
|
||||
...market.liquidityMonitoringParameters.targetStakeParameters,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Liquidity'),
|
||||
content: (
|
||||
<LiquidityInfoPanel market={market}>
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
targetStake: market.data && market.data.targetStake,
|
||||
suppliedStake: market.data && market.data?.suppliedStake,
|
||||
marketValueProxy: market.data && market.data.marketValueProxy,
|
||||
}}
|
||||
decimalPlaces={assetDecimals}
|
||||
assetSymbol={assetSymbol}
|
||||
>
|
||||
<Link
|
||||
to={`/liquidity/${market.id}`}
|
||||
onClick={() => onSelect(market.id)}
|
||||
@@ -167,17 +369,57 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
>
|
||||
<UILink>{t('View liquidity provision table')}</UILink>
|
||||
</Link>
|
||||
</LiquidityInfoPanel>
|
||||
</MarketInfoTable>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Liquidity price range'),
|
||||
content: <LiquidityPriceRangeInfoPanel market={market} />,
|
||||
content: (
|
||||
<>
|
||||
<p className="text-xs mb-4">
|
||||
{`For liquidity orders to count towards a commitment, they must be
|
||||
within the liquidity monitoring bounds.`}
|
||||
</p>
|
||||
<p className="text-xs mb-4">
|
||||
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
|
||||
price.`}
|
||||
</p>
|
||||
<div className="pl-2 pb-0 text-xs border-l-2">
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
|
||||
lowestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.minus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
highestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.plus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
}}
|
||||
></MarketInfoTable>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel market={market}>
|
||||
<MarketInfoTable
|
||||
data={
|
||||
market.tradableInstrument.instrument.product.dataSourceSpecBinding
|
||||
}
|
||||
>
|
||||
<ExternalLink
|
||||
href={`${VEGA_EXPLORER_URL}/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData.id}`}
|
||||
>
|
||||
@@ -188,7 +430,7 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
>
|
||||
{t('View termination oracle specification')}
|
||||
</ExternalLink>
|
||||
</OracleInfoPanel>
|
||||
</MarketInfoTable>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,418 +0,0 @@
|
||||
import type { ComponentProps } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
calcCandleVolume,
|
||||
totalFeesPercentage,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
formatNumberPercentage,
|
||||
getMarketExpiryDateFormatted,
|
||||
} from '@vegaprotocol/utils';
|
||||
import type { Get } from 'type-fest';
|
||||
import { MarketInfoTable } from './info-key-value-table';
|
||||
import type {
|
||||
MarketInfo,
|
||||
MarketInfoWithData,
|
||||
MarketInfoWithDataAndCandles,
|
||||
} from './market-info-data-provider';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { MarketTradingModeMapping } from '@vegaprotocol/types';
|
||||
|
||||
type PanelProps = Pick<
|
||||
ComponentProps<typeof MarketInfoTable>,
|
||||
'children' | 'noBorder'
|
||||
>;
|
||||
|
||||
type MarketInfoProps = {
|
||||
market: MarketInfo;
|
||||
};
|
||||
|
||||
type MarketInfoWithDataProps = {
|
||||
market: MarketInfoWithData;
|
||||
};
|
||||
|
||||
type MarketInfoWithDataAndCandlesProps = {
|
||||
market: MarketInfoWithDataAndCandles;
|
||||
};
|
||||
|
||||
export const CurrentFeesInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
<>
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
...market.fees.factors,
|
||||
totalFees: totalFeesPercentage(market.fees.factors),
|
||||
}}
|
||||
asPercentage={true}
|
||||
{...props}
|
||||
/>
|
||||
<p className="text-xs">
|
||||
{t(
|
||||
'All fees are paid by price takers and are a % of the trade notional value. Fees are not paid during auction uncrossing.'
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
|
||||
export const MarketPriceInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoWithDataProps & PanelProps) => {
|
||||
const assetSymbol =
|
||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||
const quoteUnit =
|
||||
market?.tradableInstrument.instrument.product?.quoteName || '';
|
||||
return (
|
||||
<>
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
markPrice: market.data?.markPrice,
|
||||
bestBidPrice: market.data?.bestBidPrice,
|
||||
bestOfferPrice: market.data?.bestOfferPrice,
|
||||
quoteUnit: market.tradableInstrument.instrument.product.quoteName,
|
||||
}}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
{...props}
|
||||
/>
|
||||
<p className="text-xs mt-4">
|
||||
{t(
|
||||
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
|
||||
[assetSymbol, quoteUnit]
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const MarketVolumeInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoWithDataAndCandlesProps & PanelProps) => {
|
||||
const last24hourVolume = market.candles && calcCandleVolume(market.candles);
|
||||
return (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
'24hourVolume':
|
||||
last24hourVolume && last24hourVolume !== '0'
|
||||
? addDecimalsFormatNumber(
|
||||
last24hourVolume,
|
||||
market.positionDecimalPlaces
|
||||
)
|
||||
: '-',
|
||||
openInterest: market.data?.openInterest,
|
||||
bestBidVolume: market.data?.bestBidVolume,
|
||||
bestOfferVolume: market.data?.bestOfferVolume,
|
||||
bestStaticBidVolume: market.data?.bestStaticBidVolume,
|
||||
bestStaticOfferVolume: market.data?.bestStaticOfferVolume,
|
||||
}}
|
||||
decimalPlaces={market.positionDecimalPlaces}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const InsurancePoolInfoPanel = ({
|
||||
market,
|
||||
account,
|
||||
...props
|
||||
}: {
|
||||
account: NonNullable<
|
||||
Get<MarketInfoWithData, 'accountsConnection.edges[0].node'>
|
||||
>;
|
||||
} & MarketInfoProps &
|
||||
PanelProps) => {
|
||||
const assetSymbol =
|
||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||
return (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
balance: account.balance,
|
||||
}}
|
||||
assetSymbol={assetSymbol}
|
||||
decimalPlaces={
|
||||
market.tradableInstrument.instrument.product.settlementAsset.decimals
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const KeyDetailsInfoPanel = ({
|
||||
market,
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
const assetDecimals =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
||||
return (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
name: market.tradableInstrument.instrument.name,
|
||||
marketID: market.id,
|
||||
tradingMode:
|
||||
market.tradingMode && MarketTradingModeMapping[market.tradingMode],
|
||||
marketDecimalPlaces: market.decimalPlaces,
|
||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
||||
settlementAssetDecimalPlaces: assetDecimals,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const InstrumentInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
marketName: market.tradableInstrument.instrument.name,
|
||||
code: market.tradableInstrument.instrument.code,
|
||||
productType: market.tradableInstrument.instrument.product.__typename,
|
||||
...market.tradableInstrument.instrument.product,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const SettlementAssetInfoPanel = ({
|
||||
market,
|
||||
noBorder = true,
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
const assetSymbol =
|
||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||
const quoteUnit =
|
||||
market?.tradableInstrument.instrument.product?.quoteName || '';
|
||||
const assetId = useMemo(
|
||||
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
|
||||
[market]
|
||||
);
|
||||
const { data: asset } = useAssetDataProvider(assetId ?? '');
|
||||
return asset ? (
|
||||
<>
|
||||
<AssetDetailsTable
|
||||
asset={asset}
|
||||
inline={true}
|
||||
noBorder={noBorder}
|
||||
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
|
||||
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
|
||||
/>
|
||||
<p className="text-xs mt-4">
|
||||
{t(
|
||||
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
|
||||
[assetSymbol, quoteUnit]
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
<Splash>{t('No data')}</Splash>
|
||||
);
|
||||
};
|
||||
|
||||
export const MetadataInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
expiryDate: getMarketExpiryDateFormatted(
|
||||
market.tradableInstrument.instrument.metadata.tags
|
||||
),
|
||||
...market.tradableInstrument.instrument.metadata.tags
|
||||
?.map((tag) => {
|
||||
const [key, value] = tag.split(':');
|
||||
return { [key]: value };
|
||||
})
|
||||
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const RiskModelInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
<MarketInfoTable
|
||||
data={market.tradableInstrument.riskModel}
|
||||
unformatted={true}
|
||||
omits={[]}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const RiskParametersInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
<MarketInfoTable
|
||||
data={market.tradableInstrument.riskModel.params}
|
||||
unformatted={true}
|
||||
omits={[]}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const RiskFactorsInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
<MarketInfoTable
|
||||
data={market.riskFactors}
|
||||
unformatted={true}
|
||||
omits={['market', '__typename']}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const PriceMonitoringBoundsInfoPanel = ({
|
||||
market,
|
||||
triggerIndex,
|
||||
...props
|
||||
}: {
|
||||
triggerIndex: number;
|
||||
} & MarketInfoWithDataProps &
|
||||
PanelProps) => {
|
||||
const quoteUnit =
|
||||
market?.tradableInstrument.instrument.product?.quoteName || '';
|
||||
const trigger =
|
||||
market.priceMonitoringSettings?.parameters?.triggers?.[triggerIndex];
|
||||
const bounds = market.data?.priceMonitoringBounds?.[triggerIndex];
|
||||
if (!trigger) {
|
||||
console.error(
|
||||
`Could not find data for trigger ${triggerIndex} (market id: ${market.id})`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="text-xs">
|
||||
<div className="grid grid-cols-2 text-xs mb-4">
|
||||
<p className="col-span-1">
|
||||
{t('%s probability price bounds', [
|
||||
formatNumberPercentage(
|
||||
new BigNumber(trigger.probability).times(100)
|
||||
),
|
||||
])}
|
||||
</p>
|
||||
<p className="col-span-1 text-right">
|
||||
{t('Within %s seconds', [formatNumber(trigger.horizonSecs)])}
|
||||
</p>
|
||||
</div>
|
||||
<div className="pl-2 pb-0 text-xs border-l-2">
|
||||
{bounds && (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
highestPrice: bounds.maxValidPrice,
|
||||
lowestPrice: bounds.minValidPrice,
|
||||
}}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
assetSymbol={quoteUnit}
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<p className="mt-4">
|
||||
{t('Results in %s seconds auction if breached', [
|
||||
trigger.auctionExtensionSecs.toString(),
|
||||
])}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const LiquidityMonitoringParametersInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
triggeringRatio: market.liquidityMonitoringParameters.triggeringRatio,
|
||||
...market.liquidityMonitoringParameters.targetStakeParameters,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const LiquidityInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoWithDataProps & PanelProps) => {
|
||||
const assetDecimals =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
||||
const assetSymbol =
|
||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||
return (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
targetStake: market.data && market.data.targetStake,
|
||||
suppliedStake: market.data && market.data?.suppliedStake,
|
||||
marketValueProxy: market.data && market.data.marketValueProxy,
|
||||
}}
|
||||
decimalPlaces={assetDecimals}
|
||||
assetSymbol={assetSymbol}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const LiquidityPriceRangeInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoWithDataProps & PanelProps) => {
|
||||
const quoteUnit =
|
||||
market?.tradableInstrument.instrument.product?.quoteName || '';
|
||||
const liquidityPriceRange = formatNumberPercentage(
|
||||
new BigNumber(market.lpPriceRange).times(100)
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<p className="text-xs mb-4">
|
||||
{`For liquidity orders to count towards a commitment, they must be
|
||||
within the liquidity monitoring bounds.`}
|
||||
</p>
|
||||
<p className="text-xs mb-4">
|
||||
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
|
||||
price.`}
|
||||
</p>
|
||||
<div className="pl-2 pb-0 text-xs border-l-2">
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
|
||||
lowestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.minus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
highestPrice:
|
||||
market.data?.midPrice &&
|
||||
`${addDecimalsFormatNumber(
|
||||
new BigNumber(1)
|
||||
.plus(market.lpPriceRange)
|
||||
.times(market.data.midPrice)
|
||||
.toString(),
|
||||
market.decimalPlaces
|
||||
)} ${quoteUnit}`,
|
||||
}}
|
||||
></MarketInfoTable>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const OracleInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
<MarketInfoTable
|
||||
data={market.tradableInstrument.instrument.product.dataSourceSpecBinding}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
@@ -1,8 +1,7 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import type { Position } from '../';
|
||||
import { usePositionsData, PositionsTable } from '../';
|
||||
import type { FilterChangedEvent } from 'ag-grid-community';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/wallet';
|
||||
@@ -23,7 +22,6 @@ export const PositionsManager = ({
|
||||
noBottomPlaceholder,
|
||||
}: PositionsManagerProps) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const [dataCount, setDataCount] = useState(0);
|
||||
const { data, error, loading, reload } = usePositionsData(
|
||||
partyId,
|
||||
gridRef,
|
||||
@@ -69,12 +67,7 @@ export const PositionsManager = ({
|
||||
gridRef,
|
||||
setId,
|
||||
});
|
||||
useEffect(() => {
|
||||
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
|
||||
}, [data]);
|
||||
const onFilterChanged = useCallback((event: FilterChangedEvent) => {
|
||||
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="h-full relative">
|
||||
<PositionsTable
|
||||
@@ -82,10 +75,8 @@ export const PositionsManager = ({
|
||||
ref={gridRef}
|
||||
onMarketClick={onMarketClick}
|
||||
onClose={onClose}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
noRowsOverlayComponent={() => null}
|
||||
isReadOnly={isReadOnly}
|
||||
onFilterChanged={onFilterChanged}
|
||||
{...(noBottomPlaceholder ? null : bottomPlaceholderProps)}
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
@@ -94,7 +85,7 @@ export const PositionsManager = ({
|
||||
error={error}
|
||||
data={data}
|
||||
noDataMessage={t('No positions')}
|
||||
noDataCondition={(data) => !dataCount}
|
||||
noDataCondition={(data) => !(data && data.length)}
|
||||
reload={reload}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -29,6 +29,7 @@ import { countryCodeToFlagEmoji, FALLBACK_FLAG } from './flag-emoji';
|
||||
// 🇿
|
||||
|
||||
const cases = [
|
||||
['AC', '🇦🇨'],
|
||||
['AD', '🇦🇩'],
|
||||
['AE', '🇦🇪'],
|
||||
['AF', '🇦🇫'],
|
||||
@@ -37,13 +38,11 @@ const cases = [
|
||||
['AL', '🇦🇱'],
|
||||
['AM', '🇦🇲'],
|
||||
['AO', '🇦🇴'],
|
||||
['AQ', '🇦🇶'],
|
||||
['AR', '🇦🇷'],
|
||||
['AS', '🇦🇸'],
|
||||
['AT', '🇦🇹'],
|
||||
['AU', '🇦🇺'],
|
||||
['AQ', '🇦🇶'],
|
||||
['AW', '🇦🇼'],
|
||||
['AX', '🇦🇽'],
|
||||
['AZ', '🇦🇿'],
|
||||
['BA', '🇧🇦'],
|
||||
['BB', '🇧🇧'],
|
||||
@@ -58,11 +57,10 @@ const cases = [
|
||||
['BM', '🇧🇲'],
|
||||
['BN', '🇧🇳'],
|
||||
['BO', '🇧🇴'],
|
||||
['BQ', '🇧🇶'],
|
||||
['BR', '🇧🇷'],
|
||||
['BS', '🇧🇸'],
|
||||
['BT', '🇧🇹'],
|
||||
['BV', '🇧🇻'],
|
||||
['BQ', '🇧🇶'],
|
||||
['BW', '🇧🇼'],
|
||||
['BY', '🇧🇾'],
|
||||
['BZ', '🇧🇿'],
|
||||
@@ -78,19 +76,19 @@ const cases = [
|
||||
['CM', '🇨🇲'],
|
||||
['CN', '🇨🇳'],
|
||||
['CO', '🇨🇴'],
|
||||
['CP', '🇨🇵'],
|
||||
['CR', '🇨🇷'],
|
||||
['CU', '🇨🇺'],
|
||||
['CV', '🇨🇻'],
|
||||
['CW', '🇨🇼'],
|
||||
['CX', '🇨🇽'],
|
||||
['CY', '🇨🇾'],
|
||||
['CZ', '🇨🇿'],
|
||||
['DE', '🇩🇪'],
|
||||
['DG', '🇩🇬'],
|
||||
['DJ', '🇩🇯'],
|
||||
['DK', '🇩🇰'],
|
||||
['DM', '🇩🇲'],
|
||||
['DO', '🇩🇴'],
|
||||
['DZ', '🇩🇿'],
|
||||
['EA', '🇪🇦'],
|
||||
['EC', '🇪🇨'],
|
||||
['EE', '🇪🇪'],
|
||||
['EG', '🇪🇬'],
|
||||
@@ -116,11 +114,10 @@ const cases = [
|
||||
['GM', '🇬🇲'],
|
||||
['GN', '🇬🇳'],
|
||||
['GP', '🇬🇵'],
|
||||
['GQ', '🇬🇶'],
|
||||
['GR', '🇬🇷'],
|
||||
['GS', '🇬🇸'],
|
||||
['GT', '🇬🇹'],
|
||||
['GU', '🇬🇺'],
|
||||
['GQ', '🇬🇶'],
|
||||
['GW', '🇬🇼'],
|
||||
['GY', '🇬🇾'],
|
||||
['HK', '🇭🇰'],
|
||||
@@ -128,17 +125,17 @@ const cases = [
|
||||
['HN', '🇭🇳'],
|
||||
['HR', '🇭🇷'],
|
||||
['HT', '🇭🇹'],
|
||||
['HU', '🇭🇺'],
|
||||
['IC', '🇮🇨'],
|
||||
['ID', '🇮🇩'],
|
||||
['IE', '🇮🇪'],
|
||||
['IL', '🇮🇱'],
|
||||
['IM', '🇮🇲'],
|
||||
['IN', '🇮🇳'],
|
||||
['IO', '🇮🇴'],
|
||||
['IQ', '🇮🇶'],
|
||||
['IR', '🇮🇷'],
|
||||
['IS', '🇮🇸'],
|
||||
['IT', '🇮🇹'],
|
||||
['IQ', '🇮🇶'],
|
||||
['JE', '🇯🇪'],
|
||||
['JM', '🇯🇲'],
|
||||
['JO', '🇯🇴'],
|
||||
@@ -162,8 +159,6 @@ const cases = [
|
||||
['LR', '🇱🇷'],
|
||||
['LS', '🇱🇸'],
|
||||
['LT', '🇱🇹'],
|
||||
['LU', '🇱🇺'],
|
||||
['LV', '🇱🇻'],
|
||||
['LY', '🇱🇾'],
|
||||
['MA', '🇲🇦'],
|
||||
['MC', '🇲🇨'],
|
||||
@@ -178,14 +173,11 @@ const cases = [
|
||||
['MN', '🇲🇳'],
|
||||
['MO', '🇲🇴'],
|
||||
['MP', '🇲🇵'],
|
||||
['MQ', '🇲🇶'],
|
||||
['MR', '🇲🇷'],
|
||||
['MS', '🇲🇸'],
|
||||
['MT', '🇲🇹'],
|
||||
['MU', '🇲🇺'],
|
||||
['MV', '🇲🇻'],
|
||||
['MQ', '🇲🇶'],
|
||||
['MW', '🇲🇼'],
|
||||
['MX', '🇲🇽'],
|
||||
['MY', '🇲🇾'],
|
||||
['MZ', '🇲🇿'],
|
||||
['NA', '🇳🇦'],
|
||||
@@ -198,7 +190,6 @@ const cases = [
|
||||
['NO', '🇳🇴'],
|
||||
['NP', '🇳🇵'],
|
||||
['NR', '🇳🇷'],
|
||||
['NU', '🇳🇺'],
|
||||
['NZ', '🇳🇿'],
|
||||
['OM', '🇴🇲'],
|
||||
['PA', '🇵🇦'],
|
||||
@@ -215,11 +206,9 @@ const cases = [
|
||||
['PT', '🇵🇹'],
|
||||
['PW', '🇵🇼'],
|
||||
['PY', '🇵🇾'],
|
||||
['QA', '🇶🇦'],
|
||||
['RE', '🇷🇪'],
|
||||
['RO', '🇷🇴'],
|
||||
['RS', '🇷🇸'],
|
||||
['RU', '🇷🇺'],
|
||||
['RW', '🇷🇼'],
|
||||
['SA', '🇸🇦'],
|
||||
['SB', '🇸🇧'],
|
||||
@@ -238,10 +227,9 @@ const cases = [
|
||||
['SR', '🇸🇷'],
|
||||
['SS', '🇸🇸'],
|
||||
['ST', '🇸🇹'],
|
||||
['SV', '🇸🇻'],
|
||||
['SX', '🇸🇽'],
|
||||
['SY', '🇸🇾'],
|
||||
['SZ', '🇸🇿'],
|
||||
['TA', '🇹🇦'],
|
||||
['TC', '🇹🇨'],
|
||||
['TD', '🇹🇩'],
|
||||
['TF', '🇹🇫'],
|
||||
@@ -255,22 +243,10 @@ const cases = [
|
||||
['TO', '🇹🇴'],
|
||||
['TR', '🇹🇷'],
|
||||
['TT', '🇹🇹'],
|
||||
['TV', '🇹🇻'],
|
||||
['TW', '🇹🇼'],
|
||||
['TZ', '🇹🇿'],
|
||||
['UA', '🇺🇦'],
|
||||
['UG', '🇺🇬'],
|
||||
['UM', '🇺🇲'],
|
||||
['US', '🇺🇸'],
|
||||
['UY', '🇺🇾'],
|
||||
['UZ', '🇺🇿'],
|
||||
['VA', '🇻🇦'],
|
||||
['VC', '🇻🇨'],
|
||||
['VE', '🇻🇪'],
|
||||
['QA', '🇶🇦'],
|
||||
['VG', '🇻🇬'],
|
||||
['VI', '🇻🇮'],
|
||||
['VN', '🇻🇳'],
|
||||
['VU', '🇻🇺'],
|
||||
['WF', '🇼🇫'],
|
||||
['WS', '🇼🇸'],
|
||||
['YE', '🇾🇪'],
|
||||
@@ -278,23 +254,6 @@ const cases = [
|
||||
['ZA', '🇿🇦'],
|
||||
['ZM', '🇿🇲'],
|
||||
['ZW', '🇿🇼'],
|
||||
// UK
|
||||
['ENGLAND', '🏴'],
|
||||
['GB-ENG', '🏴'],
|
||||
['ENG', '🏴'],
|
||||
['SCOTLAND', '🏴'],
|
||||
['GB-SCT', '🏴'],
|
||||
['SCT', '🏴'],
|
||||
['WALES', '🏴'],
|
||||
['GB-WLS', '🏴'],
|
||||
['WLS', '🏴'],
|
||||
['CYMRU', '🏴'],
|
||||
['GB-CYM', '🏴'],
|
||||
['CYM', '🏴'],
|
||||
['NORTHERN IRELAND', '🇬🇧'],
|
||||
['GB-NIR', '🇬🇧'],
|
||||
['NIR', '🇬🇧'],
|
||||
['UK', '🇬🇧'],
|
||||
// unknown
|
||||
['AA', FALLBACK_FLAG],
|
||||
['XX', FALLBACK_FLAG],
|
||||
|
||||
@@ -2,303 +2,23 @@ import compact from 'lodash/compact';
|
||||
|
||||
export const FALLBACK_FLAG = '🏳';
|
||||
|
||||
const KNOWN_CODES = [
|
||||
'AD',
|
||||
'AE',
|
||||
'AF',
|
||||
'AG',
|
||||
'AI',
|
||||
'AL',
|
||||
'AM',
|
||||
'AO',
|
||||
'AQ',
|
||||
'AR',
|
||||
'AS',
|
||||
'AT',
|
||||
'AU',
|
||||
'AW',
|
||||
'AX',
|
||||
'AZ',
|
||||
'BA',
|
||||
'BB',
|
||||
'BD',
|
||||
'BE',
|
||||
'BF',
|
||||
'BG',
|
||||
'BH',
|
||||
'BI',
|
||||
'BJ',
|
||||
'BL',
|
||||
'BM',
|
||||
'BN',
|
||||
'BO',
|
||||
'BQ',
|
||||
'BR',
|
||||
'BS',
|
||||
'BT',
|
||||
'BV',
|
||||
'BW',
|
||||
'BY',
|
||||
'BZ',
|
||||
'CA',
|
||||
'CC',
|
||||
'CD',
|
||||
'CF',
|
||||
'CG',
|
||||
'CH',
|
||||
'CI',
|
||||
'CK',
|
||||
'CL',
|
||||
'CM',
|
||||
'CN',
|
||||
'CO',
|
||||
'CR',
|
||||
'CU',
|
||||
'CV',
|
||||
'CW',
|
||||
'CX',
|
||||
'CY',
|
||||
'CZ',
|
||||
'DE',
|
||||
'DJ',
|
||||
'DK',
|
||||
'DM',
|
||||
'DO',
|
||||
'DZ',
|
||||
'EC',
|
||||
'EE',
|
||||
'EG',
|
||||
'EH',
|
||||
'ER',
|
||||
'ES',
|
||||
'ET',
|
||||
'FI',
|
||||
'FJ',
|
||||
'FK',
|
||||
'FM',
|
||||
'FO',
|
||||
'FR',
|
||||
'GA',
|
||||
'GB',
|
||||
'GD',
|
||||
'GE',
|
||||
'GF',
|
||||
'GG',
|
||||
'GH',
|
||||
'GI',
|
||||
'GL',
|
||||
'GM',
|
||||
'GN',
|
||||
'GP',
|
||||
'GQ',
|
||||
'GR',
|
||||
'GS',
|
||||
'GT',
|
||||
'GU',
|
||||
'GW',
|
||||
'GY',
|
||||
'HK',
|
||||
'HM',
|
||||
'HN',
|
||||
'HR',
|
||||
'HT',
|
||||
'HU',
|
||||
'ID',
|
||||
'IE',
|
||||
'IL',
|
||||
'IM',
|
||||
'IN',
|
||||
'IO',
|
||||
'IQ',
|
||||
'IR',
|
||||
'IS',
|
||||
'IT',
|
||||
'JE',
|
||||
'JM',
|
||||
'JO',
|
||||
'JP',
|
||||
'KE',
|
||||
'KG',
|
||||
'KH',
|
||||
'KI',
|
||||
'KM',
|
||||
'KN',
|
||||
'KP',
|
||||
'KR',
|
||||
'KW',
|
||||
'KY',
|
||||
'KZ',
|
||||
'LA',
|
||||
'LB',
|
||||
'LC',
|
||||
'LI',
|
||||
'LK',
|
||||
'LR',
|
||||
'LS',
|
||||
'LT',
|
||||
'LU',
|
||||
'LV',
|
||||
'LY',
|
||||
'MA',
|
||||
'MC',
|
||||
'MD',
|
||||
'ME',
|
||||
'MF',
|
||||
'MG',
|
||||
'MH',
|
||||
'MK',
|
||||
'ML',
|
||||
'MM',
|
||||
'MN',
|
||||
'MO',
|
||||
'MP',
|
||||
'MQ',
|
||||
'MR',
|
||||
'MS',
|
||||
'MT',
|
||||
'MU',
|
||||
'MV',
|
||||
'MW',
|
||||
'MX',
|
||||
'MY',
|
||||
'MZ',
|
||||
'NA',
|
||||
'NC',
|
||||
'NE',
|
||||
'NF',
|
||||
'NG',
|
||||
'NI',
|
||||
'NL',
|
||||
'NO',
|
||||
'NP',
|
||||
'NR',
|
||||
'NU',
|
||||
'NZ',
|
||||
'OM',
|
||||
'PA',
|
||||
'PE',
|
||||
'PF',
|
||||
'PG',
|
||||
'PH',
|
||||
'PK',
|
||||
'PL',
|
||||
'PM',
|
||||
'PN',
|
||||
'PR',
|
||||
'PS',
|
||||
'PT',
|
||||
'PW',
|
||||
'PY',
|
||||
'QA',
|
||||
'RE',
|
||||
'RO',
|
||||
'RS',
|
||||
'RU',
|
||||
'RW',
|
||||
'SA',
|
||||
'SB',
|
||||
'SC',
|
||||
'SD',
|
||||
'SE',
|
||||
'SG',
|
||||
'SH',
|
||||
'SI',
|
||||
'SJ',
|
||||
'SK',
|
||||
'SL',
|
||||
'SM',
|
||||
'SN',
|
||||
'SO',
|
||||
'SR',
|
||||
'SS',
|
||||
'ST',
|
||||
'SV',
|
||||
'SX',
|
||||
'SY',
|
||||
'SZ',
|
||||
'TC',
|
||||
'TD',
|
||||
'TF',
|
||||
'TG',
|
||||
'TH',
|
||||
'TJ',
|
||||
'TK',
|
||||
'TL',
|
||||
'TM',
|
||||
'TN',
|
||||
'TO',
|
||||
'TR',
|
||||
'TT',
|
||||
'TV',
|
||||
'TW',
|
||||
'TZ',
|
||||
'UA',
|
||||
'UG',
|
||||
'UM',
|
||||
'US',
|
||||
'UY',
|
||||
'UZ',
|
||||
'VA',
|
||||
'VC',
|
||||
'VE',
|
||||
'VG',
|
||||
'VI',
|
||||
'VN',
|
||||
'VU',
|
||||
'WF',
|
||||
'WS',
|
||||
'YE',
|
||||
'YT',
|
||||
'ZA',
|
||||
'ZM',
|
||||
'ZW',
|
||||
];
|
||||
const KNOWN_CODES = `AC AD AE AF AG AI AL AM AO AR AS AT AQ AW AZ BA BB BD BE BF
|
||||
BG BH BI BJ BL BM BN BO BR BS BT BQ BW BY BZ CA CC CD CF CG CH CI CK CL CM CN
|
||||
CO CP CR CW CY CZ DE DG DJ DK DM DO DZ EA EC EE EG EH ER ES ET FI FJ FK FM FO
|
||||
FR GA GB GD GE GF GG GH GI GL GM GN GP GR GS GT GQ GW GY HK HM HN HR HT IC ID
|
||||
IE IL IM IN IO IR IS IT IQ JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ LA LB
|
||||
LC LI LK LR LS LT LY MA MC MD ME MF MG MH MK ML MM MN MO MP MR MS MT MQ MW MY
|
||||
MZ NA NC NE NF NG NI NL NO NP NR NZ OM PA PE PF PG PH PK PL PM PN PR PS PT PW
|
||||
PY RE RO RS RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR SS ST SY SZ TA TC
|
||||
TD TF TG TH TJ TK TL TM TN TO TR TT TW TZ QA VG WF WS YE YT ZA ZM ZW`;
|
||||
|
||||
const ENGLAND = '🏴';
|
||||
const SCOTLAND = '🏴';
|
||||
const WALES = '🏴';
|
||||
const NORTHERN_IRELAND = '🇬🇧';
|
||||
|
||||
const UK = new Map([
|
||||
['ENGLAND', ENGLAND],
|
||||
['GB-ENG', ENGLAND],
|
||||
['ENG', ENGLAND],
|
||||
['SCOTLAND', SCOTLAND],
|
||||
['GB-SCT', SCOTLAND],
|
||||
['SCT', SCOTLAND],
|
||||
['WALES', WALES],
|
||||
['GB-WLS', WALES],
|
||||
['WLS', WALES],
|
||||
['CYMRU', WALES],
|
||||
['GB-CYM', WALES],
|
||||
['CYM', WALES],
|
||||
['NORTHERN IRELAND', NORTHERN_IRELAND],
|
||||
['GB-NIR', NORTHERN_IRELAND],
|
||||
['NIR', NORTHERN_IRELAND],
|
||||
['UNITED KINGDOM', '🇬🇧'],
|
||||
['UK', '🇬🇧'],
|
||||
]);
|
||||
|
||||
const EU = new Map([['EU', '🇪🇺']]);
|
||||
|
||||
const getCode = (countryCode: string): string => {
|
||||
export const countryCodeToFlagEmoji = (countryCode: string) => {
|
||||
const code = countryCode.trim().toUpperCase();
|
||||
return code;
|
||||
};
|
||||
|
||||
export const countryCodeToFlagEmoji = (countryCode: string): string => {
|
||||
const code = getCode(countryCode);
|
||||
const known = compact(KNOWN_CODES.map((ch) => ch.trim()));
|
||||
const known = compact(KNOWN_CODES.split(' ').map((ch) => ch.trim()));
|
||||
if (known.includes(code)) {
|
||||
return code.replace(/./g, (char) =>
|
||||
String.fromCodePoint(0x1f1a5 + char.toUpperCase().charCodeAt(0))
|
||||
);
|
||||
}
|
||||
if (UK.has(code)) {
|
||||
return UK.get(code) as string;
|
||||
}
|
||||
if (EU.has(code)) {
|
||||
return EU.get(code) as string;
|
||||
}
|
||||
return FALLBACK_FLAG;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user