chore: fix data and no data message update issues in trading data grids (#2620)
This commit is contained in:
parent
c70ec7676e
commit
1a6266e2ec
@ -33,17 +33,16 @@ const AccountsManager = () => {
|
||||
update,
|
||||
variables,
|
||||
});
|
||||
const getRows = async ({
|
||||
successCallback,
|
||||
startRow,
|
||||
endRow,
|
||||
}: IGetRowsParams) => {
|
||||
const rowsThisBlock = dataRef.current
|
||||
? dataRef.current.slice(startRow, endRow)
|
||||
: [];
|
||||
const lastRow = dataRef.current ? dataRef.current.length : 0;
|
||||
successCallback(rowsThisBlock, lastRow);
|
||||
};
|
||||
const getRows = useCallback(
|
||||
async ({ successCallback, startRow, endRow }: IGetRowsParams) => {
|
||||
const rowsThisBlock = dataRef.current
|
||||
? dataRef.current.slice(startRow, endRow)
|
||||
: [];
|
||||
const lastRow = dataRef.current ? dataRef.current.length : 0;
|
||||
successCallback(rowsThisBlock, lastRow);
|
||||
},
|
||||
[]
|
||||
);
|
||||
const { columnDefs, defaultColDef } = useAccountColumnDefinitions();
|
||||
return (
|
||||
<>
|
||||
|
@ -13,7 +13,7 @@ import useColumnDefinitions from './use-column-definitions';
|
||||
const Positions = () => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const { partyId } = useOutletContext<{ partyId: string }>();
|
||||
const { data, error, loading } = usePositionsData(partyId, gridRef);
|
||||
const { data, error, loading, getRows } = usePositionsData(partyId, gridRef);
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions();
|
||||
return (
|
||||
<AsyncRenderer
|
||||
@ -29,7 +29,8 @@ const Positions = () => {
|
||||
columnDefs={columnDefs}
|
||||
defaultColDef={defaultColDef}
|
||||
getRowId={getRowId}
|
||||
rowData={data || undefined}
|
||||
rowModelType="infinite"
|
||||
datasource={{ getRows }}
|
||||
components={{ PriceFlashCell }}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
t,
|
||||
useDataProvider,
|
||||
useNetworkParams,
|
||||
updateGridData,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
@ -22,21 +23,18 @@ import {
|
||||
Indicator,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
|
||||
import { Header, HeaderStat } from '../../components/header';
|
||||
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { IGetRowsParams } from 'ag-grid-community';
|
||||
|
||||
import type { LiquidityProvisionData } from '@vegaprotocol/liquidity';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
MarketDealTicket,
|
||||
SingleMarketFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { marketProvider, marketDataProvider } from '@vegaprotocol/market-list';
|
||||
|
||||
import { useMarket, useStaticMarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
export const Liquidity = () => {
|
||||
const params = useParams();
|
||||
@ -44,86 +42,42 @@ export const Liquidity = () => {
|
||||
return <LiquidityViewContainer marketId={marketId} />;
|
||||
};
|
||||
|
||||
const useReloadLiquidityData = (marketId: string | undefined) => {
|
||||
const { reload } = useDataProvider({
|
||||
dataProvider: liquidityProvisionsDataProvider,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
});
|
||||
useEffect(() => {
|
||||
const interval = setInterval(reload, 10000);
|
||||
return () => clearInterval(interval);
|
||||
}, [reload]);
|
||||
};
|
||||
|
||||
export const LiquidityContainer = ({
|
||||
marketId,
|
||||
}: {
|
||||
marketId: string | undefined;
|
||||
}) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const [market, setMarket] = useState<MarketDealTicket | null>(null);
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
marketId: marketId,
|
||||
}),
|
||||
[marketId]
|
||||
);
|
||||
|
||||
const { data: marketProvision } = useDataProvider<
|
||||
SingleMarketFieldsFragment,
|
||||
never
|
||||
>({
|
||||
dataProvider: marketProvider,
|
||||
variables,
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
const updateMarket = useCallback(
|
||||
({ data: marketData }: { data: MarketData | null }) => {
|
||||
if (marketData) {
|
||||
setMarket({
|
||||
...marketProvision,
|
||||
data: marketData,
|
||||
} as MarketDealTicket);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[marketProvision]
|
||||
);
|
||||
|
||||
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
|
||||
dataProvider: marketDataProvider,
|
||||
update: updateMarket,
|
||||
variables,
|
||||
skip: !marketId || !marketProvision,
|
||||
});
|
||||
const market = useMarket(marketId);
|
||||
const dataRef = useRef<LiquidityProvisionData[] | null>(null);
|
||||
|
||||
const { reload } = useDataProvider({
|
||||
dataProvider: liquidityProvisionsDataProvider,
|
||||
variables,
|
||||
});
|
||||
// To be removed when liquidityProvision subscriptions are working
|
||||
useReloadLiquidityData(marketId);
|
||||
|
||||
const update = useCallback(
|
||||
({ data }: { data: LiquidityProvisionData[] | null }) => {
|
||||
if (!gridRef.current?.api) {
|
||||
return false;
|
||||
}
|
||||
if (dataRef.current?.length) {
|
||||
dataRef.current = data;
|
||||
gridRef.current.api.refreshInfiniteCache();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return updateGridData(dataRef, data, gridRef);
|
||||
},
|
||||
[gridRef]
|
||||
);
|
||||
|
||||
const {
|
||||
data: liquidityProviders,
|
||||
loading,
|
||||
error,
|
||||
} = useDataProvider({
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: lpAggregatedDataProvider,
|
||||
update,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
});
|
||||
|
||||
// To be removed when liquidityProvision subscriptions are working
|
||||
useEffect(() => {
|
||||
const interval = setInterval(reload, 10000);
|
||||
return () => clearInterval(interval);
|
||||
}, [reload]);
|
||||
|
||||
const assetDecimalPlaces =
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0;
|
||||
const symbol =
|
||||
@ -133,28 +87,38 @@ export const LiquidityContainer = ({
|
||||
NetworkParams.market_liquidity_stakeToCcyVolume,
|
||||
]);
|
||||
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
|
||||
const filteredEdges = useMemo(
|
||||
() =>
|
||||
liquidityProviders?.filter((e) =>
|
||||
[
|
||||
Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
|
||||
Schema.LiquidityProvisionStatus.STATUS_UNDEPLOYED,
|
||||
Schema.LiquidityProvisionStatus.STATUS_PENDING,
|
||||
].includes(e.status)
|
||||
),
|
||||
[liquidityProviders]
|
||||
|
||||
const getRows = useCallback(
|
||||
async ({ successCallback, startRow, endRow }: IGetRowsParams) => {
|
||||
const rowsThisBlock = dataRef.current
|
||||
? dataRef.current.slice(startRow, endRow)
|
||||
: [];
|
||||
const lastRow = dataRef.current ? dataRef.current.length : 0;
|
||||
successCallback(rowsThisBlock, lastRow);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={filteredEdges}>
|
||||
<div className="h-full relative">
|
||||
<LiquidityTable
|
||||
ref={gridRef}
|
||||
data={filteredEdges}
|
||||
datasource={{ getRows }}
|
||||
rowModelType="infinite"
|
||||
symbol={symbol}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<AsyncRenderer
|
||||
loading={loading}
|
||||
error={error}
|
||||
data={data}
|
||||
noDataMessage={t('No liquidity provisions')}
|
||||
noDataCondition={(data) => !data?.length}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -165,48 +129,13 @@ export const LiquidityViewContainer = ({
|
||||
}) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const [market, setMarket] = useState<MarketDealTicket | null>(null);
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
marketId: marketId,
|
||||
}),
|
||||
[marketId]
|
||||
);
|
||||
const market = useMarket(marketId);
|
||||
const marketData = useStaticMarketData(marketId);
|
||||
|
||||
const { data: marketProvision } = useDataProvider<
|
||||
SingleMarketFieldsFragment,
|
||||
never
|
||||
>({
|
||||
dataProvider: marketProvider,
|
||||
variables,
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
const updateMarket = useCallback(
|
||||
({ data: marketData }: { data: MarketData | null }) => {
|
||||
if (marketData) {
|
||||
setMarket({
|
||||
...marketProvision,
|
||||
data: marketData,
|
||||
} as MarketDealTicket);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[marketProvision]
|
||||
);
|
||||
|
||||
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
|
||||
dataProvider: marketDataProvider,
|
||||
update: updateMarket,
|
||||
variables,
|
||||
skip: !marketId || !marketProvision,
|
||||
});
|
||||
const dataRef = useRef<LiquidityProvisionData[] | null>(null);
|
||||
|
||||
const { reload } = useDataProvider({
|
||||
dataProvider: liquidityProvisionsDataProvider,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
});
|
||||
// To be removed when liquidityProvision subscriptions are working
|
||||
useReloadLiquidityData(marketId);
|
||||
|
||||
const update = useCallback(
|
||||
({ data }: { data: LiquidityProvisionData[] | null }) => {
|
||||
@ -233,14 +162,8 @@ export const LiquidityViewContainer = ({
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
});
|
||||
|
||||
// To be removed when liquidityProvision subscriptions are working
|
||||
useEffect(() => {
|
||||
const interval = setInterval(reload, 10000);
|
||||
return () => clearInterval(interval);
|
||||
}, [reload]);
|
||||
|
||||
const targetStake = market?.data?.targetStake;
|
||||
const suppliedStake = market?.data?.suppliedStake;
|
||||
const targetStake = marketData?.targetStake;
|
||||
const suppliedStake = marketData?.suppliedStake;
|
||||
const assetDecimalPlaces =
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0;
|
||||
const symbol =
|
||||
@ -359,7 +282,7 @@ export const LiquidityViewContainer = ({
|
||||
{myLpEdges && (
|
||||
<LiquidityTable
|
||||
ref={gridRef}
|
||||
data={myLpEdges}
|
||||
rowData={myLpEdges}
|
||||
symbol={symbol}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
@ -370,7 +293,7 @@ export const LiquidityViewContainer = ({
|
||||
{activeEdges && (
|
||||
<LiquidityTable
|
||||
ref={gridRef}
|
||||
data={activeEdges}
|
||||
rowData={activeEdges}
|
||||
symbol={symbol}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
@ -382,7 +305,7 @@ export const LiquidityViewContainer = ({
|
||||
{inactiveEdges && (
|
||||
<LiquidityTable
|
||||
ref={gridRef}
|
||||
data={inactiveEdges}
|
||||
rowData={inactiveEdges}
|
||||
symbol={symbol}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
|
@ -9,15 +9,20 @@ export const DepositsContainer = () => {
|
||||
|
||||
return (
|
||||
<div className="h-full grid grid-rows-[1fr,min-content]">
|
||||
<div>
|
||||
<AsyncRenderer
|
||||
data={deposits}
|
||||
loading={loading}
|
||||
error={error}
|
||||
render={(data) => {
|
||||
return <DepositsTable deposits={data} />;
|
||||
}}
|
||||
<div className="h-full relative">
|
||||
<DepositsTable
|
||||
rowData={deposits || []}
|
||||
noRowsOverlayComponent={() => null}
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<AsyncRenderer
|
||||
data={deposits}
|
||||
loading={loading}
|
||||
error={error}
|
||||
noDataCondition={(data) => !(data && data.length)}
|
||||
noDataMessage={t('No deposits')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full dark:bg-black bg-white absolute bottom-0 h-auto flex justify-end px-[11px] py-2">
|
||||
<Button
|
||||
|
@ -1,4 +1,8 @@
|
||||
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
t,
|
||||
useDataProvider,
|
||||
updateGridData,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { useRef, useMemo, useCallback, memo } from 'react';
|
||||
@ -25,10 +29,7 @@ export const AccountManager = ({
|
||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||
const update = useCallback(
|
||||
({ data }: { data: AccountFields[] | null }) => {
|
||||
const isEmpty = !dataRef.current?.length;
|
||||
dataRef.current = data;
|
||||
gridRef.current?.api?.refreshInfiniteCache();
|
||||
return Boolean((isEmpty && !data?.length) || (!isEmpty && data?.length));
|
||||
return updateGridData(dataRef, data, gridRef);
|
||||
},
|
||||
[gridRef]
|
||||
);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { AgGridColumn } from 'ag-grid-react';
|
||||
import {
|
||||
t,
|
||||
@ -9,25 +10,27 @@ import {
|
||||
import type {
|
||||
VegaICellRendererParams,
|
||||
VegaValueFormatterParams,
|
||||
TypedDataAgGrid,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridDynamic as AgGrid, Link } from '@vegaprotocol/ui-toolkit';
|
||||
import type { DepositFieldsFragment } from './__generated__/Deposit';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { DepositStatusMapping } from '@vegaprotocol/types';
|
||||
|
||||
export interface DepositsTableProps {
|
||||
deposits: DepositFieldsFragment[];
|
||||
}
|
||||
|
||||
export const DepositsTable = ({ deposits }: DepositsTableProps) => {
|
||||
export const DepositsTable = forwardRef<
|
||||
AgGridReact,
|
||||
TypedDataAgGrid<DepositFieldsFragment>
|
||||
>((props, ref) => {
|
||||
const { ETHERSCAN_URL } = useEnvironment();
|
||||
return (
|
||||
<AgGrid
|
||||
rowData={deposits}
|
||||
ref={ref}
|
||||
overlayNoRowsTemplate={t('No deposits')}
|
||||
defaultColDef={{ flex: 1, resizable: true }}
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
suppressCellFocus={true}
|
||||
{...props}
|
||||
>
|
||||
<AgGridColumn headerName="Asset" field="asset.symbol" />
|
||||
<AgGridColumn
|
||||
@ -84,4 +87,4 @@ export const DepositsTable = ({ deposits }: DepositsTableProps) => {
|
||||
/>
|
||||
</AgGrid>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ import { useCallback, useMemo, useRef } from 'react';
|
||||
import {
|
||||
makeInfiniteScrollGetRows,
|
||||
useDataProvider,
|
||||
updateGridData,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type { Trade, TradeEdge } from './fills-data-provider';
|
||||
import { fillsWithMarketProvider } from './fills-data-provider';
|
||||
@ -53,13 +54,7 @@ export const useFillsList = ({
|
||||
).length;
|
||||
}
|
||||
}
|
||||
dataRef.current = data;
|
||||
const avoidRerender = !!(
|
||||
(dataRef.current?.length && data?.length) ||
|
||||
(!dataRef.current?.length && !data?.length)
|
||||
);
|
||||
gridRef.current?.api?.refreshInfiniteCache();
|
||||
return avoidRerender;
|
||||
return updateGridData(dataRef, data, gridRef);
|
||||
}
|
||||
dataRef.current = data;
|
||||
return false;
|
||||
@ -75,11 +70,10 @@ export const useFillsList = ({
|
||||
data: (TradeEdge | null)[] | null;
|
||||
totalCount?: number;
|
||||
}) => {
|
||||
dataRef.current = data;
|
||||
totalCountRef.current = totalCount;
|
||||
return true;
|
||||
return updateGridData(dataRef, data, gridRef);
|
||||
},
|
||||
[]
|
||||
[gridRef]
|
||||
);
|
||||
|
||||
const variables = useMemo(() => ({ partyId, marketId }), [partyId, marketId]);
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
makeDataProvider,
|
||||
makeDerivedDataProvider,
|
||||
useDataProvider,
|
||||
updateGridData,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type * as Schema from '@vegaprotocol/types';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
@ -158,12 +159,7 @@ export const useLedgerEntriesDataProvider = ({
|
||||
|
||||
const update = useCallback(
|
||||
({ data }: { data: (AggregatedLedgerEntriesEdge | null)[] | null }) => {
|
||||
dataRef.current = data;
|
||||
const rerender =
|
||||
(!dataRef.current?.length && data?.length) ||
|
||||
(dataRef.current?.length && !data?.length);
|
||||
gridRef.current?.api?.refreshInfiniteCache();
|
||||
return !rerender;
|
||||
return updateGridData(dataRef, data, gridRef);
|
||||
},
|
||||
[gridRef]
|
||||
);
|
||||
@ -178,9 +174,9 @@ export const useLedgerEntriesDataProvider = ({
|
||||
}) => {
|
||||
dataRef.current = data;
|
||||
totalCountRef.current = totalCount;
|
||||
return true;
|
||||
return updateGridData(dataRef, data, gridRef);
|
||||
},
|
||||
[]
|
||||
[gridRef]
|
||||
);
|
||||
|
||||
const { data, error, loading, load, totalCount } = useDataProvider({
|
||||
|
@ -22,7 +22,7 @@ export const ledgerEntriesQuery = (
|
||||
'eyJ2ZWdhX3RpbWUiOiIyMDIyLTExLTIzVDE3OjI3OjU2LjczNDM2NFoifQ==',
|
||||
endCursor:
|
||||
'eyJ2ZWdhX3RpbWUiOiIyMDIyLTExLTIzVDEzOjExOjE2LjU0NjM2M1oifQ==',
|
||||
hasNextPage: true,
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
__typename: 'PageInfo',
|
||||
},
|
||||
|
@ -152,10 +152,7 @@ export const liquidityFeeShareDataProvider = makeDataProvider<
|
||||
|
||||
export const lpAggregatedDataProvider = makeDerivedDataProvider(
|
||||
[
|
||||
(callback, client, variables) =>
|
||||
liquidityProvisionsDataProvider(callback, client, {
|
||||
marketId: variables?.marketId,
|
||||
}),
|
||||
liquidityProvisionsDataProvider,
|
||||
marketLiquidityDataProvider,
|
||||
liquidityFeeShareDataProvider,
|
||||
],
|
||||
@ -177,32 +174,43 @@ export const getLiquidityProvision = (
|
||||
marketLiquidity: MarketLpQuery,
|
||||
liquidityFeeShare: LiquidityProviderFeeShareFieldsFragment[]
|
||||
): LiquidityProvisionData[] => {
|
||||
return liquidityProvisions.map((lp) => {
|
||||
const market = marketLiquidity?.market;
|
||||
const feeShare = liquidityFeeShare.find((f) => f.party.id === lp.party.id);
|
||||
if (!feeShare) return lp;
|
||||
const accounts = compact(lp.party.accountsConnection?.edges).map(
|
||||
(e) => e.node
|
||||
return liquidityProvisions
|
||||
.map((lp) => {
|
||||
const market = marketLiquidity?.market;
|
||||
const feeShare = liquidityFeeShare.find(
|
||||
(f) => f.party.id === lp.party.id
|
||||
);
|
||||
if (!feeShare) return lp;
|
||||
const accounts = compact(lp.party.accountsConnection?.edges).map(
|
||||
(e) => e.node
|
||||
);
|
||||
const bondAccounts = accounts?.filter(
|
||||
(a) => a?.type === Schema.AccountType.ACCOUNT_TYPE_BOND
|
||||
);
|
||||
const balance =
|
||||
bondAccounts
|
||||
?.reduce(
|
||||
(acc, a) => acc.plus(new BigNumber(a.balance ?? 0)),
|
||||
new BigNumber(0)
|
||||
)
|
||||
.toString() || '0';
|
||||
return {
|
||||
...lp,
|
||||
averageEntryValuation: feeShare?.averageEntryValuation,
|
||||
equityLikeShare: feeShare?.equityLikeShare,
|
||||
assetDecimalPlaces:
|
||||
market?.tradableInstrument.instrument.product.settlementAsset
|
||||
.decimals,
|
||||
balance,
|
||||
};
|
||||
})
|
||||
.filter((e) =>
|
||||
[
|
||||
Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
|
||||
Schema.LiquidityProvisionStatus.STATUS_UNDEPLOYED,
|
||||
Schema.LiquidityProvisionStatus.STATUS_PENDING,
|
||||
].includes(e.status)
|
||||
);
|
||||
const bondAccounts = accounts?.filter(
|
||||
(a) => a?.type === Schema.AccountType.ACCOUNT_TYPE_BOND
|
||||
);
|
||||
const balance =
|
||||
bondAccounts
|
||||
?.reduce(
|
||||
(acc, a) => acc.plus(new BigNumber(a.balance ?? 0)),
|
||||
new BigNumber(0)
|
||||
)
|
||||
.toString() || '0';
|
||||
return {
|
||||
...lp,
|
||||
averageEntryValuation: feeShare?.averageEntryValuation,
|
||||
equityLikeShare: feeShare?.equityLikeShare,
|
||||
assetDecimalPlaces:
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.decimals,
|
||||
balance,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export interface LiquidityProvisionData
|
||||
|
@ -22,7 +22,7 @@ describe('LiquidityTable', () => {
|
||||
it('should render successfully', async () => {
|
||||
await act(async () => {
|
||||
const { baseElement } = render(
|
||||
<LiquidityTable data={[]} stakeToCcyVolume={'1'} />
|
||||
<LiquidityTable rowData={[]} stakeToCcyVolume={'1'} />
|
||||
);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
@ -30,7 +30,9 @@ describe('LiquidityTable', () => {
|
||||
|
||||
it('should render correct columns', async () => {
|
||||
await act(async () => {
|
||||
render(<LiquidityTable data={singleRowData} stakeToCcyVolume={'0.3'} />);
|
||||
render(
|
||||
<LiquidityTable rowData={singleRowData} stakeToCcyVolume={'0.3'} />
|
||||
);
|
||||
});
|
||||
|
||||
const headers = await screen.getAllByRole('columnheader');
|
||||
|
@ -5,7 +5,10 @@ import {
|
||||
getDateTimeFormat,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
|
||||
import type {
|
||||
VegaValueFormatterParams,
|
||||
TypedDataAgGrid,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
AgGridDynamic as AgGrid,
|
||||
TooltipCellComponent,
|
||||
@ -30,15 +33,15 @@ const dateValueFormatter = ({ value }: { value?: string | null }) => {
|
||||
return getDateTimeFormat().format(new Date(value));
|
||||
};
|
||||
|
||||
export interface LiquidityTableProps {
|
||||
data?: LiquidityProvisionData[];
|
||||
export interface LiquidityTableProps
|
||||
extends TypedDataAgGrid<LiquidityProvisionData> {
|
||||
symbol?: string;
|
||||
assetDecimalPlaces?: number;
|
||||
stakeToCcyVolume: string | null;
|
||||
}
|
||||
|
||||
export const LiquidityTable = forwardRef<AgGridReact, LiquidityTableProps>(
|
||||
({ data, symbol = '', assetDecimalPlaces, stakeToCcyVolume }, ref) => {
|
||||
({ symbol = '', assetDecimalPlaces, stakeToCcyVolume, ...props }, ref) => {
|
||||
const assetDecimalsFormatter = ({ value }: ValueFormatterParams) => {
|
||||
if (!value) return '-';
|
||||
return `${addDecimalsFormatNumber(value, assetDecimalPlaces ?? 0, 5)}`;
|
||||
@ -51,7 +54,6 @@ export const LiquidityTable = forwardRef<AgGridReact, LiquidityTableProps>(
|
||||
return `${addDecimalsFormatNumber(newValue, assetDecimalPlaces ?? 0, 5)}`;
|
||||
};
|
||||
|
||||
if (!data) return null;
|
||||
return (
|
||||
<AgGrid
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
@ -66,7 +68,7 @@ export const LiquidityTable = forwardRef<AgGridReact, LiquidityTableProps>(
|
||||
tooltipComponent: TooltipCellComponent,
|
||||
sortable: true,
|
||||
}}
|
||||
rowData={data}
|
||||
{...props}
|
||||
>
|
||||
<AgGridColumn
|
||||
headerName={t('Party')}
|
||||
|
@ -128,9 +128,10 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
|
||||
const marketDataUpdate = useCallback(
|
||||
({ data }: { data: MarketData | null }) => {
|
||||
marketDataRef.current = data;
|
||||
updateDepthData();
|
||||
return true;
|
||||
},
|
||||
[]
|
||||
[updateDepthData]
|
||||
);
|
||||
|
||||
const {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { MarketListTable } from './market-list-table';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
@ -15,7 +16,7 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
|
||||
});
|
||||
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||
<div className="h-full relative">
|
||||
<MarketListTable
|
||||
rowData={data}
|
||||
onRowClicked={(rowEvent: RowClickedEvent) => {
|
||||
@ -29,6 +30,14 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
|
||||
onSelect((data as MarketWithData).id);
|
||||
}}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<AsyncRenderer
|
||||
loading={loading}
|
||||
error={error}
|
||||
data={data}
|
||||
noDataMessage={t('No markets')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ import type { AgGridReact } from 'ag-grid-react';
|
||||
import {
|
||||
makeInfiniteScrollGetRows,
|
||||
useDataProvider,
|
||||
updateGridData,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { ordersWithMarketProvider } from '../order-data-provider/order-data-provider';
|
||||
import type {
|
||||
@ -99,13 +100,7 @@ export const useOrderListData = ({
|
||||
).length;
|
||||
}
|
||||
}
|
||||
dataRef.current = data;
|
||||
totalCountRef.current = totalCount;
|
||||
const rerender =
|
||||
(!dataRef.current?.length && data?.length) ||
|
||||
(dataRef.current?.length && !data?.length);
|
||||
gridRef.current?.api?.refreshInfiniteCache();
|
||||
return !rerender;
|
||||
return updateGridData(dataRef, data, gridRef);
|
||||
},
|
||||
[gridRef, scrolledToTop]
|
||||
);
|
||||
@ -118,11 +113,10 @@ export const useOrderListData = ({
|
||||
data: (OrderEdge | null)[] | null;
|
||||
totalCount?: number;
|
||||
}) => {
|
||||
dataRef.current = data;
|
||||
totalCountRef.current = totalCount;
|
||||
return true;
|
||||
return updateGridData(dataRef, data, gridRef);
|
||||
},
|
||||
[]
|
||||
[gridRef]
|
||||
);
|
||||
|
||||
const { data, error, loading, load, totalCount } = useDataProvider({
|
||||
|
@ -13,7 +13,7 @@ interface PositionsManagerProps {
|
||||
|
||||
export const PositionsManager = ({ partyId }: PositionsManagerProps) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const { data, error, loading } = usePositionsData(partyId, gridRef);
|
||||
const { data, error, loading, getRows } = usePositionsData(partyId, gridRef);
|
||||
const {
|
||||
submit,
|
||||
closingOrder,
|
||||
@ -26,8 +26,9 @@ export const PositionsManager = ({ partyId }: PositionsManagerProps) => {
|
||||
return (
|
||||
<div className="h-full relative">
|
||||
<PositionsTable
|
||||
rowModelType="infinite"
|
||||
ref={gridRef}
|
||||
rowData={data}
|
||||
datasource={{ getRows }}
|
||||
onClose={(position) => submit(position)}
|
||||
noRowsOverlayComponent={() => null}
|
||||
/>
|
||||
|
@ -53,22 +53,13 @@ describe('usePositionData Hook', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
const mockApplyTransactions = jest.fn();
|
||||
const mockApplyTransactionsAsync = jest.fn();
|
||||
const mockRefreshInfiniteCache = jest.fn();
|
||||
const mockGetRowNode = jest
|
||||
.fn()
|
||||
.mockImplementation((id: string) =>
|
||||
mockData.find((position) => position.marketId === id)
|
||||
);
|
||||
const partyId = 'partyId';
|
||||
const aNewOne = {
|
||||
marketId: 'market-5',
|
||||
openVolume: '1',
|
||||
};
|
||||
const toRemoveOne = {
|
||||
marketId: 'market-0',
|
||||
openVolume: '0',
|
||||
};
|
||||
const anUpdatedOne = {
|
||||
marketId: 'market-1',
|
||||
openVolume: '1',
|
||||
@ -76,8 +67,7 @@ describe('usePositionData Hook', () => {
|
||||
const gridRef = {
|
||||
current: {
|
||||
api: {
|
||||
applyTransaction: mockApplyTransactions,
|
||||
applyTransactionAsync: mockApplyTransactionsAsync,
|
||||
refreshInfiniteCache: mockRefreshInfiniteCache,
|
||||
getRowNode: mockGetRowNode,
|
||||
},
|
||||
} as unknown as AgGridReact,
|
||||
@ -87,27 +77,10 @@ describe('usePositionData Hook', () => {
|
||||
const { result } = renderHook(() => usePositionsData(partyId, gridRef), {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(result.current.data?.length ?? 0).toEqual(3);
|
||||
expect(result.current.data?.length ?? 0).toEqual(5);
|
||||
});
|
||||
|
||||
it('should append by sync', async () => {
|
||||
renderHook(() => usePositionsData(partyId, gridRef), {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
updateMock({ delta: [aNewOne, toRemoveOne, anUpdatedOne] as Position[] });
|
||||
});
|
||||
|
||||
expect(mockApplyTransactions).toHaveBeenCalledWith({
|
||||
update: [anUpdatedOne],
|
||||
add: [aNewOne],
|
||||
remove: [toRemoveOne],
|
||||
addIndex: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('should append by async', async () => {
|
||||
it('should call mockRefreshInfiniteCache', async () => {
|
||||
renderHook(() => usePositionsData(partyId, gridRef), {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
@ -115,12 +88,7 @@ describe('usePositionData Hook', () => {
|
||||
updateMock({ delta: [anUpdatedOne] as Position[] });
|
||||
});
|
||||
|
||||
expect(mockApplyTransactionsAsync).toHaveBeenCalledWith({
|
||||
update: [anUpdatedOne],
|
||||
add: [],
|
||||
remove: [],
|
||||
addIndex: 0,
|
||||
});
|
||||
expect(mockRefreshInfiniteCache).toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it('no data should return null', () => {
|
||||
|
@ -4,7 +4,8 @@ import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { Position } from './positions-data-providers';
|
||||
import { positionsMetricsProvider } from './positions-data-providers';
|
||||
import type { PositionsMetricsProviderVariables } from './positions-data-providers';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { useDataProvider, updateGridData } from '@vegaprotocol/react-helpers';
|
||||
import type { GetRowsParams } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const getRowId = ({ data }: { data: Position }) => data.marketId;
|
||||
|
||||
@ -18,49 +19,8 @@ export const usePositionsData = (
|
||||
);
|
||||
const dataRef = useRef<Position[] | null>(null);
|
||||
const update = useCallback(
|
||||
({
|
||||
data,
|
||||
delta,
|
||||
}: {
|
||||
data: Position[] | null;
|
||||
delta?: Position[] | null;
|
||||
}) => {
|
||||
dataRef.current = data;
|
||||
|
||||
const update: Position[] = [];
|
||||
const add: Position[] = [];
|
||||
const remove: Position[] = [];
|
||||
if (!gridRef.current?.api) {
|
||||
return false;
|
||||
}
|
||||
(delta || []).forEach((position) => {
|
||||
const rowNode = gridRef.current?.api.getRowNode(
|
||||
getRowId({ data: position })
|
||||
);
|
||||
if (rowNode) {
|
||||
if (position.openVolume === '0') {
|
||||
remove.push(position);
|
||||
} else {
|
||||
update.push(position);
|
||||
}
|
||||
} else if (position.openVolume !== '0') {
|
||||
add.push(position);
|
||||
}
|
||||
});
|
||||
if (update.length || add.length || remove.length) {
|
||||
const rowDataTransaction = {
|
||||
update,
|
||||
add,
|
||||
remove,
|
||||
addIndex: 0,
|
||||
};
|
||||
if (add.length || remove.length) {
|
||||
gridRef.current.api.applyTransaction(rowDataTransaction);
|
||||
} else {
|
||||
gridRef.current.api.applyTransactionAsync(rowDataTransaction);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
({ data }: { data: Position[] | null }) => {
|
||||
return updateGridData(dataRef, data, gridRef);
|
||||
},
|
||||
[gridRef]
|
||||
);
|
||||
@ -69,9 +29,20 @@ export const usePositionsData = (
|
||||
update,
|
||||
variables,
|
||||
});
|
||||
const getRows = useCallback(
|
||||
async ({ successCallback, startRow, endRow }: GetRowsParams<Position>) => {
|
||||
const rowsThisBlock = dataRef.current
|
||||
? dataRef.current.slice(startRow, endRow)
|
||||
: [];
|
||||
const lastRow = dataRef.current ? dataRef.current.length : 0;
|
||||
successCallback(rowsThisBlock, lastRow);
|
||||
},
|
||||
[]
|
||||
);
|
||||
return {
|
||||
data: data?.filter((position) => position.openVolume !== '0'),
|
||||
data,
|
||||
error,
|
||||
loading,
|
||||
getRows,
|
||||
};
|
||||
};
|
||||
|
@ -6,6 +6,7 @@ export * from './lib/get-events';
|
||||
export * from './lib/grid';
|
||||
export * from './lib/i18n';
|
||||
export * from './lib/pagination';
|
||||
export * from './lib/ag-grid-update';
|
||||
export * from './lib/remove-0x';
|
||||
export * from './lib/storage';
|
||||
export * from './lib/time';
|
||||
|
28
libs/react-helpers/src/lib/ag-grid-update.ts
Normal file
28
libs/react-helpers/src/lib/ag-grid-update.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import type { MutableRefObject, RefObject } from 'react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { IGetRowsParams } from 'ag-grid-community';
|
||||
type AnyArray = Array<any> | null; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
export const isXOrWasEmpty = (prev?: AnyArray, curr?: AnyArray) =>
|
||||
Boolean(Number(!!prev?.length) ^ Number(!!curr?.length));
|
||||
|
||||
export const updateGridData = (
|
||||
dataRef: MutableRefObject<AnyArray>,
|
||||
data: AnyArray,
|
||||
gridRef: RefObject<AgGridReact>
|
||||
) => {
|
||||
const rerender = isXOrWasEmpty(dataRef.current, data);
|
||||
dataRef.current = data;
|
||||
gridRef.current?.api?.refreshInfiniteCache();
|
||||
return !rerender;
|
||||
};
|
||||
|
||||
export const makeGetRows =
|
||||
(dataRef: MutableRefObject<AnyArray>) =>
|
||||
() =>
|
||||
async ({ successCallback, startRow, endRow }: IGetRowsParams) => {
|
||||
const rowsThisBlock = dataRef.current
|
||||
? dataRef.current.slice(startRow, endRow)
|
||||
: [];
|
||||
const lastRow = dataRef.current ? dataRef.current.length : 0;
|
||||
successCallback(rowsThisBlock, lastRow);
|
||||
};
|
Loading…
Reference in New Issue
Block a user