chore(trading): market list tweaks (#4756)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
parent
293288286b
commit
41804d9869
@ -59,7 +59,7 @@ export const MarketNameCell = ({
|
|||||||
(data as { market: Market })?.market?.tradableInstrument.instrument.product
|
(data as { market: Market })?.market?.tradableInstrument.instrument.product
|
||||||
.__typename;
|
.__typename;
|
||||||
|
|
||||||
if (!value) return;
|
if (!value) return null;
|
||||||
const content = (
|
const content = (
|
||||||
<>
|
<>
|
||||||
<span data-testid="market-code" data-market-id={id}>
|
<span data-testid="market-code" data-market-id={id}>
|
||||||
@ -72,7 +72,7 @@ export const MarketNameCell = ({
|
|||||||
<button
|
<button
|
||||||
onClick={handleOnClick}
|
onClick={handleOnClick}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className="block text-left text-ellipsis overflow-hidden whitespace-nowrap w-full"
|
className="block w-full overflow-hidden text-left text-ellipsis whitespace-nowrap"
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</button>
|
</button>
|
||||||
|
@ -83,8 +83,9 @@ describe('MarketsContainer', () => {
|
|||||||
await userEvent.click(
|
await userEvent.click(
|
||||||
screen.getByRole('button', {
|
screen.getByRole('button', {
|
||||||
name: (_name, element) =>
|
name: (_name, element) =>
|
||||||
(element.parentNode as Element)?.getAttribute('id') ===
|
(element.parentNode as Element)
|
||||||
'cell-market-actions-9',
|
?.getAttribute('id')
|
||||||
|
?.startsWith('cell-market-actions-') || false,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -126,36 +127,6 @@ describe('MarketsContainer', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('SuccessorMarketRenderer should be rendered', async () => {
|
|
||||||
const successorMarketName = 'Successor Market Name';
|
|
||||||
const spySuccessorMarketRenderer = jest
|
|
||||||
.fn()
|
|
||||||
.mockReturnValue(successorMarketName);
|
|
||||||
|
|
||||||
render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MarketsContainer
|
|
||||||
onSelect={spyOnSelect}
|
|
||||||
SuccessorMarketRenderer={spySuccessorMarketRenderer}
|
|
||||||
/>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(spySuccessorMarketRenderer).toHaveBeenCalled();
|
|
||||||
expect(
|
|
||||||
screen.getByRole('columnheader', {
|
|
||||||
name: (_name, element) =>
|
|
||||||
element.getAttribute('col-id') === 'successorMarketID',
|
|
||||||
})
|
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(
|
|
||||||
screen.getByRole('presentation', {
|
|
||||||
name: (_name, element) =>
|
|
||||||
element.getAttribute('id') === 'cell-successorMarketID-14',
|
|
||||||
})
|
|
||||||
).toHaveTextContent(successorMarketName);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('feature flag should hide successorMarketID column', async () => {
|
it('feature flag should hide successorMarketID column', async () => {
|
||||||
const mockedFlags = jest.mocked(FLAGS);
|
const mockedFlags = jest.mocked(FLAGS);
|
||||||
mockedFlags.SUCCESSOR_MARKETS = false;
|
mockedFlags.SUCCESSOR_MARKETS = false;
|
||||||
|
@ -4,8 +4,10 @@ import type { CellClickedEvent } from 'ag-grid-community';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { MarketListTable } from './market-list-table';
|
import { MarketListTable } from './market-list-table';
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
import { marketsWithDataProvider as dataProvider } from '../../markets-provider';
|
import { marketListProvider as dataProvider } from '../../markets-provider';
|
||||||
import type { MarketMaybeWithData } from '../../markets-provider';
|
import type { MarketMaybeWithData } from '../../markets-provider';
|
||||||
|
import { useYesterday } from '@vegaprotocol/react-helpers';
|
||||||
|
import { Interval } from '@vegaprotocol/types';
|
||||||
|
|
||||||
const POLLING_TIME = 2000;
|
const POLLING_TIME = 2000;
|
||||||
interface MarketsContainerProps {
|
interface MarketsContainerProps {
|
||||||
@ -17,9 +19,13 @@ export const MarketsContainer = ({
|
|||||||
onSelect,
|
onSelect,
|
||||||
SuccessorMarketRenderer,
|
SuccessorMarketRenderer,
|
||||||
}: MarketsContainerProps) => {
|
}: MarketsContainerProps) => {
|
||||||
|
const yesterday = useYesterday();
|
||||||
const { data, error, reload } = useDataProvider({
|
const { data, error, reload } = useDataProvider({
|
||||||
dataProvider,
|
dataProvider,
|
||||||
variables: undefined,
|
variables: {
|
||||||
|
since: new Date(yesterday).toISOString(),
|
||||||
|
interval: Interval.INTERVAL_I1H,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import type { ColDef } from 'ag-grid-community';
|
import type { ColDef, ValueFormatterParams } from 'ag-grid-community';
|
||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type {
|
import type {
|
||||||
@ -10,11 +10,14 @@ import type {
|
|||||||
import { COL_DEFS, SetFilter } from '@vegaprotocol/datagrid';
|
import { COL_DEFS, SetFilter } from '@vegaprotocol/datagrid';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { addDecimalsFormatNumber, toBigNum } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber, toBigNum } from '@vegaprotocol/utils';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import { FLAGS } from '@vegaprotocol/environment';
|
import type {
|
||||||
import type { MarketMaybeWithData } from '../../markets-provider';
|
MarketMaybeWithData,
|
||||||
|
MarketMaybeWithDataAndCandles,
|
||||||
|
} from '../../markets-provider';
|
||||||
import { MarketActionsDropdown } from './market-table-actions';
|
import { MarketActionsDropdown } from './market-table-actions';
|
||||||
|
import { calcCandleVolume } from '../../market-utils';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onMarketClick: (marketId: string, metaKey?: boolean) => void;
|
onMarketClick: (marketId: string, metaKey?: boolean) => void;
|
||||||
@ -32,26 +35,42 @@ export const useColumnDefs = ({ onMarketClick }: Props) => {
|
|||||||
field: 'tradableInstrument.instrument.code',
|
field: 'tradableInstrument.instrument.code',
|
||||||
cellRenderer: 'MarketName',
|
cellRenderer: 'MarketName',
|
||||||
cellRendererParams: { onMarketClick },
|
cellRendererParams: { onMarketClick },
|
||||||
|
flex: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: t('Description'),
|
headerName: t('Description'),
|
||||||
field: 'tradableInstrument.instrument.name',
|
field: 'tradableInstrument.instrument.name',
|
||||||
|
flex: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: t('Trading mode'),
|
headerName: t('Trading mode'),
|
||||||
field: 'tradingMode',
|
field: 'tradingMode',
|
||||||
valueFormatter: ({
|
cellRenderer: ({
|
||||||
data,
|
data,
|
||||||
}: VegaValueFormatterParams<MarketMaybeWithData, 'data'>) => {
|
}: VegaICellRendererParams<MarketMaybeWithData, 'data'>) => {
|
||||||
if (!data?.data) return '-';
|
if (!data?.data) return '-';
|
||||||
const { trigger, marketTradingMode } = data.data;
|
const { trigger, marketTradingMode } = data.data;
|
||||||
return marketTradingMode ===
|
|
||||||
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
const withTriggerInfo =
|
||||||
|
marketTradingMode ===
|
||||||
|
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
||||||
trigger &&
|
trigger &&
|
||||||
trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED
|
trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED;
|
||||||
? `${Schema.MarketTradingModeMapping[marketTradingMode]}
|
|
||||||
- ${Schema.AuctionTriggerMapping[trigger]}`
|
if (withTriggerInfo) {
|
||||||
: Schema.MarketTradingModeMapping[marketTradingMode];
|
return (
|
||||||
|
<Tooltip
|
||||||
|
description={`${Schema.MarketTradingModeMapping[marketTradingMode]}
|
||||||
|
- ${Schema.AuctionTriggerMapping[trigger]}`}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{Schema.MarketTradingModeMapping[marketTradingMode]}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Schema.MarketTradingModeMapping[marketTradingMode];
|
||||||
},
|
},
|
||||||
filter: SetFilter,
|
filter: SetFilter,
|
||||||
filterParams: {
|
filterParams: {
|
||||||
@ -71,69 +90,6 @@ export const useColumnDefs = ({ onMarketClick }: Props) => {
|
|||||||
set: Schema.MarketStateMapping,
|
set: Schema.MarketStateMapping,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
FLAGS.SUCCESSOR_MARKETS && {
|
|
||||||
headerName: t('Successor market'),
|
|
||||||
field: 'successorMarketID',
|
|
||||||
cellRenderer: 'SuccessorMarketRenderer',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headerName: t('Best bid'),
|
|
||||||
field: 'data.bestBidPrice',
|
|
||||||
type: 'rightAligned',
|
|
||||||
cellRenderer: 'PriceFlashCell',
|
|
||||||
filter: 'agNumberColumnFilter',
|
|
||||||
valueGetter: ({
|
|
||||||
data,
|
|
||||||
}: VegaValueGetterParams<MarketMaybeWithData>) => {
|
|
||||||
return data?.data?.bestBidPrice === undefined
|
|
||||||
? undefined
|
|
||||||
: toBigNum(
|
|
||||||
data?.data?.bestBidPrice,
|
|
||||||
data.decimalPlaces
|
|
||||||
).toNumber();
|
|
||||||
},
|
|
||||||
valueFormatter: ({
|
|
||||||
data,
|
|
||||||
}: VegaValueFormatterParams<
|
|
||||||
MarketMaybeWithData,
|
|
||||||
'data.bestBidPrice'
|
|
||||||
>) =>
|
|
||||||
data?.data?.bestBidPrice === undefined
|
|
||||||
? '-'
|
|
||||||
: addDecimalsFormatNumber(
|
|
||||||
data.data.bestBidPrice,
|
|
||||||
data.decimalPlaces
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headerName: t('Best offer'),
|
|
||||||
field: 'data.bestOfferPrice',
|
|
||||||
type: 'rightAligned',
|
|
||||||
cellRenderer: 'PriceFlashCell',
|
|
||||||
filter: 'agNumberColumnFilter',
|
|
||||||
valueGetter: ({
|
|
||||||
data,
|
|
||||||
}: VegaValueGetterParams<MarketMaybeWithData>) => {
|
|
||||||
return data?.data?.bestOfferPrice === undefined
|
|
||||||
? undefined
|
|
||||||
: toBigNum(
|
|
||||||
data?.data?.bestOfferPrice,
|
|
||||||
data.decimalPlaces
|
|
||||||
).toNumber();
|
|
||||||
},
|
|
||||||
valueFormatter: ({
|
|
||||||
data,
|
|
||||||
}: VegaValueFormatterParams<
|
|
||||||
MarketMaybeWithData,
|
|
||||||
'data.bestOfferPrice'
|
|
||||||
>) =>
|
|
||||||
data?.data?.bestOfferPrice === undefined
|
|
||||||
? '-'
|
|
||||||
: addDecimalsFormatNumber(
|
|
||||||
data.data.bestOfferPrice,
|
|
||||||
data.decimalPlaces
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
headerName: t('Mark price'),
|
headerName: t('Mark price'),
|
||||||
field: 'data.markPrice',
|
field: 'data.markPrice',
|
||||||
@ -157,6 +113,33 @@ export const useColumnDefs = ({ onMarketClick }: Props) => {
|
|||||||
data.decimalPlaces
|
data.decimalPlaces
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
headerName: t('24h volume'),
|
||||||
|
type: 'rightAligned',
|
||||||
|
field: 'data.candles',
|
||||||
|
valueGetter: ({
|
||||||
|
data,
|
||||||
|
}: VegaValueGetterParams<MarketMaybeWithDataAndCandles>) => {
|
||||||
|
if (!data) return 0;
|
||||||
|
const candles = data?.candles;
|
||||||
|
const vol = candles ? calcCandleVolume(candles) : '0';
|
||||||
|
return Number(vol);
|
||||||
|
},
|
||||||
|
valueFormatter: ({
|
||||||
|
data,
|
||||||
|
}: ValueFormatterParams<
|
||||||
|
MarketMaybeWithDataAndCandles,
|
||||||
|
'candles'
|
||||||
|
>) => {
|
||||||
|
const candles = data?.candles;
|
||||||
|
const vol = candles ? calcCandleVolume(candles) : '0';
|
||||||
|
const volume =
|
||||||
|
data && vol && vol !== '0'
|
||||||
|
? addDecimalsFormatNumber(vol, data.positionDecimalPlaces)
|
||||||
|
: '0.00';
|
||||||
|
return volume;
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
headerName: t('Settlement asset'),
|
headerName: t('Settlement asset'),
|
||||||
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||||
@ -181,6 +164,49 @@ export const useColumnDefs = ({ onMarketClick }: Props) => {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Spread'),
|
||||||
|
field: 'data.bestBidPrice',
|
||||||
|
type: 'rightAligned',
|
||||||
|
filter: 'agNumberColumnFilter',
|
||||||
|
cellRenderer: 'PriceFlashCell',
|
||||||
|
valueGetter: ({
|
||||||
|
data,
|
||||||
|
}: VegaValueGetterParams<MarketMaybeWithData>) => {
|
||||||
|
if (
|
||||||
|
!data ||
|
||||||
|
!data.data?.bestOfferPrice ||
|
||||||
|
!data.data?.bestBidPrice
|
||||||
|
) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const offer = toBigNum(
|
||||||
|
data.data.bestOfferPrice,
|
||||||
|
data.decimalPlaces
|
||||||
|
);
|
||||||
|
const bid = toBigNum(data.data.bestBidPrice, data.decimalPlaces);
|
||||||
|
|
||||||
|
const spread = offer.minus(bid).toNumber();
|
||||||
|
|
||||||
|
// The calculation above can result in '-0' being rendered after formatting
|
||||||
|
// so return Math.abs to remove it and just render '0'
|
||||||
|
if (spread === 0) {
|
||||||
|
return Math.abs(spread);
|
||||||
|
}
|
||||||
|
|
||||||
|
return spread;
|
||||||
|
},
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<
|
||||||
|
MarketMaybeWithData,
|
||||||
|
'data.bestBidPrice'
|
||||||
|
>) => {
|
||||||
|
if (!value) return '-';
|
||||||
|
return value.toString();
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
colId: 'market-actions',
|
colId: 'market-actions',
|
||||||
field: 'id',
|
field: 'id',
|
||||||
|
Loading…
Reference in New Issue
Block a user