fix(trading): refactor market info accordion to avoid remount on candle reload (#3447)
This commit is contained in:
parent
460ccdb3a2
commit
c15051d457
2
.github/workflows/ci-cd-trigger.yml
vendored
2
.github/workflows/ci-cd-trigger.yml
vendored
@ -50,7 +50,7 @@ jobs:
|
|||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
lint-test-build:
|
lint-test-build:
|
||||||
timeout-minutes: 20
|
timeout-minutes: 60
|
||||||
needs: node-modules
|
needs: node-modules
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
name: '(CI) lint + unit test + build'
|
name: '(CI) lint + unit test + build'
|
||||||
|
@ -60,9 +60,11 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
<>
|
<>
|
||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
noBorder={false}
|
noBorder={false}
|
||||||
data={trigger}
|
data={{
|
||||||
|
maxValidPrice: trigger.maxValidPrice,
|
||||||
|
minValidPrice: trigger.minValidPrice,
|
||||||
|
}}
|
||||||
decimalPlaces={market.decimalPlaces}
|
decimalPlaces={market.decimalPlaces}
|
||||||
omits={['referencePrice', '__typename']}
|
|
||||||
/>
|
/>
|
||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
noBorder={false}
|
noBorder={false}
|
||||||
|
@ -108,18 +108,14 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
|||||||
|
|
||||||
it('risk model displayed', () => {
|
it('risk model displayed', () => {
|
||||||
cy.getByTestId(marketTitle).contains('Risk model').click();
|
cy.getByTestId(marketTitle).contains('Risk model').click();
|
||||||
|
validateMarketDataRow(0, 'Tau', '0.0001140771161');
|
||||||
validateMarketDataRow(0, 'Typename', 'LogNormalRiskModel');
|
validateMarketDataRow(1, 'Risk Aversion Parameter', '0.01');
|
||||||
validateMarketDataRow(1, 'Tau', '0.0001140771161');
|
|
||||||
validateMarketDataRow(2, 'Risk Aversion Parameter', '0.01');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('risk parameters displayed', () => {
|
it('risk parameters displayed', () => {
|
||||||
cy.getByTestId(marketTitle).contains('Risk parameters').click();
|
cy.getByTestId(marketTitle).contains('Risk parameters').click();
|
||||||
|
validateMarketDataRow(0, 'R', '0.016');
|
||||||
validateMarketDataRow(0, 'Typename', 'LogNormalModelParams');
|
validateMarketDataRow(1, 'Sigma', '0.3');
|
||||||
validateMarketDataRow(1, 'R', '0.016');
|
|
||||||
validateMarketDataRow(2, 'Sigma', '0.3');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('risk factors displayed', () => {
|
it('risk factors displayed', () => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { DealTicketContainer } from '@vegaprotocol/deal-ticket';
|
import { DealTicketContainer } from '@vegaprotocol/deal-ticket';
|
||||||
import { MarketInfoContainer } from '@vegaprotocol/market-info';
|
import { MarketInfoAccordionContainer } from '@vegaprotocol/market-info';
|
||||||
import { OrderbookContainer } from '@vegaprotocol/market-depth';
|
import { OrderbookContainer } from '@vegaprotocol/market-depth';
|
||||||
import { OrderListContainer } from '@vegaprotocol/orders';
|
import { OrderListContainer } from '@vegaprotocol/orders';
|
||||||
import { FillsContainer } from '@vegaprotocol/fills';
|
import { FillsContainer } from '@vegaprotocol/fills';
|
||||||
@ -38,7 +38,7 @@ type MarketDependantView =
|
|||||||
| typeof CandlesChartContainer
|
| typeof CandlesChartContainer
|
||||||
| typeof DepthChartContainer
|
| typeof DepthChartContainer
|
||||||
| typeof DealTicketContainer
|
| typeof DealTicketContainer
|
||||||
| typeof MarketInfoContainer
|
| typeof MarketInfoAccordionContainer
|
||||||
| typeof OrderbookContainer
|
| typeof OrderbookContainer
|
||||||
| typeof TradesContainer;
|
| typeof TradesContainer;
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ const TradingViews = {
|
|||||||
Depth: requiresMarket(DepthChartContainer),
|
Depth: requiresMarket(DepthChartContainer),
|
||||||
Liquidity: requiresMarket(LiquidityContainer),
|
Liquidity: requiresMarket(LiquidityContainer),
|
||||||
Ticket: requiresMarket(DealTicketContainer),
|
Ticket: requiresMarket(DealTicketContainer),
|
||||||
Info: requiresMarket(MarketInfoContainer),
|
Info: requiresMarket(MarketInfoAccordionContainer),
|
||||||
Orderbook: requiresMarket(OrderbookContainer),
|
Orderbook: requiresMarket(OrderbookContainer),
|
||||||
Trades: requiresMarket(TradesContainer),
|
Trades: requiresMarket(TradesContainer),
|
||||||
Positions: PositionsContainer,
|
Positions: PositionsContainer,
|
||||||
|
@ -13,8 +13,7 @@ import type { OnCellClickHandler } from '../../components/select-market';
|
|||||||
import { Header, HeaderStat } from '../../components/header';
|
import { Header, HeaderStat } from '../../components/header';
|
||||||
import { NO_MARKET } from './constants';
|
import { NO_MARKET } from './constants';
|
||||||
import { MarketMarkPrice } from '../../components/market-mark-price';
|
import { MarketMarkPrice } from '../../components/market-mark-price';
|
||||||
import { Last24hPriceChange } from '../../components/last-24h-price-change';
|
import { Last24hPriceChange, Last24hVolume } from '@vegaprotocol/market-info';
|
||||||
import { Last24hVolume } from '../../components/last-24h-volume';
|
|
||||||
import { MarketState } from '../../components/market-state';
|
import { MarketState } from '../../components/market-state';
|
||||||
import { HeaderStatMarketTradingMode } from '../../components/market-trading-mode';
|
import { HeaderStatMarketTradingMode } from '../../components/market-trading-mode';
|
||||||
import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
|
import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
|
||||||
|
@ -14,9 +14,8 @@ import type { CandleClose } from '@vegaprotocol/types';
|
|||||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/market-list';
|
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/market-list';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { MarketMarkPrice } from '../market-mark-price';
|
import { MarketMarkPrice } from '../market-mark-price';
|
||||||
import { Last24hPriceChange } from '../last-24h-price-change';
|
import { Last24hPriceChange, Last24hVolume } from '@vegaprotocol/market-info';
|
||||||
import { MarketTradingMode } from '../market-trading-mode';
|
import { MarketTradingMode } from '../market-trading-mode';
|
||||||
import { Last24hVolume } from '../last-24h-volume';
|
|
||||||
import { Links, Routes } from '../../pages/client-router';
|
import { Links, Routes } from '../../pages/client-router';
|
||||||
|
|
||||||
const ellipsisClasses = 'whitespace-nowrap overflow-hidden text-ellipsis';
|
const ellipsisClasses = 'whitespace-nowrap overflow-hidden text-ellipsis';
|
||||||
|
@ -16,19 +16,18 @@ export const useInitialMargin = (
|
|||||||
order?: OrderSubmissionBody['orderSubmission']
|
order?: OrderSubmissionBody['orderSubmission']
|
||||||
) => {
|
) => {
|
||||||
const { pubKey } = useVegaWallet();
|
const { pubKey } = useVegaWallet();
|
||||||
const commonVariables = { marketId, partyId: pubKey || '' };
|
|
||||||
const { data: marketData } = useDataProvider({
|
const { data: marketData } = useDataProvider({
|
||||||
dataProvider: marketDataProvider,
|
dataProvider: marketDataProvider,
|
||||||
variables: { marketId },
|
variables: { marketId },
|
||||||
});
|
});
|
||||||
const { data: activeVolumeAndMargin } = useDataProvider({
|
const { data: activeVolumeAndMargin } = useDataProvider({
|
||||||
dataProvider: volumeAndMarginProvider,
|
dataProvider: volumeAndMarginProvider,
|
||||||
variables: commonVariables,
|
variables: { marketId, partyId: pubKey || '' },
|
||||||
skip: !pubKey,
|
skip: !pubKey,
|
||||||
});
|
});
|
||||||
const { data: marketInfo } = useDataProvider({
|
const { data: marketInfo } = useDataProvider({
|
||||||
dataProvider: marketInfoProvider,
|
dataProvider: marketInfoProvider,
|
||||||
variables: commonVariables,
|
variables: { marketId },
|
||||||
});
|
});
|
||||||
let totalMargin = '0';
|
let totalMargin = '0';
|
||||||
let margin = '0';
|
let margin = '0';
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
export * from './market-info';
|
export * from './market-info';
|
||||||
|
export * from './last-24h-price-change';
|
||||||
|
export * from './last-24h-volume';
|
||||||
export * from './fees-breakdown';
|
export * from './fees-breakdown';
|
||||||
|
@ -9,7 +9,6 @@ import { PriceChangeCell } from '@vegaprotocol/datagrid';
|
|||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import type { CandleClose } from '@vegaprotocol/types';
|
import type { CandleClose } from '@vegaprotocol/types';
|
||||||
import { marketCandlesProvider } from '@vegaprotocol/market-list';
|
import { marketCandlesProvider } from '@vegaprotocol/market-list';
|
||||||
import { THROTTLE_UPDATE_TIME } from '../constants';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
marketId?: string;
|
marketId?: string;
|
||||||
@ -28,8 +27,7 @@ export const Last24hPriceChange = ({
|
|||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
||||||
const yesterday = useYesterday();
|
const yesterday = useYesterday();
|
||||||
const { data, error } = useThrottledDataProvider(
|
const { data, error } = useThrottledDataProvider({
|
||||||
{
|
|
||||||
dataProvider: marketCandlesProvider,
|
dataProvider: marketCandlesProvider,
|
||||||
variables: {
|
variables: {
|
||||||
marketId: marketId || '',
|
marketId: marketId || '',
|
||||||
@ -37,9 +35,7 @@ export const Last24hPriceChange = ({
|
|||||||
since: new Date(yesterday).toISOString(),
|
since: new Date(yesterday).toISOString(),
|
||||||
},
|
},
|
||||||
skip: !marketId || !inView,
|
skip: !marketId || !inView,
|
||||||
},
|
});
|
||||||
THROTTLE_UPDATE_TIME
|
|
||||||
);
|
|
||||||
|
|
||||||
const candles =
|
const candles =
|
||||||
data
|
data
|
@ -10,7 +10,6 @@ import {
|
|||||||
useYesterday,
|
useYesterday,
|
||||||
} from '@vegaprotocol/react-helpers';
|
} from '@vegaprotocol/react-helpers';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { THROTTLE_UPDATE_TIME } from '../constants';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
marketId?: string;
|
marketId?: string;
|
||||||
@ -30,8 +29,7 @@ export const Last24hVolume = ({
|
|||||||
const yesterday = useYesterday();
|
const yesterday = useYesterday();
|
||||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
||||||
|
|
||||||
const { data } = useThrottledDataProvider(
|
const { data } = useThrottledDataProvider({
|
||||||
{
|
|
||||||
dataProvider: marketCandlesProvider,
|
dataProvider: marketCandlesProvider,
|
||||||
variables: {
|
variables: {
|
||||||
marketId: marketId || '',
|
marketId: marketId || '',
|
||||||
@ -39,9 +37,7 @@ export const Last24hVolume = ({
|
|||||||
since: new Date(yesterday).toISOString(),
|
since: new Date(yesterday).toISOString(),
|
||||||
},
|
},
|
||||||
skip: !(inView && marketId),
|
skip: !(inView && marketId),
|
||||||
},
|
});
|
||||||
THROTTLE_UPDATE_TIME
|
|
||||||
);
|
|
||||||
const candleVolume = data ? calcCandleVolume(data) : initialValue;
|
const candleVolume = data ? calcCandleVolume(data) : initialValue;
|
||||||
return (
|
return (
|
||||||
<span ref={ref}>
|
<span ref={ref}>
|
@ -1,5 +1,5 @@
|
|||||||
export * from './info-key-value-table';
|
export * from './info-key-value-table';
|
||||||
export * from './info-market';
|
export * from './market-info-accordion';
|
||||||
export * from './tooltip-mapping';
|
export * from './tooltip-mapping';
|
||||||
export * from './__generated__/MarketInfo';
|
export * from './__generated__/MarketInfo';
|
||||||
export * from './market-info-data-provider';
|
export * from './market-info-data-provider';
|
||||||
|
@ -17,7 +17,7 @@ import { tooltipMapping } from './tooltip-mapping';
|
|||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
interface RowProps {
|
interface RowProps {
|
||||||
field: string;
|
field: string;
|
||||||
value: unknown;
|
value: ReactNode;
|
||||||
decimalPlaces?: number;
|
decimalPlaces?: number;
|
||||||
asPercentage?: boolean;
|
asPercentage?: boolean;
|
||||||
unformatted?: boolean;
|
unformatted?: boolean;
|
||||||
@ -36,8 +36,8 @@ const Row = ({
|
|||||||
}: RowProps) => {
|
}: RowProps) => {
|
||||||
const className = 'text-black dark:text-white text-sm !px-0';
|
const className = 'text-black dark:text-white text-sm !px-0';
|
||||||
|
|
||||||
const getFormattedValue = (value: unknown) => {
|
const getFormattedValue = (value: ReactNode) => {
|
||||||
if (typeof value !== 'string' && typeof value !== 'number') return null;
|
if (typeof value !== 'string' && typeof value !== 'number') return value;
|
||||||
if (unformatted || isNaN(Number(value))) {
|
if (unformatted || isNaN(Number(value))) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ const Row = ({
|
|||||||
return `${formatNumber(Number(value))} ${assetSymbol}`;
|
return `${formatNumber(Number(value))} ${assetSymbol}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formattedValue: string | number | null = getFormattedValue(value);
|
const formattedValue = getFormattedValue(value);
|
||||||
|
|
||||||
if (!formattedValue) return null;
|
if (!formattedValue) return null;
|
||||||
return (
|
return (
|
||||||
@ -70,11 +70,10 @@ const Row = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface MarketInfoTableProps {
|
export interface MarketInfoTableProps {
|
||||||
data: unknown;
|
data: Record<string, ReactNode> | null | undefined;
|
||||||
decimalPlaces?: number;
|
decimalPlaces?: number;
|
||||||
asPercentage?: boolean;
|
asPercentage?: boolean;
|
||||||
unformatted?: boolean;
|
unformatted?: boolean;
|
||||||
omits?: string[];
|
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
assetSymbol?: string;
|
assetSymbol?: string;
|
||||||
noBorder?: boolean;
|
noBorder?: boolean;
|
||||||
@ -85,7 +84,6 @@ export const MarketInfoTable = ({
|
|||||||
decimalPlaces,
|
decimalPlaces,
|
||||||
asPercentage,
|
asPercentage,
|
||||||
unformatted,
|
unformatted,
|
||||||
omits = ['__typename'],
|
|
||||||
children,
|
children,
|
||||||
assetSymbol,
|
assetSymbol,
|
||||||
noBorder,
|
noBorder,
|
||||||
@ -96,9 +94,7 @@ export const MarketInfoTable = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<KeyValueTable>
|
<KeyValueTable>
|
||||||
{Object.entries(data)
|
{Object.entries(data).map(([key, value]) => (
|
||||||
.filter(([key]) => !omits.includes(key))
|
|
||||||
.map(([key, value]) => (
|
|
||||||
<Row
|
<Row
|
||||||
key={key}
|
key={key}
|
||||||
field={key}
|
field={key}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import { removePaginationWrapper, TokenLinks } from '@vegaprotocol/utils';
|
import { removePaginationWrapper, TokenLinks } from '@vegaprotocol/utils';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useDataProvider, useYesterday } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
@ -11,12 +11,11 @@ import {
|
|||||||
Splash,
|
Splash,
|
||||||
TinyScroll,
|
TinyScroll,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { generatePath, Link } from 'react-router-dom';
|
import { generatePath, Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { marketInfoWithDataAndCandlesProvider } from './market-info-data-provider';
|
import { marketInfoProvider } from './market-info-data-provider';
|
||||||
|
|
||||||
import type { MarketInfoWithDataAndCandles } from './market-info-data-provider';
|
import type { MarketInfo } from './market-info-data-provider';
|
||||||
import { MarketProposalNotification } from '@vegaprotocol/proposals';
|
import { MarketProposalNotification } from '@vegaprotocol/proposals';
|
||||||
import {
|
import {
|
||||||
CurrentFeesInfoPanel,
|
CurrentFeesInfoPanel,
|
||||||
@ -37,8 +36,8 @@ import {
|
|||||||
SettlementAssetInfoPanel,
|
SettlementAssetInfoPanel,
|
||||||
} from './market-info-panels';
|
} from './market-info-panels';
|
||||||
|
|
||||||
export interface InfoProps {
|
export interface MarketInfoAccordionProps {
|
||||||
market: MarketInfoWithDataAndCandles;
|
market: MarketInfo;
|
||||||
onSelect?: (id: string, metaKey?: boolean) => void;
|
onSelect?: (id: string, metaKey?: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,34 +45,21 @@ export interface MarketInfoContainerProps {
|
|||||||
marketId: string;
|
marketId: string;
|
||||||
onSelect?: (id: string, metaKey?: boolean) => void;
|
onSelect?: (id: string, metaKey?: boolean) => void;
|
||||||
}
|
}
|
||||||
export const MarketInfoContainer = ({
|
export const MarketInfoAccordionContainer = ({
|
||||||
marketId,
|
marketId,
|
||||||
onSelect,
|
onSelect,
|
||||||
}: MarketInfoContainerProps) => {
|
}: MarketInfoContainerProps) => {
|
||||||
const yesterday = useYesterday();
|
|
||||||
const yTimestamp = useMemo(() => {
|
|
||||||
return new Date(yesterday).toISOString();
|
|
||||||
}, [yesterday]);
|
|
||||||
const variables = useMemo(
|
|
||||||
() => ({
|
|
||||||
marketId,
|
|
||||||
since: yTimestamp,
|
|
||||||
interval: Schema.Interval.INTERVAL_I1H,
|
|
||||||
}),
|
|
||||||
[marketId, yTimestamp]
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data, loading, error, reload } = useDataProvider({
|
const { data, loading, error, reload } = useDataProvider({
|
||||||
dataProvider: marketInfoWithDataAndCandlesProvider,
|
dataProvider: marketInfoProvider,
|
||||||
skipUpdates: true,
|
skipUpdates: true,
|
||||||
variables,
|
variables: { marketId },
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer data={data} loading={loading} error={error} reload={reload}>
|
<AsyncRenderer data={data} loading={loading} error={error} reload={reload}>
|
||||||
{data ? (
|
{data ? (
|
||||||
<TinyScroll className="h-full overflow-auto">
|
<TinyScroll className="h-full overflow-auto">
|
||||||
<Info market={data} onSelect={onSelect} />
|
<MarketInfoAccordion market={data} onSelect={onSelect} />
|
||||||
</TinyScroll>
|
</TinyScroll>
|
||||||
) : (
|
) : (
|
||||||
<Splash>
|
<Splash>
|
||||||
@ -84,7 +70,10 @@ export const MarketInfoContainer = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Info = ({ market, onSelect }: InfoProps) => {
|
const MarketInfoAccordion = ({
|
||||||
|
market,
|
||||||
|
onSelect,
|
||||||
|
}: MarketInfoAccordionProps) => {
|
||||||
const { VEGA_TOKEN_URL } = useEnvironment();
|
const { VEGA_TOKEN_URL } = useEnvironment();
|
||||||
const headerClassName = 'uppercase text-lg';
|
const headerClassName = 'uppercase text-lg';
|
||||||
|
|
@ -3,15 +3,8 @@ import type {
|
|||||||
MarketInfoQuery,
|
MarketInfoQuery,
|
||||||
MarketInfoQueryVariables,
|
MarketInfoQueryVariables,
|
||||||
} from './__generated__/MarketInfo';
|
} from './__generated__/MarketInfo';
|
||||||
import {
|
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||||
marketDataProvider,
|
import type { MarketData, Candle } from '@vegaprotocol/market-list';
|
||||||
marketCandlesProvider,
|
|
||||||
} from '@vegaprotocol/market-list';
|
|
||||||
import type {
|
|
||||||
MarketData,
|
|
||||||
Candle,
|
|
||||||
MarketCandlesQueryVariables,
|
|
||||||
} from '@vegaprotocol/market-list';
|
|
||||||
import { MarketInfoDocument } from './__generated__/MarketInfo';
|
import { MarketInfoDocument } from './__generated__/MarketInfo';
|
||||||
|
|
||||||
export type MarketInfo = NonNullable<MarketInfoQuery['market']>;
|
export type MarketInfo = NonNullable<MarketInfoQuery['market']>;
|
||||||
@ -49,20 +42,3 @@ export const marketInfoWithDataProvider = makeDerivedDataProvider<
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const marketInfoWithDataAndCandlesProvider = makeDerivedDataProvider<
|
|
||||||
MarketInfoWithDataAndCandles,
|
|
||||||
never,
|
|
||||||
MarketCandlesQueryVariables
|
|
||||||
>([marketInfoProvider, marketDataProvider, marketCandlesProvider], (parts) => {
|
|
||||||
const market: MarketInfo | null = parts[0];
|
|
||||||
const marketData: MarketData | null = parts[1];
|
|
||||||
const candles: Candle[] | null = parts[2];
|
|
||||||
return (
|
|
||||||
market && {
|
|
||||||
...market,
|
|
||||||
data: marketData || undefined,
|
|
||||||
candles: candles || undefined,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
@ -3,8 +3,8 @@ import { useMemo } from 'react';
|
|||||||
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import {
|
import {
|
||||||
calcCandleVolume,
|
|
||||||
totalFeesPercentage,
|
totalFeesPercentage,
|
||||||
|
marketDataProvider,
|
||||||
} from '@vegaprotocol/market-list';
|
} from '@vegaprotocol/market-list';
|
||||||
import { ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import {
|
import {
|
||||||
@ -18,8 +18,8 @@ import { MarketInfoTable } from './info-key-value-table';
|
|||||||
import type {
|
import type {
|
||||||
MarketInfo,
|
MarketInfo,
|
||||||
MarketInfoWithData,
|
MarketInfoWithData,
|
||||||
MarketInfoWithDataAndCandles,
|
|
||||||
} from './market-info-data-provider';
|
} from './market-info-data-provider';
|
||||||
|
import { Last24hVolume } from '../last-24h-volume';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import type { DataSourceDefinition, SignerKind } from '@vegaprotocol/types';
|
import type { DataSourceDefinition, SignerKind } from '@vegaprotocol/types';
|
||||||
import { ConditionOperatorMapping } from '@vegaprotocol/types';
|
import { ConditionOperatorMapping } from '@vegaprotocol/types';
|
||||||
@ -27,6 +27,7 @@ import { MarketTradingModeMapping } from '@vegaprotocol/types';
|
|||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import type { Provider } from '@vegaprotocol/oracles';
|
import type { Provider } from '@vegaprotocol/oracles';
|
||||||
import { useOracleProofs } from '@vegaprotocol/oracles';
|
import { useOracleProofs } from '@vegaprotocol/oracles';
|
||||||
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
type PanelProps = Pick<
|
type PanelProps = Pick<
|
||||||
ComponentProps<typeof MarketInfoTable>,
|
ComponentProps<typeof MarketInfoTable>,
|
||||||
@ -37,14 +38,6 @@ type MarketInfoProps = {
|
|||||||
market: MarketInfo;
|
market: MarketInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
type MarketInfoWithDataProps = {
|
|
||||||
market: MarketInfoWithData;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MarketInfoWithDataAndCandlesProps = {
|
|
||||||
market: MarketInfoWithDataAndCandles;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CurrentFeesInfoPanel = ({
|
export const CurrentFeesInfoPanel = ({
|
||||||
market,
|
market,
|
||||||
...props
|
...props
|
||||||
@ -52,7 +45,9 @@ export const CurrentFeesInfoPanel = ({
|
|||||||
<>
|
<>
|
||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
data={{
|
data={{
|
||||||
...market.fees.factors,
|
makerFee: market.fees.factors.makerFee,
|
||||||
|
infrastructureFee: market.fees.factors.infrastructureFee,
|
||||||
|
liquidityFee: market.fees.factors.liquidityFee,
|
||||||
totalFees: totalFeesPercentage(market.fees.factors),
|
totalFees: totalFeesPercentage(market.fees.factors),
|
||||||
}}
|
}}
|
||||||
asPercentage={true}
|
asPercentage={true}
|
||||||
@ -69,18 +64,22 @@ export const CurrentFeesInfoPanel = ({
|
|||||||
export const MarketPriceInfoPanel = ({
|
export const MarketPriceInfoPanel = ({
|
||||||
market,
|
market,
|
||||||
...props
|
...props
|
||||||
}: MarketInfoWithDataProps & PanelProps) => {
|
}: MarketInfoProps & PanelProps) => {
|
||||||
const assetSymbol =
|
const assetSymbol =
|
||||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||||
const quoteUnit =
|
const quoteUnit =
|
||||||
market?.tradableInstrument.instrument.product?.quoteName || '';
|
market?.tradableInstrument.instrument.product?.quoteName || '';
|
||||||
|
const { data } = useDataProvider({
|
||||||
|
dataProvider: marketDataProvider,
|
||||||
|
variables: { marketId: market.id },
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
data={{
|
data={{
|
||||||
markPrice: market.data?.markPrice,
|
markPrice: data?.markPrice,
|
||||||
bestBidPrice: market.data?.bestBidPrice,
|
bestBidPrice: data?.bestBidPrice,
|
||||||
bestOfferPrice: market.data?.bestOfferPrice,
|
bestOfferPrice: data?.bestOfferPrice,
|
||||||
quoteUnit: market.tradableInstrument.instrument.product.quoteName,
|
quoteUnit: market.tradableInstrument.instrument.product.quoteName,
|
||||||
}}
|
}}
|
||||||
decimalPlaces={market.decimalPlaces}
|
decimalPlaces={market.decimalPlaces}
|
||||||
@ -99,8 +98,11 @@ export const MarketPriceInfoPanel = ({
|
|||||||
export const MarketVolumeInfoPanel = ({
|
export const MarketVolumeInfoPanel = ({
|
||||||
market,
|
market,
|
||||||
...props
|
...props
|
||||||
}: MarketInfoWithDataAndCandlesProps & PanelProps) => {
|
}: MarketInfoProps & PanelProps) => {
|
||||||
const last24hourVolume = market.candles && calcCandleVolume(market.candles);
|
const { data } = useDataProvider({
|
||||||
|
dataProvider: marketDataProvider,
|
||||||
|
variables: { marketId: market.id },
|
||||||
|
});
|
||||||
|
|
||||||
const dash = (value: string | undefined) =>
|
const dash = (value: string | undefined) =>
|
||||||
value && value !== '0' ? value : '-';
|
value && value !== '0' ? value : '-';
|
||||||
@ -108,12 +110,17 @@ export const MarketVolumeInfoPanel = ({
|
|||||||
return (
|
return (
|
||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
data={{
|
data={{
|
||||||
'24hourVolume': dash(last24hourVolume),
|
'24hourVolume': (
|
||||||
openInterest: dash(market.data?.openInterest),
|
<Last24hVolume
|
||||||
bestBidVolume: dash(market.data?.bestBidVolume),
|
marketId={market.id}
|
||||||
bestOfferVolume: dash(market.data?.bestOfferVolume),
|
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||||
bestStaticBidVolume: dash(market.data?.bestStaticBidVolume),
|
/>
|
||||||
bestStaticOfferVolume: dash(market.data?.bestStaticOfferVolume),
|
),
|
||||||
|
openInterest: dash(data?.openInterest),
|
||||||
|
bestBidVolume: dash(data?.bestBidVolume),
|
||||||
|
bestOfferVolume: dash(data?.bestOfferVolume),
|
||||||
|
bestStaticBidVolume: dash(data?.bestStaticBidVolume),
|
||||||
|
bestStaticOfferVolume: dash(data?.bestStaticOfferVolume),
|
||||||
}}
|
}}
|
||||||
decimalPlaces={market.positionDecimalPlaces}
|
decimalPlaces={market.positionDecimalPlaces}
|
||||||
{...props}
|
{...props}
|
||||||
@ -176,7 +183,7 @@ export const InstrumentInfoPanel = ({
|
|||||||
marketName: market.tradableInstrument.instrument.name,
|
marketName: market.tradableInstrument.instrument.name,
|
||||||
code: market.tradableInstrument.instrument.code,
|
code: market.tradableInstrument.instrument.code,
|
||||||
productType: market.tradableInstrument.instrument.product.__typename,
|
productType: market.tradableInstrument.instrument.product.__typename,
|
||||||
...market.tradableInstrument.instrument.product,
|
quoteName: market.tradableInstrument.instrument.product.quoteName,
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
@ -239,38 +246,52 @@ export const MetadataInfoPanel = ({
|
|||||||
export const RiskModelInfoPanel = ({
|
export const RiskModelInfoPanel = ({
|
||||||
market,
|
market,
|
||||||
...props
|
...props
|
||||||
}: MarketInfoProps & PanelProps) => (
|
}: MarketInfoProps & PanelProps) => {
|
||||||
|
if (market.tradableInstrument.riskModel.__typename !== 'LogNormalRiskModel') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { tau, riskAversionParameter } = market.tradableInstrument.riskModel;
|
||||||
|
return (
|
||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
data={market.tradableInstrument.riskModel}
|
data={{ tau, riskAversionParameter }}
|
||||||
unformatted={true}
|
unformatted
|
||||||
omits={[]}
|
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const RiskParametersInfoPanel = ({
|
export const RiskParametersInfoPanel = ({
|
||||||
market,
|
market,
|
||||||
...props
|
...props
|
||||||
}: MarketInfoProps & PanelProps) => (
|
}: MarketInfoProps & PanelProps) => {
|
||||||
|
if (market.tradableInstrument.riskModel.__typename === 'LogNormalRiskModel') {
|
||||||
|
const { r, sigma, mu } = market.tradableInstrument.riskModel.params;
|
||||||
|
return <MarketInfoTable data={{ r, sigma, mu }} unformatted {...props} />;
|
||||||
|
}
|
||||||
|
if (market.tradableInstrument.riskModel.__typename === 'SimpleRiskModel') {
|
||||||
|
const { factorLong, factorShort } =
|
||||||
|
market.tradableInstrument.riskModel.params;
|
||||||
|
return (
|
||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
data={market.tradableInstrument.riskModel.params}
|
data={{ factorLong, factorShort }}
|
||||||
unformatted={true}
|
unformatted
|
||||||
omits={[]}
|
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
export const RiskFactorsInfoPanel = ({
|
export const RiskFactorsInfoPanel = ({
|
||||||
market,
|
market,
|
||||||
...props
|
...props
|
||||||
}: MarketInfoProps & PanelProps) => (
|
}: MarketInfoProps & PanelProps) => {
|
||||||
<MarketInfoTable
|
if (!market.riskFactors) {
|
||||||
data={market.riskFactors}
|
return null;
|
||||||
unformatted={true}
|
}
|
||||||
omits={['market', '__typename']}
|
const { short, long } = market.riskFactors;
|
||||||
{...props}
|
return <MarketInfoTable data={{ short, long }} unformatted {...props} />;
|
||||||
/>
|
};
|
||||||
);
|
|
||||||
|
|
||||||
export const PriceMonitoringBoundsInfoPanel = ({
|
export const PriceMonitoringBoundsInfoPanel = ({
|
||||||
market,
|
market,
|
||||||
@ -278,13 +299,17 @@ export const PriceMonitoringBoundsInfoPanel = ({
|
|||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
triggerIndex: number;
|
triggerIndex: number;
|
||||||
} & MarketInfoWithDataProps &
|
} & MarketInfoProps &
|
||||||
PanelProps) => {
|
PanelProps) => {
|
||||||
|
const { data } = useDataProvider({
|
||||||
|
dataProvider: marketDataProvider,
|
||||||
|
variables: { marketId: market.id },
|
||||||
|
});
|
||||||
const quoteUnit =
|
const quoteUnit =
|
||||||
market?.tradableInstrument.instrument.product?.quoteName || '';
|
market?.tradableInstrument.instrument.product?.quoteName || '';
|
||||||
const trigger =
|
const trigger =
|
||||||
market.priceMonitoringSettings?.parameters?.triggers?.[triggerIndex];
|
market.priceMonitoringSettings?.parameters?.triggers?.[triggerIndex];
|
||||||
const bounds = market.data?.priceMonitoringBounds?.[triggerIndex];
|
const bounds = data?.priceMonitoringBounds?.[triggerIndex];
|
||||||
if (!trigger) {
|
if (!trigger) {
|
||||||
console.error(
|
console.error(
|
||||||
`Could not find data for trigger ${triggerIndex} (market id: ${market.id})`
|
`Could not find data for trigger ${triggerIndex} (market id: ${market.id})`
|
||||||
@ -334,7 +359,11 @@ export const LiquidityMonitoringParametersInfoPanel = ({
|
|||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
data={{
|
data={{
|
||||||
triggeringRatio: market.liquidityMonitoringParameters.triggeringRatio,
|
triggeringRatio: market.liquidityMonitoringParameters.triggeringRatio,
|
||||||
...market.liquidityMonitoringParameters.targetStakeParameters,
|
timeWindow:
|
||||||
|
market.liquidityMonitoringParameters.targetStakeParameters.timeWindow,
|
||||||
|
scalingFactor:
|
||||||
|
market.liquidityMonitoringParameters.targetStakeParameters
|
||||||
|
.scalingFactor,
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
@ -343,17 +372,21 @@ export const LiquidityMonitoringParametersInfoPanel = ({
|
|||||||
export const LiquidityInfoPanel = ({
|
export const LiquidityInfoPanel = ({
|
||||||
market,
|
market,
|
||||||
...props
|
...props
|
||||||
}: MarketInfoWithDataProps & PanelProps) => {
|
}: MarketInfoProps & PanelProps) => {
|
||||||
const assetDecimals =
|
const assetDecimals =
|
||||||
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
||||||
const assetSymbol =
|
const assetSymbol =
|
||||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||||
|
const { data } = useDataProvider({
|
||||||
|
dataProvider: marketDataProvider,
|
||||||
|
variables: { marketId: market.id },
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
data={{
|
data={{
|
||||||
targetStake: market.data && market.data.targetStake,
|
targetStake: data?.targetStake,
|
||||||
suppliedStake: market.data && market.data?.suppliedStake,
|
suppliedStake: data?.suppliedStake,
|
||||||
marketValueProxy: market.data && market.data.marketValueProxy,
|
marketValueProxy: data?.marketValueProxy,
|
||||||
}}
|
}}
|
||||||
decimalPlaces={assetDecimals}
|
decimalPlaces={assetDecimals}
|
||||||
assetSymbol={assetSymbol}
|
assetSymbol={assetSymbol}
|
||||||
@ -365,12 +398,16 @@ export const LiquidityInfoPanel = ({
|
|||||||
export const LiquidityPriceRangeInfoPanel = ({
|
export const LiquidityPriceRangeInfoPanel = ({
|
||||||
market,
|
market,
|
||||||
...props
|
...props
|
||||||
}: MarketInfoWithDataProps & PanelProps) => {
|
}: MarketInfoProps & PanelProps) => {
|
||||||
const quoteUnit =
|
const quoteUnit =
|
||||||
market?.tradableInstrument.instrument.product?.quoteName || '';
|
market?.tradableInstrument.instrument.product?.quoteName || '';
|
||||||
const liquidityPriceRange = formatNumberPercentage(
|
const liquidityPriceRange = formatNumberPercentage(
|
||||||
new BigNumber(market.lpPriceRange).times(100)
|
new BigNumber(market.lpPriceRange).times(100)
|
||||||
);
|
);
|
||||||
|
const { data } = useDataProvider({
|
||||||
|
dataProvider: marketDataProvider,
|
||||||
|
variables: { marketId: market.id },
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<p className="text-xs mb-4">
|
<p className="text-xs mb-4">
|
||||||
@ -386,20 +423,20 @@ export const LiquidityPriceRangeInfoPanel = ({
|
|||||||
data={{
|
data={{
|
||||||
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
|
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
|
||||||
lowestPrice:
|
lowestPrice:
|
||||||
market.data?.midPrice &&
|
data?.midPrice &&
|
||||||
`${addDecimalsFormatNumber(
|
`${addDecimalsFormatNumber(
|
||||||
new BigNumber(1)
|
new BigNumber(1)
|
||||||
.minus(market.lpPriceRange)
|
.minus(market.lpPriceRange)
|
||||||
.times(market.data.midPrice)
|
.times(data.midPrice)
|
||||||
.toString(),
|
.toString(),
|
||||||
market.decimalPlaces
|
market.decimalPlaces
|
||||||
)} ${quoteUnit}`,
|
)} ${quoteUnit}`,
|
||||||
highestPrice:
|
highestPrice:
|
||||||
market.data?.midPrice &&
|
data?.midPrice &&
|
||||||
`${addDecimalsFormatNumber(
|
`${addDecimalsFormatNumber(
|
||||||
new BigNumber(1)
|
new BigNumber(1)
|
||||||
.plus(market.lpPriceRange)
|
.plus(market.lpPriceRange)
|
||||||
.times(market.data.midPrice)
|
.times(data.midPrice)
|
||||||
.toString(),
|
.toString(),
|
||||||
market.decimalPlaces
|
market.decimalPlaces
|
||||||
)} ${quoteUnit}`,
|
)} ${quoteUnit}`,
|
||||||
@ -418,7 +455,15 @@ export const OracleInfoPanel = ({
|
|||||||
const { VEGA_EXPLORER_URL, ORACLE_PROOFS_URL } = useEnvironment();
|
const { VEGA_EXPLORER_URL, ORACLE_PROOFS_URL } = useEnvironment();
|
||||||
const { data } = useOracleProofs(ORACLE_PROOFS_URL);
|
const { data } = useOracleProofs(ORACLE_PROOFS_URL);
|
||||||
return (
|
return (
|
||||||
<MarketInfoTable data={product.dataSourceSpecBinding} {...props}>
|
<MarketInfoTable
|
||||||
|
data={{
|
||||||
|
settlementDataProperty:
|
||||||
|
product.dataSourceSpecBinding.settlementDataProperty,
|
||||||
|
tradingTerminationProperty:
|
||||||
|
product.dataSourceSpecBinding.tradingTerminationProperty,
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className="flex flex-col gap-2 mt-4"
|
className="flex flex-col gap-2 mt-4"
|
||||||
data-testid="oracle-proof-links"
|
data-testid="oracle-proof-links"
|
||||||
|
@ -354,10 +354,10 @@ export const volumeAndMarginProvider = makeDerivedDataProvider<
|
|||||||
partyId,
|
partyId,
|
||||||
marketId,
|
marketId,
|
||||||
}),
|
}),
|
||||||
(callback, client, variables) =>
|
(callback, client, { marketId }) =>
|
||||||
marketDataProvider(callback, client, { marketId: variables.marketId }),
|
marketDataProvider(callback, client, { marketId }),
|
||||||
(callback, client, variables) =>
|
(callback, client, { marketId }) =>
|
||||||
marketInfoProvider(callback, client, { marketId: variables.marketId }),
|
marketInfoProvider(callback, client, { marketId }),
|
||||||
openVolumeDataProvider,
|
openVolumeDataProvider,
|
||||||
],
|
],
|
||||||
(data) => {
|
(data) => {
|
||||||
|
@ -6,7 +6,7 @@ import { MockedProvider } from '@apollo/client/testing';
|
|||||||
|
|
||||||
type Data = number;
|
type Data = number;
|
||||||
type Delta = number;
|
type Delta = number;
|
||||||
type Variables = { partyId: string };
|
type Variables = { partyId: string; marketIds?: string[] };
|
||||||
|
|
||||||
const unsubscribe = jest.fn();
|
const unsubscribe = jest.fn();
|
||||||
const reload = jest.fn();
|
const reload = jest.fn();
|
||||||
@ -156,6 +156,121 @@ describe('useDataProvider hook', () => {
|
|||||||
expect(insert.mock.calls[1][0].insertionData).toEqual(insertionData);
|
expect(insert.mock.calls[1][0].insertionData).toEqual(insertionData);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('calls dataProvider with updated variables if skip switched to true', async () => {
|
||||||
|
const { rerender } = render({
|
||||||
|
dataProvider,
|
||||||
|
variables: { partyId: '' },
|
||||||
|
skip: true,
|
||||||
|
});
|
||||||
|
expect(dataProvider).toBeCalledTimes(0);
|
||||||
|
rerender({
|
||||||
|
dataProvider,
|
||||||
|
variables,
|
||||||
|
});
|
||||||
|
expect(dataProvider).toBeCalledTimes(1);
|
||||||
|
expect(dataProvider.mock.calls[0][2]).toEqual(variables);
|
||||||
|
});
|
||||||
|
it('uses same data provider when rerendered with equal variables', async () => {
|
||||||
|
const { rerender } = render({
|
||||||
|
dataProvider,
|
||||||
|
variables: { ...variables, marketIds: ['a', 'b'] },
|
||||||
|
});
|
||||||
|
expect(dataProvider).toBeCalledTimes(1);
|
||||||
|
rerender({
|
||||||
|
dataProvider,
|
||||||
|
variables: { ...variables, marketIds: ['b', 'a'] },
|
||||||
|
});
|
||||||
|
expect(dataProvider).toBeCalledTimes(1);
|
||||||
|
rerender({
|
||||||
|
dataProvider,
|
||||||
|
variables: { ...variables },
|
||||||
|
});
|
||||||
|
expect(dataProvider).toBeCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls new update and insert when replaced', async () => {
|
||||||
|
const { rerender } = render({
|
||||||
|
dataProvider,
|
||||||
|
update,
|
||||||
|
insert,
|
||||||
|
variables,
|
||||||
|
});
|
||||||
|
const data = 0;
|
||||||
|
const delta = 0;
|
||||||
|
const insertionData = 0;
|
||||||
|
const callback = dataProvider.mock.calls[0][0];
|
||||||
|
await act(async () => {
|
||||||
|
callback({ ...updateCallbackPayload, data });
|
||||||
|
});
|
||||||
|
const newUpdate = jest.fn();
|
||||||
|
const newInsert = jest.fn();
|
||||||
|
expect(update).toBeCalledTimes(2);
|
||||||
|
expect(insert).toBeCalledTimes(0);
|
||||||
|
rerender({ dataProvider, update: newUpdate, insert: newInsert, variables });
|
||||||
|
await act(async () => {
|
||||||
|
callback({
|
||||||
|
...updateCallbackPayload,
|
||||||
|
data: data,
|
||||||
|
delta,
|
||||||
|
isUpdate: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
expect(newUpdate).toBeCalledTimes(1);
|
||||||
|
await act(async () => {
|
||||||
|
callback({
|
||||||
|
...updateCallbackPayload,
|
||||||
|
data,
|
||||||
|
insertionData,
|
||||||
|
isInsert: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
expect(newUpdate).toBeCalledTimes(2);
|
||||||
|
expect(newInsert).toBeCalledTimes(1);
|
||||||
|
expect(update).toBeCalledTimes(2);
|
||||||
|
expect(insert).toBeCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skip updates if skipUpdates is true', async () => {
|
||||||
|
const { result, rerender } = render({
|
||||||
|
dataProvider,
|
||||||
|
update,
|
||||||
|
variables,
|
||||||
|
skipUpdates: true,
|
||||||
|
});
|
||||||
|
expect(update).toBeCalledTimes(1);
|
||||||
|
let data = 0;
|
||||||
|
const delta = 1;
|
||||||
|
const callback = dataProvider.mock.calls[0][0];
|
||||||
|
await act(async () => {
|
||||||
|
callback({ ...updateCallbackPayload, data });
|
||||||
|
});
|
||||||
|
expect(update).toBeCalledTimes(2);
|
||||||
|
expect(result.current.data).toEqual(data);
|
||||||
|
await act(async () => {
|
||||||
|
callback({
|
||||||
|
...updateCallbackPayload,
|
||||||
|
data: data + delta,
|
||||||
|
delta,
|
||||||
|
isUpdate: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
expect(update).toBeCalledTimes(2);
|
||||||
|
expect(result.current.data).toEqual(data);
|
||||||
|
rerender({ dataProvider, variables, update });
|
||||||
|
expect(update).toBeCalledTimes(2);
|
||||||
|
await act(async () => {
|
||||||
|
callback({
|
||||||
|
...updateCallbackPayload,
|
||||||
|
data: (data = data + delta),
|
||||||
|
delta,
|
||||||
|
isUpdate: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
expect(update).toBeCalledTimes(3);
|
||||||
|
expect(result.current.data).toEqual(data);
|
||||||
|
expect(dataProvider).toBeCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
it('change data provider instance on variables change', async () => {
|
it('change data provider instance on variables change', async () => {
|
||||||
const { result, rerender } = render({ dataProvider, update, variables });
|
const { result, rerender } = render({ dataProvider, update, variables });
|
||||||
const callback = dataProvider.mock.calls[0][0];
|
const callback = dataProvider.mock.calls[0][0];
|
||||||
|
@ -63,6 +63,9 @@ export const useDataProvider = <
|
|||||||
const reloadRef = useRef<((force?: boolean) => void) | undefined>(undefined);
|
const reloadRef = useRef<((force?: boolean) => void) | undefined>(undefined);
|
||||||
const loadRef = useRef<Load<Data> | undefined>(undefined);
|
const loadRef = useRef<Load<Data> | undefined>(undefined);
|
||||||
const variablesRef = useRef<Variables>(props.variables);
|
const variablesRef = useRef<Variables>(props.variables);
|
||||||
|
const updateRef = useRef(update);
|
||||||
|
const insertRef = useRef(insert);
|
||||||
|
const skipUpdatesRef = useRef(skipUpdates);
|
||||||
const variables = useMemo(() => {
|
const variables = useMemo(() => {
|
||||||
if (
|
if (
|
||||||
!isEqualWith(
|
!isEqualWith(
|
||||||
@ -91,8 +94,7 @@ export const useDataProvider = <
|
|||||||
}
|
}
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}, []);
|
}, []);
|
||||||
const callback = useCallback<UpdateCallback<Data, Delta>>(
|
const callback = useCallback<UpdateCallback<Data, Delta>>((args) => {
|
||||||
(args) => {
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
delta,
|
delta,
|
||||||
@ -110,35 +112,51 @@ export const useDataProvider = <
|
|||||||
if (!loading) {
|
if (!loading) {
|
||||||
if (
|
if (
|
||||||
isUpdate &&
|
isUpdate &&
|
||||||
!skipUpdates &&
|
(skipUpdatesRef.current ||
|
||||||
update &&
|
(!skipUpdatesRef.current &&
|
||||||
update({ delta, data, totalCount })
|
updateRef.current &&
|
||||||
|
updateRef.current({ delta, data, totalCount })))
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isInsert && insert && insert({ insertionData, data, totalCount })) {
|
if (
|
||||||
|
isInsert &&
|
||||||
|
insertRef.current &&
|
||||||
|
insertRef.current({ insertionData, data, totalCount })
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTotalCount(totalCount);
|
setTotalCount(totalCount);
|
||||||
setData(data);
|
setData(data);
|
||||||
if (!loading && !isUpdate && update) {
|
if (!loading && !isUpdate && updateRef.current) {
|
||||||
update({ data });
|
updateRef.current({ data });
|
||||||
}
|
}
|
||||||
},
|
}, []);
|
||||||
[update, insert, skipUpdates]
|
|
||||||
);
|
useEffect(() => {
|
||||||
|
updateRef.current = update;
|
||||||
|
}, [update]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
insertRef.current = insert;
|
||||||
|
}, [insert]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
skipUpdatesRef.current = skipUpdates;
|
||||||
|
}, [skipUpdates]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setData(null);
|
setData(null);
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
setTotalCount(undefined);
|
setTotalCount(undefined);
|
||||||
if (update) {
|
if (updateRef.current) {
|
||||||
update({ data: null });
|
updateRef.current({ data: null });
|
||||||
}
|
}
|
||||||
if (skip) {
|
if (skip) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
if (update) {
|
if (updateRef.current) {
|
||||||
update({ data: null });
|
updateRef.current({ data: null });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -157,7 +175,7 @@ export const useDataProvider = <
|
|||||||
loadRef.current = undefined;
|
loadRef.current = undefined;
|
||||||
return unsubscribe();
|
return unsubscribe();
|
||||||
};
|
};
|
||||||
}, [client, dataProvider, callback, variables, skip, update]);
|
}, [client, dataProvider, callback, variables, skip]);
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
loading,
|
loading,
|
||||||
@ -175,7 +193,7 @@ export const useThrottledDataProvider = <
|
|||||||
Variables extends OperationVariables = OperationVariables
|
Variables extends OperationVariables = OperationVariables
|
||||||
>(
|
>(
|
||||||
params: Omit<useDataProviderParams<Data, Delta, Variables>, 'update'>,
|
params: Omit<useDataProviderParams<Data, Delta, Variables>, 'update'>,
|
||||||
wait?: number
|
wait = 500
|
||||||
) => {
|
) => {
|
||||||
const [data, setData] = useState<Data | null>(null);
|
const [data, setData] = useState<Data | null>(null);
|
||||||
const dataRef = useRef<Data | null>(null);
|
const dataRef = useRef<Data | null>(null);
|
||||||
|
Loading…
Reference in New Issue
Block a user