chore(trading): ag-grid upgrade (#4187)

This commit is contained in:
Bartłomiej Głownia 2023-07-01 13:02:23 +02:00 committed by GitHub
parent 6e9e7c2a5c
commit 43aff8e359
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1107 additions and 1189 deletions

View File

@ -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<ColDef[]>(
() => [
{ 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<AssetFieldsFragment, 'id'>) =>
value ? (
<ButtonLink
onClick={(e) => {
navigate(value);
}}
>
{t('View details')}
</ButtonLink>
) : (
''
),
},
],
[navigate]
);
return (
<AgGrid
ref={ref}
@ -46,60 +98,11 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
filterParams: { buttons: ['reset'] },
autoHeight: true,
}}
columnDefs={columnDefs}
suppressCellFocus={true}
onRowClicked={({ data }: RowClickedEvent) => {
navigate(data.id);
}}
>
<AgGridColumn headerName={t('Symbol')} field="symbol" />
<AgGridColumn headerName={t('Name')} field="name" />
<AgGridColumn
flex="2"
headerName={t('ID')}
field="id"
hide={window.innerWidth < BREAKPOINT_MD}
/>
<AgGridColumn
colId="type"
headerName={t('Type')}
field="source.__typename"
hide={window.innerWidth < BREAKPOINT_MD}
valueFormatter={({ value }: { value?: string }) =>
value && AssetTypeMapping[value].value
}
/>
<AgGridColumn
headerName={t('Status')}
field="status"
hide={window.innerWidth < BREAKPOINT_MD}
valueFormatter={({ value }: { value?: string }) =>
value && AssetStatusMapping[value].value
}
/>
<AgGridColumn
colId="actions"
headerName=""
sortable={false}
filter={false}
resizable={false}
wrapText={true}
field="id"
cellRenderer={({
value,
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
value ? (
<ButtonLink
onClick={(e) => {
navigate(value);
}}
>
{t('View details')}
</ButtonLink>
) : (
''
)
}
/>
</AgGrid>
/>
);
};

View File

@ -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 (
<AgGrid
ref={gridRef}
rowData={data}
getRowId={({ data }: { data: MarketFieldsFragment }) => 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);
}
}}
>
<AgGridColumn
colId="code"
headerName={t('Code')}
field="tradableInstrument.instrument.code"
/>
<AgGridColumn
colId="name"
headerName={t('Name')}
field="tradableInstrument.instrument.name"
/>
<AgGridColumn
headerName={t('Status')}
field="state"
hide={window.innerWidth <= BREAKPOINT_MD}
valueGetter={({
const columnDefs = useMemo<ColDef[]>(
() => [
{
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<MarketFieldsFragment>) => {
return data?.state ? MarketStateMapping[data?.state] : '-';
}}
/>
<AgGridColumn
colId="asset"
headerName={t('Settlement asset')}
field="tradableInstrument.instrument.product.settlementAsset.symbol"
hide={window.innerWidth <= BREAKPOINT_MD}
cellRenderer={({
},
},
{
colId: 'asset',
headerName: t('Settlement asset'),
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
hide: window.innerWidth <= BREAKPOINT_MD,
cellRenderer: ({
data,
}: VegaICellRendererParams<
MarketFieldsFragment,
@ -105,19 +86,19 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
) : (
''
);
}}
/>
<AgGridColumn
flex={2}
headerName={t('Market ID')}
field="id"
hide={window.innerWidth <= BREAKPOINT_MD}
/>
<AgGridColumn
colId="actions"
headerName=""
field="id"
cellRenderer={({
},
},
{
flex: 2,
headerName: t('Market ID'),
field: 'id',
hide: window.innerWidth <= BREAKPOINT_MD,
},
{
colId: 'actions',
headerName: '',
field: 'id',
cellRenderer: ({
value,
}: VegaICellRendererParams<MarketFieldsFragment, 'id'>) =>
value ? (
@ -126,9 +107,34 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
</Link>
) : (
''
)
),
},
],
[openAssetDetailsDialog]
);
return (
<AgGrid
ref={gridRef}
rowData={data}
getRowId={({ data }: { data: MarketFieldsFragment }) => 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);
}
/>
</AgGrid>
}}
/>
);
};

View File

@ -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<ColDef[]>(
() => [
{
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<ProposalListFieldsFragment, 'state'>) => {
return value ? ProposalStateMapping[value] : '-';
},
},
{
colId: 'voting',
maxWidth: 100,
hide: window.innerWidth <= BREAKPOINT_MD,
headerName: t('Voting'),
cellRenderer: ({
data,
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
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 (
<div className="uppercase flex h-full items-center justify-center pt-2">
<VoteProgress
threshold={requiredMajorityPercentage}
progress={yesPercentage}
/>
</div>
);
}
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<ProposalListFieldsFragment>) => {
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 (
<div className="pb-1">
<button className="underline max-md:hidden" onClick={openDialog}>
{t('View terms')}
</button>{' '}
<ExternalLink className="max-md:hidden" href={proposalPage}>
{t('Open in Governance')}
</ExternalLink>
<ExternalLink className="md:hidden" href={proposalPage}>
{t('Open')}
</ExternalLink>
</div>
);
},
},
],
[requiredMajorityPercentage, tokenLink]
);
return (
<>
<AgGrid
@ -83,6 +203,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
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');
}
}}
>
<AgGridColumn
colId="title"
headerName={t('Title')}
field="rationale.title"
flex={2}
wrapText={true}
/>
<AgGridColumn
colId="type"
maxWidth={180}
hide={window.innerWidth <= BREAKPOINT_MD}
headerName={t('Type')}
field="terms.change.__typename"
/>
<AgGridColumn
maxWidth={100}
headerName={t('State')}
field="state"
valueFormatter={({
value,
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) => {
return value ? ProposalStateMapping[value] : '-';
}}
/>
<AgGridColumn
colId="voting"
maxWidth={100}
hide={window.innerWidth <= BREAKPOINT_MD}
headerName={t('Voting')}
cellRenderer={({
data,
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
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 (
<div className="uppercase flex h-full items-center justify-center pt-2">
<VoteProgress
threshold={requiredMajorityPercentage}
progress={yesPercentage}
/>
</div>
);
}
return '-';
}}
/>
<AgGridColumn
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)) : '-';
}}
/>
<AgGridColumn
colId="eDate"
maxWidth={150}
hide={window.innerWidth <= BREAKPOINT_MD}
headerName={t('Enactment date')}
field="terms.enactmentDatetime"
valueFormatter={({
value,
}: VegaValueFormatterParams<
ProposalListFieldsFragment,
'terms.enactmentDatetime'
>) => {
return value ? getDateTimeFormat().format(new Date(value)) : '-';
}}
/>
<AgGridColumn
colId="actions"
minWidth={window.innerWidth > BREAKPOINT_MD ? 221 : 80}
maxWidth={221}
sortable={false}
filter={false}
resizable={false}
cellRenderer={({
data,
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
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 (
<div className="pb-1">
<button
className="underline max-md:hidden"
onClick={openDialog}
>
{t('View terms')}
</button>{' '}
<ExternalLink className="max-md:hidden" href={proposalPage}>
{t('Open in Governance')}
</ExternalLink>
<ExternalLink className="md:hidden" href={proposalPage}>
{t('Open')}
</ExternalLink>
</div>
);
}}
/>
</AgGrid>
/>
<JsonViewerDialog
open={dialog.open}
onChange={(isOpen) => setDialog({ ...dialog, open: isOpen })}

View File

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

View File

@ -1,6 +0,0 @@
function ReactMarkdown({ children }) {
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{children}</>;
}
export default ReactMarkdown;

View File

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

View File

@ -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<ColDef[]>(
() => [
{
headerName: t('Market (futures)'),
field: 'tradableInstrument.instrument.name',
cellRenderer: ({ value, data }: { value: string; data: Market }) => {
return (
<>
<span className="leading-3">{value}</span>
<span className="leading-3">
{
data?.tradableInstrument?.instrument?.product?.settlementAsset
?.symbol
}
</span>
</>
);
},
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<Market, 'data.markPrice'>) =>
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<Market, 'data.candles'>) => {
if (data && data.candles) {
const prices = data.candles.map((candle) => candle.close);
return (
<PriceChangeCell
candles={prices}
decimalPlaces={data?.decimalPlaces}
/>
);
} else return <div>{t('-')}</div>;
},
},
{
headerName: t('Volume (24h)'),
field: 'dayVolume',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<Market, 'dayVolume'>) =>
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<Market, 'liquidityCommitted'>) =>
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<Market, 'target'>) =>
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<Market, ''>) => {
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<Market, 'fees'>) =>
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 <Status trigger={data.data?.trigger} tradingMode={value} />;
},
headerTooltip: t(
'The current market status - those below the target stake mark are most in need of liquidity'
),
},
{
headerComponent: () => {
return (
<div>
<span>{t('Health')}</span>{' '}
<button
onClick={() => setIsHealthDialogOpen(true)}
aria-label={t('open tooltip')}
>
<Icon name="info-sign" />
</button>
</div>
);
},
field: 'tradingMode',
cellRenderer: ({
value,
data,
}: {
value: Schema.MarketTradingMode;
data: Market;
}) => (
<HealthBar
target={data.target}
decimals={
data.tradableInstrument.instrument.product.settlementAsset
.decimals
}
levels={data.feeLevels}
intent={intentForStatus(value)}
/>
),
sortable: false,
cellStyle: { overflow: 'unset' },
},
{
headerName: t('Age'),
field: 'marketTimestamps.open',
headerTooltip: t('Age of the market'),
valueFormatter: ({
value,
}: VegaValueFormatterParams<Market, 'marketTimestamps.open'>) => {
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<Market, ''>) => {
let expiry;
if (data?.tradableInstrument.instrument.metadata.tags) {
expiry = getExpiryDate(
data?.tradableInstrument.instrument.metadata.tags,
data?.marketTimestamps.close,
data?.state
);
}
return expiry ? expiry : '-';
},
},
],
[]
);
return (
<AsyncRenderer loading={loading} error={error} data={data}>
@ -64,258 +295,11 @@ export const MarketList = () => {
cellClass: ['flex', 'flex-col', 'justify-center'],
tooltipComponent: TooltipCellComponent,
}}
columnDefs={columnDefs}
getRowId={getRowId}
isRowClickable
tooltipShowDelay={500}
>
<AgGridColumn
headerName={t('Market (futures)')}
field="tradableInstrument.instrument.name"
cellRenderer={({
value,
data,
}: {
value: string;
data: Market;
}) => {
return (
<>
<span className="leading-3">{value}</span>
<span className="leading-3">
{
data?.tradableInstrument?.instrument?.product
?.settlementAsset?.symbol
}
</span>
</>
);
}}
minWidth={100}
flex="1"
headerTooltip={t('The market name and settlement asset')}
/>
<AgGridColumn
headerName={t('Market Code')}
headerTooltip={t(
'The market code is a unique identifier for this market'
)}
field="tradableInstrument.instrument.code"
/>
<AgGridColumn
headerName={t('Type')}
headerTooltip={t('Type')}
field="tradableInstrument.instrument.product.__typename"
/>
<AgGridColumn
headerName={t('Last Price')}
headerTooltip={t('Latest price for this market')}
field="data.markPrice"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<Market, 'data.markPrice'>) =>
value && data
? formatWithAsset(
value,
data.tradableInstrument.instrument.product.settlementAsset
)
: '-'
}
/>
<AgGridColumn
headerName={t('Change (24h)')}
headerTooltip={t('Change in price over the last 24h')}
cellRenderer={({
data,
}: VegaValueFormatterParams<Market, 'data.candles'>) => {
if (data && data.candles) {
const prices = data.candles.map((candle) => candle.close);
return (
<PriceChangeCell
candles={prices}
decimalPlaces={data?.decimalPlaces}
/>
);
} else return <div>{t('-')}</div>;
}}
/>
<AgGridColumn
headerName={t('Volume (24h)')}
field="dayVolume"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<Market, 'dayVolume'>) =>
value && data
? `${addDecimalsFormatNumber(
value,
data.tradableInstrument.instrument.product.settlementAsset
.decimals
)} (${displayChange(data.volumeChange)})`
: '-'
}
headerTooltip={t('The trade volume over the last 24h')}
/>
<AgGridColumn
headerName={t('Total staked by LPs')}
field="liquidityCommitted"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<Market, 'liquidityCommitted'>) =>
data && value
? formatWithAsset(
value.toString(),
data.tradableInstrument.instrument.product.settlementAsset
)
: '-'
}
headerTooltip={t(
'The amount of funds allocated to provide liquidity'
)}
/>
<AgGridColumn
headerName={t('Target stake')}
field="target"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<Market, 'target'>) =>
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.'
)}
/>
<AgGridColumn
headerName={t('% Target stake met')}
valueFormatter={({
data,
}: VegaValueFormatterParams<Market, ''>) => {
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')}
/>
<AgGridColumn
headerName={t('Fee levels')}
field="fees"
valueFormatter={({
value,
}: VegaValueFormatterParams<Market, 'fees'>) =>
value ? `${value.factors.liquidityFee}%` : '-'
}
headerTooltip={t('Fee level for this market')}
/>
<AgGridColumn
headerName={t('Status')}
field="tradingMode"
cellRenderer={({
value,
data,
}: {
value: Schema.MarketTradingMode;
data: Market;
}) => {
return (
<Status trigger={data.data?.trigger} tradingMode={value} />
);
}}
headerTooltip={t(
'The current market status - those below the target stake mark are most in need of liquidity'
)}
/>
<AgGridColumn
headerComponent={() => {
return (
<div>
<span>{t('Health')}</span>{' '}
<button
onClick={() => setIsHealthDialogOpen(true)}
aria-label={t('open tooltip')}
>
<Icon name="info-sign" />
</button>
</div>
);
}}
field="tradingMode"
cellRenderer={({
value,
data,
}: {
value: Schema.MarketTradingMode;
data: Market;
}) => (
<HealthBar
target={data.target}
decimals={
data.tradableInstrument.instrument.product.settlementAsset
.decimals
}
levels={data.feeLevels}
intent={intentForStatus(value)}
/>
)}
sortable={false}
cellStyle={{ overflow: 'unset' }}
/>
<AgGridColumn
headerName={t('Age')}
field="marketTimestamps.open"
headerTooltip={t('Age of the market')}
valueFormatter={({
value,
}: VegaValueFormatterParams<Market, 'marketTimestamps.open'>) => {
return value ? formatDistanceToNow(new Date(value)) : '-';
}}
/>
<AgGridColumn
headerName={t('Closing Time')}
field="tradableInstrument.instrument.metadata.tags"
headerTooltip={t('Closing time of the market')}
valueFormatter={({
data,
}: VegaValueFormatterParams<Market, ''>) => {
let expiry;
if (data?.tradableInstrument.instrument.metadata.tags) {
expiry = getExpiryDate(
data?.tradableInstrument.instrument.metadata.tags,
data?.marketTimestamps.close,
data?.state
);
}
return expiry ? expiry : '-';
}}
/>
</Grid>
/>
<HealthDialog
isOpen={isHealthDialogOpen}
onChange={() => {

View File

@ -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<ColDef[]>(
() => [
{
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 (
<Grid
@ -49,74 +117,9 @@ export const LPProvidersGrid = ({
tooltipComponent: TooltipCellComponent,
minWidth: 100,
}}
columnDefs={columnDefs}
getRowId={getRowId}
rowHeight={92}
>
<AgGridColumn
headerName={t('LPs')}
field="party.id"
flex="1"
minWidth={100}
headerTooltip={t('Liquidity providers')}
/>
<AgGridColumn
headerName={t('Duration')}
valueFormatter={formatToHours}
field="createdAt"
headerTooltip={t('Time in market')}
/>
<AgGridColumn
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}
/>
<AgGridColumn
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}
/>
<AgGridColumn
headerName={t('Margin Req.')}
field="margin"
headerTooltip={t(
'Margin required for arising positions based on liquidity commitment'
)}
/>
<AgGridColumn
headerName={t('24h Fees')}
field="fees"
headerTooltip={t(
'Total fees earned by the liquidity provider in the last 24 hours'
)}
/>
<AgGridColumn
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"
)}
/>
<AgGridColumn
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'
)}
/>
</Grid>
/>
);
};

View File

@ -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<AgGridReactType | null>(null);
const resizeGrid = useCallback(() => {
@ -44,8 +42,6 @@ export const Grid = ({ isRowClickable, children, ...props }: Props) => {
onGridReady={handleOnGridReady}
suppressRowClickSelection
{...props}
>
{children}
</AgGridReact>
/>
);
};

View File

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

View File

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

View File

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

View File

@ -44,62 +44,79 @@ describe('AccountsTable', () => {
});
it('should apply correct formatting', async () => {
await act(async () => {
render(
<AccountTable
rowData={singleRowData}
onClickAsset={() => null}
isReadOnly={false}
/>
);
});
const { container } = render(
<AccountTable
rowData={singleRowData}
onClickAsset={() => 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(
<AccountTable
rowData={singleRowData}
onClickAsset={() => null}
isReadOnly={true}
/>
);
});
const { container } = render(
<AccountTable
rowData={singleRowData}
onClickAsset={() => 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(
<AccountTable
rowData={singleRowData}
onClickAsset={() => 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(
<AccountTable
rowData={singleRowData}
onClickAsset={() => 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(
<AccountTable
rowData={singleRowData}
onClickAsset={() => 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', () => {

View File

@ -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<AgGridReact, AccountTableProps>(
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<AgGridReact, AccountTableProps>(
};
}
return currentPinnedAssetRow;
}, [props.pinnedAsset, rowData]);
}, [pinnedAsset, rowData]);
const { getRowHeight } = props;
@ -112,17 +114,17 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
(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<AgGridReact, AccountTableProps>(
</CenteredGridCellWrapper>
);
}
return props.isReadOnly ? null : (
return isReadOnly ? null : (
<AccountsActionsDropdown
assetId={assetId}
assetContractAddress={
@ -294,13 +296,11 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
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 (
<AgGrid
@ -318,7 +318,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
}}
columnDefs={colDefs}
getRowHeight={getPinnedAssetRowHeight}
pinnedTopRowData={pinnedAsset ? [pinnedAsset] : undefined}
pinnedTopRowData={pinnedRow ? [pinnedRow] : undefined}
/>
);
}

View File

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

View File

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

View File

@ -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(<VolCell {...props} />);
expect(screen.getByTestId(props.testId)).toHaveTextContent(
props.valueFormatted
);
expect(screen.getByText(decimalPart)).toBeInTheDocument();
expect(screen.getByText(decimalPart)).toHaveClass('opacity-60');
});
it('Displays 0', () => {
render(<VolCell {...props} value={0} valueFormatted="0.00" />);
expect(screen.getByTestId(props.testId)).toHaveTextContent('0.00');
});
it('Displays - if value is not a number', () => {
render(<VolCell {...props} value={null} valueFormatted="" />);
expect(screen.getByTestId(props.testId)).toHaveTextContent('-');
});
it('renders bid volume bar', () => {
render(<VolCell {...props} type="bid" />);
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(<VolCell {...props} type="ask" />);
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,
});
});
});

View File

@ -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<VolCellProps, 'value'>;
}
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 <div data-testid={testId || 'vol'}>-</div>;
}
return (
<div className="relative" data-testid={testId || 'vol'}>
<div
data-testid="vol-bar"
className={classNames(
'h-full absolute top-0 opacity-40 dark:opacity-100',
{
'left-0': type === 'bid',
'right-0': type === 'ask',
}
)}
style={{
width: relativeValue ? `${relativeValue}%` : '0%',
backgroundColor: type === 'bid' ? BID_COLOR : ASK_COLOR,
opacity: 0.6,
}}
/>
<NumericCell value={value} valueFormatted={valueFormatted} />
</div>
);
}
);
VolCell.displayName = 'VolCell';

View File

@ -7,6 +7,6 @@ export const COL_DEFS = {
minWidth: 45,
maxWidth: 45,
type: 'rightAligned',
pinned: 'right',
pinned: 'right' as const,
},
};

View File

@ -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<TObj, TRow, TField extends Field> = Omit<
TObj,
'data' | 'value' | 'node'
'data' | 'value'
> & {
data?: TRow;
value?: Get<TRow, TField>;
node: (Omit<RowNode, 'data'> & { data?: TRow }) | null;
};
export type VegaValueFormatterParams<TRow, TField extends Field> = RowHelper<
@ -24,12 +23,8 @@ export type VegaValueFormatterParams<TRow, TField extends Field> = RowHelper<
TField
>;
export type VegaValueGetterParams<TRow> = Omit<
ValueGetterParams,
'data' | 'node'
> & {
export type VegaValueGetterParams<TRow> = Omit<ValueGetterParams, 'data'> & {
data?: TRow;
node: (Omit<RowNode, 'data'> & { data?: TRow }) | null;
};
export type VegaICellRendererParams<TRow, TField extends Field = string> = Omit<

View File

@ -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<DepositFieldsFragment>
>((props, ref) => {
return (
<AgGrid
ref={ref}
defaultColDef={{ flex: 1 }}
style={{ width: '100%', height: '100%' }}
{...props}
>
<AgGridColumn headerName="Asset" field="asset.symbol" />
<AgGridColumn
headerName="Amount"
field="amount"
valueFormatter={({
const columnDefs = useMemo<ColDef[]>(
() => [
{ headerName: 'Asset', field: 'asset.symbol' },
{
headerName: 'Amount',
field: 'amount',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<DepositFieldsFragment, 'amount'>) => {
return isNumeric(value) && data
? addDecimalsFormatNumber(value, data.asset.decimals)
: null;
}}
/>
<AgGridColumn
headerName="Created at"
field="createdTimestamp"
valueFormatter={({
: '';
},
},
{
headerName: 'Created at',
field: 'createdTimestamp',
valueFormatter: ({
value,
}: VegaValueFormatterParams<
DepositFieldsFragment,
'createdTimestamp'
>) => {
return value ? getDateTimeFormat().format(new Date(value)) : '';
}}
/>
<AgGridColumn
headerName="Status"
field="status"
valueFormatter={({
},
},
{
headerName: 'Status',
field: 'status',
valueFormatter: ({
value,
}: VegaValueFormatterParams<DepositFieldsFragment, 'status'>) => {
return value ? DepositStatusMapping[value] : '';
}}
/>
<AgGridColumn
headerName="Tx hash"
field="txHash"
cellRenderer={({
},
},
{
headerName: 'Tx hash',
field: 'txHash',
cellRenderer: ({
value,
data,
}: VegaICellRendererParams<DepositFieldsFragment, 'txHash'>) => {
@ -76,9 +71,19 @@ export const DepositsTable = forwardRef<
{truncateByChars(value)}
</EtherscanLink>
);
}}
flex={1}
/>
</AgGrid>
},
flex: 1,
},
],
[]
);
return (
<AgGrid
ref={ref}
defaultColDef={{ flex: 1 }}
columnDefs={columnDefs}
style={{ width: '100%', height: '100%' }}
{...props}
/>
);
});

View File

@ -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<AgGridReact, Props>(
({ partyId, onMarketClick, ...props }, ref) => {
return (
<AgGrid
ref={ref}
overlayNoRowsTemplate={t('No fills')}
defaultColDef={{ resizable: true }}
style={{ width: '100%', height: '100%' }}
getRowId={({ data }) => data?.id}
tooltipShowDelay={0}
tooltipHideDelay={2000}
components={{ MarketNameCell }}
{...props}
>
<AgGridColumn
headerName={t('Market')}
field="market.tradableInstrument.instrument.name"
cellRenderer="MarketNameCell"
cellRendererParams={{ idPath: 'market.id', onMarketClick }}
/>
<AgGridColumn
headerName={t('Size')}
type="rightAligned"
field="size"
cellClassRules={{
const columnDefs = useMemo<ColDef[]>(
() => [
{
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<AgGridReact, Props>(
const partySide = getPartySide(data, partyId);
return partySide === 'seller';
},
}}
valueFormatter={formatSize(partyId)}
/>
<AgGridColumn
headerName={t('Price')}
field="price"
valueFormatter={formatPrice}
type="rightAligned"
/>
<AgGridColumn
headerName={t('Notional')}
field="price"
valueFormatter={formatTotal}
type="rightAligned"
/>
<AgGridColumn
headerName={t('Role')}
field="aggressor"
valueFormatter={formatRole(partyId)}
/>
<AgGridColumn
headerName={t('Fee')}
field="market.tradableInstrument.instrument.product"
valueFormatter={formatFee(partyId)}
type="rightAligned"
tooltipField="market.tradableInstrument.instrument.product"
tooltipComponent={FeesBreakdownTooltip}
tooltipComponentParams={{ partyId }}
/>
<AgGridColumn
headerName={t('Date')}
field="createdAt"
valueFormatter={({
},
valueFormatter: formatSize(partyId),
},
{
headerName: t('Price'),
field: 'price',
valueFormatter: formatPrice,
type: 'rightAligned',
},
{
headerName: t('Notional'),
field: 'price',
valueFormatter: formatTotal,
type: 'rightAligned',
},
{
headerName: t('Role'),
field: 'aggressor',
valueFormatter: formatRole(partyId),
},
{
headerName: t('Fee'),
field: 'market.tradableInstrument.instrument.product',
valueFormatter: formatFee(partyId),
type: 'rightAligned',
tooltipField: 'market.tradableInstrument.instrument.product',
tooltipComponent: FeesBreakdownTooltip,
tooltipComponentParams: { partyId },
},
{
headerName: t('Date'),
field: 'createdAt',
valueFormatter: ({
value,
}: VegaValueFormatterParams<Trade, 'createdAt'>) => {
return value ? getDateTimeFormat().format(new Date(value)) : '';
}}
/>
<AgGridColumn
colId="fill-actions"
{...COL_DEFS.actions}
cellRenderer={({ data }: VegaICellRendererParams<Trade, 'id'>) => {
},
},
{
colId: 'fill-actions',
cellRenderer: ({ data }: VegaICellRendererParams<Trade, 'id'>) => {
if (!data) return null;
return (
<FillActionsDropdown
@ -124,9 +113,25 @@ export const FillsTable = forwardRef<AgGridReact, Props>(
tradeId={data.id}
/>
);
}}
/>
</AgGrid>
},
...COL_DEFS.actions,
},
],
[onMarketClick, partyId]
);
return (
<AgGrid
ref={ref}
columnDefs={columnDefs}
overlayNoRowsTemplate={t('No fills')}
defaultColDef={{ resizable: true }}
style={{ width: '100%', height: '100%' }}
getRowId={({ data }) => data?.id}
tooltipShowDelay={0}
tooltipHideDelay={2000}
components={{ MarketNameCell }}
{...props}
/>
);
}
);

View File

@ -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<LedgerEntry>;
export const LedgerTable = forwardRef<AgGridReact, LedgerEntryProps>(
(props, ref) => {
const columnDefs = useMemo<ColDef[]>(
() => [
{
headerName: t('Sender'),
field: 'fromAccountPartyId',
cellRenderer: ({
value,
}: VegaValueFormatterParams<LedgerEntry, 'fromAccountPartyId'>) =>
truncateByChars(value || ''),
},
{
headerName: t('Account type'),
filter: SetFilter,
filterParams: {
set: AccountTypeMapping,
},
field: 'fromAccountType',
cellRenderer: ({
value,
}: VegaValueFormatterParams<LedgerEntry, 'fromAccountType'>) =>
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<LedgerEntry, 'toAccountPartyId'>) =>
truncateByChars(value || ''),
},
{
headerName: t('Account type'),
filter: SetFilter,
filterParams: {
set: AccountTypeMapping,
},
field: 'toAccountType',
cellRenderer: ({
value,
}: VegaValueFormatterParams<LedgerEntry, 'toAccountType'>) =>
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<LedgerEntry, 'transferType'>) =>
value ? TransferTypeMapping[value] : '',
},
{
headerName: t('Quantity'),
field: 'quantity',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<LedgerEntry, 'quantity'>) => {
const assetDecimalPlaces = data?.asset?.decimals || 0;
return value
? addDecimalsFormatNumber(value, assetDecimalPlaces)
: '';
},
},
{
headerName: t('Asset'),
field: 'assetId',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<LedgerEntry, 'asset'>) =>
data?.asset?.symbol || '',
},
{
headerName: t('Sender account balance'),
field: 'fromAccountBalance',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<LedgerEntry, 'fromAccountBalance'>) => {
const assetDecimalPlaces = data?.asset?.decimals || 0;
return value
? addDecimalsFormatNumber(value, assetDecimalPlaces)
: '';
},
},
{
headerName: t('Receiver account balance'),
field: 'toAccountBalance',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<LedgerEntry, 'toAccountBalance'>) => {
const assetDecimalPlaces = data?.asset?.decimals || 0;
return value
? addDecimalsFormatNumber(value, assetDecimalPlaces)
: '';
},
},
{
headerName: t('Vega time'),
field: 'vegaTime',
valueFormatter: ({
value,
}: VegaValueFormatterParams<LedgerEntry, 'vegaTime'>) =>
value ? getDateTimeFormat().format(fromNanoSeconds(value)) : '-',
filterParams: dateRangeFilterParams,
filter: DateRangeFilter,
flex: 1,
},
],
[]
);
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
@ -61,148 +198,9 @@ export const LedgerTable = forwardRef<AgGridReact, LedgerEntryProps>(
buttons: ['reset'],
},
}}
columnDefs={columnDefs}
{...props}
>
<AgGridColumn
headerName={t('Sender')}
field="fromAccountPartyId"
cellRenderer={({
value,
}: VegaValueFormatterParams<LedgerEntry, 'fromAccountPartyId'>) =>
truncateByChars(value || '')
}
/>
<AgGridColumn
headerName={t('Account type')}
filter={SetFilter}
filterParams={{
set: AccountTypeMapping,
}}
field="fromAccountType"
cellRenderer={({
value,
}: VegaValueFormatterParams<LedgerEntry, 'fromAccountType'>) =>
value ? AccountTypeMapping[value] : '-'
}
/>
<AgGridColumn
headerName={t('Market')}
field="marketSender.tradableInstrument.instrument.code"
cellRenderer={({
value,
}: VegaValueFormatterParams<
LedgerEntry,
'marketSender.tradableInstrument.instrument.code'
>) => value || '-'}
/>
<AgGridColumn
headerName={t('Receiver')}
field="toAccountPartyId"
cellRenderer={({
value,
}: VegaValueFormatterParams<LedgerEntry, 'toAccountPartyId'>) =>
truncateByChars(value || '')
}
/>
<AgGridColumn
headerName={t('Account type')}
filter={SetFilter}
filterParams={{
set: AccountTypeMapping,
}}
field="toAccountType"
cellRenderer={({
value,
}: VegaValueFormatterParams<LedgerEntry, 'toAccountType'>) =>
value ? AccountTypeMapping[value] : '-'
}
/>
<AgGridColumn
headerName={t('Market')}
field="marketReceiver.tradableInstrument.instrument.code"
cellRenderer={({
value,
}: VegaValueFormatterParams<
LedgerEntry,
'marketReceiver.tradableInstrument.instrument.code'
>) => value || '-'}
/>
<AgGridColumn
headerName={t('Transfer type')}
field="transferType"
tooltipField="transferType"
filter={SetFilter}
filterParams={{
set: TransferTypeMapping,
}}
valueFormatter={({
value,
}: VegaValueFormatterParams<LedgerEntry, 'transferType'>) =>
value ? TransferTypeMapping[value] : ''
}
/>
<AgGridColumn
headerName={t('Quantity')}
field="quantity"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<LedgerEntry, 'quantity'>) => {
const assetDecimalPlaces = data?.asset?.decimals || 0;
return value
? addDecimalsFormatNumber(value, assetDecimalPlaces)
: value;
}}
/>
<AgGridColumn
headerName={t('Asset')}
field="assetId"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<LedgerEntry, 'asset'>) =>
data?.asset?.symbol || value
}
/>
<AgGridColumn
headerName={t('Sender account balance')}
field="fromAccountBalance"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<LedgerEntry, 'fromAccountBalance'>) => {
const assetDecimalPlaces = data?.asset?.decimals || 0;
return value
? addDecimalsFormatNumber(value, assetDecimalPlaces)
: value;
}}
/>
<AgGridColumn
headerName={t('Receiver account balance')}
field="toAccountBalance"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<LedgerEntry, 'toAccountBalance'>) => {
const assetDecimalPlaces = data?.asset?.decimals || 0;
return value
? addDecimalsFormatNumber(value, assetDecimalPlaces)
: value;
}}
/>
<AgGridColumn
headerName={t('Vega time')}
field="vegaTime"
valueFormatter={({
value,
}: VegaValueFormatterParams<LedgerEntry, 'vegaTime'>) =>
value ? getDateTimeFormat().format(fromNanoSeconds(value)) : '-'
}
filterParams={dateRangeFilterParams}
filter={DateRangeFilter}
flex={1}
/>
</AgGrid>
/>
);
}
);

View File

@ -188,7 +188,7 @@ export const LiquidityTable = forwardRef<AgGridReact, LiquidityTableProps>(
<AgGrid
style={{ width: '100%', height: '100%' }}
overlayNoRowsTemplate={t('No liquidity provisions')}
getRowId={({ data }) => data.id}
getRowId={({ data }: { data: LiquidityProvisionData }) => data.id || ''}
ref={ref}
tooltipShowDelay={500}
defaultColDef={{

View File

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

View File

@ -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<AgGridReact, Props>((props, ref) => {
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
getRowId={({ data }) => data.id}
ref={ref}
defaultColDef={{
flex: 1,
}}
{...props}
>
<AgGridColumn
headerName={t('Price')}
field="price"
type="rightAligned"
width={130}
cellClass={changeCellClass}
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<Trade, 'price'>) => {
if (!value || !data?.market) {
return null;
}
return addDecimalsFormatNumber(value, data.market.decimalPlaces);
}}
cellRenderer={({
value,
data,
}: VegaICellRendererParams<Trade, 'price'>) => {
if (!data?.market || !value) {
return null;
}
return (
<button
onClick={() =>
props.onClick &&
props.onClick(
addDecimal(value, data.market?.decimalPlaces || 0)
)
}
className="hover:dark:bg-neutral-800 hover:bg-neutral-200"
>
{addDecimalsFormatNumber(value, data.market.decimalPlaces)}
</button>
);
}}
/>
<AgGridColumn
headerName={t('Size')}
field="size"
width={125}
type="rightAligned"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<Trade, 'size'>) => {
if (!value || !data?.market) {
return null;
}
return addDecimalsFormatNumber(
export const TradesTable = forwardRef<AgGridReact, Props>(
({ onClick, ...props }, ref) => {
const columnDefs = useMemo<ColDef[]>(
() => [
{
headerName: t('Price'),
field: 'price',
type: 'rightAligned',
width: 130,
cellClass: changeCellClass,
valueFormatter: ({
value,
data.market.positionDecimalPlaces
);
data,
}: VegaValueFormatterParams<Trade, 'price'>) => {
if (!value || !data?.market) {
return '';
}
return addDecimalsFormatNumber(value, data.market.decimalPlaces);
},
cellRenderer: ({
value,
data,
}: VegaICellRendererParams<Trade, 'price'>) => {
if (!data?.market || !value) {
return '';
}
return (
<button
onClick={() =>
onClick &&
onClick(addDecimal(value, data.market?.decimalPlaces || 0))
}
className="hover:dark:bg-neutral-800 hover:bg-neutral-200"
>
{addDecimalsFormatNumber(value, data.market.decimalPlaces)}
</button>
);
},
},
{
headerName: t('Size'),
field: 'size',
width: 125,
type: 'rightAligned',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<Trade, 'size'>) => {
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<Trade, 'createdAt'>) => {
return value && getDateTimeFormat().format(new Date(value));
},
},
],
[onClick]
);
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
getRowId={({ data }) => data.id}
ref={ref}
defaultColDef={{
flex: 1,
}}
cellRenderer={NumericCell}
columnDefs={columnDefs}
{...props}
/>
<AgGridColumn
headerName={t('Created at')}
field="createdAt"
type="rightAligned"
width={170}
cellClass="text-right"
valueFormatter={({
value,
}: VegaValueFormatterParams<Trade, 'createdAt'>) => {
return value && getDateTimeFormat().format(new Date(value));
}}
/>
</AgGrid>
);
});
);
}
);

View File

@ -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<WithdrawalFieldsFragment> & {
ready?: TimestampedWithdrawals;
delayed?: TimestampedWithdrawals;
}
) => {
export const WithdrawalsTable = ({
delayed,
ready,
...props
}: TypedDataAgGrid<WithdrawalFieldsFragment> & {
ready?: TimestampedWithdrawals;
delayed?: TimestampedWithdrawals;
}) => {
const gridRef = useRef<AgGridReact | null>(null);
const createWithdrawApproval = useEthWithdrawApprovalsStore(
(store) => store.create
);
const columnDefs = useMemo<ColDef[]>(
() => [
{ headerName: 'Asset', field: 'asset.symbol' },
{
headerName: t('Amount'),
field: 'amount',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<WithdrawalFieldsFragment, 'amount'>) => {
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<WithdrawalFieldsFragment>) => ({
component: data?.txHash ? 'EtherscanLinkCell' : 'CompleteCell',
}),
},
],
[createWithdrawApproval, delayed, ready]
);
return (
<AgGrid
overlayNoRowsTemplate={t('No withdrawals')}
columnDefs={columnDefs}
defaultColDef={{ flex: 1 }}
style={{ width: '100%', height: '100%' }}
components={{
@ -59,93 +150,7 @@ export const WithdrawalsTable = (
suppressCellFocus
ref={gridRef}
{...props}
>
<AgGridColumn headerName="Asset" field="asset.symbol" />
<AgGridColumn
headerName={t('Amount')}
field="amount"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<WithdrawalFieldsFragment, 'amount'>) => {
return isNumeric(value) && data?.asset
? addDecimalsFormatNumber(value, data.asset.decimals)
: '';
}}
/>
<AgGridColumn
headerName={t('Recipient')}
field="details.receiverAddress"
cellRenderer="RecipientCell"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<
WithdrawalFieldsFragment,
'details.receiverAddress'
>) => {
if (!data) return null;
if (!value) return '-';
return truncateByChars(value);
}}
/>
<AgGridColumn
headerName={t('Created')}
field="createdTimestamp"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<
WithdrawalFieldsFragment,
'createdTimestamp'
>) =>
data
? value
? getDateTimeFormat().format(new Date(value))
: '-'
: null
}
/>
<AgGridColumn
headerName={t('Completed')}
field="withdrawnTimestamp"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<
WithdrawalFieldsFragment,
'withdrawnTimestamp'
>) =>
data
? value
? getDateTimeFormat().format(new Date(value))
: '-'
: null
}
/>
<AgGridColumn
headerName={t('Status')}
field="status"
cellRendererParams={{ ready: props.ready, delayed: props.delayed }}
cellRenderer="StatusCell"
/>
<AgGridColumn
headerName={t('Transaction')}
field="txHash"
flex={2}
type="rightAligned"
cellRendererParams={{
complete: (withdrawal: WithdrawalFieldsFragment) => {
createWithdrawApproval(withdrawal);
},
}}
cellRendererSelector={({
data,
}: VegaICellRendererParams<WithdrawalFieldsFragment>) => ({
component: data?.txHash ? 'EtherscanLinkCell' : 'CompleteCell',
})}
/>
</AgGrid>
/>
);
};

View File

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

View File

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