* 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:
parent
9b356e53b4
commit
9ddedd0b78
@ -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',
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
3
apps/trading/client-pages/market/constants.ts
Normal file
3
apps/trading/client-pages/market/constants.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const NO_MARKET = t('No market');
|
@ -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;
|
||||
|
143
apps/trading/client-pages/market/trade-market-header.tsx
Normal file
143
apps/trading/client-pages/market/trade-market-header.tsx
Normal 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;
|
||||
};
|
1
apps/trading/components/market-state/index.ts
Normal file
1
apps/trading/components/market-state/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './market-state';
|
105
apps/trading/components/market-state/market-state.tsx
Normal file
105
apps/trading/components/market-state/market-state.tsx
Normal 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;
|
||||
};
|
@ -26,7 +26,7 @@ interface Props {
|
||||
initialTrigger?: Types.AuctionTrigger;
|
||||
}
|
||||
|
||||
export const MarketTradingModeComponent = ({
|
||||
export const MarketTradingMode = ({
|
||||
marketId,
|
||||
onSelect,
|
||||
isHeader = false,
|
||||
|
@ -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}
|
||||
|
@ -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: [
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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__
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
)}
|
||||
|
||||
</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
|
||||
)}
|
||||
|
||||
</span>
|
||||
<span data-testid="price-change">
|
||||
{addDecimalsFormatNumber(change.toString(), decimalPlaces ?? 0, 3)}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user