chore(#2004): add market status to trade header (#2269)

* feat: add status header stat, move header to own component

* chore: fix alignment of price change values when arrow is not rendered

* test: add check for market state display

* feat: add market state component and adjust queries to handle sub updates to market state

* test: update mocks to include data.marketState fields

* chore: add missing market state to console-lite mock

* chore: test adjustment

* fix: botched conflict resolution

* chore: update select market columns test

* chore: add missing fields to test helper functions

Co-authored-by: Rado <szpiechrados@gmail.com>
This commit is contained in:
Matthew Russell 2022-12-01 18:33:30 -06:00 committed by GitHub
parent 9b356e53b4
commit 9ddedd0b78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 368 additions and 212 deletions

View File

@ -1413,6 +1413,7 @@ export const generateMarketData = (): MarketDataQuery => {
},
marketTradingMode:
Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',

View File

@ -81,6 +81,7 @@ const market: MarketDealTicket = {
trigger: Types.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
staticMidPrice: '1606156850',
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
indicativeVolume: '0',
indicativePrice: '0',
bestStaticBidPrice: '1605489971',
@ -92,8 +93,9 @@ const market: MarketDealTicket = {
market: { __typename: 'Market', id: 'market-id' },
},
marketTimestamps: {
open: null,
__typename: 'MarketTimestamps',
close: null,
open: null,
},
};

View File

@ -1,4 +1,4 @@
import { Schema, MarketTradingModeMapping } from '@vegaprotocol/types';
import { MarketTradingModeMapping } from '@vegaprotocol/types';
const marketInfoBtn = 'Info';
const row = 'key-value-table-row';
@ -210,42 +210,3 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
});
}
});
describe('market states', { tags: '@smoke' }, function () {
//7002-SORD-062
//7002-SORD-063
//7002-SORD-066
const states = [
Schema.MarketState.STATE_REJECTED,
Schema.MarketState.STATE_CANCELLED,
Schema.MarketState.STATE_CLOSED,
Schema.MarketState.STATE_SETTLED,
Schema.MarketState.STATE_TRADING_TERMINATED,
];
states.forEach((marketState) => {
describe(marketState, function () {
beforeEach(function () {
cy.mockTradingPage(marketState);
cy.mockGQLSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
});
it.skip('must display correct market state');
//7002-/SORD-/061 no state displayed
it('must display that market is not accepting orders', function () {
cy.getByTestId('place-order').click();
cy.getByTestId('dealticket-error-message-summary').should(
'have.text',
`This market is ${marketState
.split('_')
.pop()
?.toLowerCase()} and not accepting orders`
);
cy.getByTestId('place-order').should('be.disabled');
});
});
});
});

View File

@ -11,6 +11,7 @@ const marketPrice = 'market-price';
const marketChange = 'market-change';
const marketVolume = 'market-volume';
const marketMode = 'market-trading-mode';
const marketState = 'market-state';
const marketSettlement = 'market-settlement-asset';
const percentageValue = 'price-change-percentage';
const priceChangeValue = 'price-change';
@ -36,6 +37,7 @@ describe('Market proposal notification', { tags: '@smoke' }, () => {
cy.wait('@MarketData');
cy.getByTestId(marketSummaryBlock).should('be.visible');
});
it('should display market proposal notification if proposal found', () => {
cy.getByTestId(marketSummaryBlock).within(() => {
cy.getByTestId('market-proposal-notification').should(
@ -119,6 +121,16 @@ describe('Market trading page', () => {
});
});
it('must see market state', () => {
//7002-SORD-061
cy.getByTestId(marketSummaryBlock).within(() => {
cy.getByTestId(marketState).within(() => {
cy.getByTestId(itemHeader).should('have.text', 'Status');
cy.getByTestId(itemValue).should('not.be.empty');
});
});
});
it('must see market settlement', () => {
cy.getByTestId(marketSummaryBlock).within(() => {
cy.getByTestId(marketSettlement).within(() => {
@ -203,3 +215,40 @@ describe('Market trading page', () => {
});
});
});
describe('market states not accepting orders', { tags: '@smoke' }, function () {
//7002-SORD-062
//7002-SORD-063
//7002-SORD-066
const states = [
Schema.MarketState.STATE_REJECTED,
Schema.MarketState.STATE_CANCELLED,
Schema.MarketState.STATE_CLOSED,
Schema.MarketState.STATE_SETTLED,
Schema.MarketState.STATE_TRADING_TERMINATED,
];
states.forEach((marketState) => {
describe(marketState, function () {
beforeEach(function () {
cy.mockTradingPage(marketState);
cy.mockGQLSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
});
it('must display that market is not accepting orders', function () {
cy.getByTestId('place-order').click();
cy.getByTestId('dealticket-error-message-summary').should(
'have.text',
`This market is ${marketState
.split('_')
.pop()
?.toLowerCase()} and not accepting orders`
);
cy.getByTestId('place-order').should('be.disabled');
});
});
});
});

View File

@ -91,6 +91,7 @@ export const generateMarketData = (
targetStake: '1000000',
suppliedStake: '1000',
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',

View File

@ -218,6 +218,7 @@ export const generateMarketsData = (
__typename: 'Market',
},
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
@ -235,6 +236,7 @@ export const generateMarketsData = (
__typename: 'Market',
},
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
@ -252,6 +254,7 @@ export const generateMarketsData = (
__typename: 'Market',
},
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
@ -269,6 +272,7 @@ export const generateMarketsData = (
__typename: 'Market',
},
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',

View File

@ -0,0 +1,3 @@
import { t } from '@vegaprotocol/react-helpers';
export const NO_MARKET = t('No market');

View File

@ -1,5 +1,5 @@
import { DealTicketContainer } from '@vegaprotocol/deal-ticket';
import { MarketInfoContainer, getExpiryDate } from '@vegaprotocol/market-info';
import { MarketInfoContainer } from '@vegaprotocol/market-info';
import { OrderbookContainer } from '@vegaprotocol/market-depth';
import { OrderListContainer } from '@vegaprotocol/orders';
import { FillsContainer } from '@vegaprotocol/fills';
@ -17,29 +17,14 @@ import {
Tabs,
ResizableGrid,
ResizableGridPanel,
ButtonLink,
Link,
Splash,
} from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment';
import { Header, HeaderStat } from '../../components/header';
import { AccountsContainer } from '../../components/accounts-container';
import {
ColumnKind,
SelectMarketPopover,
} from '../../components/select-market';
import type { OnCellClickHandler } from '../../components/select-market';
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
import { Last24hPriceChange } from '../../components/last-24h-price-change';
import { MarketMarkPrice } from '../../components/market-mark-price';
import { MarketTradingModeComponent } from '../../components/market-trading-mode';
import { Last24hVolume } from '../../components/last-24h-volume';
import { MarketProposalNotification } from '@vegaprotocol/governance';
import { VegaWalletContainer } from '../../components/vega-wallet-container';
const NO_MARKET = t('No market');
import { TradeMarketHeader } from './trade-market-header';
import { NO_MARKET } from './constants';
type MarketDependantView =
| typeof CandlesChartContainer
@ -73,133 +58,6 @@ const TradingViews = {
type TradingView = keyof typeof TradingViews;
type ExpiryLabelProps = {
market: SingleMarketFieldsFragment | null;
};
const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
const content = market ? getExpiryDate(market) : '-';
return <div data-testid="trading-expiry">{content}</div>;
};
type ExpiryTooltipContentProps = {
market: SingleMarketFieldsFragment;
explorerUrl?: string;
};
const ExpiryTooltipContent = ({
market,
explorerUrl,
}: ExpiryTooltipContentProps) => {
if (market?.marketTimestamps.close === null) {
const oracleId =
market.tradableInstrument.instrument.product
.dataSourceSpecForTradingTermination?.id;
return (
<section data-testid="expiry-tool-tip">
<p className="mb-2">
{t(
'This market expires when triggered by its oracle, not on a set date.'
)}
</p>
{explorerUrl && oracleId && (
<Link href={`${explorerUrl}/oracles#${oracleId}`} target="_blank">
{t('View oracle specification')}
</Link>
)}
</section>
);
}
return null;
};
interface TradeMarketHeaderProps {
market: SingleMarketFieldsFragment | null;
onSelect: (marketId: string) => void;
}
export const TradeMarketHeader = ({
market,
onSelect,
}: TradeMarketHeaderProps) => {
const { VEGA_EXPLORER_URL } = useEnvironment();
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
const asset = market?.tradableInstrument.instrument.product?.settlementAsset;
const onCellClick: OnCellClickHandler = (e, kind, value) => {
if (value && kind === ColumnKind.Asset) {
openAssetDetailsDialog(value, e.target as HTMLElement);
}
};
return (
<Header
title={
<SelectMarketPopover
marketName={market?.tradableInstrument.instrument.name || NO_MARKET}
onSelect={onSelect}
onCellClick={onCellClick}
/>
}
>
<HeaderStat
heading={t('Expiry')}
description={
market && (
<ExpiryTooltipContent
market={market}
explorerUrl={VEGA_EXPLORER_URL}
/>
)
}
testId="market-expiry"
>
<ExpiryLabel market={market} />
</HeaderStat>
<MarketMarkPrice
marketId={market?.id}
decimalPlaces={market?.decimalPlaces}
isHeader
/>
<Last24hPriceChange
marketId={market?.id}
decimalPlaces={market?.decimalPlaces}
isHeader
/>
<Last24hVolume
marketId={market?.id}
positionDecimalPlaces={market?.positionDecimalPlaces}
isHeader
/>
<MarketTradingModeComponent
marketId={market?.id}
onSelect={onSelect}
isHeader
/>
{asset ? (
<HeaderStat
heading={t('Settlement asset')}
testId="market-settlement-asset"
>
<div>
<ButtonLink
onClick={(e) => {
openAssetDetailsDialog(asset.id, e.target as HTMLElement);
}}
>
{asset.symbol}
</ButtonLink>
</div>
</HeaderStat>
) : null}
<MarketProposalNotification marketId={market?.id} />
</Header>
);
};
interface TradeGridProps {
market: SingleMarketFieldsFragment | null;
onSelect: (marketId: string) => void;

View File

@ -0,0 +1,143 @@
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment';
import { ButtonLink, Link } from '@vegaprotocol/ui-toolkit';
import { MarketProposalNotification } from '@vegaprotocol/governance';
import { getExpiryDate } from '@vegaprotocol/market-info';
import { t } from '@vegaprotocol/react-helpers';
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
import {
ColumnKind,
SelectMarketPopover,
} from '../../components/select-market';
import type { OnCellClickHandler } from '../../components/select-market';
import { Header, HeaderStat } from '../../components/header';
import { NO_MARKET } from './constants';
import { MarketMarkPrice } from '../../components/market-mark-price';
import { Last24hPriceChange } from '../../components/last-24h-price-change';
import { Last24hVolume } from '../../components/last-24h-volume';
import { MarketState } from '../../components/market-state';
import { MarketTradingMode } from '../../components/market-trading-mode';
interface TradeMarketHeaderProps {
market: SingleMarketFieldsFragment | null;
onSelect: (marketId: string) => void;
}
export const TradeMarketHeader = ({
market,
onSelect,
}: TradeMarketHeaderProps) => {
const { VEGA_EXPLORER_URL } = useEnvironment();
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
const asset = market?.tradableInstrument.instrument.product?.settlementAsset;
const onCellClick: OnCellClickHandler = (e, kind, value) => {
if (value && kind === ColumnKind.Asset) {
openAssetDetailsDialog(value, e.target as HTMLElement);
}
};
return (
<Header
title={
<SelectMarketPopover
marketName={market?.tradableInstrument.instrument.name || NO_MARKET}
onSelect={onSelect}
onCellClick={onCellClick}
/>
}
>
<HeaderStat
heading={t('Expiry')}
description={
market && (
<ExpiryTooltipContent
market={market}
explorerUrl={VEGA_EXPLORER_URL}
/>
)
}
testId="market-expiry"
>
<ExpiryLabel market={market} />
</HeaderStat>
<MarketMarkPrice
marketId={market?.id}
decimalPlaces={market?.decimalPlaces}
isHeader
/>
<Last24hPriceChange
marketId={market?.id}
decimalPlaces={market?.decimalPlaces}
isHeader
/>
<Last24hVolume
marketId={market?.id}
positionDecimalPlaces={market?.positionDecimalPlaces}
isHeader
/>
<MarketTradingMode marketId={market?.id} onSelect={onSelect} isHeader />
<MarketState market={market} />
{asset ? (
<HeaderStat
heading={t('Settlement asset')}
testId="market-settlement-asset"
>
<div>
<ButtonLink
onClick={(e) => {
openAssetDetailsDialog(asset.id, e.target as HTMLElement);
}}
>
{asset.symbol}
</ButtonLink>
</div>
</HeaderStat>
) : null}
<MarketProposalNotification marketId={market?.id} />
</Header>
);
};
type ExpiryLabelProps = {
market: SingleMarketFieldsFragment | null;
};
const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
const content = market ? getExpiryDate(market) : '-';
return <div data-testid="trading-expiry">{content}</div>;
};
type ExpiryTooltipContentProps = {
market: SingleMarketFieldsFragment;
explorerUrl?: string;
};
const ExpiryTooltipContent = ({
market,
explorerUrl,
}: ExpiryTooltipContentProps) => {
if (market?.marketTimestamps.close === null) {
const oracleId =
market.tradableInstrument.instrument.product
.dataSourceSpecForTradingTermination?.id;
return (
<section data-testid="expiry-tool-tip">
<p className="mb-2">
{t(
'This market expires when triggered by its oracle, not on a set date.'
)}
</p>
{explorerUrl && oracleId && (
<Link href={`${explorerUrl}/oracles#${oracleId}`} target="_blank">
{t('View oracle specification')}
</Link>
)}
</section>
);
}
return null;
};

View File

@ -0,0 +1 @@
export * from './market-state';

View File

@ -0,0 +1,105 @@
import throttle from 'lodash/throttle';
import type {
MarketData,
MarketDataUpdateFieldsFragment,
SingleMarketFieldsFragment,
} from '@vegaprotocol/market-list';
import { marketDataProvider } from '@vegaprotocol/market-list';
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
import { MarketStateMapping, Schema } from '@vegaprotocol/types';
import { HeaderStat } from '../header';
import { useCallback, useMemo, useRef, useState } from 'react';
import * as constants from '../constants';
export const MarketState = ({
market,
}: {
market: SingleMarketFieldsFragment | null;
}) => {
const [marketState, setMarketState] = useState<Schema.MarketState | null>(
null
);
const throttledSetMarketState = useRef(
throttle((state: Schema.MarketState) => {
setMarketState(state);
}, constants.DEBOUNCE_UPDATE_TIME)
).current;
const update = useCallback(
({ data: marketData }: { data: MarketData | null }) => {
if (marketData) {
throttledSetMarketState(marketData.marketState);
}
return true;
},
[throttledSetMarketState]
);
const variables = useMemo(
() => ({ marketId: market?.id || '' }),
[market?.id]
);
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
dataProvider: marketDataProvider,
update,
variables,
skip: !market?.id,
});
return (
<HeaderStat
heading={t('Status')}
description={getMarketStateTooltip(marketState)}
testId="market-state"
>
{marketState ? MarketStateMapping[marketState] : '-'}
</HeaderStat>
);
};
const getMarketStateTooltip = (state: Schema.MarketState | null) => {
if (state === Schema.MarketState.STATE_ACTIVE) {
return t('Enactment date reached and usual auction exit checks pass');
}
if (state === Schema.MarketState.STATE_CANCELLED) {
return t(
'Market triggers cancellation or governance vote has passed to cancel'
);
}
if (state === Schema.MarketState.STATE_CLOSED) {
return t('Governance vote passed to close the market');
}
if (state === Schema.MarketState.STATE_PENDING) {
return t(
'Governance vote has passed and market is awaiting opening auction exit'
);
}
if (state === Schema.MarketState.STATE_PROPOSED) {
return t('Governance vote for this market is valid and has been accepted');
}
if (state === Schema.MarketState.STATE_REJECTED) {
return t('Governance vote for this market has been rejected');
}
if (state === Schema.MarketState.STATE_SETTLED) {
return t('Settlement defined by product has been triggered and completed');
}
if (state === Schema.MarketState.STATE_SUSPENDED) {
return t('Suspended due to price or liquidity monitoring trigger');
}
if (state === Schema.MarketState.STATE_TRADING_TERMINATED) {
return t(
'Trading has been terminated as a result of the product definition'
);
}
return undefined;
};

View File

@ -26,7 +26,7 @@ interface Props {
initialTrigger?: Types.AuctionTrigger;
}
export const MarketTradingModeComponent = ({
export const MarketTradingMode = ({
marketId,
onSelect,
isHeader = false,

View File

@ -20,7 +20,7 @@ import type {
import { Link } from 'react-router-dom';
import { MarketMarkPrice } from '../market-mark-price';
import { Last24hPriceChange } from '../last-24h-price-change';
import { MarketTradingModeComponent } from '../market-trading-mode';
import { MarketTradingMode } from '../market-trading-mode';
import { Last24hVolume } from '../last-24h-volume';
type Market = MarketWithData & MarketWithCandles;
@ -325,7 +325,7 @@ export const columns = (
{
kind: ColumnKind.TradingMode,
value: (
<MarketTradingModeComponent
<MarketTradingMode
marketId={market?.id}
noUpdate={noUpdate}
initialMode={market.tradingMode}
@ -513,7 +513,7 @@ export const columnsPositionMarkets = (
{
kind: ColumnKind.TradingMode,
value: (
<MarketTradingModeComponent
<MarketTradingMode
marketId={market?.id}
noUpdate={noUpdate}
initialMode={market.tradingMode}

View File

@ -64,6 +64,8 @@ const MARKET_A: PartialMarket = {
},
markPrice: '90',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_OPENING,
marketState: Schema.MarketState.STATE_PENDING,
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
indicativeVolume: '1000',
},
candles: [
@ -134,6 +136,8 @@ const MARKET_B: PartialMarket = {
},
markPrice: '123.123',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_OPENING,
marketState: Schema.MarketState.STATE_PENDING,
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
indicativeVolume: '2000',
},
candles: [

View File

@ -52,6 +52,7 @@ export function generateMarket(
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_BATCH,
staticMidPrice: '100',
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
indicativePrice: '100',
indicativeVolume: '10',
bestStaticBidPrice: '100',

View File

@ -3,23 +3,23 @@ import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string };
export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string };
export type MarketDataUpdateSubscriptionVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string }> };
export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string }> };
export type MarketDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } };
export type MarketDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } };
export type MarketDataQueryVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type MarketDataQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', data?: { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } } | null } }> } | null };
export type MarketDataQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', data?: { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } } | null } }> } | null };
export const MarketDataUpdateFieldsFragmentDoc = gql`
fragment MarketDataUpdateFields on ObservableMarketData {
@ -30,6 +30,7 @@ export const MarketDataUpdateFieldsFragmentDoc = gql`
trigger
staticMidPrice
marketTradingMode
marketState
indicativeVolume
indicativePrice
bestStaticBidPrice
@ -47,6 +48,7 @@ export const MarketDataFieldsFragmentDoc = gql`
trigger
staticMidPrice
marketTradingMode
marketState
indicativeVolume
indicativePrice
bestStaticBidPrice

View File

@ -1,28 +1,49 @@
import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import { MarketDataFieldsFragmentDoc } from './market-data';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type MarketsDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } };
export type MarketsDataQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type MarketsDataQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', data?: { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } } | null } }> } | null };
export const MarketsDataFieldsFragmentDoc = gql`
fragment MarketsDataFields on MarketData {
market {
id
}
bestBidPrice
bestOfferPrice
markPrice
trigger
staticMidPrice
marketTradingMode
indicativeVolume
indicativePrice
bestStaticBidPrice
bestStaticOfferPrice
targetStake
suppliedStake
auctionStart
auctionEnd
}
`;
export const MarketsDataDocument = gql`
query MarketsData {
marketsConnection {
edges {
node {
data {
...MarketDataFields
...MarketsDataFields
}
}
}
}
}
${MarketDataFieldsFragmentDoc}`;
${MarketsDataFieldsFragmentDoc}`;
/**
* __useMarketsDataQuery__

View File

@ -6,6 +6,7 @@ fragment MarketDataUpdateFields on ObservableMarketData {
trigger
staticMidPrice
marketTradingMode
marketState
indicativeVolume
indicativePrice
bestStaticBidPrice
@ -28,6 +29,7 @@ fragment MarketDataFields on MarketData {
trigger
staticMidPrice
marketTradingMode
marketState
indicativeVolume
indicativePrice
bestStaticBidPrice

View File

@ -1,4 +1,4 @@
fragment MarketDataFields on MarketData {
fragment MarketsDataFields on MarketData {
market {
id
}
@ -23,7 +23,7 @@ query MarketsData {
edges {
node {
data {
...MarketDataFields
...MarketsDataFields
}
}
}

View File

@ -44,20 +44,18 @@ export const PriceCellChange = React.memo(
<span
className={`${signedNumberCssClass(
change
)} flex items-center gap-2 justify-end`}
)} flex items-center gap-2 font-mono text-ui-small`}
>
<Arrow value={change} />
<span className="flex items-center gap-2 font-mono text-ui-small">
<span data-testid="price-change-percentage">
{formatNumberPercentage(
new BigNumber(changePercentage.toString()),
2
)}
&nbsp;
</span>
<span data-testid="price-change">
{addDecimalsFormatNumber(change.toString(), decimalPlaces ?? 0, 3)}
</span>
<span data-testid="price-change-percentage">
{formatNumberPercentage(
new BigNumber(changePercentage.toString()),
2
)}
&nbsp;
</span>
<span data-testid="price-change">
{addDecimalsFormatNumber(change.toString(), decimalPlaces ?? 0, 3)}
</span>
</span>
);