feat(trading): market list snags and disable column removal (#5324)

Co-authored-by: bwallacee <ben@vega.xyz>
This commit is contained in:
m.ray 2023-11-22 15:51:39 +02:00 committed by GitHub
parent 1e9251c9c0
commit a5f2533a66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 97 additions and 26 deletions

View File

@ -1,7 +1,14 @@
import type { TypedDataAgGrid } from '@vegaprotocol/datagrid'; import type { TypedDataAgGrid } from '@vegaprotocol/datagrid';
import { AgGrid, PriceFlashCell } from '@vegaprotocol/datagrid'; import {
AgGrid,
PriceFlashCell,
useDataGridEvents,
} from '@vegaprotocol/datagrid';
import type { MarketMaybeWithData } from '@vegaprotocol/markets'; import type { MarketMaybeWithData } from '@vegaprotocol/markets';
import { useColumnDefs } from './use-column-defs'; import { useColumnDefs } from './use-column-defs';
import type { DataGridStore } from '../../stores/datagrid-store-slice';
import { type StateCreator, create } from 'zustand';
import { persist } from 'zustand/middleware';
export const getRowId = ({ data }: { data: { id: string } }) => data.id; export const getRowId = ({ data }: { data: { id: string } }) => data.id;
@ -18,8 +25,37 @@ const components = {
type Props = TypedDataAgGrid<MarketMaybeWithData>; type Props = TypedDataAgGrid<MarketMaybeWithData>;
export type DataGridSlice = {
gridStore: DataGridStore;
updateGridStore: (gridStore: DataGridStore) => void;
};
export const createDataGridSlice: StateCreator<DataGridSlice> = (set) => ({
gridStore: {},
updateGridStore: (newStore) => {
set((curr) => ({
gridStore: {
...curr.gridStore,
...newStore,
},
}));
},
});
const useMarketsStore = create<DataGridSlice>()(
persist(createDataGridSlice, {
name: 'vega_market_list_store',
})
);
export const MarketListTable = (props: Props) => { export const MarketListTable = (props: Props) => {
const columnDefs = useColumnDefs(); const columnDefs = useColumnDefs();
const gridStore = useMarketsStore((store) => store.gridStore);
const updateGridStore = useMarketsStore((store) => store.updateGridStore);
const gridStoreCallbacks = useDataGridEvents(gridStore, (colState) => {
updateGridStore(colState);
});
return ( return (
<AgGrid <AgGrid
@ -28,6 +64,7 @@ export const MarketListTable = (props: Props) => {
columnDefs={columnDefs} columnDefs={columnDefs}
components={components} components={components}
rowHeight={45} rowHeight={45}
{...gridStoreCallbacks}
{...props} {...props}
/> />
); );

View File

@ -51,6 +51,29 @@ export const useColumnDefs = () => {
headerName: t('Description'), headerName: t('Description'),
field: 'tradableInstrument.instrument.name', field: 'tradableInstrument.instrument.name',
}, },
{
headerName: t('Settlement asset'),
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
cellRenderer: ({
data,
}: VegaICellRendererParams<
MarketMaybeWithData,
'tradableInstrument.instrument.product.settlementAsset.symbol'
>) => {
const value = data && getAsset(data);
return value ? (
<ButtonLink
onClick={(e) => {
openAssetDetailsDialog(value.id, e.target as HTMLElement);
}}
>
{value.symbol}
</ButtonLink>
) : (
''
);
},
},
{ {
headerName: t('Trading mode'), headerName: t('Trading mode'),
field: 'tradingMode', field: 'tradingMode',
@ -142,27 +165,21 @@ export const useColumnDefs = () => {
}, },
}, },
{ {
headerName: t('Settlement asset'), headerName: t('Open Interest'),
field: 'tradableInstrument.instrument.product.settlementAsset.symbol', field: 'data.openInterest',
cellRenderer: ({ type: 'rightAligned',
valueFormatter: ({
data, data,
}: VegaICellRendererParams< }: VegaValueFormatterParams<
MarketMaybeWithData, MarketMaybeWithData,
'tradableInstrument.instrument.product.settlementAsset.symbol' 'data.openInterest'
>) => { >) =>
const value = data && getAsset(data); data?.data?.openInterest === undefined
return value ? ( ? '-'
<ButtonLink : addDecimalsFormatNumber(
onClick={(e) => { data?.data?.openInterest,
openAssetDetailsDialog(value.id, e.target as HTMLElement); data?.positionDecimalPlaces
}} ),
>
{value.symbol}
</ButtonLink>
) : (
''
);
},
}, },
{ {
headerName: t('Spread'), headerName: t('Spread'),

View File

@ -25,15 +25,15 @@ def test_table_headers(page: Page, create_markets):
headers = [ headers = [
"Market", "Market",
"Description", "Description",
"Settlement asset",
"Trading mode", "Trading mode",
"Status", "Status",
"Mark price", "Mark price",
"24h volume", "24h volume",
"Settlement asset", "Open Interest",
"Spread", "Spread",
"", "",
] ]
page.wait_for_selector('[data-testid="tab-open-markets"]', state="visible") page.wait_for_selector('[data-testid="tab-open-markets"]', state="visible")
page_headers = ( page_headers = (
page.get_by_test_id("tab-open-markets").locator(".ag-header-cell-text").all() page.get_by_test_id("tab-open-markets").locator(".ag-header-cell-text").all()
@ -157,4 +157,4 @@ def test_drag_and_drop_column(page: Page, create_markets):
page.locator(col_instrument_code).drag_to( page.locator(col_instrument_code).drag_to(
page.locator('.ag-header-row [col-id="data.bestBidPrice"]') page.locator('.ag-header-row [col-id="data.bestBidPrice"]')
) )
expect(page.locator(col_instrument_code)).to_have_attribute("aria-colindex", "8") expect(page.locator(col_instrument_code)).to_have_attribute("aria-colindex", "9")

View File

@ -39,6 +39,7 @@ export const AgGridThemed = ({
ref={gridRef} ref={gridRef}
overlayLoadingTemplate={t('Loading...')} overlayLoadingTemplate={t('Loading...')}
overlayNoRowsTemplate={t('No data')} overlayNoRowsTemplate={t('No data')}
suppressDragLeaveHidesColumns
{...defaultProps} {...defaultProps}
{...props} {...props}
/> />

View File

@ -3,12 +3,12 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; const defaultOptions = {} as const;
export type MarketsDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketState: Types.MarketState, 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 MarketsDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, openInterest: string, market: { __typename?: 'Market', id: string } };
export type MarketsDataQueryVariables = Types.Exact<{ [key: string]: never; }>; 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, marketState: Types.MarketState, 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 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, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, openInterest: string, market: { __typename?: 'Market', id: string } } | null } }> } | null };
export const MarketsDataFieldsFragmentDoc = gql` export const MarketsDataFieldsFragmentDoc = gql`
fragment MarketsDataFields on MarketData { fragment MarketsDataFields on MarketData {
@ -30,6 +30,7 @@ export const MarketsDataFieldsFragmentDoc = gql`
suppliedStake suppliedStake
auctionStart auctionStart
auctionEnd auctionEnd
openInterest
} }
`; `;
export const MarketsDataDocument = gql` export const MarketsDataDocument = gql`

View File

@ -17,6 +17,7 @@ fragment MarketsDataFields on MarketData {
suppliedStake suppliedStake
auctionStart auctionStart
auctionEnd auctionEnd
openInterest
} }
query MarketsData { query MarketsData {

View File

@ -40,6 +40,7 @@ export const createMarketsDataFragment = (
bestStaticBidPrice: '0', bestStaticBidPrice: '0',
bestStaticOfferPrice: '0', bestStaticOfferPrice: '0',
indicativeVolume: '0', indicativeVolume: '0',
openInterest: '0',
bestBidPrice: '0', bestBidPrice: '0',
bestOfferPrice: '0', bestOfferPrice: '0',
markPrice: '4612690058', markPrice: '4612690058',

View File

@ -267,6 +267,7 @@ export const preparePositions = (metrics: Position[], showClosed: boolean) => {
MarketState.STATE_ACTIVE, MarketState.STATE_ACTIVE,
MarketState.STATE_PENDING, MarketState.STATE_PENDING,
MarketState.STATE_SUSPENDED, MarketState.STATE_SUSPENDED,
MarketState.STATE_SUSPENDED_VIA_GOVERNANCE,
].includes(p.marketState) ].includes(p.marketState)
) { ) {
return true; return true;

View File

@ -4376,7 +4376,19 @@ export type Query = {
/** The last block process by the blockchain */ /** The last block process by the blockchain */
lastBlockHeight: Scalars['String']; lastBlockHeight: Scalars['String'];
/** /**
* Get ledger entries by asset, market, party, account type, transfer type within the given date range. * Get a list of ledger entries within the given date range. The date range is restricted to a maximum of 5 days.
* This query requests and sums the number of ledger entries from a given subset of accounts, specified via the 'filter' argument.
* It returns a time series - implemented as a list of AggregateLedgerEntry structs - with a row for every time
* the summed ledger entries of the set of specified accounts changes.
* Each account filter must contain no more than one party ID.
* At least one party ID must be specified in the from or to account filter.
*
* Entries can be filtered by:
* - the sending account (market ID, asset ID, account type)
* - receiving account (market ID, asset ID, account type)
* - sending AND receiving account
* - transfer type either in addition to the above filters or as a standalone option
*
* Note: The date range is restricted to any 5 days. * Note: The date range is restricted to any 5 days.
* If no start or end date is provided, only ledger entries from the last 5 days will be returned. * If no start or end date is provided, only ledger entries from the last 5 days will be returned.
* If a start and end date are provided, but the end date is more than 5 days after the start date, only data up to 5 days after the start date will be returned. * If a start and end date are provided, but the end date is more than 5 days after the start date, only data up to 5 days after the start date will be returned.