fix(trading): market info refactor (#3985)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
parent
d6e2432955
commit
011e4e4cec
@ -1,5 +1,6 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||
import { PriceMonitoringBoundsInfoPanel } from '@vegaprotocol/markets';
|
||||
import {
|
||||
LiquidityInfoPanel,
|
||||
LiquidityMonitoringParametersInfoPanel,
|
||||
@ -39,133 +40,69 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
return [];
|
||||
};
|
||||
|
||||
const oraclePanels = isEqual(
|
||||
const showTwoOracles = isEqual(
|
||||
getSigners(settlementData),
|
||||
getSigners(terminationData)
|
||||
)
|
||||
? [
|
||||
{
|
||||
title: t('Settlement Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="settlementData"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Termination Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="termination"
|
||||
/>
|
||||
),
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
title: t('Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="settlementData"
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
);
|
||||
|
||||
const panels = [
|
||||
{
|
||||
title: t('Key details'),
|
||||
content: <KeyDetailsInfoPanel noBorder={false} market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Instrument'),
|
||||
content: <InstrumentInfoPanel noBorder={false} market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Settlement asset'),
|
||||
content: <SettlementAssetInfoPanel market={market} noBorder={false} />,
|
||||
},
|
||||
{
|
||||
title: t('Metadata'),
|
||||
content: <MetadataInfoPanel noBorder={false} market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Risk model'),
|
||||
content: <RiskModelInfoPanel noBorder={false} market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Risk parameters'),
|
||||
content: <RiskParametersInfoPanel noBorder={false} market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Risk factors'),
|
||||
content: <RiskFactorsInfoPanel noBorder={false} market={market} />,
|
||||
},
|
||||
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||
(trigger, i) => ({
|
||||
title: t(`Price monitoring trigger ${i + 1}`),
|
||||
content: <MarketInfoTable noBorder={false} data={trigger} />,
|
||||
})
|
||||
),
|
||||
...(market.data?.priceMonitoringBounds || []).map((trigger, i) => ({
|
||||
title: t(`Price monitoring bound ${i + 1}`),
|
||||
content: (
|
||||
<>
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={{
|
||||
maxValidPrice: trigger.maxValidPrice,
|
||||
minValidPrice: trigger.minValidPrice,
|
||||
}}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
/>
|
||||
<MarketInfoTable
|
||||
noBorder={false}
|
||||
data={{ referencePrice: trigger.referencePrice }}
|
||||
decimalPlaces={
|
||||
market.tradableInstrument.instrument.product.settlementAsset
|
||||
.decimals
|
||||
}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
})),
|
||||
{
|
||||
title: t('Liquidity monitoring parameters'),
|
||||
content: (
|
||||
<LiquidityMonitoringParametersInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Liquidity'),
|
||||
content: <LiquidityInfoPanel market={market} noBorder={false} />,
|
||||
},
|
||||
{
|
||||
title: t('Liquidity price range'),
|
||||
content: (
|
||||
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
|
||||
),
|
||||
},
|
||||
...oraclePanels,
|
||||
];
|
||||
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className={headerClassName}>{t('Key details')}</h2>
|
||||
<KeyDetailsInfoPanel market={market} />
|
||||
<h2 className={headerClassName}>{t('Instrument')}</h2>
|
||||
<InstrumentInfoPanel market={market} />
|
||||
<h2 className={headerClassName}>{t('Settlement asset')}</h2>
|
||||
<SettlementAssetInfoPanel market={market} />
|
||||
<h2 className={headerClassName}>{t('Metadata')}</h2>
|
||||
<MetadataInfoPanel market={market} />
|
||||
<h2 className={headerClassName}>{t('Risk model')}</h2>
|
||||
<RiskModelInfoPanel market={market} />
|
||||
<h2 className={headerClassName}>{t('Risk parameters')}</h2>
|
||||
<RiskParametersInfoPanel market={market} />
|
||||
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
||||
<RiskFactorsInfoPanel market={market} />
|
||||
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
||||
<>
|
||||
{panels.map((p) => (
|
||||
<div key={p.title} className="mb-3">
|
||||
<h2 className="font-alpha calt text-xl">{p.title}</h2>
|
||||
{p.content}
|
||||
</div>
|
||||
))}
|
||||
<h2 className={headerClassName}>
|
||||
{t('Price monitoring bounds %s', [(i + 1).toString()])}
|
||||
</h2>
|
||||
<PriceMonitoringBoundsInfoPanel
|
||||
market={market}
|
||||
triggerIndex={i + 1}
|
||||
/>
|
||||
</>
|
||||
))}
|
||||
{(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||
(trigger, i) => (
|
||||
<>
|
||||
<h2 className={headerClassName}>
|
||||
{t('Price monitoring settings %s', [(i + 1).toString()])}
|
||||
</h2>
|
||||
<MarketInfoTable data={trigger} key={i} />
|
||||
</>
|
||||
)
|
||||
)}
|
||||
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
||||
<LiquidityMonitoringParametersInfoPanel market={market} />
|
||||
<h2 className={headerClassName}>{t('Liquidity')}</h2>
|
||||
<LiquidityInfoPanel market={market} />
|
||||
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
||||
<LiquidityPriceRangeInfoPanel market={market} />
|
||||
{showTwoOracles ? (
|
||||
<>
|
||||
<h2 className={headerClassName}>{t('Settlement oracle')}</h2>
|
||||
<OracleInfoPanel market={market} type="settlementData" />
|
||||
<h2 className={headerClassName}>{t('Termination oracle')}</h2>
|
||||
<OracleInfoPanel market={market} type="termination" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h2 className={headerClassName}>{t('Oracle')}</h2>
|
||||
<OracleInfoPanel market={market} type="settlementData" />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -55,12 +55,9 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
validateMarketDataRow(3, 'Quote Unit', 'BTC');
|
||||
});
|
||||
|
||||
// TODO: fix this test
|
||||
// New volume check logic, added by https://github.com/vegaprotocol/frontend-monorepo/pull/3870 has caused the
|
||||
// 24hr volume assertion to fail as it now reads 'Unknown'
|
||||
it.skip('market volume displayed', () => {
|
||||
it('market volume displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Market volume').click();
|
||||
validateMarketDataRow(0, '24 Hour Volume', '1');
|
||||
validateMarketDataRow(0, '24 Hour Volume', 'Unknown');
|
||||
validateMarketDataRow(1, 'Open Interest', '-');
|
||||
validateMarketDataRow(2, 'Best Bid Volume', '1');
|
||||
validateMarketDataRow(3, 'Best Offer Volume', '3');
|
||||
|
@ -34,7 +34,7 @@ const Row = ({
|
||||
assetSymbol = '',
|
||||
noBorder = true,
|
||||
}: RowProps) => {
|
||||
const className = 'text-black dark:text-white text-sm !px-0';
|
||||
const className = 'text-sm';
|
||||
|
||||
const getFormattedValue = (value: ReactNode) => {
|
||||
if (typeof value !== 'string' && typeof value !== 'number') return value;
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
Link as UILink,
|
||||
Splash,
|
||||
TinyScroll,
|
||||
AccordionItem,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { generatePath, Link } from 'react-router-dom';
|
||||
|
||||
@ -85,26 +86,6 @@ export const MarketInfoAccordion = ({
|
||||
market.accountsConnection?.edges
|
||||
);
|
||||
|
||||
const marketDataPanels = [
|
||||
{
|
||||
title: t('Current fees'),
|
||||
content: <CurrentFeesInfoPanel market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Market price'),
|
||||
content: <MarketPriceInfoPanel market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Market volume'),
|
||||
content: <MarketVolumeInfoPanel market={market} />,
|
||||
},
|
||||
...marketAccounts
|
||||
.filter((a) => a.type === Schema.AccountType.ACCOUNT_TYPE_INSURANCE)
|
||||
.map((a) => ({
|
||||
title: t(`Insurance pool`),
|
||||
content: <InsurancePoolInfoPanel market={market} account={a} />,
|
||||
})),
|
||||
];
|
||||
const settlementData = market.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
||||
const terminationData = market.tradableInstrument.instrument.product
|
||||
@ -123,115 +104,156 @@ export const MarketInfoAccordion = ({
|
||||
}
|
||||
return [];
|
||||
};
|
||||
const oraclePanels = isEqual(
|
||||
getSigners(settlementData),
|
||||
getSigners(terminationData)
|
||||
)
|
||||
? [
|
||||
{
|
||||
title: t('Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="settlementData"
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div className="mb-8">
|
||||
<h3 className={headerClassName}>{t('Market data')}</h3>
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
itemId="current-fees"
|
||||
title={t('Current fees')}
|
||||
content={<CurrentFeesInfoPanel market={market} />}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
title: t('Settlement Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="settlementData"
|
||||
<AccordionItem
|
||||
itemId="market-price"
|
||||
title={t('Market price')}
|
||||
content={<MarketPriceInfoPanel market={market} />}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Termination Oracle'),
|
||||
content: (
|
||||
<OracleInfoPanel
|
||||
noBorder={false}
|
||||
market={market}
|
||||
type="termination"
|
||||
<AccordionItem
|
||||
itemId="market-volume"
|
||||
title={t('Market volume')}
|
||||
content={<MarketVolumeInfoPanel market={market} />}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
const marketSpecPanels = [
|
||||
{
|
||||
title: t('Key details'),
|
||||
content: <KeyDetailsInfoPanel market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Instrument'),
|
||||
content: <InstrumentInfoPanel market={market} />,
|
||||
},
|
||||
...oraclePanels,
|
||||
{
|
||||
title: t('Settlement asset'),
|
||||
content: <SettlementAssetInfoPanel market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Metadata'),
|
||||
content: <MetadataInfoPanel market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Risk model'),
|
||||
content: <RiskModelInfoPanel market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Risk parameters'),
|
||||
content: <RiskParametersInfoPanel market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Risk factors'),
|
||||
content: <RiskFactorsInfoPanel market={market} />,
|
||||
},
|
||||
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||
(_, triggerIndex) => ({
|
||||
title: t(`Price monitoring bounds ${triggerIndex + 1}`),
|
||||
content: (
|
||||
{marketAccounts
|
||||
.filter((a) => a.type === Schema.AccountType.ACCOUNT_TYPE_INSURANCE)
|
||||
.map((a) => (
|
||||
<AccordionItem
|
||||
itemId={`${a.type}:${a.asset.id}`}
|
||||
title={t('Insurance pool')}
|
||||
content={<InsurancePoolInfoPanel market={market} account={a} />}
|
||||
/>
|
||||
))}
|
||||
</Accordion>
|
||||
</div>
|
||||
<div className="mb-8">
|
||||
<MarketProposalNotification marketId={market.id} />
|
||||
<h3 className={headerClassName}>{t('Market specification')}</h3>
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
itemId="key-details"
|
||||
title={t('Key details')}
|
||||
content={<KeyDetailsInfoPanel market={market} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="instrument"
|
||||
title={t('Instrument')}
|
||||
content={<InstrumentInfoPanel market={market} />}
|
||||
/>
|
||||
{isEqual(getSigners(settlementData), getSigners(terminationData)) ? (
|
||||
<AccordionItem
|
||||
itemId="oracles"
|
||||
title={t('Oracle')}
|
||||
content={
|
||||
<OracleInfoPanel market={market} type="settlementData" />
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<AccordionItem
|
||||
itemId="settlement-oracle"
|
||||
title={t('Settlement Oracle')}
|
||||
content={
|
||||
<OracleInfoPanel market={market} type="settlementData" />
|
||||
}
|
||||
/>
|
||||
|
||||
<AccordionItem
|
||||
itemId="termination-oracle"
|
||||
title={t('Termination Oracle')}
|
||||
content={<OracleInfoPanel market={market} type="termination" />}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<AccordionItem
|
||||
itemId="settlement-asset"
|
||||
title={t('Settlement asset')}
|
||||
content={<SettlementAssetInfoPanel market={market} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="metadata"
|
||||
title={t('Metadata')}
|
||||
content={<MetadataInfoPanel market={market} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="risk-model"
|
||||
title={t('Risk model')}
|
||||
content={<RiskModelInfoPanel market={market} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="risk-parameters"
|
||||
title={t('Risk parameters')}
|
||||
content={<RiskParametersInfoPanel market={market} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="risk-factors"
|
||||
title={t('Risk factors')}
|
||||
content={<RiskFactorsInfoPanel market={market} />}
|
||||
/>
|
||||
{(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||
(_, triggerIndex) => (
|
||||
<AccordionItem
|
||||
itemId={`trigger-${triggerIndex}`}
|
||||
title={t(`Price monitoring bounds ${triggerIndex + 1}`)}
|
||||
content={
|
||||
<PriceMonitoringBoundsInfoPanel
|
||||
market={market}
|
||||
triggerIndex={triggerIndex}
|
||||
/>
|
||||
),
|
||||
})
|
||||
),
|
||||
{
|
||||
title: t('Liquidity monitoring parameters'),
|
||||
content: <LiquidityMonitoringParametersInfoPanel market={market} />,
|
||||
},
|
||||
{
|
||||
title: t('Liquidity'),
|
||||
content: (
|
||||
}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<AccordionItem
|
||||
itemId="liqudity-monitoring-parameters"
|
||||
title={t('Liquidity monitoring parameters')}
|
||||
content={<LiquidityMonitoringParametersInfoPanel market={market} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="liquidity"
|
||||
title={t('Liquidity')}
|
||||
content={
|
||||
<LiquidityInfoPanel market={market}>
|
||||
<div className="mt-2">
|
||||
<Link
|
||||
to={`/liquidity/${market.id}`}
|
||||
onClick={(ev) => onSelect?.(market.id, ev.metaKey || ev.ctrlKey)}
|
||||
onClick={(ev) =>
|
||||
onSelect?.(market.id, ev.metaKey || ev.ctrlKey)
|
||||
}
|
||||
data-testid="view-liquidity-link"
|
||||
>
|
||||
<UILink>{t('View liquidity provision table')}</UILink>
|
||||
</Link>
|
||||
</div>
|
||||
</LiquidityInfoPanel>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('Liquidity price range'),
|
||||
content: <LiquidityPriceRangeInfoPanel market={market} />,
|
||||
},
|
||||
];
|
||||
|
||||
const marketGovPanels = [
|
||||
{
|
||||
title: t('Proposal'),
|
||||
content: (
|
||||
<div className="">
|
||||
{VEGA_TOKEN_URL && (
|
||||
}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="liquidity-price-range"
|
||||
title={t('Liquidity price range')}
|
||||
content={<LiquidityPriceRangeInfoPanel market={market} />}
|
||||
/>
|
||||
</Accordion>
|
||||
</div>
|
||||
{VEGA_TOKEN_URL && market.proposal?.id && (
|
||||
<div>
|
||||
<h3 className={headerClassName}>{t('Market governance')}</h3>
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
itemId="proposal"
|
||||
title={t('Proposal')}
|
||||
content={
|
||||
<>
|
||||
<ExternalLink
|
||||
className="mb-2 w-full"
|
||||
href={generatePath(TokenStaticLinks.PROPOSAL_PAGE, {
|
||||
@ -246,8 +268,6 @@ export const MarketInfoAccordion = ({
|
||||
>
|
||||
{t('View governance proposal')}
|
||||
</ExternalLink>
|
||||
)}
|
||||
{VEGA_TOKEN_URL && (
|
||||
<ExternalLink
|
||||
className="w-full"
|
||||
href={generatePath(TokenStaticLinks.UPDATE_PROPOSAL_PAGE, {
|
||||
@ -261,27 +281,10 @@ export const MarketInfoAccordion = ({
|
||||
>
|
||||
{t('Propose a change to market')}
|
||||
</ExternalLink>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div className="mb-8">
|
||||
<h3 className={headerClassName}>{t('Market data')}</h3>
|
||||
<Accordion panels={marketDataPanels} />
|
||||
</div>
|
||||
<div className="mb-8">
|
||||
<MarketProposalNotification marketId={market.id} />
|
||||
<h3 className={headerClassName}>{t('Market specification')}</h3>
|
||||
<Accordion panels={marketSpecPanels} />
|
||||
</div>
|
||||
{VEGA_TOKEN_URL && marketGovPanels && market.proposal?.id && (
|
||||
<div>
|
||||
<h3 className={headerClassName}>{t('Market governance')}</h3>
|
||||
<Accordion panels={marketGovPanels} />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</Accordion>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { ComponentProps } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
@ -30,19 +30,12 @@ import { useOracleProofs } from '../../hooks';
|
||||
import { OracleDialog } from '../oracle-dialog/oracle-dialog';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
|
||||
type PanelProps = Pick<
|
||||
ComponentProps<typeof MarketInfoTable>,
|
||||
'children' | 'noBorder'
|
||||
>;
|
||||
|
||||
type MarketInfoProps = {
|
||||
market: MarketInfo;
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
export const CurrentFeesInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
export const CurrentFeesInfoPanel = ({ market }: MarketInfoProps) => (
|
||||
<>
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
@ -52,7 +45,6 @@ export const CurrentFeesInfoPanel = ({
|
||||
totalFees: totalFeesPercentage(market.fees.factors),
|
||||
}}
|
||||
asPercentage={true}
|
||||
{...props}
|
||||
/>
|
||||
<p className="text-xs">
|
||||
{t(
|
||||
@ -62,10 +54,7 @@ export const CurrentFeesInfoPanel = ({
|
||||
</>
|
||||
);
|
||||
|
||||
export const MarketPriceInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
export const MarketPriceInfoPanel = ({ market }: MarketInfoProps) => {
|
||||
const assetSymbol =
|
||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||
const quoteUnit =
|
||||
@ -84,9 +73,8 @@ export const MarketPriceInfoPanel = ({
|
||||
quoteUnit: market.tradableInstrument.instrument.product.quoteName,
|
||||
}}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
{...props}
|
||||
/>
|
||||
<p className="text-xs mt-4">
|
||||
<p className="text-xs mt-2">
|
||||
{t(
|
||||
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
|
||||
[assetSymbol, quoteUnit]
|
||||
@ -96,10 +84,7 @@ export const MarketPriceInfoPanel = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const MarketVolumeInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
export const MarketVolumeInfoPanel = ({ market }: MarketInfoProps) => {
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
variables: { marketId: market.id },
|
||||
@ -124,7 +109,6 @@ export const MarketVolumeInfoPanel = ({
|
||||
bestStaticOfferVolume: dash(data?.bestStaticOfferVolume),
|
||||
}}
|
||||
decimalPlaces={market.positionDecimalPlaces}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -132,13 +116,11 @@ export const MarketVolumeInfoPanel = ({
|
||||
export const InsurancePoolInfoPanel = ({
|
||||
market,
|
||||
account,
|
||||
...props
|
||||
}: {
|
||||
account: NonNullable<
|
||||
Get<MarketInfoWithData, 'accountsConnection.edges[0].node'>
|
||||
>;
|
||||
} & MarketInfoProps &
|
||||
PanelProps) => {
|
||||
} & MarketInfoProps) => {
|
||||
const assetSymbol =
|
||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||
return (
|
||||
@ -150,14 +132,11 @@ export const InsurancePoolInfoPanel = ({
|
||||
decimalPlaces={
|
||||
market.tradableInstrument.instrument.product.settlementAsset.decimals
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const KeyDetailsInfoPanel = ({
|
||||
market,
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
export const KeyDetailsInfoPanel = ({ market }: MarketInfoProps) => {
|
||||
const assetDecimals =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
||||
return (
|
||||
@ -175,10 +154,7 @@ export const KeyDetailsInfoPanel = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const InstrumentInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
export const InstrumentInfoPanel = ({ market }: MarketInfoProps) => (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
marketName: market.tradableInstrument.instrument.name,
|
||||
@ -186,14 +162,10 @@ export const InstrumentInfoPanel = ({
|
||||
productType: market.tradableInstrument.instrument.product.__typename,
|
||||
quoteName: market.tradableInstrument.instrument.product.quoteName,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const SettlementAssetInfoPanel = ({
|
||||
market,
|
||||
noBorder = true,
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
export const SettlementAssetInfoPanel = ({ market }: MarketInfoProps) => {
|
||||
const assetSymbol =
|
||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||
const quoteUnit =
|
||||
@ -208,7 +180,7 @@ export const SettlementAssetInfoPanel = ({
|
||||
<AssetDetailsTable
|
||||
asset={asset}
|
||||
inline={true}
|
||||
noBorder={noBorder}
|
||||
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"
|
||||
/>
|
||||
@ -224,10 +196,7 @@ export const SettlementAssetInfoPanel = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const MetadataInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
export const MetadataInfoPanel = ({ market }: MarketInfoProps) => (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
expiryDate: getMarketExpiryDateFormatted(
|
||||
@ -240,68 +209,44 @@ export const MetadataInfoPanel = ({
|
||||
})
|
||||
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const RiskModelInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
export const RiskModelInfoPanel = ({ market }: MarketInfoProps) => {
|
||||
if (market.tradableInstrument.riskModel.__typename !== 'LogNormalRiskModel') {
|
||||
return null;
|
||||
}
|
||||
const { tau, riskAversionParameter } = market.tradableInstrument.riskModel;
|
||||
return (
|
||||
<MarketInfoTable
|
||||
data={{ tau, riskAversionParameter }}
|
||||
unformatted
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
return <MarketInfoTable data={{ tau, riskAversionParameter }} unformatted />;
|
||||
};
|
||||
|
||||
export const RiskParametersInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
export const RiskParametersInfoPanel = ({ market }: MarketInfoProps) => {
|
||||
if (market.tradableInstrument.riskModel.__typename === 'LogNormalRiskModel') {
|
||||
const { r, sigma, mu } = market.tradableInstrument.riskModel.params;
|
||||
return <MarketInfoTable data={{ r, sigma, mu }} unformatted {...props} />;
|
||||
return <MarketInfoTable data={{ r, sigma, mu }} unformatted />;
|
||||
}
|
||||
if (market.tradableInstrument.riskModel.__typename === 'SimpleRiskModel') {
|
||||
const { factorLong, factorShort } =
|
||||
market.tradableInstrument.riskModel.params;
|
||||
return (
|
||||
<MarketInfoTable
|
||||
data={{ factorLong, factorShort }}
|
||||
unformatted
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
return <MarketInfoTable data={{ factorLong, factorShort }} unformatted />;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const RiskFactorsInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
export const RiskFactorsInfoPanel = ({ market }: MarketInfoProps) => {
|
||||
if (!market.riskFactors) {
|
||||
return null;
|
||||
}
|
||||
const { short, long } = market.riskFactors;
|
||||
return <MarketInfoTable data={{ short, long }} unformatted {...props} />;
|
||||
return <MarketInfoTable data={{ short, long }} unformatted />;
|
||||
};
|
||||
|
||||
export const PriceMonitoringBoundsInfoPanel = ({
|
||||
market,
|
||||
triggerIndex,
|
||||
...props
|
||||
}: {
|
||||
}: MarketInfoProps & {
|
||||
triggerIndex: number;
|
||||
} & MarketInfoProps &
|
||||
PanelProps) => {
|
||||
}) => {
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
variables: { marketId: market.id },
|
||||
@ -318,8 +263,8 @@ export const PriceMonitoringBoundsInfoPanel = ({
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="text-xs">
|
||||
<div className="grid grid-cols-2 text-xs mb-4">
|
||||
<>
|
||||
<div className="grid grid-cols-2 text-sm mb-2">
|
||||
<p className="col-span-1">
|
||||
{t('%s probability price bounds', [
|
||||
formatNumberPercentage(
|
||||
@ -331,7 +276,6 @@ export const PriceMonitoringBoundsInfoPanel = ({
|
||||
{t('Within %s seconds', [formatNumber(trigger.horizonSecs)])}
|
||||
</p>
|
||||
</div>
|
||||
<div className="pl-2 pb-0 text-xs border-l-2">
|
||||
{bounds && (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
@ -340,23 +284,20 @@ export const PriceMonitoringBoundsInfoPanel = ({
|
||||
}}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
assetSymbol={quoteUnit}
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<p className="mt-4">
|
||||
<p className="text-xs mt-2">
|
||||
{t('Results in %s seconds auction if breached', [
|
||||
trigger.auctionExtensionSecs.toString(),
|
||||
])}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const LiquidityMonitoringParametersInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => (
|
||||
}: MarketInfoProps) => (
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
triggeringRatio: market.liquidityMonitoringParameters.triggeringRatio,
|
||||
@ -366,14 +307,10 @@ export const LiquidityMonitoringParametersInfoPanel = ({
|
||||
market.liquidityMonitoringParameters.targetStakeParameters
|
||||
.scalingFactor,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const LiquidityInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
export const LiquidityInfoPanel = ({ market, children }: MarketInfoProps) => {
|
||||
const assetDecimals =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
||||
const assetSymbol =
|
||||
@ -383,6 +320,7 @@ export const LiquidityInfoPanel = ({
|
||||
variables: { marketId: market.id },
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
targetStake: data?.targetStake,
|
||||
@ -391,15 +329,13 @@ export const LiquidityInfoPanel = ({
|
||||
}}
|
||||
decimalPlaces={assetDecimals}
|
||||
assetSymbol={assetSymbol}
|
||||
{...props}
|
||||
/>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const LiquidityPriceRangeInfoPanel = ({
|
||||
market,
|
||||
...props
|
||||
}: MarketInfoProps & PanelProps) => {
|
||||
export const LiquidityPriceRangeInfoPanel = ({ market }: MarketInfoProps) => {
|
||||
const quoteUnit =
|
||||
market?.tradableInstrument.instrument.product?.quoteName || '';
|
||||
const liquidityPriceRange = formatNumberPercentage(
|
||||
@ -411,15 +347,14 @@ export const LiquidityPriceRangeInfoPanel = ({
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<p className="text-xs mb-4">
|
||||
<p className="text-sm mb-2">
|
||||
{`For liquidity orders to count towards a commitment, they must be
|
||||
within the liquidity monitoring bounds.`}
|
||||
</p>
|
||||
<p className="text-xs mb-4">
|
||||
<p className="text-sm mb-2">
|
||||
{`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`,
|
||||
@ -443,7 +378,6 @@ export const LiquidityPriceRangeInfoPanel = ({
|
||||
)} ${quoteUnit}`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -451,8 +385,7 @@ export const LiquidityPriceRangeInfoPanel = ({
|
||||
export const OracleInfoPanel = ({
|
||||
market,
|
||||
type,
|
||||
}: MarketInfoProps &
|
||||
PanelProps & { type: 'settlementData' | 'termination' }) => {
|
||||
}: MarketInfoProps & { type: 'settlementData' | 'termination' }) => {
|
||||
const product = market.tradableInstrument.instrument.product;
|
||||
const { VEGA_EXPLORER_URL, ORACLE_PROOFS_URL } = useEnvironment();
|
||||
const { data } = useOracleProofs(ORACLE_PROOFS_URL);
|
||||
@ -469,7 +402,7 @@ export const OracleInfoPanel = ({
|
||||
) as DataSourceDefinition;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<DataSourceProof
|
||||
data-testid="oracle-proof-links"
|
||||
data={dataSourceSpec}
|
||||
@ -593,7 +526,7 @@ const OracleLink = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mt-2">
|
||||
{signerProviders.map((provider) => (
|
||||
<OracleProfile
|
||||
key={dataSourceSpecId}
|
||||
|
@ -112,31 +112,27 @@ export const OracleBasicProfile = ({
|
||||
<Icon size={3} name={icon as IconName} />
|
||||
</span>
|
||||
</span>
|
||||
<p className="dark:text-vega-light-300 text-vega-dark-300">{message}</p>
|
||||
<p className="text-sm dark:text-vega-light-300 text-vega-dark-300 mb-2">
|
||||
{message}
|
||||
</p>
|
||||
{oracleMarkets && (
|
||||
<p
|
||||
data-testid="signed-proofs"
|
||||
className="dark:text-vega-light-300 text-vega-dark-300"
|
||||
className="text-sm dark:text-vega-light-300 text-vega-dark-300 mb-2"
|
||||
>
|
||||
{oracleMarkets &&
|
||||
t('Involved in %s %s', [
|
||||
{t('Involved in %s %s', [
|
||||
oracleMarkets.length.toString(),
|
||||
oracleMarkets.length !== 1 ? t('markets') : t('market'),
|
||||
])}
|
||||
</p>
|
||||
)}
|
||||
{links.length > 0 && (
|
||||
<div className="flex flex-row gap-1">
|
||||
<div className="flex flex-row gap-3">
|
||||
{links.map((link) => (
|
||||
<ExternalLink
|
||||
key={link.url}
|
||||
href={link.url}
|
||||
data-testid={link.url}
|
||||
className="flex align-items-bottom underline text-sm"
|
||||
>
|
||||
<span className="pt-1 pr-1">
|
||||
<ExternalLink key={link.url} href={link.url} data-testid={link.url}>
|
||||
<span className="flex gap-1 items-center">
|
||||
<VegaIcon name={getLinkIcon(link.type)} />
|
||||
</span>
|
||||
<span className="underline capitalize">
|
||||
{link.type}
|
||||
<span className="capitalize underline">{link.type}</span>
|
||||
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={13} />
|
||||
</span>
|
||||
</ExternalLink>
|
||||
|
@ -1,15 +1,17 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
|
||||
import { Accordion } from './accordion';
|
||||
import { Accordion, AccordionItem } from './accordion';
|
||||
|
||||
describe('Accordion', () => {
|
||||
it('should render successfully', () => {
|
||||
render(
|
||||
<Accordion
|
||||
panels={[
|
||||
{ title: 'Lorem ipsum title', content: 'Lorem ipsum content' },
|
||||
]}
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
itemId="1"
|
||||
title="Lorem ipsum title"
|
||||
content="Lorem ipsum content"
|
||||
/>
|
||||
</Accordion>
|
||||
);
|
||||
expect(screen.queryByTestId('accordion-title')).toHaveTextContent(
|
||||
'Lorem ipsum title'
|
||||
@ -18,11 +20,13 @@ describe('Accordion', () => {
|
||||
|
||||
it('should toggle and open expansion panel', () => {
|
||||
render(
|
||||
<Accordion
|
||||
panels={[
|
||||
{ title: 'Lorem ipsum title', content: 'Lorem ipsum content' },
|
||||
]}
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
itemId="1"
|
||||
title="Lorem ipsum title"
|
||||
content="Lorem ipsum content"
|
||||
/>
|
||||
</Accordion>
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('accordion-toggle'));
|
||||
expect(screen.queryByTestId('accordion-title')).toHaveTextContent(
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { Story, Meta } from '@storybook/react';
|
||||
import { Accordion } from './accordion';
|
||||
import { Accordion, AccordionItem } from './accordion';
|
||||
|
||||
export default {
|
||||
component: Accordion,
|
||||
@ -10,18 +10,21 @@ const Template: Story = (args) => <Accordion panels={args.panels} />;
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
panels: [
|
||||
{
|
||||
title: 'Title of expansion panel',
|
||||
content: 'Lorem ipsum',
|
||||
},
|
||||
{
|
||||
title: 'Title of expansion panel',
|
||||
content: 'Lorem ipsum',
|
||||
},
|
||||
{
|
||||
title: 'Title of expansion panel',
|
||||
content: 'Lorem ipsum',
|
||||
},
|
||||
children: [
|
||||
<AccordionItem
|
||||
itemId="1"
|
||||
title={'Title of expansion panel'}
|
||||
content={'Lorem ipsum'}
|
||||
/>,
|
||||
<AccordionItem
|
||||
itemId="2"
|
||||
title={'Title of expansion panel'}
|
||||
content={'Lorem ipsum'}
|
||||
/>,
|
||||
<AccordionItem
|
||||
itemId="3"
|
||||
title={'Title of expansion panel'}
|
||||
content={'Lorem ipsum'}
|
||||
/>,
|
||||
],
|
||||
};
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
||||
import classNames from 'classnames';
|
||||
import { Icon } from '../icon';
|
||||
import { VegaIcon, VegaIconNames } from '../icon';
|
||||
|
||||
export interface AccordionItemProps {
|
||||
title: React.ReactNode;
|
||||
@ -10,7 +9,6 @@ export interface AccordionItemProps {
|
||||
|
||||
export interface AccordionPanelProps extends AccordionItemProps {
|
||||
itemId: string;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export interface AccordionProps {
|
||||
@ -19,23 +17,8 @@ export interface AccordionProps {
|
||||
}
|
||||
|
||||
export const Accordion = ({ panels, children }: AccordionProps) => {
|
||||
const [values, setValues] = useState<string[]>([]);
|
||||
|
||||
return (
|
||||
<AccordionPrimitive.Root
|
||||
type="multiple"
|
||||
value={values}
|
||||
onValueChange={setValues}
|
||||
>
|
||||
{panels?.map(({ title, content }, i) => (
|
||||
<AccordionItem
|
||||
key={`item-${i + 1}`}
|
||||
itemId={`item-${i + 1}`}
|
||||
title={title}
|
||||
content={content}
|
||||
active={values.includes(`item-${i + 1}`)}
|
||||
/>
|
||||
))}
|
||||
<AccordionPrimitive.Root type="multiple">
|
||||
{children}
|
||||
</AccordionPrimitive.Root>
|
||||
);
|
||||
@ -45,11 +28,11 @@ export const AccordionItem = ({
|
||||
title,
|
||||
content,
|
||||
itemId,
|
||||
active,
|
||||
}: AccordionPanelProps) => {
|
||||
const triggerClassNames = classNames(
|
||||
'w-full py-2',
|
||||
'flex items-center justify-between border-b border-neutral-500 text-sm'
|
||||
'flex items-center justify-between border-b border-vega-light-200 dark:border-vega-dark-200 text-sm',
|
||||
'group'
|
||||
);
|
||||
return (
|
||||
<AccordionPrimitive.Item value={itemId}>
|
||||
@ -59,26 +42,28 @@ export const AccordionItem = ({
|
||||
className={triggerClassNames}
|
||||
>
|
||||
<span data-testid="accordion-title">{title}</span>
|
||||
<AccordionChevron active={active} aria-hidden />
|
||||
<AccordionChevron aria-hidden />
|
||||
</AccordionPrimitive.Trigger>
|
||||
</AccordionPrimitive.Header>
|
||||
<AccordionPrimitive.Content data-testid="accordion-content-ref">
|
||||
<div className="py-4 text-sm" data-testid="accordion-content">
|
||||
<AccordionPrimitive.Content
|
||||
className="py-3 text-sm"
|
||||
data-testid="accordion-content"
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
</AccordionPrimitive.Content>
|
||||
</AccordionPrimitive.Item>
|
||||
);
|
||||
};
|
||||
|
||||
export const AccordionChevron = ({ active }: { active: boolean }) => {
|
||||
export const AccordionChevron = () => {
|
||||
return (
|
||||
<Icon
|
||||
name="chevron-down"
|
||||
className={classNames('transition ease-in-out duration-300', {
|
||||
'transform rotate-180': active,
|
||||
})}
|
||||
aria-hidden
|
||||
/>
|
||||
<span
|
||||
className={classNames(
|
||||
'transform transition ease-in-out duration-300',
|
||||
'group-data-[state=open]:rotate-180'
|
||||
)}
|
||||
>
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} aria-hidden />
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
@ -43,8 +43,8 @@ Link.displayName = 'Link';
|
||||
export const ExternalLink = ({ children, className, ...props }: LinkProps) => (
|
||||
<Link
|
||||
className={classNames(
|
||||
className,
|
||||
'inline-flex gap-1 items-baseline underline-offset-4'
|
||||
'inline-flex items-center gap-1 underline-offset-4',
|
||||
className
|
||||
)}
|
||||
target="_blank"
|
||||
data-testid="external-link"
|
||||
|
@ -42,7 +42,9 @@ export const Tooltip = ({
|
||||
alignOffset={8}
|
||||
className="max-w-sm border border-neutral-600 bg-neutral-100 dark:bg-neutral-800 px-4 py-2 z-20 rounded text-sm text-black dark:text-white break-word"
|
||||
>
|
||||
<div className="relative z-0">{description}</div>
|
||||
<div className="relative z-0" data-testid="tooltip-content">
|
||||
{description}
|
||||
</div>
|
||||
</Content>
|
||||
</Portal>
|
||||
)}
|
||||
|
Loading…
Reference in New Issue
Block a user