diff --git a/apps/explorer/src/app/components/markets/market-details.tsx b/apps/explorer/src/app/components/markets/market-details.tsx index 29a9b7722..48409bb60 100644 --- a/apps/explorer/src/app/components/markets/market-details.tsx +++ b/apps/explorer/src/app/components/markets/market-details.tsx @@ -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: ( - - ), - }, - { - title: t('Termination Oracle'), - content: ( - - ), - }, - ] - : [ - { - title: t('Oracle'), - content: ( - - ), - }, - ]; + ); - const panels = [ - { - title: t('Key details'), - content: , - }, - { - title: t('Instrument'), - content: , - }, - { - title: t('Settlement asset'), - content: , - }, - { - title: t('Metadata'), - content: , - }, - { - title: t('Risk model'), - content: , - }, - { - title: t('Risk parameters'), - content: , - }, - { - title: t('Risk factors'), - content: , - }, - ...(market.priceMonitoringSettings?.parameters?.triggers || []).map( - (trigger, i) => ({ - title: t(`Price monitoring trigger ${i + 1}`), - content: , - }) - ), - ...(market.data?.priceMonitoringBounds || []).map((trigger, i) => ({ - title: t(`Price monitoring bound ${i + 1}`), - content: ( - <> - - - - ), - })), - { - title: t('Liquidity monitoring parameters'), - content: ( - - ), - }, - { - title: t('Liquidity'), - content: , - }, - { - title: t('Liquidity price range'), - content: ( - - ), - }, - ...oraclePanels, - ]; + const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2'; return ( - <> - {panels.map((p) => ( -
-

{p.title}

- {p.content} -
+
+

{t('Key details')}

+ +

{t('Instrument')}

+ +

{t('Settlement asset')}

+ +

{t('Metadata')}

+ +

{t('Risk model')}

+ +

{t('Risk parameters')}

+ +

{t('Risk factors')}

+ + {(market.data?.priceMonitoringBounds || []).map((trigger, i) => ( + <> +

+ {t('Price monitoring bounds %s', [(i + 1).toString()])} +

+ + ))} - + {(market.priceMonitoringSettings?.parameters?.triggers || []).map( + (trigger, i) => ( + <> +

+ {t('Price monitoring settings %s', [(i + 1).toString()])} +

+ + + ) + )} +

{t('Liquidity monitoring')}

+ +

{t('Liquidity')}

+ +

{t('Liquidity price range')}

+ + {showTwoOracles ? ( + <> +

{t('Settlement oracle')}

+ +

{t('Termination oracle')}

+ + + ) : ( + <> +

{t('Oracle')}

+ + + )} +
); }; diff --git a/apps/trading-e2e/src/integration/market-info.cy.ts b/apps/trading-e2e/src/integration/market-info.cy.ts index 6e1c0fe9b..849e557cc 100644 --- a/apps/trading-e2e/src/integration/market-info.cy.ts +++ b/apps/trading-e2e/src/integration/market-info.cy.ts @@ -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'); diff --git a/libs/markets/src/lib/components/market-info/info-key-value-table.tsx b/libs/markets/src/lib/components/market-info/info-key-value-table.tsx index e2c38818f..bbbc04795 100644 --- a/libs/markets/src/lib/components/market-info/info-key-value-table.tsx +++ b/libs/markets/src/lib/components/market-info/info-key-value-table.tsx @@ -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; diff --git a/libs/markets/src/lib/components/market-info/market-info-accordion.tsx b/libs/markets/src/lib/components/market-info/market-info-accordion.tsx index 0835819d3..da773ee9d 100644 --- a/libs/markets/src/lib/components/market-info/market-info-accordion.tsx +++ b/libs/markets/src/lib/components/market-info/market-info-accordion.tsx @@ -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: , - }, - { - title: t('Market price'), - content: , - }, - { - title: t('Market volume'), - content: , - }, - ...marketAccounts - .filter((a) => a.type === Schema.AccountType.ACCOUNT_TYPE_INSURANCE) - .map((a) => ({ - title: t(`Insurance pool`), - content: , - })), - ]; const settlementData = market.tradableInstrument.instrument.product .dataSourceSpecForSettlementData.data as DataSourceDefinition; const terminationData = market.tradableInstrument.instrument.product @@ -123,165 +104,187 @@ export const MarketInfoAccordion = ({ } return []; }; - const oraclePanels = isEqual( - getSigners(settlementData), - getSigners(terminationData) - ) - ? [ - { - title: t('Oracle'), - content: ( - - ), - }, - ] - : [ - { - title: t('Settlement Oracle'), - content: ( - - ), - }, - { - title: t('Termination Oracle'), - content: ( - - ), - }, - ]; - const marketSpecPanels = [ - { - title: t('Key details'), - content: , - }, - { - title: t('Instrument'), - content: , - }, - ...oraclePanels, - { - title: t('Settlement asset'), - content: , - }, - { - title: t('Metadata'), - content: , - }, - { - title: t('Risk model'), - content: , - }, - { - title: t('Risk parameters'), - content: , - }, - { - title: t('Risk factors'), - content: , - }, - ...(market.priceMonitoringSettings?.parameters?.triggers || []).map( - (_, triggerIndex) => ({ - title: t(`Price monitoring bounds ${triggerIndex + 1}`), - content: ( - - ), - }) - ), - { - title: t('Liquidity monitoring parameters'), - content: , - }, - { - title: t('Liquidity'), - content: ( - - onSelect?.(market.id, ev.metaKey || ev.ctrlKey)} - data-testid="view-liquidity-link" - > - {t('View liquidity provision table')} - - - ), - }, - { - title: t('Liquidity price range'), - content: , - }, - ]; - - const marketGovPanels = [ - { - title: t('Proposal'), - content: ( -
- {VEGA_TOKEN_URL && ( - - {t('View governance proposal')} - - )} - {VEGA_TOKEN_URL && ( - - {t('Propose a change to market')} - - )} -
- ), - }, - ]; return (

{t('Market data')}

- + + } + /> + } + /> + } + /> + {marketAccounts + .filter((a) => a.type === Schema.AccountType.ACCOUNT_TYPE_INSURANCE) + .map((a) => ( + } + /> + ))} +

{t('Market specification')}

- + + } + /> + } + /> + {isEqual(getSigners(settlementData), getSigners(terminationData)) ? ( + + } + /> + ) : ( + <> + + } + /> + + } + /> + + )} + } + /> + } + /> + } + /> + } + /> + } + /> + {(market.priceMonitoringSettings?.parameters?.triggers || []).map( + (_, triggerIndex) => ( + + } + /> + ) + )} + } + /> + +
+ + onSelect?.(market.id, ev.metaKey || ev.ctrlKey) + } + data-testid="view-liquidity-link" + > + {t('View liquidity provision table')} + +
+ + } + /> + } + /> +
- {VEGA_TOKEN_URL && marketGovPanels && market.proposal?.id && ( + {VEGA_TOKEN_URL && market.proposal?.id && (

{t('Market governance')}

- + + + + {t('View governance proposal')} + + + {t('Propose a change to market')} + + + } + /> +
)}
diff --git a/libs/markets/src/lib/components/market-info/market-info-panels.tsx b/libs/markets/src/lib/components/market-info/market-info-panels.tsx index da470ecbf..6fb4af889 100644 --- a/libs/markets/src/lib/components/market-info/market-info-panels.tsx +++ b/libs/markets/src/lib/components/market-info/market-info-panels.tsx @@ -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, - 'children' | 'noBorder' ->; - type MarketInfoProps = { market: MarketInfo; + children?: ReactNode; }; -export const CurrentFeesInfoPanel = ({ - market, - ...props -}: MarketInfoProps & PanelProps) => ( +export const CurrentFeesInfoPanel = ({ market }: MarketInfoProps) => ( <>

{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} /> -

+

{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 >; -} & 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) => ( ); -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 = ({ @@ -224,10 +196,7 @@ export const SettlementAssetInfoPanel = ({ ); }; -export const MetadataInfoPanel = ({ - market, - ...props -}: MarketInfoProps & PanelProps) => ( +export const MetadataInfoPanel = ({ market }: MarketInfoProps) => ( ({ ...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 ( - - ); + return ; }; -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 ; + return ; } if (market.tradableInstrument.riskModel.__typename === 'SimpleRiskModel') { const { factorLong, factorShort } = market.tradableInstrument.riskModel.params; - return ( - - ); + return ; } 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 ; + return ; }; 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 ( -

-
+ <> +

{t('%s probability price bounds', [ formatNumberPercentage( @@ -331,32 +276,28 @@ export const PriceMonitoringBoundsInfoPanel = ({ {t('Within %s seconds', [formatNumber(trigger.horizonSecs)])}

-
- {bounds && ( - - )} -
-

+ {bounds && ( + + )} +

{t('Results in %s seconds auction if breached', [ trigger.auctionExtensionSecs.toString(), ])}

-
+ ); }; export const LiquidityMonitoringParametersInfoPanel = ({ market, - ...props -}: MarketInfoProps & PanelProps) => ( +}: MarketInfoProps) => ( ); -export const LiquidityInfoPanel = ({ - market, - ...props -}: MarketInfoProps & PanelProps) => { +export const LiquidityInfoPanel = ({ market, children }: MarketInfoProps) => { const assetDecimals = market.tradableInstrument.instrument.product.settlementAsset.decimals; const assetSymbol = @@ -383,23 +320,22 @@ export const LiquidityInfoPanel = ({ variables: { marketId: market.id }, }); return ( - + <> + + {children} + ); }; -export const LiquidityPriceRangeInfoPanel = ({ - market, - ...props -}: MarketInfoProps & PanelProps) => { +export const LiquidityPriceRangeInfoPanel = ({ market }: MarketInfoProps) => { const quoteUnit = market?.tradableInstrument.instrument.product?.quoteName || ''; const liquidityPriceRange = formatNumberPercentage( @@ -411,39 +347,37 @@ export const LiquidityPriceRangeInfoPanel = ({ }); return ( <> -

+

{`For liquidity orders to count towards a commitment, they must be within the liquidity monitoring bounds.`}

-

+

{`The liquidity price range is a ${liquidityPriceRange} difference from the mid price.`}

-
- -
+ ); }; @@ -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 ( -
+
+
{signerProviders.map((provider) => ( -

{message}

-

- {oracleMarkets && - t('Involved in %s %s', [ +

+ {message} +

+ {oracleMarkets && ( +

+ {t('Involved in %s %s', [ oracleMarkets.length.toString(), oracleMarkets.length !== 1 ? t('markets') : t('market'), ])} -

+

+ )} {links.length > 0 && ( -
+
{links.map((link) => ( - - + + - - - {link.type} + {link.type} diff --git a/libs/ui-toolkit/src/components/accordion/accordion.spec.tsx b/libs/ui-toolkit/src/components/accordion/accordion.spec.tsx index b6f2f9c20..a3c82b9f5 100644 --- a/libs/ui-toolkit/src/components/accordion/accordion.spec.tsx +++ b/libs/ui-toolkit/src/components/accordion/accordion.spec.tsx @@ -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( - + + + ); expect(screen.queryByTestId('accordion-title')).toHaveTextContent( 'Lorem ipsum title' @@ -18,11 +20,13 @@ describe('Accordion', () => { it('should toggle and open expansion panel', () => { render( - + + + ); fireEvent.click(screen.getByTestId('accordion-toggle')); expect(screen.queryByTestId('accordion-title')).toHaveTextContent( diff --git a/libs/ui-toolkit/src/components/accordion/accordion.stories.tsx b/libs/ui-toolkit/src/components/accordion/accordion.stories.tsx index 775d7d807..99b542e20 100644 --- a/libs/ui-toolkit/src/components/accordion/accordion.stories.tsx +++ b/libs/ui-toolkit/src/components/accordion/accordion.stories.tsx @@ -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) => ; 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: [ + , + , + , ], }; diff --git a/libs/ui-toolkit/src/components/accordion/accordion.tsx b/libs/ui-toolkit/src/components/accordion/accordion.tsx index 41f9525bc..9e52f8250 100644 --- a/libs/ui-toolkit/src/components/accordion/accordion.tsx +++ b/libs/ui-toolkit/src/components/accordion/accordion.tsx @@ -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([]); - return ( - - {panels?.map(({ title, content }, i) => ( - - ))} + {children} ); @@ -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 ( @@ -59,26 +42,28 @@ export const AccordionItem = ({ className={triggerClassNames} > {title} - + - -
- {content} -
+ + {content}
); }; -export const AccordionChevron = ({ active }: { active: boolean }) => { +export const AccordionChevron = () => { return ( - + + + ); }; diff --git a/libs/ui-toolkit/src/components/link/link.tsx b/libs/ui-toolkit/src/components/link/link.tsx index 2059a5e62..524ba3fd6 100644 --- a/libs/ui-toolkit/src/components/link/link.tsx +++ b/libs/ui-toolkit/src/components/link/link.tsx @@ -43,8 +43,8 @@ Link.displayName = 'Link'; export const ExternalLink = ({ children, className, ...props }: LinkProps) => ( -
{description}
+
+ {description} +
)}