chore(trading): market list tweaks (#4756)

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
Art 2023-09-12 19:41:45 +02:00 committed by GitHub
parent 293288286b
commit 41804d9869
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 114 additions and 111 deletions

View File

@ -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>

View File

@ -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;

View File

@ -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(() => {

View File

@ -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',