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