chore: ag grid row data and value can be undefined (#1709)
* chore: improve ag-grid typings - fix runtime bug * chore: improve ag-grid typings - add numeric type checking * chore: improve ag-grid typings - remove redundant cl * chore: improve ag-grid typings - remove redundant cl * chore: improve ag-grid typings - add some basic unit test * chore: improve ag-grid typings - add some basic unit test Co-authored-by: maciek <maciek@vegaprotocol.io>
This commit is contained in:
parent
50df63c858
commit
00381a2b3e
@ -1,7 +1,11 @@
|
||||
import { forwardRef, useState } from 'react';
|
||||
import type { ValueFormatterParams } from 'ag-grid-community';
|
||||
import type { Asset } from '@vegaprotocol/assets';
|
||||
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
isNumeric,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
ValueProps,
|
||||
VegaICellRendererParams,
|
||||
@ -95,7 +99,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
cellRenderer={({
|
||||
value,
|
||||
}: VegaICellRendererParams<AccountFields, 'asset.symbol'>) => {
|
||||
return (
|
||||
return value ? (
|
||||
<ButtonLink
|
||||
data-testid="deposit"
|
||||
onClick={() => {
|
||||
@ -104,7 +108,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
>
|
||||
{value}
|
||||
</ButtonLink>
|
||||
);
|
||||
) : null;
|
||||
}}
|
||||
maxWidth={300}
|
||||
/>
|
||||
@ -120,6 +124,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
}: VegaValueFormatterParams<AccountFields, 'deposited'>) =>
|
||||
data &&
|
||||
data.asset &&
|
||||
isNumeric(value) &&
|
||||
addDecimalsFormatNumber(value, data.asset.decimals)
|
||||
}
|
||||
maxWidth={300}
|
||||
@ -162,7 +167,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
cellRenderer={({
|
||||
data,
|
||||
}: VegaICellRendererParams<AccountFields>) => {
|
||||
return (
|
||||
return data ? (
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button
|
||||
size="xs"
|
||||
@ -184,7 +189,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
{t('Withdraw')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
) : null;
|
||||
}}
|
||||
/>
|
||||
</AgGrid>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { forwardRef } from 'react';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
isNumeric,
|
||||
PriceCell,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
@ -48,7 +49,7 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
|
||||
valueFormatter={({
|
||||
value,
|
||||
}: VegaValueFormatterParams<AccountFields, 'type'>) =>
|
||||
AccountTypeMapping[value]
|
||||
value ? AccountTypeMapping[value] : ''
|
||||
}
|
||||
/>
|
||||
<AgGridColumn
|
||||
@ -81,7 +82,7 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<AccountFields, 'balance'>) => {
|
||||
if (data && data.asset) {
|
||||
if (data && data.asset && isNumeric(value)) {
|
||||
return addDecimalsFormatNumber(value, data.asset.decimals);
|
||||
}
|
||||
return '-';
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
getDateTimeFormat,
|
||||
truncateByChars,
|
||||
isNumeric,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
VegaICellRendererParams,
|
||||
@ -36,7 +37,9 @@ export const DepositsTable = ({ deposits }: DepositsTableProps) => {
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<DepositFieldsFragment, 'amount'>) => {
|
||||
return addDecimalsFormatNumber(value, data.asset.decimals);
|
||||
return isNumeric(value) && data
|
||||
? addDecimalsFormatNumber(value, data.asset.decimals)
|
||||
: null;
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
@ -48,7 +51,7 @@ export const DepositsTable = ({ deposits }: DepositsTableProps) => {
|
||||
DepositFieldsFragment,
|
||||
'createdTimestamp'
|
||||
>) => {
|
||||
return getDateTimeFormat().format(new Date(value));
|
||||
return value ? getDateTimeFormat().format(new Date(value)) : '';
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
@ -57,7 +60,7 @@ export const DepositsTable = ({ deposits }: DepositsTableProps) => {
|
||||
valueFormatter={({
|
||||
value,
|
||||
}: VegaValueFormatterParams<DepositFieldsFragment, 'status'>) => {
|
||||
return DepositStatusMapping[value];
|
||||
return value ? DepositStatusMapping[value] : '';
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
positiveClassNames,
|
||||
negativeClassNames,
|
||||
t,
|
||||
isNumeric,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import { AgGridColumn } from 'ag-grid-react';
|
||||
@ -81,7 +82,7 @@ export const FillsTable = forwardRef<AgGridReact, Props>(
|
||||
valueFormatter={({
|
||||
value,
|
||||
}: VegaValueFormatterParams<Trade, 'createdAt'>) => {
|
||||
return getDateTimeFormat().format(new Date(value));
|
||||
return value ? getDateTimeFormat().format(new Date(value)) : '';
|
||||
}}
|
||||
/>
|
||||
</AgGrid>
|
||||
@ -93,7 +94,7 @@ const formatPrice = ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<Trade, 'price'>) => {
|
||||
if (!data.market) {
|
||||
if (!data?.market || !isNumeric(value)) {
|
||||
return '-';
|
||||
}
|
||||
const asset =
|
||||
@ -107,7 +108,7 @@ const formatPrice = ({
|
||||
|
||||
const formatSize = (partyId: string) => {
|
||||
return ({ value, data }: VegaValueFormatterParams<Trade, 'size'>) => {
|
||||
if (!data.market) {
|
||||
if (!data?.market || !isNumeric(value)) {
|
||||
return '-';
|
||||
}
|
||||
let prefix = '';
|
||||
@ -144,7 +145,7 @@ const formatTotal = ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<Trade, 'price'>) => {
|
||||
if (!data?.market) {
|
||||
if (!data?.market || !isNumeric(value)) {
|
||||
return '-';
|
||||
}
|
||||
const asset =
|
||||
@ -189,7 +190,7 @@ const formatFee = (partyId: string) => {
|
||||
Trade,
|
||||
'market.tradableInstrument.instrument.product'
|
||||
>) => {
|
||||
if (!value?.settlementAsset) {
|
||||
if (!value?.settlementAsset || !data) {
|
||||
return '-';
|
||||
}
|
||||
const asset = value.settlementAsset;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { act, render, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { addDecimal, getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
||||
import { OrderTimeInForce, OrderType } from '@vegaprotocol/types';
|
||||
import {
|
||||
OrderRejectionReasonMapping,
|
||||
@ -108,7 +108,7 @@ describe('OrderListTable', () => {
|
||||
OrderTypeMapping[limitOrder.type || OrderType.TYPE_LIMIT],
|
||||
OrderStatusMapping[limitOrder.status],
|
||||
'5',
|
||||
addDecimal(limitOrder.price, limitOrder.market?.decimalPlaces ?? 0),
|
||||
'-',
|
||||
`${
|
||||
OrderTimeInForceMapping[limitOrder.timeInForce]
|
||||
}: ${getDateTimeFormat().format(new Date(limitOrder.expiresAt ?? ''))}`,
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
t,
|
||||
positiveClassNames,
|
||||
negativeClassNames,
|
||||
isNumeric,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
VegaICellRendererParams,
|
||||
@ -128,7 +129,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<Order, 'size'>) => {
|
||||
if (!data.market) {
|
||||
if (!data?.market || !isNumeric(value)) {
|
||||
return '-';
|
||||
}
|
||||
const prefix = data
|
||||
@ -148,8 +149,8 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
value,
|
||||
}: VegaValueFormatterParams<Order, 'type'>) => {
|
||||
if (!value) return '-';
|
||||
if (order.peggedOrder) return t('Pegged');
|
||||
if (order.liquidityProvision) return t('Liquidity provision');
|
||||
if (order?.peggedOrder) return t('Pegged');
|
||||
if (order?.liquidityProvision) return t('Liquidity provision');
|
||||
return OrderTypeMapping[value];
|
||||
}}
|
||||
/>
|
||||
@ -161,11 +162,11 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
}: VegaValueFormatterParams<Order, 'status'>) => {
|
||||
if (value === OrderStatus.STATUS_REJECTED) {
|
||||
return `${OrderStatusMapping[value]}: ${
|
||||
data.rejectionReason &&
|
||||
data?.rejectionReason &&
|
||||
OrderRejectionReasonMapping[data.rejectionReason]
|
||||
}`;
|
||||
}
|
||||
return OrderStatusMapping[value];
|
||||
return value ? OrderStatusMapping[value] : '';
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
@ -177,7 +178,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
data,
|
||||
value,
|
||||
}: VegaValueFormatterParams<Order, 'remaining'>) => {
|
||||
if (!data.market) {
|
||||
if (!data?.market || !isNumeric(value) || !isNumeric(data.size)) {
|
||||
return '-';
|
||||
}
|
||||
const dps = data.market.positionDecimalPlaces;
|
||||
@ -198,7 +199,11 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<Order, 'price'>) => {
|
||||
if (!data.market || data.type === OrderType.TYPE_MARKET) {
|
||||
if (
|
||||
!data?.market ||
|
||||
data.type === OrderType.TYPE_MARKET ||
|
||||
!isNumeric(value)
|
||||
) {
|
||||
return '-';
|
||||
}
|
||||
return addDecimal(value, data.market.decimalPlaces);
|
||||
@ -212,7 +217,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
}: VegaValueFormatterParams<Order, 'timeInForce'>) => {
|
||||
if (
|
||||
value === OrderTimeInForce.TIME_IN_FORCE_GTT &&
|
||||
data.expiresAt
|
||||
data?.expiresAt
|
||||
) {
|
||||
const expiry = getDateTimeFormat().format(
|
||||
new Date(data.expiresAt)
|
||||
@ -220,7 +225,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
return `${OrderTimeInForceMapping[value]}: ${expiry}`;
|
||||
}
|
||||
|
||||
return OrderTimeInForceMapping[value];
|
||||
return value ? OrderTimeInForceMapping[value] : '';
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
@ -245,7 +250,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
field="status"
|
||||
cellRenderer={({ data }: VegaICellRendererParams<Order>) => {
|
||||
if (isOrderAmendable(data)) {
|
||||
return (
|
||||
return data ? (
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
data-testid="edit"
|
||||
@ -262,7 +267,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
|
||||
{t('Cancel')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
) : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1,5 +1,10 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { formatNumber, formatNumberPercentage, toNumberParts } from './number';
|
||||
import {
|
||||
formatNumber,
|
||||
formatNumberPercentage,
|
||||
toNumberParts,
|
||||
isNumeric,
|
||||
} from './number';
|
||||
|
||||
describe('formatNumber and formatNumberPercentage', () => {
|
||||
it.each([
|
||||
@ -46,3 +51,41 @@ describe('toNumberParts', () => {
|
||||
expect(toNumberParts(v, d)).toStrictEqual(o);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isNumeric', () => {
|
||||
it.each([
|
||||
{ i: null, o: false },
|
||||
{ i: undefined, o: false },
|
||||
{ i: 1, o: true },
|
||||
{ i: '1', o: true },
|
||||
{ i: '-1', o: true },
|
||||
{ i: 0.1, o: true },
|
||||
{ i: '.1', o: true },
|
||||
{ i: '-.1', o: true },
|
||||
{ i: 123, o: true },
|
||||
{ i: -123, o: true },
|
||||
{ i: '123', o: true },
|
||||
{ i: '123.01', o: true },
|
||||
{ i: '-123.01', o: true },
|
||||
{ i: '--123.01', o: false },
|
||||
{ i: '123.', o: false },
|
||||
{ i: '123.1.1', o: false },
|
||||
{ i: new BigNumber(123), o: true },
|
||||
{ i: new BigNumber(123.123), o: true },
|
||||
{ i: new BigNumber(123.123).toString(), o: true },
|
||||
{ i: new BigNumber(123), o: true },
|
||||
{ i: Infinity, o: false },
|
||||
{ i: NaN, o: false },
|
||||
])(
|
||||
'returns correct results',
|
||||
({
|
||||
i,
|
||||
o,
|
||||
}: {
|
||||
i: number | string | undefined | null | BigNumber;
|
||||
o: boolean;
|
||||
}) => {
|
||||
expect(isNumeric(i)).toStrictEqual(o);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -96,3 +96,7 @@ export const useNumberParts = (
|
||||
): [integers: string, decimalPlaces: string] => {
|
||||
return React.useMemo(() => toNumberParts(value, decimals), [decimals, value]);
|
||||
};
|
||||
|
||||
export const isNumeric = (
|
||||
value?: string | number | BigNumber | null
|
||||
): value is NonNullable<number | string> => /^-?\d*\.?\d+$/.test(String(value));
|
||||
|
@ -16,8 +16,8 @@ type RowHelper<TObj, TRow, TField extends Field> = Omit<
|
||||
TObj,
|
||||
'data' | 'value'
|
||||
> & {
|
||||
data: TRow;
|
||||
value: Get<TRow, TField>;
|
||||
data?: TRow;
|
||||
value?: Get<TRow, TField>;
|
||||
};
|
||||
|
||||
export type VegaValueFormatterParams<TRow, TField extends Field> = RowHelper<
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
t,
|
||||
truncateByChars,
|
||||
addDecimalsFormatNumber,
|
||||
isNumeric,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
TypedDataAgGrid,
|
||||
@ -60,7 +61,9 @@ export const PendingWithdrawalsTable = (
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<WithdrawalFields, 'amount'>) => {
|
||||
return addDecimalsFormatNumber(value, data.asset.decimals);
|
||||
return isNumeric(value) && data?.asset
|
||||
? addDecimalsFormatNumber(value, data.asset.decimals)
|
||||
: null;
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
@ -105,7 +108,7 @@ export const PendingWithdrawalsTable = (
|
||||
WithdrawalFields,
|
||||
'createdTimestamp'
|
||||
>) => {
|
||||
return getDateTimeFormat().format(new Date(value));
|
||||
return value ? getDateTimeFormat().format(new Date(value)) : '';
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
t,
|
||||
truncateByChars,
|
||||
addDecimalsFormatNumber,
|
||||
isNumeric,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
TypedDataAgGrid,
|
||||
@ -37,7 +38,9 @@ export const WithdrawalsTable = (props: TypedDataAgGrid<WithdrawalFields>) => {
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<WithdrawalFields, 'amount'>) => {
|
||||
return addDecimalsFormatNumber(value, data.asset.decimals);
|
||||
return isNumeric(value) && data?.asset
|
||||
? addDecimalsFormatNumber(value, data.asset.decimals)
|
||||
: '';
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
@ -64,7 +67,7 @@ export const WithdrawalsTable = (props: TypedDataAgGrid<WithdrawalFields>) => {
|
||||
WithdrawalFields,
|
||||
'withdrawnTimestamp'
|
||||
>) => {
|
||||
const ts = data.withdrawnTimestamp;
|
||||
const ts = data?.withdrawnTimestamp;
|
||||
if (!ts) return '-';
|
||||
return getDateTimeFormat().format(new Date(ts));
|
||||
}}
|
||||
|
Loading…
Reference in New Issue
Block a user