feat(trading): clarify collateral and breakdown tables (#3113)

This commit is contained in:
m.ray 2023-03-13 14:15:53 -04:00 committed by GitHub
parent 3edd91eadb
commit 64cf0c90a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 386 additions and 294 deletions

View File

@ -22,24 +22,25 @@ describe('accounts', { tags: '@smoke' }, () => {
cy.getByTestId('tab-accounts')
.get(tradingAccountRowId)
.find('[col-id="breakdown"] [data-testid="breakdown"]')
.should('have.text', 'Breakdown');
.find('[col-id="accounts-actions"]')
.should('have.text', 'DepositWithdraw');
cy.getByTestId('tab-accounts')
.get(tradingAccountRowId)
.find('[col-id="breakdown"] [data-testid="deposit"]')
.find('[data-testid="deposit"]')
.should('have.text', 'Deposit');
cy.getByTestId('tab-accounts')
.get(tradingAccountRowId)
.find('[col-id="breakdown"] [data-testid="withdraw"]')
.find('[col-id="accounts-actions"] [data-testid="withdraw"]')
.should('have.text', 'Withdraw');
cy.getByTestId('tab-accounts')
.get(tradingAccountRowId)
.find('[col-id="deposited"]')
.find('[col-id="total"]')
.should('have.text', '100,001.01');
});
describe('sorting by ag-grid columns should work well', () => {
it('sorting by asset', () => {
cy.getByTestId('Collateral').click();
@ -78,7 +79,7 @@ describe('accounts', { tags: '@smoke' }, () => {
'1,000.00',
];
checkSorting(
'deposited',
'total',
marketsSortedDefault,
marketsSortedAsc,
marketsSortedDesc
@ -87,9 +88,27 @@ describe('accounts', { tags: '@smoke' }, () => {
it('sorting by used', () => {
cy.getByTestId('Collateral').click();
const marketsSortedDefault = ['0.00', '1.01', '0.01', '0.00', '0.00'];
const marketsSortedAsc = ['0.00', '0.00', '0.00', '0.01', '1.01'];
const marketsSortedDesc = ['1.01', '0.01', '0.00', '0.00', '0.00'];
const marketsSortedDefault = [
'0.000.00%',
'1.010.00%',
'0.010.00%',
'0.000.00%',
'0.000.00%',
];
const marketsSortedAsc = [
'0.000.00%',
'0.000.00%',
'0.000.00%',
'0.010.00%',
'1.010.00%',
];
const marketsSortedDesc = [
'1.010.00%',
'0.010.00%',
'0.000.00%',
'0.000.00%',
'0.000.00%',
];
checkSorting(
'used',
marketsSortedDefault,
@ -98,32 +117,32 @@ describe('accounts', { tags: '@smoke' }, () => {
);
});
it('sorting by available', () => {
it('sorting by total', () => {
cy.getByTestId('Collateral').click();
const marketsSortedDefault = [
'1,000.00002',
'100,000.00',
'1,000.00',
'100,001.01',
'1,000.01',
'1,000.00',
'1,000.00001',
];
const marketsSortedAsc = [
'1,000.00',
'1,000.00',
'1,000.00001',
'1,000.00002',
'100,000.00',
'1,000.01',
'100,001.01',
];
const marketsSortedDesc = [
'100,000.00',
'100,001.01',
'1,000.01',
'1,000.00002',
'1,000.00001',
'1,000.00',
'1,000.00',
];
checkSorting(
'available',
'total',
marketsSortedDefault,
marketsSortedAsc,
marketsSortedDesc

View File

@ -159,38 +159,50 @@ const accountResult = [
{
asset: {
__typename: 'Asset',
decimals: 5,
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'tBTC',
decimals: 5,
},
available: '4000000000000001006031',
balance: '4000000000000001006031',
breakdown: [],
deposited: '4000000000000001006031',
type: AccountType.ACCOUNT_TYPE_GENERAL,
type: 'ACCOUNT_TYPE_GENERAL',
available: '4000000000000001006031',
used: '0',
total: '4000000000000001006031',
breakdown: [
{
__typename: 'AccountBalance',
type: 'ACCOUNT_TYPE_GENERAL',
balance: '4000000000000001006031',
market: null,
asset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'tBTC',
decimals: 5,
},
total: '4000000000000001006031',
available: '4000000000000001006031',
used: '4000000000000001006031',
},
],
},
{
asset: {
__typename: 'Asset',
decimals: 5,
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
decimals: 5,
},
available: '5000593078',
balance: '5000593078',
type: 'ACCOUNT_TYPE_GENERAL',
available: '5000593078',
used: '406922',
total: '5001000000',
breakdown: [
{
__typename: 'AccountBalance',
asset: {
__typename: 'Asset',
decimals: 5,
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
},
available: '5000593078',
type: 'ACCOUNT_TYPE_MARGIN',
balance: '406922',
deposited: '5001000000',
market: {
__typename: 'Market',
id: '9c1ee71959e566c484fcea796513137f8a02219cca2e973b7ae72dc29d099581',
@ -202,35 +214,50 @@ const accountResult = [
},
},
},
type: AccountType.ACCOUNT_TYPE_MARGIN,
asset: {
__typename: 'Asset',
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
decimals: 5,
},
total: '5001000000',
available: '5000593078',
used: '406922',
},
{
__typename: 'AccountBalance',
type: 'ACCOUNT_TYPE_GENERAL',
balance: '5000593078',
market: null,
asset: {
__typename: 'Asset',
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
decimals: 5,
},
total: '5001000000',
available: '5000593078',
used: '5000593078',
},
],
deposited: '5001000000',
type: AccountType.ACCOUNT_TYPE_GENERAL,
used: '406922',
},
{
asset: {
__typename: 'Asset',
decimals: 5,
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
symbol: 'tEURO',
decimals: 5,
},
available: '2996218603',
balance: '2996218603',
type: 'ACCOUNT_TYPE_GENERAL',
available: '2996218603',
used: '2781397',
total: '2999000000',
breakdown: [
{
__typename: 'AccountBalance',
asset: {
__typename: 'Asset',
decimals: 5,
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
symbol: 'tEURO',
},
available: '2996218603',
type: 'ACCOUNT_TYPE_MARGIN',
balance: '2781397',
deposited: '2999000000',
market: {
__typename: 'Market',
id: 'd90fd7c746286625504d7a3f5f420a280875acd3cd611676d9e70acc675f4540',
@ -242,40 +269,91 @@ const accountResult = [
},
},
},
type: AccountType.ACCOUNT_TYPE_MARGIN,
asset: {
__typename: 'Asset',
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
symbol: 'tEURO',
decimals: 5,
},
total: '2999000000',
available: '2996218603',
used: '2781397',
},
{
__typename: 'AccountBalance',
type: 'ACCOUNT_TYPE_GENERAL',
balance: '2996218603',
market: null,
asset: {
__typename: 'Asset',
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
symbol: 'tEURO',
decimals: 5,
},
total: '2999000000',
available: '2996218603',
used: '2996218603',
},
],
deposited: '2999000000',
type: AccountType.ACCOUNT_TYPE_GENERAL,
used: '2781397',
},
{
asset: {
__typename: 'Asset',
decimals: 5,
id: '993ed98f4f770d91a796faab1738551193ba45c62341d20597df70fea6704ede',
symbol: 'tUSDC',
decimals: 5,
},
available: '1990351587',
balance: '1990351587',
breakdown: [],
deposited: '1990351587',
type: AccountType.ACCOUNT_TYPE_GENERAL,
type: 'ACCOUNT_TYPE_GENERAL',
available: '1990351587',
used: '0',
total: '1990351587',
breakdown: [
{
__typename: 'AccountBalance',
type: 'ACCOUNT_TYPE_GENERAL',
balance: '1990351587',
market: null,
asset: {
__typename: 'Asset',
id: '993ed98f4f770d91a796faab1738551193ba45c62341d20597df70fea6704ede',
symbol: 'tUSDC',
decimals: 5,
},
total: '1990351587',
available: '1990351587',
used: '1990351587',
},
],
},
{
asset: {
__typename: 'Asset',
decimals: 5,
id: 'XYZalpha',
symbol: 'XYZalpha',
decimals: 5,
},
available: '10001000000',
balance: '10001000000',
breakdown: [],
deposited: '10001000000',
type: AccountType.ACCOUNT_TYPE_GENERAL,
type: 'ACCOUNT_TYPE_GENERAL',
available: '10001000000',
used: '0',
total: '10001000000',
breakdown: [
{
__typename: 'AccountBalance',
type: 'ACCOUNT_TYPE_GENERAL',
balance: '10001000000',
market: null,
asset: {
__typename: 'Asset',
id: 'XYZalpha',
symbol: 'XYZalpha',
decimals: 5,
},
total: '10001000000',
available: '10001000000',
used: '10001000000',
},
],
},
] as AccountFields[];

View File

@ -99,7 +99,7 @@ export const accountsOnlyDataProvider = makeDataProvider<
export interface AccountFields extends Account {
available: string;
used: string;
deposited: string;
total: string;
balance: string;
breakdown?: AccountFields[];
}
@ -145,15 +145,17 @@ const getAssetAccountAggregation = (
type: AccountType.ACCOUNT_TYPE_GENERAL,
available: available.toString(),
used: used.toString(),
deposited: (available + used).toString(),
total: (available + used).toString(),
};
const breakdown = accounts
.filter((a) => USE_ACCOUNT_TYPES.includes(a.type))
.filter((a) =>
[...USE_ACCOUNT_TYPES, AccountType.ACCOUNT_TYPE_GENERAL].includes(a.type)
)
.map((a) => ({
...a,
asset: accounts[0].asset,
deposited: balanceAccount.deposited,
total: balanceAccount.total,
available: balanceAccount.available,
used: a.balance,
}))

View File

@ -27,7 +27,7 @@ const singleRow = {
},
available: '125600000',
used: '125600000',
deposited: '125600000',
total: '251200000',
} as AccountFields;
const singleRowData = [singleRow];
@ -42,7 +42,7 @@ describe('AccountsTable', () => {
/>
);
});
const expectedHeaders = ['Asset', 'Total', 'Used', 'Available', ''];
const expectedHeaders = ['Asset', 'Used', 'Available', 'Total', ''];
const headers = await screen.findAllByRole('columnheader');
expect(headers).toHaveLength(expectedHeaders.length);
expect(
@ -65,8 +65,7 @@ describe('AccountsTable', () => {
'tBTC',
'1,256.00',
'1,256.00',
'1,256.00',
'Breakdown',
'2,512.00',
'Deposit',
'Withdraw',
];
@ -88,13 +87,8 @@ describe('AccountsTable', () => {
);
});
const cells = await screen.findAllByRole('gridcell');
const expectedValues = [
'tBTC',
'1,256.00',
'1,256.00',
'1,256.00',
'Breakdown',
];
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]);
});
@ -145,7 +139,7 @@ describe('AccountsTable', () => {
},
available: '0',
balance: '125600000',
deposited: '125600000',
total: '125600000',
market: {
__typename: 'Market',
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
@ -161,7 +155,7 @@ describe('AccountsTable', () => {
used: '125600000',
},
],
deposited: '125600000',
total: '125600000',
type: 'ACCOUNT_TYPE_GENERAL',
used: '125600000',
},

View File

@ -8,7 +8,6 @@ import { t } from '@vegaprotocol/i18n';
import type {
VegaICellRendererParams,
VegaValueFormatterParams,
VegaValueGetterParams,
} from '@vegaprotocol/datagrid';
import { Button, ButtonLink, Dialog } from '@vegaprotocol/ui-toolkit';
import { TooltipCellComponent } from '@vegaprotocol/ui-toolkit';
@ -17,12 +16,56 @@ import {
CenteredGridCellWrapper,
} from '@vegaprotocol/datagrid';
import { AgGridColumn } from 'ag-grid-react';
import type { IDatasource, IGetRowsParams } from 'ag-grid-community';
import type { IDatasource, IGetRowsParams, RowNode } from 'ag-grid-community';
import type { AgGridReact, AgGridReactProps } from 'ag-grid-react';
import BreakdownTable from './breakdown-table';
import type { AccountFields } from './accounts-data-provider';
import type { Asset } from '@vegaprotocol/types';
import BigNumber from 'bignumber.js';
import classNames from 'classnames';
const colorClass = (percentageUsed: number, neutral = false) => {
return classNames({
'text-neutral-500 dark:text-neutral-400': percentageUsed < 75 && !neutral,
'text-vega-orange': percentageUsed >= 75 && percentageUsed < 90,
'text-vega-pink': percentageUsed >= 90,
});
};
export const percentageValue = (part?: string, total?: string) =>
new BigNumber(part || 0)
.dividedBy(total || 1)
.multipliedBy(100)
.toNumber();
const formatWithAssetDecimals = (
data: AccountFields | undefined,
value: string | undefined
) => {
return (
data &&
data.asset &&
isNumeric(value) &&
addDecimalsFormatNumber(value, data.asset.decimals)
);
};
export const accountValuesComparator = (
valueA: string,
valueB: string,
nodeA: RowNode,
nodeB: RowNode
) => {
if (isNumeric(valueA) && isNumeric(valueB)) {
const a = toBigNum(valueA, nodeA.data.asset?.decimals);
const b = toBigNum(valueB, nodeB.data.asset?.decimals);
if (a.isEqualTo(b)) return 0;
return a.isGreaterThan(b) ? 1 : -1;
}
if (valueA === valueB) return 0;
return valueA > valueB ? 1 : -1;
};
export interface GetRowsParams extends Omit<IGetRowsParams, 'successCallback'> {
successCallback(rowsThisBlock: AccountFields[], lastRow?: number): void;
@ -47,7 +90,7 @@ export interface AccountTableProps extends AgGridReactProps {
export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
({ onClickAsset, onClickWithdraw, onClickDeposit, ...props }, ref) => {
const [openBreakdown, setOpenBreakdown] = useState(false);
const [breakdown, setBreakdown] = useState<AccountFields[] | null>(null);
const [row, setRow] = useState<AccountFields>();
const pinnedAssetId = props.pinnedAsset?.id;
const pinnedAssetRow = useMemo(() => {
@ -60,7 +103,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
asset: props.pinnedAsset,
available: '0',
used: '0',
deposited: '0',
total: '0',
balance: '0',
};
}
@ -81,6 +124,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
resizable: true,
tooltipComponent: TooltipCellComponent,
sortable: true,
comparator: accountValuesComparator,
}}
{...props}
pinnedTopRowData={pinnedAssetRow ? [pinnedAssetRow] : undefined}
@ -94,90 +138,64 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
cellRenderer={({
value,
data,
node,
}: VegaICellRendererParams<AccountFields, 'asset.symbol'>) => {
return value ? (
<CenteredGridCellWrapper
className={node.rowPinned ? 'h-[30px]' : undefined}
return (
<ButtonLink
data-testid="asset"
onClick={() => {
if (data) {
onClickAsset(data.asset.id);
}
}}
>
<ButtonLink
data-testid="asset"
onClick={() => {
if (data) {
onClickAsset(data.asset.id);
}
}}
>
{value}
</ButtonLink>
</CenteredGridCellWrapper>
) : null;
}}
maxWidth={300}
/>
<AgGridColumn
headerName={t('Total')}
type="rightAligned"
field="deposited"
headerTooltip={t(
'This is the total amount of collateral used plus the amount available in your general account.'
)}
valueGetter={({
data,
}: VegaValueGetterParams<AccountFields, 'deposited'>) => {
return !data?.deposited
? undefined
: toBigNum(data.deposited, data.asset.decimals).toNumber();
}}
maxWidth={300}
cellRenderer={({
data,
node,
}: VegaICellRendererParams<AccountFields, 'deposited'>) => {
const valueFormatted =
data &&
data.asset &&
isNumeric(data.deposited) &&
addDecimalsFormatNumber(data.deposited, data.asset.decimals);
return node.rowPinned ? (
<CenteredGridCellWrapper className="h-[30px] justify-end">
{valueFormatted}
</CenteredGridCellWrapper>
) : (
valueFormatted
{value}
</ButtonLink>
);
}}
maxWidth={300}
/>
<AgGridColumn
headerName={t('Used')}
type="rightAligned"
field="used"
headerTooltip={t(
'This is the amount of collateral used from your general account.'
'Currently allocated to a market as margin or bond. Check the breakdown for details.'
)}
valueGetter={({
data,
}: VegaValueGetterParams<AccountFields, 'used'>) => {
return !data?.used
? undefined
: toBigNum(data.used, data.asset.decimals).toNumber();
}}
maxWidth={300}
cellRenderer={({
data,
node,
value,
}: VegaICellRendererParams<AccountFields, 'used'>) => {
const valueFormatted =
data &&
data.asset &&
isNumeric(data.used) &&
addDecimalsFormatNumber(data.used, data.asset.decimals);
return node.rowPinned ? (
<CenteredGridCellWrapper className="h-[30px] justify-end">
{valueFormatted}
</CenteredGridCellWrapper>
if (!data) return null;
const percentageUsed = percentageValue(value, data.total);
const valueFormatted = formatWithAssetDecimals(data, value);
return data.breakdown ? (
<>
<ButtonLink
data-testid="breakdown"
onClick={() => {
setOpenBreakdown(!openBreakdown);
setRow(data);
}}
>
<span>{valueFormatted}</span>
</ButtonLink>
<span
className={classNames(
colorClass(percentageUsed),
'ml-2 inline-block w-14'
)}
>
{percentageUsed.toFixed(2)}%
</span>
</>
) : (
valueFormatted
<>
<span>{valueFormatted}</span>
<span className="ml-2 inline-block w-14 text-neutral-500 dark:text-neutral-400">
0.00%
</span>
</>
);
}}
/>
@ -186,115 +204,113 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
field="available"
type="rightAligned"
headerTooltip={t(
'This is the amount of collateral available in your general account.'
'Deposited on the network, but not allocated to a market. Free to use for placing orders or providing liquidity.'
)}
valueGetter={({
data,
}: VegaValueGetterParams<AccountFields, 'available'>) => {
return !data?.available
? undefined
: toBigNum(data.available, data.asset.decimals).toNumber();
}}
valueFormatter={({
data,
}: VegaValueFormatterParams<AccountFields, 'available'>) =>
data &&
data.asset &&
isNumeric(data.available) &&
addDecimalsFormatNumber(data.available, data.asset.decimals)
}
maxWidth={300}
cellRenderer={({
value,
data,
node,
}: VegaICellRendererParams<AccountFields, 'available'>) => {
const valueFormatted =
data &&
data.asset &&
isNumeric(data.available) &&
addDecimalsFormatNumber(data.available, data.asset.decimals);
return node.rowPinned ? (
<CenteredGridCellWrapper className="h-[30px] justify-end">
{valueFormatted}
</CenteredGridCellWrapper>
) : (
valueFormatted
const percentageUsed = percentageValue(data?.used, data?.total);
return (
<span className={colorClass(percentageUsed, true)}>
{formatWithAssetDecimals(data, value)}
</span>
);
}}
/>
<AgGridColumn
colId="breakdown"
headerName=""
sortable={false}
minWidth={200}
headerName={t('Total')}
type="rightAligned"
cellRenderer={({
field="total"
headerTooltip={t(
'The total amount of each asset on this key. Includes used and available collateral.'
)}
valueFormatter={({
data,
}: VegaICellRendererParams<AccountFields>) => {
if (!data) return null;
else {
if (
data.asset.id === pinnedAssetId &&
new BigNumber(data.deposited).isLessThanOrEqualTo(0)
) {
}: VegaValueFormatterParams<AccountFields, 'total'>) =>
formatWithAssetDecimals(data, data?.total)
}
/>
{
<AgGridColumn
colId="accounts-actions"
headerName=""
sortable={false}
minWidth={200}
type="rightAligned"
cellRenderer={({
data,
}: VegaICellRendererParams<AccountFields>) => {
if (!data) return null;
else {
if (
data.asset.id === pinnedAssetId &&
new BigNumber(data.total).isLessThanOrEqualTo(0)
) {
return (
<CenteredGridCellWrapper className="h-[30px] justify-end py-1">
<Button
size="xs"
variant="primary"
data-testid="deposit"
onClick={() => {
onClickDeposit && onClickDeposit(data.asset.id);
}}
>
{t('Deposit to trade')}
</Button>
</CenteredGridCellWrapper>
);
}
return (
<CenteredGridCellWrapper className="h-[30px] justify-end py-1">
<Button
size="xs"
variant="primary"
data-testid="deposit"
onClick={() => {
onClickDeposit && onClickDeposit(data.asset.id);
}}
>
{t('Deposit to trade')}
</Button>
</CenteredGridCellWrapper>
<>
<span className="mx-1" />
{!props.isReadOnly && (
<ButtonLink
data-testid="deposit"
onClick={() => {
onClickDeposit && onClickDeposit(data.asset.id);
}}
>
{t('Deposit')}
</ButtonLink>
)}
<span className="mx-1" />
{!props.isReadOnly && (
<ButtonLink
data-testid="withdraw"
onClick={() =>
onClickWithdraw && onClickWithdraw(data.asset.id)
}
>
{t('Withdraw')}
</ButtonLink>
)}
</>
);
}
return (
<>
<ButtonLink
data-testid="breakdown"
onClick={() => {
setOpenBreakdown(!openBreakdown);
setBreakdown(data.breakdown || null);
}}
>
{t('Breakdown')}
</ButtonLink>
<span className="mx-1" />
{!props.isReadOnly && (
<ButtonLink
data-testid="deposit"
onClick={() => {
onClickDeposit && onClickDeposit(data.asset.id);
}}
>
{t('Deposit')}
</ButtonLink>
)}
<span className="mx-1" />
{!props.isReadOnly && (
<ButtonLink
data-testid="withdraw"
onClick={() =>
onClickWithdraw && onClickWithdraw(data.asset.id)
}
>
{t('Withdraw')}
</ButtonLink>
)}
</>
);
}
}}
/>
}}
/>
}
</AgGrid>
<Dialog size="medium" open={openBreakdown} onChange={setOpenBreakdown}>
<div className="h-[35vh] w-full m-auto flex flex-col">
<h1 className="text-xl mb-4">{t('Collateral breakdown')}</h1>
<BreakdownTable data={breakdown} domLayout="autoHeight" />
<h1 className="text-xl mb-4">
{row?.asset?.symbol} {t('usage breakdown')}
</h1>
{row && (
<p className="mb-2 text-sm">
{t('You have %s %s in total.', [
addDecimalsFormatNumber(row.total, row.asset.decimals),
row.asset.symbol,
])}
</p>
)}
<BreakdownTable
data={row?.breakdown || null}
domLayout="autoHeight"
/>
</div>
</Dialog>
</>

View File

@ -27,7 +27,7 @@ const singleRow = {
},
available: '125600000',
used: '125600000',
deposited: '125600000',
total: '251200000',
} as AccountFields;
const singleRowData = [singleRow];
@ -37,10 +37,10 @@ describe('BreakdownTable', () => {
render(<BreakdownTable data={singleRowData} />);
});
const headers = await screen.findAllByRole('columnheader');
expect(headers).toHaveLength(4);
expect(headers).toHaveLength(3);
expect(
headers.map((h) => h.querySelector('[ref="eText"]')?.textContent?.trim())
).toEqual(['Account type', 'Market', 'Used', 'Balance']);
).toEqual(['Market', 'Account type', 'Balance']);
});
it('should apply correct formatting', async () => {
@ -49,9 +49,9 @@ describe('BreakdownTable', () => {
});
const cells = await screen.findAllByRole('gridcell');
const expectedValues = [
'Margin',
'BTCUSD Monthly (30 Jun 2022)',
'1,256.001,256.00',
'Margin',
'1,256.00 (50%)',
'1,256.00',
'1,256.00',
];
@ -83,7 +83,7 @@ describe('BreakdownTable', () => {
},
available: '0',
balance: '125600000',
deposited: '125600000',
total: '125600000',
market: {
__typename: 'Market',
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
@ -99,7 +99,7 @@ describe('BreakdownTable', () => {
used: '125600000',
},
],
deposited: '125600000',
total: '125600000',
type: 'ACCOUNT_TYPE_GENERAL',
used: '125600000',
},

View File

@ -1,5 +1,5 @@
import { forwardRef } from 'react';
import { addDecimalsFormatNumber, isNumeric } from '@vegaprotocol/utils';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import {
Intent,
@ -13,6 +13,7 @@ import type { ValueProps } from '@vegaprotocol/ui-toolkit';
import type { VegaValueFormatterParams } from '@vegaprotocol/datagrid';
import { AgGridDynamic as AgGrid, PriceCell } from '@vegaprotocol/datagrid';
import type { ValueFormatterParams } from 'ag-grid-community';
import { accountValuesComparator } from './accounts-table';
export const progressBarValueFormatter = ({
data,
@ -23,24 +24,16 @@ export const progressBarValueFormatter = ({
}
const min = BigInt(data.used);
const mid = BigInt(data.available);
const max = BigInt(data.deposited);
const max = BigInt(data.total);
const range = max > min ? max : min;
return {
low: addDecimalsFormatNumber(min.toString(), data.asset.decimals, 4),
high: addDecimalsFormatNumber(mid.toString(), data.asset.decimals, 4),
low: addDecimalsFormatNumber(min.toString(), data.asset.decimals),
high: addDecimalsFormatNumber(mid.toString(), data.asset.decimals),
value: range ? Number((min * BigInt(100)) / range) : 0,
intent: Intent.Warning,
};
};
export const progressBarHeaderComponentParams = {
template:
'<div class="ag-cell-label-container" role="presentation">' +
` <span>${t('Available')}</span>` +
' <span ref="eText" class="ag-header-cell-text"></span>' +
'</div>',
};
interface BreakdownTableProps extends AgGridReactProps {
data: AccountFields[] | null;
}
@ -62,8 +55,23 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
defaultColDef={{
flex: 1,
resizable: true,
sortable: true,
}}
>
<AgGridColumn
headerName={t('Market')}
field="market.tradableInstrument.instrument.name"
valueFormatter={({
value,
}: VegaValueFormatterParams<
AccountFields,
'market.tradableInstrument.instrument.name'
>) => {
if (!value) return 'None';
return value;
}}
minWidth={200}
/>
<AgGridColumn
headerName={t('Account type')}
field="type"
@ -76,42 +84,15 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
: ''
}
/>
<AgGridColumn
headerName={t('Market')}
field="market.tradableInstrument.instrument.name"
valueFormatter={({
value,
}: VegaValueFormatterParams<
AccountFields,
'market.tradableInstrument.instrument.name'
>) => {
if (!value) return '-';
return value;
}}
minWidth={200}
/>
<AgGridColumn
headerName={t('Used')}
headerName={t('Balance')}
field="used"
flex={2}
maxWidth={500}
headerComponentParams={progressBarHeaderComponentParams}
cellRendererSelector={progressBarCellRendererSelector}
valueFormatter={progressBarValueFormatter}
/>
<AgGridColumn
headerName={t('Balance')}
field="balance"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<AccountFields, 'balance'>) => {
if (data && data.asset && isNumeric(value)) {
return addDecimalsFormatNumber(value, data.asset.decimals);
}
return '-';
}}
maxWidth={300}
comparator={accountValuesComparator}
/>
</AgGrid>
);

View File

@ -53,6 +53,7 @@ export const checkSorting = (
});
checkSortChange(orderTabDesc, column);
};
const checkSortChange = (tabsArr: string[], column: string) => {
cy.get('.ag-center-cols-container').within(() => {
tabsArr.forEach((entry, i) => {

View File

@ -20,8 +20,9 @@ export const ProgressBarCell = ({ valueFormatted }: ValueProps) => {
return valueFormatted ? (
<>
<div className="flex justify-between leading-tight font-mono">
<div>{valueFormatted.low}</div>
<div>{valueFormatted.high}</div>
<div>
{valueFormatted.low} ({valueFormatted.value}%)
</div>
</div>
<ProgressBar
value={valueFormatted.value}