From 43aff8e359ab059c5d59e9beaf942aa9295c825b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20G=C5=82ownia?= Date: Sat, 1 Jul 2023 13:02:23 +0200 Subject: [PATCH] chore(trading): ag-grid upgrade (#4187) --- .../app/components/assets/assets-table.tsx | 109 ++-- .../app/components/markets/markets-table.tsx | 130 ++--- .../components/proposals/proposals-table.tsx | 250 ++++----- apps/explorer/src/styles.css | 5 +- apps/governance/__mocks__/react-markdown.js | 6 - apps/governance/src/styles.css | 5 +- .../dashboard/market-list/market-list.tsx | 492 +++++++++--------- .../components/detail/providers/providers.tsx | 143 ++--- .../src/app/components/grid/grid.tsx | 12 +- .../src/integration/trading-orders.cy.ts | 2 +- .../src/integration/trading-positions.cy.ts | 2 +- apps/trading/pages/styles.css | 5 +- libs/accounts/src/lib/accounts-table.spec.tsx | 97 ++-- libs/accounts/src/lib/accounts-table.tsx | 34 +- libs/datagrid/src/index.ts | 1 - .../src/lib/cells/cumulative-vol-cell.tsx | 4 +- libs/datagrid/src/lib/cells/vol-cell.spec.tsx | 49 -- libs/datagrid/src/lib/cells/vol-cell.tsx | 50 -- libs/datagrid/src/lib/column-definitions.ts | 2 +- libs/datagrid/src/lib/type-helpers.ts | 11 +- libs/deposits/src/lib/deposits-table.tsx | 79 +-- libs/fills/src/lib/fills-table.tsx | 139 ++--- libs/ledger/src/lib/ledger-table.tsx | 284 +++++----- libs/liquidity/src/lib/liquidity-table.tsx | 2 +- libs/liquidity/src/lib/liquidity.mock.ts | 2 + libs/trades/src/lib/trades-table.tsx | 166 +++--- libs/withdraws/src/lib/withdrawals-table.tsx | 195 +++---- package.json | 4 +- yarn.lock | 16 +- 29 files changed, 1107 insertions(+), 1189 deletions(-) delete mode 100644 apps/governance/__mocks__/react-markdown.js delete mode 100644 libs/datagrid/src/lib/cells/vol-cell.spec.tsx delete mode 100644 libs/datagrid/src/lib/cells/vol-cell.tsx diff --git a/apps/explorer/src/app/components/assets/assets-table.tsx b/apps/explorer/src/app/components/assets/assets-table.tsx index a8d76beb2..fb245be95 100644 --- a/apps/explorer/src/app/components/assets/assets-table.tsx +++ b/apps/explorer/src/app/components/assets/assets-table.tsx @@ -1,15 +1,15 @@ +import { useMemo } from 'react'; import type { AssetFieldsFragment } from '@vegaprotocol/assets'; import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets'; import { t } from '@vegaprotocol/i18n'; import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import type { AgGridReact } from 'ag-grid-react'; -import { AgGridColumn } from 'ag-grid-react'; import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import type { VegaICellRendererParams } from '@vegaprotocol/datagrid'; import { useRef, useLayoutEffect } from 'react'; import { BREAKPOINT_MD } from '../../config/breakpoints'; import { useNavigate } from 'react-router-dom'; -import type { RowClickedEvent } from 'ag-grid-community'; +import type { RowClickedEvent, ColDef } from 'ag-grid-community'; type AssetsTableProps = { data: AssetFieldsFragment[] | null; @@ -31,6 +31,58 @@ export const AssetsTable = ({ data }: AssetsTableProps) => { }; }, []); + const columnDefs = useMemo( + () => [ + { headerName: t('Symbol'), field: 'symbol' }, + { headerName: t('Name'), field: 'name' }, + { + flex: 2, + headerName: t('ID'), + field: 'id', + hide: window.innerWidth < BREAKPOINT_MD, + }, + { + colId: 'type', + headerName: t('Type'), + field: 'source.__typename', + hide: window.innerWidth < BREAKPOINT_MD, + valueFormatter: ({ value }: { value?: string }) => + value ? AssetTypeMapping[value].value : '', + }, + { + headerName: t('Status'), + field: 'status', + hide: window.innerWidth < BREAKPOINT_MD, + valueFormatter: ({ value }: { value?: string }) => + value ? AssetStatusMapping[value].value : '', + }, + { + colId: 'actions', + headerName: '', + sortable: false, + filter: false, + resizable: false, + wrapText: true, + field: 'id', + cellRenderer: ({ + value, + }: VegaICellRendererParams) => + value ? ( + { + navigate(value); + }} + > + {t('View details')} + + ) : ( + '' + ), + }, + ], + [navigate] + ); + return ( { filterParams: { buttons: ['reset'] }, autoHeight: true, }} + columnDefs={columnDefs} suppressCellFocus={true} onRowClicked={({ data }: RowClickedEvent) => { navigate(data.id); }} - > - - - - - value && AssetTypeMapping[value].value - } - /> - - value && AssetStatusMapping[value].value - } - /> - ) => - value ? ( - { - navigate(value); - }} - > - {t('View details')} - - ) : ( - '' - ) - } - /> - + /> ); }; diff --git a/apps/explorer/src/app/components/markets/markets-table.tsx b/apps/explorer/src/app/components/markets/markets-table.tsx index a28a36161..32665f6d2 100644 --- a/apps/explorer/src/app/components/markets/markets-table.tsx +++ b/apps/explorer/src/app/components/markets/markets-table.tsx @@ -1,8 +1,9 @@ +import { useMemo } from 'react'; import type { MarketFieldsFragment } from '@vegaprotocol/markets'; import { t } from '@vegaprotocol/i18n'; import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import type { AgGridReact } from 'ag-grid-react'; -import { AgGridColumn } from 'ag-grid-react'; +import type { ColDef } from 'ag-grid-community'; import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import type { VegaICellRendererParams, @@ -39,54 +40,34 @@ export const MarketsTable = ({ data }: MarketsTableProps) => { }; }, []); - return ( - data.id} - overlayNoRowsTemplate={t('This chain has no markets')} - domLayout="autoHeight" - defaultColDef={{ - flex: 1, - resizable: true, - sortable: true, - filter: true, - filterParams: { buttons: ['reset'] }, - autoHeight: true, - }} - suppressCellFocus={true} - onRowClicked={({ data, event }: RowClickedEvent) => { - if ((event?.target as HTMLElement).tagName.toUpperCase() !== 'BUTTON') { - navigate(data.id); - } - }} - > - - - ( + () => [ + { + colId: 'code', + headerName: t('Code'), + field: 'tradableInstrument.instrument.code', + }, + { + colId: 'name', + headerName: t('Name'), + field: 'tradableInstrument.instrument.name', + }, + { + headerName: t('Status'), + field: 'state', + hide: window.innerWidth <= BREAKPOINT_MD, + valueGetter: ({ data, }: VegaValueGetterParams) => { return data?.state ? MarketStateMapping[data?.state] : '-'; - }} - /> - { ) : ( '' ); - }} - /> - - ) => value ? ( @@ -126,9 +107,34 @@ export const MarketsTable = ({ data }: MarketsTableProps) => { ) : ( '' - ) + ), + }, + ], + [openAssetDetailsDialog] + ); + + return ( + data.id} + overlayNoRowsTemplate={t('This chain has no markets')} + domLayout="autoHeight" + defaultColDef={{ + flex: 1, + resizable: true, + sortable: true, + filter: true, + filterParams: { buttons: ['reset'] }, + autoHeight: true, + }} + columnDefs={columnDefs} + suppressCellFocus={true} + onRowClicked={({ data, event }: RowClickedEvent) => { + if ((event?.target as HTMLElement).tagName.toUpperCase() !== 'BUTTON') { + navigate(data.id); } - /> - + }} + /> ); }; diff --git a/apps/explorer/src/app/components/proposals/proposals-table.tsx b/apps/explorer/src/app/components/proposals/proposals-table.tsx index c5068ba3a..6dc9d4b80 100644 --- a/apps/explorer/src/app/components/proposals/proposals-table.tsx +++ b/apps/explorer/src/app/components/proposals/proposals-table.tsx @@ -1,7 +1,6 @@ import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals'; import { VoteProgress } from '@vegaprotocol/proposals'; import type { AgGridReact } from 'ag-grid-react'; -import { AgGridColumn } from 'ag-grid-react'; import { ExternalLink } from '@vegaprotocol/ui-toolkit'; import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import type { @@ -9,7 +8,7 @@ import type { VegaValueFormatterParams, } from '@vegaprotocol/datagrid'; import { useLayoutEffect, useMemo, useRef, useState } from 'react'; -import type { RowClickedEvent } from 'ag-grid-community'; +import type { RowClickedEvent, ColDef } from 'ag-grid-community'; import { getDateTimeFormat } from '@vegaprotocol/utils'; import { t } from '@vegaprotocol/i18n'; import { @@ -64,7 +63,128 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => { title: '', content: null, }); - + const columnDefs = useMemo( + () => [ + { + colId: 'title', + headerName: t('Title'), + field: 'rationale.title', + flex: 2, + wrapText: true, + }, + { + colId: 'type', + maxWidth: 180, + hide: window.innerWidth <= BREAKPOINT_MD, + headerName: t('Type'), + field: 'terms.change.__typename', + }, + { + maxWidth: 100, + headerName: t('State'), + field: 'state', + valueFormatter: ({ + value, + }: VegaValueFormatterParams) => { + return value ? ProposalStateMapping[value] : '-'; + }, + }, + { + colId: 'voting', + maxWidth: 100, + hide: window.innerWidth <= BREAKPOINT_MD, + headerName: t('Voting'), + cellRenderer: ({ + data, + }: VegaICellRendererParams) => { + if (data) { + const yesTokens = new BigNumber(data.votes.yes.totalTokens); + const noTokens = new BigNumber(data.votes.no.totalTokens); + const totalTokensVoted = yesTokens.plus(noTokens); + const yesPercentage = totalTokensVoted.isZero() + ? new BigNumber(0) + : yesTokens.multipliedBy(100).dividedBy(totalTokensVoted); + return ( +
+ +
+ ); + } + return '-'; + }, + }, + { + colId: 'cDate', + maxWidth: 150, + hide: window.innerWidth <= BREAKPOINT_MD, + headerName: t('Closing date'), + field: 'terms.closingDatetime', + valueFormatter: ({ + value, + }: VegaValueFormatterParams< + ProposalListFieldsFragment, + 'terms.closingDatetime' + >) => { + return value ? getDateTimeFormat().format(new Date(value)) : '-'; + }, + }, + { + colId: 'eDate', + maxWidth: 150, + hide: window.innerWidth <= BREAKPOINT_MD, + headerName: t('Enactment date'), + field: 'terms.enactmentDatetime', + valueFormatte: ({ + value, + }: VegaValueFormatterParams< + ProposalListFieldsFragment, + 'terms.enactmentDatetime' + >) => { + return value ? getDateTimeFormat().format(new Date(value)) : '-'; + }, + }, + { + colId: 'actions', + minWidth: window.innerWidth > BREAKPOINT_MD ? 221 : 80, + maxWidth: 221, + sortable: false, + filter: false, + resizable: false, + cellRenderer: ({ + data, + }: VegaICellRendererParams) => { + const proposalPage = tokenLink( + TOKEN_PROPOSAL.replace(':id', data?.id || '') + ); + const openDialog = () => { + if (!data) return; + setDialog({ + open: true, + title: data.rationale.title, + content: data.terms, + }); + }; + return ( +
+ {' '} + + {t('Open in Governance')} + + + {t('Open')} + +
+ ); + }, + }, + ], + [requiredMajorityPercentage, tokenLink] + ); return ( <> { filterParams: { buttons: ['reset'] }, autoHeight: true, }} + columnDefs={columnDefs} suppressCellFocus={true} onRowClicked={({ data, event }: RowClickedEvent) => { if ( @@ -94,128 +215,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => { window.open(proposalPage, '_blank'); } }} - > - - - ) => { - return value ? ProposalStateMapping[value] : '-'; - }} - /> - ) => { - if (data) { - const yesTokens = new BigNumber(data.votes.yes.totalTokens); - const noTokens = new BigNumber(data.votes.no.totalTokens); - const totalTokensVoted = yesTokens.plus(noTokens); - const yesPercentage = totalTokensVoted.isZero() - ? new BigNumber(0) - : yesTokens.multipliedBy(100).dividedBy(totalTokensVoted); - return ( -
- -
- ); - } - return '-'; - }} - /> - ) => { - return value ? getDateTimeFormat().format(new Date(value)) : '-'; - }} - /> - ) => { - return value ? getDateTimeFormat().format(new Date(value)) : '-'; - }} - /> - BREAKPOINT_MD ? 221 : 80} - maxWidth={221} - sortable={false} - filter={false} - resizable={false} - cellRenderer={({ - data, - }: VegaICellRendererParams) => { - const proposalPage = tokenLink( - TOKEN_PROPOSAL.replace(':id', data?.id || '') - ); - const openDialog = () => { - if (!data) return; - setDialog({ - open: true, - title: data.rationale.title, - content: data.terms, - }); - }; - return ( -
- {' '} - - {t('Open in Governance')} - - - {t('Open')} - -
- ); - }} - /> -
+ /> setDialog({ ...dialog, open: isOpen })} diff --git a/apps/explorer/src/styles.css b/apps/explorer/src/styles.css index afaaea60f..37661f278 100644 --- a/apps/explorer/src/styles.css +++ b/apps/explorer/src/styles.css @@ -1,6 +1,5 @@ -@import 'ag-grid-community/dist/styles/ag-grid.css'; -@import 'ag-grid-community/dist/styles/ag-theme-balham.css'; -@import 'ag-grid-community/dist/styles/ag-theme-balham-dark.css'; +@import 'ag-grid-community/styles/ag-grid.css'; +@import 'ag-grid-community/styles/ag-theme-balham.css'; /* You can add global styles to this file, and also import other style files */ @tailwind base; diff --git a/apps/governance/__mocks__/react-markdown.js b/apps/governance/__mocks__/react-markdown.js deleted file mode 100644 index 70942790b..000000000 --- a/apps/governance/__mocks__/react-markdown.js +++ /dev/null @@ -1,6 +0,0 @@ -function ReactMarkdown({ children }) { - // eslint-disable-next-line react/jsx-no-useless-fragment - return <>{children}; -} - -export default ReactMarkdown; diff --git a/apps/governance/src/styles.css b/apps/governance/src/styles.css index 9e46f201b..60b6b57fc 100644 --- a/apps/governance/src/styles.css +++ b/apps/governance/src/styles.css @@ -1,6 +1,5 @@ -@import 'ag-grid-community/dist/styles/ag-grid.css'; -@import 'ag-grid-community/dist/styles/ag-theme-balham.css'; -@import 'ag-grid-community/dist/styles/ag-theme-balham-dark.css'; +@import 'ag-grid-community/styles/ag-grid.css'; +@import 'ag-grid-community/styles/ag-theme-balham.css'; @tailwind base; @tailwind components; diff --git a/apps/liquidity-provision-dashboard/src/app/components/dashboard/market-list/market-list.tsx b/apps/liquidity-provision-dashboard/src/app/components/dashboard/market-list/market-list.tsx index 4a413dcf4..07302bd9f 100644 --- a/apps/liquidity-provision-dashboard/src/app/components/dashboard/market-list/market-list.tsx +++ b/apps/liquidity-provision-dashboard/src/app/components/dashboard/market-list/market-list.tsx @@ -21,11 +21,14 @@ import { HealthBar, TooltipCellComponent, } from '@vegaprotocol/ui-toolkit'; -import type { GetRowIdParams, RowClickedEvent } from 'ag-grid-community'; -import 'ag-grid-community/dist/styles/ag-grid.css'; -import 'ag-grid-community/dist/styles/ag-theme-alpine.css'; -import { AgGridColumn } from 'ag-grid-react'; -import { useCallback, useState } from 'react'; +import type { + GetRowIdParams, + RowClickedEvent, + ColDef, +} from 'ag-grid-community'; +import 'ag-grid-community/styles/ag-grid.css'; +import 'ag-grid-community/styles/ag-theme-alpine.css'; +import { useCallback, useState, useMemo } from 'react'; import { Grid } from '../../grid'; import { HealthDialog } from '../../health-dialog'; @@ -39,6 +42,234 @@ export const MarketList = () => { const consoleLink = useLinks(DApp.Console); const getRowId = useCallback(({ data }: GetRowIdParams) => data.id, []); + const columnDefs = useMemo( + () => [ + { + headerName: t('Market (futures)'), + field: 'tradableInstrument.instrument.name', + cellRenderer: ({ value, data }: { value: string; data: Market }) => { + return ( + <> + {value} + + { + data?.tradableInstrument?.instrument?.product?.settlementAsset + ?.symbol + } + + + ); + }, + minWidth: 100, + flex: 1, + headerTooltip: t('The market name and settlement asset'), + }, + + { + headerName: t('Market Code'), + headerTooltip: t( + 'The market code is a unique identifier for this market' + ), + field: 'tradableInstrument.instrument.code', + }, + + { + headerName: t('Type'), + headerTooltip: t('Type'), + field: 'tradableInstrument.instrument.product.__typename', + }, + + { + headerName: t('Last Price'), + headerTooltip: t('Latest price for this market'), + field: 'data.markPrice', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => + value && data + ? formatWithAsset( + value, + data.tradableInstrument.instrument.product.settlementAsset + ) + : '-', + }, + + { + headerName: t('Change (24h)'), + headerTooltip: t('Change in price over the last 24h'), + cellRenderer: ({ + data, + }: VegaValueFormatterParams) => { + if (data && data.candles) { + const prices = data.candles.map((candle) => candle.close); + return ( + + ); + } else return
{t('-')}
; + }, + }, + + { + headerName: t('Volume (24h)'), + field: 'dayVolume', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => + value && data + ? `${addDecimalsFormatNumber( + value, + data.tradableInstrument.instrument.product.settlementAsset + .decimals + )} (${displayChange(data.volumeChange)})` + : '-', + headerTooltip: t('The trade volume over the last 24h'), + }, + + { + headerName: t('Total staked by LPs'), + field: 'liquidityCommitted', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => + data && value + ? formatWithAsset( + value.toString(), + data.tradableInstrument.instrument.product.settlementAsset + ) + : '-', + headerTooltip: t('The amount of funds allocated to provide liquidity'), + }, + + { + headerName: t('Target stake'), + field: 'target', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => + data && value + ? formatWithAsset( + value, + data.tradableInstrument.instrument.product.settlementAsset + ) + : '-', + headerTooltip: t( + 'The ideal committed liquidity to operate the market. If total commitment currently below this level then LPs can set the fee level with new commitment.' + ), + }, + + { + headerName: t('% Target stake met'), + valueFormatter: ({ data }: VegaValueFormatterParams) => { + if (data) { + const roundedPercentage = + parseInt( + (data.liquidityCommitted / parseFloat(data.target)).toFixed(0) + ) * 100; + const display = Number.isNaN(roundedPercentage) + ? 'N/A' + : formatNumberPercentage(toBigNum(roundedPercentage, 0), 0); + return display; + } else return '-'; + }, + headerTooltip: t('% Target stake met'), + }, + + { + headerName: t('Fee levels'), + field: 'fees', + valueFormatter: ({ value }: VegaValueFormatterParams) => + value ? `${value.factors.liquidityFee}%` : '-', + headerTooltip: t('Fee level for this market'), + }, + + { + headerName: t('Status'), + field: 'tradingMode', + cellRenderer: ({ + value, + data, + }: { + value: Schema.MarketTradingMode; + data: Market; + }) => { + return ; + }, + headerTooltip: t( + 'The current market status - those below the target stake mark are most in need of liquidity' + ), + }, + + { + headerComponent: () => { + return ( +
+ {t('Health')}{' '} + +
+ ); + }, + field: 'tradingMode', + cellRenderer: ({ + value, + data, + }: { + value: Schema.MarketTradingMode; + data: Market; + }) => ( + + ), + sortable: false, + cellStyle: { overflow: 'unset' }, + }, + { + headerName: t('Age'), + field: 'marketTimestamps.open', + headerTooltip: t('Age of the market'), + valueFormatter: ({ + value, + }: VegaValueFormatterParams) => { + return value ? formatDistanceToNow(new Date(value)) : '-'; + }, + }, + { + headerName: t('Closing Time'), + field: 'tradableInstrument.instrument.metadata.tags', + headerTooltip: t('Closing time of the market'), + valueFormatter: ({ data }: VegaValueFormatterParams) => { + let expiry; + if (data?.tradableInstrument.instrument.metadata.tags) { + expiry = getExpiryDate( + data?.tradableInstrument.instrument.metadata.tags, + data?.marketTimestamps.close, + data?.state + ); + } + return expiry ? expiry : '-'; + }, + }, + ], + [] + ); return ( @@ -64,258 +295,11 @@ export const MarketList = () => { cellClass: ['flex', 'flex-col', 'justify-center'], tooltipComponent: TooltipCellComponent, }} + columnDefs={columnDefs} getRowId={getRowId} isRowClickable tooltipShowDelay={500} - > - { - return ( - <> - {value} - - { - data?.tradableInstrument?.instrument?.product - ?.settlementAsset?.symbol - } - - - ); - }} - minWidth={100} - flex="1" - headerTooltip={t('The market name and settlement asset')} - /> - - - - - - ) => - value && data - ? formatWithAsset( - value, - data.tradableInstrument.instrument.product.settlementAsset - ) - : '-' - } - /> - - ) => { - if (data && data.candles) { - const prices = data.candles.map((candle) => candle.close); - return ( - - ); - } else return
{t('-')}
; - }} - /> - - ) => - value && data - ? `${addDecimalsFormatNumber( - value, - data.tradableInstrument.instrument.product.settlementAsset - .decimals - )} (${displayChange(data.volumeChange)})` - : '-' - } - headerTooltip={t('The trade volume over the last 24h')} - /> - - ) => - data && value - ? formatWithAsset( - value.toString(), - data.tradableInstrument.instrument.product.settlementAsset - ) - : '-' - } - headerTooltip={t( - 'The amount of funds allocated to provide liquidity' - )} - /> - - ) => - data && value - ? formatWithAsset( - value, - data.tradableInstrument.instrument.product.settlementAsset - ) - : '-' - } - headerTooltip={t( - 'The ideal committed liquidity to operate the market. If total commitment currently below this level then LPs can set the fee level with new commitment.' - )} - /> - - ) => { - if (data) { - const roundedPercentage = - parseInt( - (data.liquidityCommitted / parseFloat(data.target)).toFixed( - 0 - ) - ) * 100; - const display = Number.isNaN(roundedPercentage) - ? 'N/A' - : formatNumberPercentage(toBigNum(roundedPercentage, 0), 0); - return display; - } else return '-'; - }} - headerTooltip={t('% Target stake met')} - /> - - ) => - value ? `${value.factors.liquidityFee}%` : '-' - } - headerTooltip={t('Fee level for this market')} - /> - - { - return ( - - ); - }} - headerTooltip={t( - 'The current market status - those below the target stake mark are most in need of liquidity' - )} - /> - - { - return ( -
- {t('Health')}{' '} - -
- ); - }} - field="tradingMode" - cellRenderer={({ - value, - data, - }: { - value: Schema.MarketTradingMode; - data: Market; - }) => ( - - )} - sortable={false} - cellStyle={{ overflow: 'unset' }} - /> - ) => { - return value ? formatDistanceToNow(new Date(value)) : '-'; - }} - /> - ) => { - let expiry; - if (data?.tradableInstrument.instrument.metadata.tags) { - expiry = getExpiryDate( - data?.tradableInstrument.instrument.metadata.tags, - data?.marketTimestamps.close, - data?.state - ); - } - return expiry ? expiry : '-'; - }} - /> - - + /> { diff --git a/apps/liquidity-provision-dashboard/src/app/components/detail/providers/providers.tsx b/apps/liquidity-provision-dashboard/src/app/components/detail/providers/providers.tsx index 9a1a79b56..4186a135e 100644 --- a/apps/liquidity-provision-dashboard/src/app/components/detail/providers/providers.tsx +++ b/apps/liquidity-provision-dashboard/src/app/components/detail/providers/providers.tsx @@ -1,7 +1,6 @@ -import { useCallback } from 'react'; -import { AgGridColumn } from 'ag-grid-react'; +import { useCallback, useMemo } from 'react'; -import type { GetRowIdParams } from 'ag-grid-community'; +import type { GetRowIdParams, ColDef } from 'ag-grid-community'; import { t } from '@vegaprotocol/i18n'; import type { @@ -36,6 +35,75 @@ export const LPProvidersGrid = ({ }; }) => { const getRowId = useCallback(({ data }: GetRowIdParams) => data.party.id, []); + const columnDefs = useMemo( + () => [ + { + headerName: t('LPs'), + field: 'party.id', + flex: 1, + minWidth: 100, + headerTooltip: t('Liquidity providers'), + }, + { + headerName: t('Duration'), + valueFormatter: formatToHours, + field: 'createdAt', + headerTooltip: t('Time in market'), + }, + { + headerName: t('Equity-like share'), + field: 'equityLikeShare', + valueFormatter: ({ value }: { value?: string | null }) => { + return value + ? `${parseFloat(parseFloat(value).toFixed(2)) * 100}%` + : ''; + }, + headerTooltip: t( + 'The share of the markets liquidity held - the earlier you commit liquidity the greater % fees you earn' + ), + minWidth: 140, + }, + { + headerName: t('committed bond'), + field: 'commitmentAmount', + valueFormatter: ({ value }: { value?: string | null }) => + value ? formatWithAsset(value, settlementAsset) : '0', + headerTooltip: t('The amount of funds allocated to provide liquidity'), + minWidth: 140, + }, + { + headerName: t('Margin Req.'), + field: 'margin', + headerTooltip: t( + 'Margin required for arising positions based on liquidity commitment' + ), + }, + { + headerName: t('24h Fees'), + field: 'fees', + headerTooltip: t( + 'Total fees earned by the liquidity provider in the last 24 hours' + ), + }, + { + headerName: t('Fee level'), + valueFormatter: ({ value }: { value?: string | null }) => `${value}%`, + field: 'fee', + headerTooltip: t( + "The market's liquidity fee, or the percentage of a trade's value which is collected from the price taker for every trade" + ), + }, + + { + headerName: t('APY'), + field: 'apy', + headerTooltip: t( + 'An annualised estimate based on the total liquidity provision fees and maker fees collected by liquidity providers, the maximum margin needed and maximum commitment (bond) over the course of 7 epochs' + ), + }, + ], + [settlementAsset] + ); return ( - - - { - return value - ? `${parseFloat(parseFloat(value).toFixed(2)) * 100}%` - : ''; - }} - headerTooltip={t( - 'The share of the markets liquidity held - the earlier you commit liquidity the greater % fees you earn' - )} - minWidth={140} - /> - - value ? formatWithAsset(value, settlementAsset) : '0' - } - headerTooltip={t('The amount of funds allocated to provide liquidity')} - minWidth={140} - /> - - - `${value}%`} - field="fee" - headerTooltip={t( - "The market's liquidity fee, or the percentage of a trade's value which is collected from the price taker for every trade" - )} - /> - - - + /> ); }; diff --git a/apps/liquidity-provision-dashboard/src/app/components/grid/grid.tsx b/apps/liquidity-provision-dashboard/src/app/components/grid/grid.tsx index 1100fdad3..a94b515d4 100644 --- a/apps/liquidity-provision-dashboard/src/app/components/grid/grid.tsx +++ b/apps/liquidity-provision-dashboard/src/app/components/grid/grid.tsx @@ -1,5 +1,4 @@ import { useRef, useCallback, useEffect } from 'react'; -import type { ReactNode } from 'react'; import { AgGridReact } from 'ag-grid-react'; import type { AgGridReactProps, @@ -7,18 +6,17 @@ import type { AgGridReact as AgGridReactType, } from 'ag-grid-react'; import classNames from 'classnames'; -import 'ag-grid-community/dist/styles/ag-grid.css'; -import 'ag-grid-community/dist/styles/ag-theme-alpine.css'; +import 'ag-grid-community/styles/ag-grid.css'; +import 'ag-grid-community/styles/ag-theme-alpine.css'; import './grid.scss'; type Props = (AgGridReactProps | AgReactUiProps) & { isRowClickable?: boolean; style?: React.CSSProperties; - children: ReactNode; }; -export const Grid = ({ isRowClickable, children, ...props }: Props) => { +export const Grid = ({ isRowClickable, ...props }: Props) => { const gridRef = useRef(null); const resizeGrid = useCallback(() => { @@ -44,8 +42,6 @@ export const Grid = ({ isRowClickable, children, ...props }: Props) => { onGridReady={handleOnGridReady} suppressRowClickSelection {...props} - > - {children} - + /> ); }; diff --git a/apps/trading-e2e/src/integration/trading-orders.cy.ts b/apps/trading-e2e/src/integration/trading-orders.cy.ts index 5ce874517..9c45973a1 100644 --- a/apps/trading-e2e/src/integration/trading-orders.cy.ts +++ b/apps/trading-e2e/src/integration/trading-orders.cy.ts @@ -90,7 +90,7 @@ describe('orders list', { tags: '@smoke', testIsolation: true }, () => { cy.getByTestId('All').click(); cy.get(`[row-id="${partiallyFilledId}"]`) - .eq(1) + .eq(0) .within(() => { cy.get(`[col-id='${orderStatus}']`).should( 'have.text', diff --git a/apps/trading-e2e/src/integration/trading-positions.cy.ts b/apps/trading-e2e/src/integration/trading-positions.cy.ts index 9159063d6..b8e922dc2 100644 --- a/apps/trading-e2e/src/integration/trading-positions.cy.ts +++ b/apps/trading-e2e/src/integration/trading-positions.cy.ts @@ -108,7 +108,7 @@ describe('positions', { tags: '@regression', testIsolation: true }, () => { cy.get( '[row-id="02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65-market-2"]' ) - .eq(1) + .eq(0) .within(() => { emptyCells.forEach((cell) => { cy.get(`[col-id="${cell}"]`).should('contain.text', '-'); diff --git a/apps/trading/pages/styles.css b/apps/trading/pages/styles.css index ca6a7e452..9c38191bb 100644 --- a/apps/trading/pages/styles.css +++ b/apps/trading/pages/styles.css @@ -1,6 +1,5 @@ -@import 'ag-grid-community/dist/styles/ag-grid.css'; -@import 'ag-grid-community/dist/styles/ag-theme-balham.css'; -@import 'ag-grid-community/dist/styles/ag-theme-balham-dark.css'; +@import 'ag-grid-community/styles/ag-grid.css'; +@import 'ag-grid-community/styles/ag-theme-balham.css'; @tailwind base; @tailwind components; diff --git a/libs/accounts/src/lib/accounts-table.spec.tsx b/libs/accounts/src/lib/accounts-table.spec.tsx index 00fcc457c..c81030d37 100644 --- a/libs/accounts/src/lib/accounts-table.spec.tsx +++ b/libs/accounts/src/lib/accounts-table.spec.tsx @@ -44,62 +44,79 @@ describe('AccountsTable', () => { }); it('should apply correct formatting', async () => { - await act(async () => { - render( - null} - isReadOnly={false} - /> - ); - }); + const { container } = render( + null} + isReadOnly={false} + /> + ); + const cells = await screen.findAllByRole('gridcell'); const expectedValues = ['tBTC', '1,256.00', '1,256.00', '2,512.00', '']; cells.forEach((cell, i) => { expect(cell).toHaveTextContent(expectedValues[i]); }); - const rows = await screen.findAllByRole('row'); - expect(rows.length).toBe(6); + const rows = container.querySelector('.ag-center-cols-container'); + expect(rows?.childElementCount).toBe(1); }); it('should apply correct formatting in view as user mode', async () => { - await act(async () => { - render( - null} - isReadOnly={true} - /> - ); - }); + const { container } = render( + null} + isReadOnly={true} + /> + ); + const cells = await screen.findAllByRole('gridcell'); const expectedValues = ['tBTC', '1,256.00', '1,256.00', '2,512.00', '']; expect(cells.length).toBe(expectedValues.length); cells.forEach((cell, i) => { expect(cell).toHaveTextContent(expectedValues[i]); }); - const rows = await screen.findAllByRole('row'); - expect(rows.length).toBe(6); + const rows = container.querySelector('.ag-center-cols-container'); + expect(rows?.childElementCount).toBe(1); }); - it('should not add first asset as pinned', async () => { - await act(async () => { - render( - null} - isReadOnly={false} - pinnedAsset={{ - decimals: 5, - id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c', - symbol: 'tBTC', - name: 'tBTC', - }} - /> - ); - }); - const rows = await screen.findAllByRole('row'); - expect(rows.length).toBe(6); + it('should add asset as pinned', async () => { + const { container, rerender } = render( + null} + isReadOnly={false} + pinnedAsset={{ + decimals: 5, + id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c', + symbol: 'tBTC', + name: 'tBTC', + }} + /> + ); + await screen.findAllByRole('rowgroup'); + let rows = container.querySelector('.ag-center-cols-container'); + expect(rows?.childElementCount).toBe(0); + let pinnedRows = container.querySelector('.ag-floating-top-container'); + expect(pinnedRows?.childElementCount ?? 0).toBe(1); + + rerender( + null} + isReadOnly={false} + pinnedAsset={{ + decimals: 5, + id: '', + symbol: 'tBTC', + name: 'tBTC', + }} + /> + ); + rows = container.querySelector('.ag-center-cols-container'); + expect(rows?.childElementCount ?? 0).toBe(1); + pinnedRows = container.querySelector('.ag-floating-top-container'); + expect(pinnedRows?.childElementCount ?? 0).toBe(1); }); it('should get correct account data', () => { diff --git a/libs/accounts/src/lib/accounts-table.tsx b/libs/accounts/src/lib/accounts-table.tsx index 54755ac45..d95da2e81 100644 --- a/libs/accounts/src/lib/accounts-table.tsx +++ b/libs/accounts/src/lib/accounts-table.tsx @@ -17,7 +17,7 @@ import { TooltipCellComponent } from '@vegaprotocol/ui-toolkit'; import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import type { IGetRowsParams, - RowNode, + IRowNode, RowHeightParams, ColDef, } from 'ag-grid-community'; @@ -45,8 +45,8 @@ export const percentageValue = (part: string, total: string) => { export const accountValuesComparator = ( valueA: string, valueB: string, - nodeA: RowNode, - nodeB: RowNode + nodeA: IRowNode, + nodeB: IRowNode ) => { if (isNumeric(valueA) && isNumeric(valueB)) { const a = toBigNum(valueA, nodeA.data.asset?.decimals); @@ -83,20 +83,22 @@ export const AccountTable = forwardRef( onClickDeposit, onClickBreakdown, rowData, + isReadOnly, + pinnedAsset, ...props }, ref ) => { - const pinnedAsset = useMemo(() => { - if (!props.pinnedAsset) { + const pinnedRow = useMemo(() => { + if (!pinnedAsset) { return; } const currentPinnedAssetRow = rowData?.find( - (row) => row.asset.id === props.pinnedAsset?.id + (row) => row.asset.id === pinnedAsset?.id ); if (!currentPinnedAssetRow) { return { - asset: props.pinnedAsset, + asset: pinnedAsset, available: '0', used: '0', total: '0', @@ -104,7 +106,7 @@ export const AccountTable = forwardRef( }; } return currentPinnedAssetRow; - }, [props.pinnedAsset, rowData]); + }, [pinnedAsset, rowData]); const { getRowHeight } = props; @@ -112,17 +114,17 @@ export const AccountTable = forwardRef( (params: RowHeightParams) => { if ( params.node.rowPinned && - params.data.asset.id === props.pinnedAsset?.id && + params.data.asset.id === pinnedAsset?.id && new BigNumber(params.data.total).isLessThanOrEqualTo(0) ) { return 32; } return getRowHeight ? getRowHeight(params) : undefined; }, - [props.pinnedAsset?.id, getRowHeight] + [pinnedAsset?.id, getRowHeight] ); - const showDepositButton = pinnedAsset?.balance === '0'; + const showDepositButton = pinnedRow?.balance === '0'; const colDefs = useMemo(() => { const defs: ColDef[] = [ @@ -266,7 +268,7 @@ export const AccountTable = forwardRef( ); } - return props.isReadOnly ? null : ( + return isReadOnly ? null : ( ( onClickBreakdown, onClickDeposit, onClickWithdraw, - props.isReadOnly, + isReadOnly, showDepositButton, ]); - const data = rowData?.filter( - (data) => data.asset.id !== props.pinnedAsset?.id - ); + const data = rowData?.filter((data) => data.asset.id !== pinnedAsset?.id); return ( ( }} columnDefs={colDefs} getRowHeight={getPinnedAssetRowHeight} - pinnedTopRowData={pinnedAsset ? [pinnedAsset] : undefined} + pinnedTopRowData={pinnedRow ? [pinnedRow] : undefined} /> ); } diff --git a/libs/datagrid/src/index.ts b/libs/datagrid/src/index.ts index 94443e56b..758100e6d 100644 --- a/libs/datagrid/src/index.ts +++ b/libs/datagrid/src/index.ts @@ -8,7 +8,6 @@ export * from './lib/cells/numeric-cell'; export * from './lib/cells/price-cell'; export * from './lib/cells/price-change-cell'; export * from './lib/cells/price-flash-cell'; -export * from './lib/cells/vol-cell'; export * from './lib/cells/centered-grid-cell'; export * from './lib/cells/market-name-cell'; export * from './lib/cells/order-type-cell'; diff --git a/libs/datagrid/src/lib/cells/cumulative-vol-cell.tsx b/libs/datagrid/src/lib/cells/cumulative-vol-cell.tsx index 2015a08e2..7d6043f45 100644 --- a/libs/datagrid/src/lib/cells/cumulative-vol-cell.tsx +++ b/libs/datagrid/src/lib/cells/cumulative-vol-cell.tsx @@ -1,8 +1,10 @@ import { memo } from 'react'; -import { BID_COLOR, ASK_COLOR } from './vol-cell'; import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils'; import { NumericCell } from './numeric-cell'; +import { theme } from '@vegaprotocol/tailwindcss-config'; +const BID_COLOR = theme.colors.vega.green.DEFAULT; +const ASK_COLOR = theme.colors.vega.pink.DEFAULT; export interface CumulativeVolProps { ask?: number; bid?: number; diff --git a/libs/datagrid/src/lib/cells/vol-cell.spec.tsx b/libs/datagrid/src/lib/cells/vol-cell.spec.tsx deleted file mode 100644 index 5c31dd44d..000000000 --- a/libs/datagrid/src/lib/cells/vol-cell.spec.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import { VolCell } from './vol-cell'; -import * as tailwind from '@vegaprotocol/tailwindcss-config'; - -describe('VolCell', () => { - const significantPart = '12,345'; - const decimalPart = '67'; - const props = { - value: 1234567, - valueFormatted: `${significantPart}.${decimalPart}`, - type: 'ask' as const, - testId: 'cell', - }; - - it('Displays formatted value', () => { - render(); - expect(screen.getByTestId(props.testId)).toHaveTextContent( - props.valueFormatted - ); - expect(screen.getByText(decimalPart)).toBeInTheDocument(); - expect(screen.getByText(decimalPart)).toHaveClass('opacity-60'); - }); - - it('Displays 0', () => { - render(); - expect(screen.getByTestId(props.testId)).toHaveTextContent('0.00'); - }); - - it('Displays - if value is not a number', () => { - render(); - expect(screen.getByTestId(props.testId)).toHaveTextContent('-'); - }); - - it('renders bid volume bar', () => { - render(); - expect(screen.getByTestId('vol-bar')).toHaveClass('left-0'); // renders bid bars from the left - expect(screen.getByTestId('vol-bar')).toHaveStyle({ - backgroundColor: tailwind.theme.colors.vega.green.DEFAULT, - }); - }); - - it('renders ask volume bar', () => { - render(); - expect(screen.getByTestId('vol-bar')).toHaveClass('right-0'); // renders ask bars from the right - expect(screen.getByTestId('vol-bar')).toHaveStyle({ - backgroundColor: tailwind.theme.colors.vega.pink.DEFAULT, - }); - }); -}); diff --git a/libs/datagrid/src/lib/cells/vol-cell.tsx b/libs/datagrid/src/lib/cells/vol-cell.tsx deleted file mode 100644 index 9de4e8a68..000000000 --- a/libs/datagrid/src/lib/cells/vol-cell.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { memo } from 'react'; -import type { ICellRendererParams } from 'ag-grid-community'; -import classNames from 'classnames'; -import { theme } from '@vegaprotocol/tailwindcss-config'; -import { NumericCell } from './numeric-cell'; - -export interface VolCellProps { - value: number | bigint | null | undefined; - valueFormatted: string; - relativeValue?: number; - type: 'ask' | 'bid'; - testId?: string; -} -export interface IVolCellProps extends ICellRendererParams { - value: number | bigint | null | undefined; - valueFormatted: Omit; -} - -export const BID_COLOR = theme.colors.vega.green.DEFAULT; -export const ASK_COLOR = theme.colors.vega.pink.DEFAULT; - -export const VolCell = memo( - ({ value, valueFormatted, relativeValue, type, testId }: VolCellProps) => { - if ((!value && value !== 0) || isNaN(Number(value))) { - return
-
; - } - return ( -
-
- -
- ); - } -); - -VolCell.displayName = 'VolCell'; diff --git a/libs/datagrid/src/lib/column-definitions.ts b/libs/datagrid/src/lib/column-definitions.ts index e398643c2..038adcc59 100644 --- a/libs/datagrid/src/lib/column-definitions.ts +++ b/libs/datagrid/src/lib/column-definitions.ts @@ -7,6 +7,6 @@ export const COL_DEFS = { minWidth: 45, maxWidth: 45, type: 'rightAligned', - pinned: 'right', + pinned: 'right' as const, }, }; diff --git a/libs/datagrid/src/lib/type-helpers.ts b/libs/datagrid/src/lib/type-helpers.ts index 471883ca8..26903184d 100644 --- a/libs/datagrid/src/lib/type-helpers.ts +++ b/libs/datagrid/src/lib/type-helpers.ts @@ -4,18 +4,17 @@ import type { ValueFormatterParams, ValueGetterParams, } from 'ag-grid-community'; -import type { IDatasource, IGetRowsParams, RowNode } from 'ag-grid-community'; +import type { IDatasource, IGetRowsParams } from 'ag-grid-community'; import type { AgGridReactProps } from 'ag-grid-react'; type Field = string | readonly string[]; type RowHelper = Omit< TObj, - 'data' | 'value' | 'node' + 'data' | 'value' > & { data?: TRow; value?: Get; - node: (Omit & { data?: TRow }) | null; }; export type VegaValueFormatterParams = RowHelper< @@ -24,12 +23,8 @@ export type VegaValueFormatterParams = RowHelper< TField >; -export type VegaValueGetterParams = Omit< - ValueGetterParams, - 'data' | 'node' -> & { +export type VegaValueGetterParams = Omit & { data?: TRow; - node: (Omit & { data?: TRow }) | null; }; export type VegaICellRendererParams = Omit< diff --git a/libs/deposits/src/lib/deposits-table.tsx b/libs/deposits/src/lib/deposits-table.tsx index 5fc838366..2e2771661 100644 --- a/libs/deposits/src/lib/deposits-table.tsx +++ b/libs/deposits/src/lib/deposits-table.tsx @@ -1,11 +1,11 @@ -import { forwardRef } from 'react'; -import { AgGridColumn } from 'ag-grid-react'; +import { forwardRef, useMemo } from 'react'; import { addDecimalsFormatNumber, getDateTimeFormat, truncateByChars, isNumeric, } from '@vegaprotocol/utils'; +import type { ColDef } from 'ag-grid-community'; import type { AgGridReact } from 'ag-grid-react'; import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import type { @@ -21,51 +21,46 @@ export const DepositsTable = forwardRef< AgGridReact, TypedDataAgGrid >((props, ref) => { - return ( - - - ( + () => [ + { headerName: 'Asset', field: 'asset.symbol' }, + { + headerName: 'Amount', + field: 'amount', + valueFormatter: ({ value, data, }: VegaValueFormatterParams) => { return isNumeric(value) && data ? addDecimalsFormatNumber(value, data.asset.decimals) - : null; - }} - /> - ) => { return value ? getDateTimeFormat().format(new Date(value)) : ''; - }} - /> - ) => { return value ? DepositStatusMapping[value] : ''; - }} - /> - ) => { @@ -76,9 +71,19 @@ export const DepositsTable = forwardRef< {truncateByChars(value)} ); - }} - flex={1} - /> - + }, + flex: 1, + }, + ], + [] + ); + return ( + ); }); diff --git a/libs/fills/src/lib/fills-table.tsx b/libs/fills/src/lib/fills-table.tsx index 50e6e7a4f..4b473586e 100644 --- a/libs/fills/src/lib/fills-table.tsx +++ b/libs/fills/src/lib/fills-table.tsx @@ -1,9 +1,10 @@ +import { useMemo } from 'react'; import type { AgGridReact, AgGridReactProps, AgReactUiProps, } from 'ag-grid-react'; -import type { ITooltipParams } from 'ag-grid-community'; +import type { ITooltipParams, ColDef } from 'ag-grid-community'; import { addDecimal, addDecimalsFormatNumber, @@ -13,7 +14,6 @@ import { } from '@vegaprotocol/utils'; import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; -import { AgGridColumn } from 'ag-grid-react'; import { AgGridLazy as AgGrid, positiveClassNames, @@ -43,29 +43,19 @@ export type Props = (AgGridReactProps | AgReactUiProps) & { export const FillsTable = forwardRef( ({ partyId, onMarketClick, ...props }, ref) => { - return ( - data?.id} - tooltipShowDelay={0} - tooltipHideDelay={2000} - components={{ MarketNameCell }} - {...props} - > - - ( + () => [ + { + headerName: t('Market'), + field: 'market.tradableInstrument.instrument.name', + cellRenderer: 'MarketNameCell', + cellRendererParams: { idPath: 'market.id', onMarketClick }, + }, + { + headerName: t('Size'), + type: 'rightAligned', + field: 'size', + cellClassRules: { [positiveClassNames]: ({ data }: { data: Trade }) => { const partySide = getPartySide(data, partyId); return partySide === 'buyer'; @@ -74,48 +64,47 @@ export const FillsTable = forwardRef( const partySide = getPartySide(data, partyId); return partySide === 'seller'; }, - }} - valueFormatter={formatSize(partyId)} - /> - - - - - ) => { return value ? getDateTimeFormat().format(new Date(value)) : ''; - }} - /> - ) => { + }, + }, + { + colId: 'fill-actions', + cellRenderer: ({ data }: VegaICellRendererParams) => { if (!data) return null; return ( ( tradeId={data.id} /> ); - }} - /> - + }, + ...COL_DEFS.actions, + }, + ], + [onMarketClick, partyId] + ); + return ( + data?.id} + tooltipShowDelay={0} + tooltipHideDelay={2000} + components={{ MarketNameCell }} + {...props} + /> ); } ); diff --git a/libs/ledger/src/lib/ledger-table.tsx b/libs/ledger/src/lib/ledger-table.tsx index 03f68055d..9c1137690 100644 --- a/libs/ledger/src/lib/ledger-table.tsx +++ b/libs/ledger/src/lib/ledger-table.tsx @@ -15,15 +15,15 @@ import { SetFilter, } from '@vegaprotocol/datagrid'; import type { AgGridReact } from 'ag-grid-react'; -import { AgGridColumn } from 'ag-grid-react'; import type * as Types from '@vegaprotocol/types'; +import type { ColDef } from 'ag-grid-community'; import { AccountTypeMapping, DescriptionTransferTypeMapping, TransferTypeMapping, } from '@vegaprotocol/types'; import type { LedgerEntry } from './ledger-entries-data-provider'; -import { forwardRef } from 'react'; +import { forwardRef, useMemo } from 'react'; import { formatRFC3339, subDays } from 'date-fns'; export const TransferTooltipCellComponent = ({ @@ -47,6 +47,143 @@ type LedgerEntryProps = TypedDataAgGrid; export const LedgerTable = forwardRef( (props, ref) => { + const columnDefs = useMemo( + () => [ + { + headerName: t('Sender'), + field: 'fromAccountPartyId', + cellRenderer: ({ + value, + }: VegaValueFormatterParams) => + truncateByChars(value || ''), + }, + { + headerName: t('Account type'), + filter: SetFilter, + filterParams: { + set: AccountTypeMapping, + }, + field: 'fromAccountType', + cellRenderer: ({ + value, + }: VegaValueFormatterParams) => + value ? AccountTypeMapping[value] : '-', + }, + { + headerName: t('Market'), + field: 'marketSender.tradableInstrument.instrument.code', + cellRenderer: ({ + value, + }: VegaValueFormatterParams< + LedgerEntry, + 'marketSender.tradableInstrument.instrument.code' + >) => value || '-', + }, + { + headerName: t('Receiver'), + field: 'toAccountPartyId', + cellRenderer: ({ + value, + }: VegaValueFormatterParams) => + truncateByChars(value || ''), + }, + { + headerName: t('Account type'), + filter: SetFilter, + filterParams: { + set: AccountTypeMapping, + }, + field: 'toAccountType', + cellRenderer: ({ + value, + }: VegaValueFormatterParams) => + value ? AccountTypeMapping[value] : '-', + }, + { + headerName: t('Market'), + field: 'marketReceiver.tradableInstrument.instrument.code', + cellRenderer: ({ + value, + }: VegaValueFormatterParams< + LedgerEntry, + 'marketReceiver.tradableInstrument.instrument.code' + >) => value || '-', + }, + { + headerName: t('Transfer type'), + field: 'transferType', + tooltipField: 'transferType', + filter: SetFilter, + filterParams: { + set: TransferTypeMapping, + }, + valueFormatter: ({ + value, + }: VegaValueFormatterParams) => + value ? TransferTypeMapping[value] : '', + }, + { + headerName: t('Quantity'), + field: 'quantity', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => { + const assetDecimalPlaces = data?.asset?.decimals || 0; + return value + ? addDecimalsFormatNumber(value, assetDecimalPlaces) + : ''; + }, + }, + { + headerName: t('Asset'), + field: 'assetId', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => + data?.asset?.symbol || '', + }, + { + headerName: t('Sender account balance'), + field: 'fromAccountBalance', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => { + const assetDecimalPlaces = data?.asset?.decimals || 0; + return value + ? addDecimalsFormatNumber(value, assetDecimalPlaces) + : ''; + }, + }, + { + headerName: t('Receiver account balance'), + field: 'toAccountBalance', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => { + const assetDecimalPlaces = data?.asset?.decimals || 0; + return value + ? addDecimalsFormatNumber(value, assetDecimalPlaces) + : ''; + }, + }, + { + headerName: t('Vega time'), + field: 'vegaTime', + valueFormatter: ({ + value, + }: VegaValueFormatterParams) => + value ? getDateTimeFormat().format(fromNanoSeconds(value)) : '-', + filterParams: dateRangeFilterParams, + filter: DateRangeFilter, + flex: 1, + }, + ], + [] + ); return ( ( buttons: ['reset'], }, }} + columnDefs={columnDefs} {...props} - > - ) => - truncateByChars(value || '') - } - /> - ) => - value ? AccountTypeMapping[value] : '-' - } - /> - ) => value || '-'} - /> - ) => - truncateByChars(value || '') - } - /> - ) => - value ? AccountTypeMapping[value] : '-' - } - /> - ) => value || '-'} - /> - ) => - value ? TransferTypeMapping[value] : '' - } - /> - ) => { - const assetDecimalPlaces = data?.asset?.decimals || 0; - return value - ? addDecimalsFormatNumber(value, assetDecimalPlaces) - : value; - }} - /> - ) => - data?.asset?.symbol || value - } - /> - ) => { - const assetDecimalPlaces = data?.asset?.decimals || 0; - return value - ? addDecimalsFormatNumber(value, assetDecimalPlaces) - : value; - }} - /> - ) => { - const assetDecimalPlaces = data?.asset?.decimals || 0; - return value - ? addDecimalsFormatNumber(value, assetDecimalPlaces) - : value; - }} - /> - ) => - value ? getDateTimeFormat().format(fromNanoSeconds(value)) : '-' - } - filterParams={dateRangeFilterParams} - filter={DateRangeFilter} - flex={1} - /> - + /> ); } ); diff --git a/libs/liquidity/src/lib/liquidity-table.tsx b/libs/liquidity/src/lib/liquidity-table.tsx index 00433ac59..f35d4c249 100644 --- a/libs/liquidity/src/lib/liquidity-table.tsx +++ b/libs/liquidity/src/lib/liquidity-table.tsx @@ -188,7 +188,7 @@ export const LiquidityTable = forwardRef( data.id} + getRowId={({ data }: { data: LiquidityProvisionData }) => data.id || ''} ref={ref} tooltipShowDelay={500} defaultColDef={{ diff --git a/libs/liquidity/src/lib/liquidity.mock.ts b/libs/liquidity/src/lib/liquidity.mock.ts index a91902557..c4d94fd5a 100644 --- a/libs/liquidity/src/lib/liquidity.mock.ts +++ b/libs/liquidity/src/lib/liquidity.mock.ts @@ -67,6 +67,7 @@ export const liquidityProviderFeeShareQuery = ( export const liquidityFields: LiquidityProvisionFieldsFragment[] = [ { + id: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f', party: { id: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f', accountsConnection: { @@ -92,6 +93,7 @@ export const liquidityFields: LiquidityProvisionFieldsFragment[] = [ __typename: 'LiquidityProvision', }, { + id: 'cc464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f', party: { id: 'cc464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f', accountsConnection: { diff --git a/libs/trades/src/lib/trades-table.tsx b/libs/trades/src/lib/trades-table.tsx index 09729b534..d68c5e141 100644 --- a/libs/trades/src/lib/trades-table.tsx +++ b/libs/trades/src/lib/trades-table.tsx @@ -1,5 +1,6 @@ import type { AgGridReact } from 'ag-grid-react'; -import { AgGridColumn } from 'ag-grid-react'; +import { useMemo } from 'react'; +import type { ColDef } from 'ag-grid-community'; import { forwardRef } from 'react'; import type { VegaICellRendererParams, @@ -47,85 +48,90 @@ interface Props extends AgGridReactProps { onClick?: (price?: string) => void; } -export const TradesTable = forwardRef((props, ref) => { - return ( - data.id} - ref={ref} - defaultColDef={{ - flex: 1, - }} - {...props} - > - ) => { - if (!value || !data?.market) { - return null; - } - return addDecimalsFormatNumber(value, data.market.decimalPlaces); - }} - cellRenderer={({ - value, - data, - }: VegaICellRendererParams) => { - if (!data?.market || !value) { - return null; - } - return ( - - ); - }} - /> - ) => { - if (!value || !data?.market) { - return null; - } - return addDecimalsFormatNumber( +export const TradesTable = forwardRef( + ({ onClick, ...props }, ref) => { + const columnDefs = useMemo( + () => [ + { + headerName: t('Price'), + field: 'price', + type: 'rightAligned', + width: 130, + cellClass: changeCellClass, + valueFormatter: ({ value, - data.market.positionDecimalPlaces - ); + data, + }: VegaValueFormatterParams) => { + if (!value || !data?.market) { + return ''; + } + return addDecimalsFormatNumber(value, data.market.decimalPlaces); + }, + cellRenderer: ({ + value, + data, + }: VegaICellRendererParams) => { + if (!data?.market || !value) { + return ''; + } + return ( + + ); + }, + }, + { + headerName: t('Size'), + field: 'size', + width: 125, + type: 'rightAligned', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => { + if (!value || !data?.market) { + return ''; + } + return addDecimalsFormatNumber( + value, + data.market.positionDecimalPlaces + ); + }, + cellRenderer: NumericCell, + }, + { + headerName: t('Created at'), + field: 'createdAt', + type: 'rightAligned', + width: 170, + cellClass: 'text-right', + valueFormatter: ({ + value, + }: VegaValueFormatterParams) => { + return value && getDateTimeFormat().format(new Date(value)); + }, + }, + ], + [onClick] + ); + return ( + data.id} + ref={ref} + defaultColDef={{ + flex: 1, }} - cellRenderer={NumericCell} + columnDefs={columnDefs} + {...props} /> - ) => { - return value && getDateTimeFormat().format(new Date(value)); - }} - /> - - ); -}); + ); + } +); diff --git a/libs/withdraws/src/lib/withdrawals-table.tsx b/libs/withdraws/src/lib/withdrawals-table.tsx index af25e3e35..ff4fdc94f 100644 --- a/libs/withdraws/src/lib/withdrawals-table.tsx +++ b/libs/withdraws/src/lib/withdrawals-table.tsx @@ -1,6 +1,6 @@ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useRef, useState, useMemo } from 'react'; import type { AgGridReact } from 'ag-grid-react'; -import { AgGridColumn } from 'ag-grid-react'; +import type { ColDef } from 'ag-grid-community'; import { addDecimalsFormatNumber, convertToCountdownString, @@ -34,20 +34,111 @@ import * as Schema from '@vegaprotocol/types'; import type { TimestampedWithdrawals } from './use-ready-to-complete-withdrawals-toast'; import classNames from 'classnames'; -export const WithdrawalsTable = ( - props: TypedDataAgGrid & { - ready?: TimestampedWithdrawals; - delayed?: TimestampedWithdrawals; - } -) => { +export const WithdrawalsTable = ({ + delayed, + ready, + ...props +}: TypedDataAgGrid & { + ready?: TimestampedWithdrawals; + delayed?: TimestampedWithdrawals; +}) => { const gridRef = useRef(null); const createWithdrawApproval = useEthWithdrawApprovalsStore( (store) => store.create ); + const columnDefs = useMemo( + () => [ + { headerName: 'Asset', field: 'asset.symbol' }, + { + headerName: t('Amount'), + field: 'amount', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams) => { + return isNumeric(value) && data?.asset + ? addDecimalsFormatNumber(value, data.asset.decimals) + : ''; + }, + }, + { + headerName: t('Recipient'), + field: 'details.receiverAddress', + cellRenderer: 'RecipientCell', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams< + WithdrawalFieldsFragment, + 'details.receiverAddress' + >) => { + if (!data) return ''; + if (!value) return '-'; + return truncateByChars(value); + }, + }, + { + headerName: t('Created'), + field: 'createdTimestamp', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams< + WithdrawalFieldsFragment, + 'createdTimestamp' + >) => + data + ? value + ? getDateTimeFormat().format(new Date(value)) + : '-' + : '', + }, + { + headerName: t('Completed'), + field: 'withdrawnTimestamp', + valueFormatter: ({ + value, + data, + }: VegaValueFormatterParams< + WithdrawalFieldsFragment, + 'withdrawnTimestamp' + >) => + data + ? value + ? getDateTimeFormat().format(new Date(value)) + : '-' + : '', + }, + { + headerName: t('Status'), + field: 'status', + cellRenderer: 'StatusCell', + cellRendererParams: { ready, delayed }, + }, + { + headerName: t('Transaction'), + field: 'txHash', + flex: 2, + type: 'rightAligned', + cellRendererParams: { + complete: (withdrawal: WithdrawalFieldsFragment) => { + createWithdrawApproval(withdrawal); + }, + }, + cellRendererSelector: ({ + data, + }: VegaICellRendererParams) => ({ + component: data?.txHash ? 'EtherscanLinkCell' : 'CompleteCell', + }), + }, + ], + [createWithdrawApproval, delayed, ready] + ); return ( - - ) => { - return isNumeric(value) && data?.asset - ? addDecimalsFormatNumber(value, data.asset.decimals) - : ''; - }} - /> - ) => { - if (!data) return null; - if (!value) return '-'; - return truncateByChars(value); - }} - /> - ) => - data - ? value - ? getDateTimeFormat().format(new Date(value)) - : '-' - : null - } - /> - ) => - data - ? value - ? getDateTimeFormat().format(new Date(value)) - : '-' - : null - } - /> - - { - createWithdrawApproval(withdrawal); - }, - }} - cellRendererSelector={({ - data, - }: VegaICellRendererParams) => ({ - component: data?.txHash ? 'EtherscanLinkCell' : 'CompleteCell', - })} - /> - + /> ); }; diff --git a/package.json b/package.json index 0409e62c6..c6b587433 100644 --- a/package.json +++ b/package.json @@ -46,8 +46,8 @@ "@web3-react/metamask": "^8.1.2-beta.0", "@web3-react/walletconnect": "8.1.3-beta.0", "@web3-react/walletconnect-v2": "^8.1.3-beta.0", - "ag-grid-community": "^27.0.1", - "ag-grid-react": "^27.0.1", + "ag-grid-community": "^29.3.5", + "ag-grid-react": "^29.3.5", "allotment": "1.18.1", "alpha-lyrae": "vegaprotocol/alpha-lyrae", "apollo": "^2.33.9", diff --git a/yarn.lock b/yarn.lock index 240b6bd3b..d0c8e36e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8809,15 +8809,15 @@ aes-js@^3.1.2: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ== -ag-grid-community@^27.0.1: - version "27.3.0" - resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-27.3.0.tgz#b1e94a58026aaf2f0cd7920e35833325b5e762c7" - integrity sha512-R5oZMXEHXnOLrmhn91J8lR0bv6IAnRcU6maO+wKLMJxffRWaAYFAuw1jt7bdmcKCv8c65F6LEBx4ykSOALa9vA== +ag-grid-community@^29.3.5: + version "29.3.5" + resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-29.3.5.tgz#16897896d10fa3ecac79279aad50d3aaa17c5f33" + integrity sha512-LxUo21f2/CH31ACEs1C7Q/ggGGI1fQPSTB4aY5OThmM+lBkygZ7QszBE8jpfgWOIjvjdtcdIeQbmbjkHeMsA7A== -ag-grid-react@^27.0.1: - version "27.3.0" - resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-27.3.0.tgz#fe06647653f8b0b349b8e613aab8ea2e07915562" - integrity sha512-2bs9YfJ/shvBZQLLjny4NFvht+ic6VtpTPO0r3bHHOhlL3Fjx2rGvS6AHSwfvu+kJacHCta30PjaEbX8T3UDyw== +ag-grid-react@^29.3.5: + version "29.3.5" + resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-29.3.5.tgz#0eae8934d372c7751e98789542fc663aee0ad6ad" + integrity sha512-Eg0GJ8hEBuxdVaN5g+qITOzhw0MGL9avL0Oaajr+p7QRtq2pIFHLZSknWsCBzUTjidiu75WZMKwlZjtGEuafdQ== dependencies: prop-types "^15.8.1"