chore: handle not found errors as correct response (#2759)
This commit is contained in:
parent
05559f3ea0
commit
00e319b3c6
@ -5,10 +5,12 @@ import { Heading } from '../../components/heading';
|
|||||||
import { SplashLoader } from '../../components/splash-loader';
|
import { SplashLoader } from '../../components/splash-loader';
|
||||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
||||||
import {
|
import {
|
||||||
useWithdrawals,
|
withdrawalProvider,
|
||||||
useWithdrawalDialog,
|
useWithdrawalDialog,
|
||||||
WithdrawalsTable,
|
WithdrawalsTable,
|
||||||
} from '@vegaprotocol/withdraws';
|
} from '@vegaprotocol/withdraws';
|
||||||
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||||
import type { RouteChildProps } from '../index';
|
import type { RouteChildProps } from '../index';
|
||||||
|
|
||||||
@ -29,7 +31,12 @@ const Withdrawals = ({ name }: RouteChildProps) => {
|
|||||||
const WithdrawPendingContainer = () => {
|
const WithdrawPendingContainer = () => {
|
||||||
const openWithdrawalDialog = useWithdrawalDialog((state) => state.open);
|
const openWithdrawalDialog = useWithdrawalDialog((state) => state.open);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { data, loading, error } = useWithdrawals();
|
const { pubKey } = useVegaWallet();
|
||||||
|
const { data, loading, error } = useDataProvider({
|
||||||
|
dataProvider: withdrawalProvider,
|
||||||
|
variables: { partyId: pubKey || '' },
|
||||||
|
skip: !pubKey,
|
||||||
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
|
@ -1,22 +1,28 @@
|
|||||||
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useDepositDialog, DepositsTable } from '@vegaprotocol/deposits';
|
import { useDepositDialog, DepositsTable } from '@vegaprotocol/deposits';
|
||||||
import { useDeposits } from '@vegaprotocol/deposits';
|
import { depositsProvider } from '@vegaprotocol/deposits';
|
||||||
import { t } from '@vegaprotocol/react-helpers';
|
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
export const DepositsContainer = () => {
|
export const DepositsContainer = () => {
|
||||||
const { deposits, loading, error } = useDeposits();
|
const { pubKey } = useVegaWallet();
|
||||||
|
const { data, loading, error } = useDataProvider({
|
||||||
|
dataProvider: depositsProvider,
|
||||||
|
variables: { partyId: pubKey || '' },
|
||||||
|
skip: !pubKey,
|
||||||
|
});
|
||||||
const openDepositDialog = useDepositDialog((state) => state.open);
|
const openDepositDialog = useDepositDialog((state) => state.open);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full grid grid-rows-[1fr,min-content]">
|
<div className="h-full grid grid-rows-[1fr,min-content]">
|
||||||
<div className="h-full relative">
|
<div className="h-full relative">
|
||||||
<DepositsTable
|
<DepositsTable
|
||||||
rowData={deposits || []}
|
rowData={data || []}
|
||||||
noRowsOverlayComponent={() => null}
|
noRowsOverlayComponent={() => null}
|
||||||
/>
|
/>
|
||||||
<div className="pointer-events-none absolute inset-0">
|
<div className="pointer-events-none absolute inset-0">
|
||||||
<AsyncRenderer
|
<AsyncRenderer
|
||||||
data={deposits}
|
data={data}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
error={error}
|
error={error}
|
||||||
noDataCondition={(data) => !(data && data.length)}
|
noDataCondition={(data) => !(data && data.length)}
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
|
||||||
import {
|
import {
|
||||||
useWithdrawals,
|
withdrawalProvider,
|
||||||
useWithdrawalDialog,
|
useWithdrawalDialog,
|
||||||
WithdrawalsTable,
|
WithdrawalsTable,
|
||||||
} from '@vegaprotocol/withdraws';
|
} from '@vegaprotocol/withdraws';
|
||||||
import { t } from '@vegaprotocol/react-helpers';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
|
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
||||||
|
|
||||||
export const WithdrawalsContainer = () => {
|
export const WithdrawalsContainer = () => {
|
||||||
const { data, loading, error } = useWithdrawals();
|
const { pubKey } = useVegaWallet();
|
||||||
|
const { data, loading, error } = useDataProvider({
|
||||||
|
dataProvider: withdrawalProvider,
|
||||||
|
variables: { partyId: pubKey || '' },
|
||||||
|
skip: !pubKey,
|
||||||
|
});
|
||||||
const openWithdrawDialog = useWithdrawalDialog((state) => state.open);
|
const openWithdrawDialog = useWithdrawalDialog((state) => state.open);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -50,10 +50,10 @@ export type Account = Omit<AccountFieldsFragment, 'market' | 'asset'> & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const update = (
|
const update = (
|
||||||
data: AccountFieldsFragment[],
|
data: AccountFieldsFragment[] | null,
|
||||||
deltas: AccountEventsSubscription['accounts']
|
deltas: AccountEventsSubscription['accounts']
|
||||||
) => {
|
) => {
|
||||||
return produce(data, (draft) => {
|
return produce(data || [], (draft) => {
|
||||||
deltas.forEach((delta) => {
|
deltas.forEach((delta) => {
|
||||||
const id = getId(delta);
|
const id = getId(delta);
|
||||||
const index = draft.findIndex((a) => getId(a) === id);
|
const index = draft.findIndex((a) => getId(a) === id);
|
||||||
@ -73,15 +73,8 @@ const update = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = (
|
const getData = (responseData: AccountsQuery | null): AccountFieldsFragment[] =>
|
||||||
responseData: AccountsQuery
|
removePaginationWrapper(responseData?.party?.accountsConnection?.edges) || [];
|
||||||
): AccountFieldsFragment[] | null => {
|
|
||||||
return (
|
|
||||||
removePaginationWrapper(responseData.party?.accountsConnection?.edges) ??
|
|
||||||
null
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getDelta = (
|
const getDelta = (
|
||||||
subscriptionData: AccountEventsSubscription
|
subscriptionData: AccountEventsSubscription
|
||||||
): AccountEventsSubscription['accounts'] => {
|
): AccountEventsSubscription['accounts'] => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { ApolloError, InMemoryCacheConfig } from '@apollo/client';
|
import type { InMemoryCacheConfig } from '@apollo/client';
|
||||||
import {
|
import {
|
||||||
ApolloClient,
|
ApolloClient,
|
||||||
from,
|
from,
|
||||||
@ -13,7 +13,6 @@ import { createClient as createWSClient } from 'graphql-ws';
|
|||||||
import { onError } from '@apollo/client/link/error';
|
import { onError } from '@apollo/client/link/error';
|
||||||
import { RetryLink } from '@apollo/client/link/retry';
|
import { RetryLink } from '@apollo/client/link/retry';
|
||||||
import ApolloLinkTimeout from 'apollo-link-timeout';
|
import ApolloLinkTimeout from 'apollo-link-timeout';
|
||||||
import type { GraphQLErrors } from '@apollo/client/errors';
|
|
||||||
import { localLoggerFactory } from '@vegaprotocol/react-helpers';
|
import { localLoggerFactory } from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
const isBrowser = typeof window !== 'undefined';
|
const isBrowser = typeof window !== 'undefined';
|
||||||
@ -110,21 +109,3 @@ export function createClient({
|
|||||||
connectToDevTools,
|
connectToDevTools,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const isApolloGraphQLError = (
|
|
||||||
error: ApolloError | Error | undefined
|
|
||||||
): error is ApolloError => {
|
|
||||||
return !!error && !!(error as ApolloError).graphQLErrors;
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasNotFoundGraphQLErrors = (errors: GraphQLErrors) => {
|
|
||||||
return errors.some((e) => e.extensions && e.extensions['type'] === NOT_FOUND);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isNotFoundGraphQLError = (
|
|
||||||
error: Error | ApolloError | undefined
|
|
||||||
) => {
|
|
||||||
return (
|
|
||||||
isApolloGraphQLError(error) && hasNotFoundGraphQLErrors(error.graphQLErrors)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@ -6,20 +6,15 @@ import { AssetDocument } from './__generated__/Asset';
|
|||||||
|
|
||||||
export type Asset = AssetFieldsFragment;
|
export type Asset = AssetFieldsFragment;
|
||||||
|
|
||||||
const getData = (responseData: AssetQuery) => {
|
const getData = (responseData: AssetQuery | null) => {
|
||||||
const foundAssets = responseData.assetsConnection?.edges
|
const foundAssets = responseData?.assetsConnection?.edges
|
||||||
?.filter((e) => Boolean(e?.node))
|
?.filter((e) => Boolean(e?.node))
|
||||||
.map((e) => e?.node as Asset);
|
.map((e) => e?.node as Asset);
|
||||||
if (foundAssets && foundAssets?.length > 0) return foundAssets[0];
|
if (foundAssets && foundAssets?.length > 0) return foundAssets[0];
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const assetProvider = makeDataProvider<
|
export const assetProvider = makeDataProvider<AssetQuery, Asset, never, never>({
|
||||||
AssetQuery,
|
|
||||||
Asset | null,
|
|
||||||
never,
|
|
||||||
never
|
|
||||||
>({
|
|
||||||
query: AssetDocument,
|
query: AssetDocument,
|
||||||
getData,
|
getData,
|
||||||
});
|
});
|
||||||
|
@ -16,14 +16,14 @@ export type BuiltinAsset = Omit<Asset, 'source'> & {
|
|||||||
source: BuiltinAssetSource;
|
source: BuiltinAssetSource;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = (responseData: AssetsQuery) =>
|
const getData = (responseData: AssetsQuery | null) =>
|
||||||
responseData.assetsConnection?.edges
|
responseData?.assetsConnection?.edges
|
||||||
?.filter((e) => Boolean(e?.node))
|
?.filter((e) => Boolean(e?.node))
|
||||||
.map((e) => e?.node as Asset) ?? [];
|
.map((e) => e?.node as Asset) ?? [];
|
||||||
|
|
||||||
export const assetsProvider = makeDataProvider<
|
export const assetsProvider = makeDataProvider<
|
||||||
AssetsQuery,
|
AssetsQuery,
|
||||||
Asset[] | null,
|
Asset[],
|
||||||
never,
|
never,
|
||||||
never
|
never
|
||||||
>({
|
>({
|
||||||
|
49
libs/deposits/src/lib/deposits-provider.ts
Normal file
49
libs/deposits/src/lib/deposits-provider.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import uniqBy from 'lodash/uniqBy';
|
||||||
|
import orderBy from 'lodash/orderBy';
|
||||||
|
import {
|
||||||
|
getEvents,
|
||||||
|
makeDataProvider,
|
||||||
|
removePaginationWrapper,
|
||||||
|
} from '@vegaprotocol/react-helpers';
|
||||||
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
import {
|
||||||
|
DepositsDocument,
|
||||||
|
DepositEventDocument,
|
||||||
|
} from './__generated__/Deposit';
|
||||||
|
import type {
|
||||||
|
DepositFieldsFragment,
|
||||||
|
DepositsQuery,
|
||||||
|
DepositEventSubscription,
|
||||||
|
DepositEventSubscriptionVariables,
|
||||||
|
} from './__generated__/Deposit';
|
||||||
|
|
||||||
|
export const depositsProvider = makeDataProvider<
|
||||||
|
DepositsQuery,
|
||||||
|
DepositFieldsFragment[],
|
||||||
|
DepositEventSubscription,
|
||||||
|
DepositEventSubscription,
|
||||||
|
DepositEventSubscriptionVariables
|
||||||
|
>({
|
||||||
|
query: DepositsDocument,
|
||||||
|
subscriptionQuery: DepositEventDocument,
|
||||||
|
getData: (data: DepositsQuery | null) =>
|
||||||
|
orderBy(
|
||||||
|
removePaginationWrapper(data?.party?.depositsConnection?.edges || []),
|
||||||
|
['createdTimestamp'],
|
||||||
|
['desc']
|
||||||
|
),
|
||||||
|
getDelta: (data: DepositEventSubscription) => data,
|
||||||
|
update: (
|
||||||
|
data: DepositFieldsFragment[] | null,
|
||||||
|
delta: DepositEventSubscription
|
||||||
|
) => {
|
||||||
|
if (!delta.busEvents?.length) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
const incoming = getEvents<DepositFieldsFragment>(
|
||||||
|
Schema.BusEventType.Deposit,
|
||||||
|
delta.busEvents
|
||||||
|
);
|
||||||
|
return uniqBy([...incoming, ...(data || [])], 'id');
|
||||||
|
},
|
||||||
|
});
|
@ -5,7 +5,7 @@ export * from './deposit-limits';
|
|||||||
export * from './deposit-manager';
|
export * from './deposit-manager';
|
||||||
export * from './deposits-table';
|
export * from './deposits-table';
|
||||||
export * from './use-deposit-balances';
|
export * from './use-deposit-balances';
|
||||||
export * from './use-deposits';
|
export * from './deposits-provider';
|
||||||
export * from './use-get-allowance';
|
export * from './use-get-allowance';
|
||||||
export * from './use-get-balance-of-erc20-token';
|
export * from './use-get-balance-of-erc20-token';
|
||||||
export * from './use-get-deposit-maximum';
|
export * from './use-get-deposit-maximum';
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
import uniqBy from 'lodash/uniqBy';
|
|
||||||
import orderBy from 'lodash/orderBy';
|
|
||||||
import { getNodes, getEvents } from '@vegaprotocol/react-helpers';
|
|
||||||
import type { UpdateQueryFn } from '@apollo/client/core/watchQueryOptions';
|
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
|
||||||
import { useEffect, useMemo } from 'react';
|
|
||||||
import * as Schema from '@vegaprotocol/types';
|
|
||||||
import {
|
|
||||||
useDepositsQuery,
|
|
||||||
DepositEventDocument,
|
|
||||||
} from './__generated__/Deposit';
|
|
||||||
import type {
|
|
||||||
DepositFieldsFragment,
|
|
||||||
DepositsQuery,
|
|
||||||
DepositEventSubscription,
|
|
||||||
DepositEventSubscriptionVariables,
|
|
||||||
} from './__generated__/Deposit';
|
|
||||||
|
|
||||||
export const useDeposits = () => {
|
|
||||||
const { pubKey } = useVegaWallet();
|
|
||||||
const { data, loading, error, subscribeToMore } = useDepositsQuery({
|
|
||||||
variables: { partyId: pubKey || '' },
|
|
||||||
skip: !pubKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
const deposits = useMemo(() => {
|
|
||||||
if (!data?.party?.depositsConnection?.edges?.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return orderBy(
|
|
||||||
getNodes<DepositFieldsFragment>(data.party?.depositsConnection),
|
|
||||||
['createdTimestamp'],
|
|
||||||
['desc']
|
|
||||||
);
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!pubKey) return;
|
|
||||||
|
|
||||||
const unsub = subscribeToMore<
|
|
||||||
DepositEventSubscription,
|
|
||||||
DepositEventSubscriptionVariables
|
|
||||||
>({
|
|
||||||
document: DepositEventDocument,
|
|
||||||
variables: { partyId: pubKey },
|
|
||||||
updateQuery,
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unsub();
|
|
||||||
};
|
|
||||||
}, [pubKey, subscribeToMore]);
|
|
||||||
|
|
||||||
return { data, loading, error, deposits };
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateQuery: UpdateQueryFn<
|
|
||||||
DepositsQuery,
|
|
||||||
DepositEventSubscriptionVariables,
|
|
||||||
DepositEventSubscription
|
|
||||||
> = (prev, { subscriptionData, variables }) => {
|
|
||||||
if (!subscriptionData.data.busEvents?.length || !variables?.partyId) {
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
const curr = getNodes<DepositFieldsFragment>(prev.party?.depositsConnection);
|
|
||||||
const incoming = getEvents<DepositFieldsFragment>(
|
|
||||||
Schema.BusEventType.Deposit,
|
|
||||||
subscriptionData.data.busEvents
|
|
||||||
);
|
|
||||||
|
|
||||||
const deposits = uniqBy([...incoming, ...curr], 'id');
|
|
||||||
|
|
||||||
if (!prev.party) {
|
|
||||||
return {
|
|
||||||
...prev,
|
|
||||||
party: {
|
|
||||||
__typename: 'Party',
|
|
||||||
id: variables?.partyId,
|
|
||||||
depositsConnection: {
|
|
||||||
__typename: 'DepositsConnection',
|
|
||||||
edges: deposits.map((d) => ({ __typename: 'DepositEdge', node: d })),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...prev,
|
|
||||||
party: {
|
|
||||||
...prev.party,
|
|
||||||
id: variables?.partyId,
|
|
||||||
depositsConnection: {
|
|
||||||
__typename: 'DepositsConnection',
|
|
||||||
edges: deposits.map((d) => ({ __typename: 'DepositEdge', node: d })),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -59,8 +59,8 @@ const update = (
|
|||||||
export type Trade = Omit<FillFieldsFragment, 'market'> & { market?: Market };
|
export type Trade = Omit<FillFieldsFragment, 'market'> & { market?: Market };
|
||||||
export type TradeEdge = Edge<Trade>;
|
export type TradeEdge = Edge<Trade>;
|
||||||
|
|
||||||
const getData = (responseData: FillsQuery): FillEdgeFragment[] =>
|
const getData = (responseData: FillsQuery | null): FillEdgeFragment[] =>
|
||||||
responseData.party?.tradesConnection?.edges || [];
|
responseData?.party?.tradesConnection?.edges || [];
|
||||||
|
|
||||||
const getPageInfo = (responseData: FillsQuery): PageInfo | null =>
|
const getPageInfo = (responseData: FillsQuery): PageInfo | null =>
|
||||||
responseData.party?.tradesConnection?.pageInfo || null;
|
responseData.party?.tradesConnection?.pageInfo || null;
|
||||||
|
@ -5,8 +5,8 @@ import type {
|
|||||||
} from './__generated__/Proposals';
|
} from './__generated__/Proposals';
|
||||||
import { ProposalsListDocument } from './__generated__/Proposals';
|
import { ProposalsListDocument } from './__generated__/Proposals';
|
||||||
|
|
||||||
const getData = (responseData: ProposalsListQuery) =>
|
const getData = (responseData: ProposalsListQuery | null) =>
|
||||||
responseData.proposalsConnection?.edges
|
responseData?.proposalsConnection?.edges
|
||||||
?.filter((edge) => Boolean(edge?.node))
|
?.filter((edge) => Boolean(edge?.node))
|
||||||
.map((edge) => edge?.node as ProposalListFieldsFragment) || null;
|
.map((edge) => edge?.node as ProposalListFieldsFragment) || null;
|
||||||
|
|
||||||
|
@ -35,12 +35,12 @@ export type LedgerEntry = LedgerEntryFragment & {
|
|||||||
|
|
||||||
export type AggregatedLedgerEntriesEdge = Schema.AggregatedLedgerEntriesEdge;
|
export type AggregatedLedgerEntriesEdge = Schema.AggregatedLedgerEntriesEdge;
|
||||||
|
|
||||||
const getData = (responseData: LedgerEntriesQuery) => {
|
const getData = (responseData: LedgerEntriesQuery | null) => {
|
||||||
return responseData.ledgerEntries?.edges || [];
|
return responseData?.ledgerEntries?.edges || [];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const update = (
|
export const update = (
|
||||||
data: ReturnType<typeof getData>,
|
data: ReturnType<typeof getData> | null,
|
||||||
delta: ReturnType<typeof getData>,
|
delta: ReturnType<typeof getData>,
|
||||||
reload: () => void,
|
reload: () => void,
|
||||||
variables?: LedgerEntriesQueryVariables
|
variables?: LedgerEntriesQueryVariables
|
||||||
|
@ -35,10 +35,10 @@ export const liquidityProvisionsDataProvider = makeDataProvider<
|
|||||||
query: LiquidityProvisionsDocument,
|
query: LiquidityProvisionsDocument,
|
||||||
subscriptionQuery: LiquidityProvisionsUpdateDocument,
|
subscriptionQuery: LiquidityProvisionsUpdateDocument,
|
||||||
update: (
|
update: (
|
||||||
data: LiquidityProvisionFieldsFragment[],
|
data: LiquidityProvisionFieldsFragment[] | null,
|
||||||
deltas: LiquidityProvisionsUpdateSubscription['liquidityProvisions']
|
deltas: LiquidityProvisionsUpdateSubscription['liquidityProvisions']
|
||||||
) => {
|
) => {
|
||||||
return produce(data, (draft) => {
|
return produce(data || [], (draft) => {
|
||||||
deltas?.forEach((delta) => {
|
deltas?.forEach((delta) => {
|
||||||
const id = getId(delta);
|
const id = getId(delta);
|
||||||
const index = draft.findIndex((a) => getId(a) === id);
|
const index = draft.findIndex((a) => getId(a) === id);
|
||||||
@ -63,9 +63,9 @@ export const liquidityProvisionsDataProvider = makeDataProvider<
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getData: (responseData: LiquidityProvisionsQuery) => {
|
getData: (responseData: LiquidityProvisionsQuery | null) => {
|
||||||
return (
|
return (
|
||||||
responseData.market?.liquidityProvisionsConnection?.edges?.map(
|
responseData?.market?.liquidityProvisionsConnection?.edges?.map(
|
||||||
(e) => e?.node
|
(e) => e?.node
|
||||||
) ?? []
|
) ?? []
|
||||||
).filter((e) => !!e) as LiquidityProvisionFieldsFragment[];
|
).filter((e) => !!e) as LiquidityProvisionFieldsFragment[];
|
||||||
@ -105,7 +105,7 @@ export const marketLiquidityDataProvider = makeDataProvider<
|
|||||||
never
|
never
|
||||||
>({
|
>({
|
||||||
query: MarketLpDocument,
|
query: MarketLpDocument,
|
||||||
getData: (responseData: MarketLpQuery) => {
|
getData: (responseData: MarketLpQuery | null) => {
|
||||||
return responseData;
|
return responseData;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -119,10 +119,10 @@ export const liquidityFeeShareDataProvider = makeDataProvider<
|
|||||||
query: LiquidityProviderFeeShareDocument,
|
query: LiquidityProviderFeeShareDocument,
|
||||||
subscriptionQuery: LiquidityProviderFeeShareUpdateDocument,
|
subscriptionQuery: LiquidityProviderFeeShareUpdateDocument,
|
||||||
update: (
|
update: (
|
||||||
data: LiquidityProviderFeeShareFieldsFragment[],
|
data: LiquidityProviderFeeShareFieldsFragment[] | null,
|
||||||
deltas: LiquidityProviderFeeShareUpdateSubscription['marketsData'][0]['liquidityProviderFeeShare']
|
deltas: LiquidityProviderFeeShareUpdateSubscription['marketsData'][0]['liquidityProviderFeeShare']
|
||||||
) => {
|
) => {
|
||||||
return produce(data, (draft) => {
|
return produce(data || [], (draft) => {
|
||||||
deltas?.forEach((delta) => {
|
deltas?.forEach((delta) => {
|
||||||
const id = delta.partyId;
|
const id = delta.partyId;
|
||||||
const index = draft.findIndex((a) => a.party.id === id);
|
const index = draft.findIndex((a) => a.party.id === id);
|
||||||
@ -143,7 +143,7 @@ export const liquidityFeeShareDataProvider = makeDataProvider<
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
getData: (data) => {
|
getData: (data) => {
|
||||||
return data.market?.data?.liquidityProviderFeeShare || [];
|
return data?.market?.data?.liquidityProviderFeeShare || [];
|
||||||
},
|
},
|
||||||
getDelta: (subscriptionData: LiquidityProviderFeeShareUpdateSubscription) => {
|
getDelta: (subscriptionData: LiquidityProviderFeeShareUpdateSubscription) => {
|
||||||
return subscriptionData.marketsData[0].liquidityProviderFeeShare;
|
return subscriptionData.marketsData[0].liquidityProviderFeeShare;
|
||||||
|
@ -58,7 +58,7 @@ export interface Markets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getData = (
|
const getData = (
|
||||||
responseData: LiquidityProvisionMarketsQuery
|
responseData: LiquidityProvisionMarketsQuery | null
|
||||||
): LiquidityProvisionMarket[] | null => {
|
): LiquidityProvisionMarket[] | null => {
|
||||||
return (
|
return (
|
||||||
responseData?.marketsConnection?.edges.map((edge) => {
|
responseData?.marketsConnection?.edges.map((edge) => {
|
||||||
|
@ -53,7 +53,7 @@ export const update: Update<
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = (responseData: MarketDepthQuery) => responseData.market;
|
const getData = (responseData: MarketDepthQuery | null) => responseData?.market;
|
||||||
|
|
||||||
const getDelta = (subscriptionData: MarketDepthUpdateSubscription) =>
|
const getDelta = (subscriptionData: MarketDepthUpdateSubscription) =>
|
||||||
subscriptionData.marketsDepthUpdate;
|
subscriptionData.marketsDepthUpdate;
|
||||||
|
@ -9,5 +9,5 @@ export const marketInfoDataProvider = makeDataProvider<
|
|||||||
never
|
never
|
||||||
>({
|
>({
|
||||||
query: MarketInfoDocument,
|
query: MarketInfoDocument,
|
||||||
getData: (responseData: MarketInfoQuery) => responseData,
|
getData: (responseData: MarketInfoQuery | null) => responseData,
|
||||||
});
|
});
|
||||||
|
@ -24,7 +24,7 @@ export const update = (data: Candle[] | null, delta: Candle) => {
|
|||||||
return [delta];
|
return [delta];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = (responseData: MarketCandlesQuery): Candle[] | null =>
|
const getData = (responseData: MarketCandlesQuery | null): Candle[] | null =>
|
||||||
responseData?.marketsConnection?.edges[0]?.node.candlesConnection?.edges
|
responseData?.marketsConnection?.edges[0]?.node.candlesConnection?.edges
|
||||||
?.filter((edge) => edge?.node)
|
?.filter((edge) => edge?.node)
|
||||||
.map((edge) => edge?.node as Candle) || null;
|
.map((edge) => edge?.node as Candle) || null;
|
||||||
|
@ -18,14 +18,20 @@ import type {
|
|||||||
|
|
||||||
export type MarketData = MarketDataFieldsFragment;
|
export type MarketData = MarketDataFieldsFragment;
|
||||||
|
|
||||||
const update = (data: MarketData, delta: MarketDataUpdateFieldsFragment) => {
|
const update = (
|
||||||
return produce(data, (draft) => {
|
data: MarketData | null,
|
||||||
const { marketId, __typename, ...marketData } = delta;
|
delta: MarketDataUpdateFieldsFragment
|
||||||
Object.assign(draft, marketData);
|
) => {
|
||||||
});
|
return (
|
||||||
|
data &&
|
||||||
|
produce(data, (draft) => {
|
||||||
|
const { marketId, __typename, ...marketData } = delta;
|
||||||
|
Object.assign(draft, marketData);
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = (responseData: MarketDataQuery): MarketData | null =>
|
const getData = (responseData: MarketDataQuery | null): MarketData | null =>
|
||||||
responseData?.marketsConnection?.edges[0].node.data || null;
|
responseData?.marketsConnection?.edges[0].node.data || null;
|
||||||
|
|
||||||
const getDelta = (
|
const getDelta = (
|
||||||
|
@ -11,7 +11,7 @@ import type { MarketData } from './market-data-provider';
|
|||||||
import { marketDataProvider } from './market-data-provider';
|
import { marketDataProvider } from './market-data-provider';
|
||||||
|
|
||||||
const getData = (
|
const getData = (
|
||||||
responseData: MarketQuery
|
responseData: MarketQuery | null
|
||||||
): SingleMarketFieldsFragment | null => responseData?.market || null;
|
): SingleMarketFieldsFragment | null => responseData?.market || null;
|
||||||
|
|
||||||
export const marketProvider = makeDataProvider<
|
export const marketProvider = makeDataProvider<
|
||||||
|
@ -8,7 +8,9 @@ export interface MarketCandles {
|
|||||||
candles: Candle[] | undefined;
|
candles: Candle[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getData = (responseData: MarketsCandlesQuery): MarketCandles[] | null =>
|
const getData = (
|
||||||
|
responseData: MarketsCandlesQuery | null
|
||||||
|
): MarketCandles[] | null =>
|
||||||
responseData?.marketsConnection?.edges.map((edge) => ({
|
responseData?.marketsConnection?.edges.map((edge) => ({
|
||||||
marketId: edge.node.id,
|
marketId: edge.node.id,
|
||||||
candles: edge.node.candlesConnection?.edges
|
candles: edge.node.candlesConnection?.edges
|
||||||
|
@ -3,8 +3,8 @@ import type { MarketsDataQuery } from './__generated__/markets-data';
|
|||||||
import { MarketsDataDocument } from './__generated__/markets-data';
|
import { MarketsDataDocument } from './__generated__/markets-data';
|
||||||
import type { MarketData } from './market-data-provider';
|
import type { MarketData } from './market-data-provider';
|
||||||
|
|
||||||
const getData = (responseData: MarketsDataQuery): MarketData[] | null =>
|
const getData = (responseData: MarketsDataQuery | null): MarketData[] | null =>
|
||||||
responseData.marketsConnection?.edges
|
responseData?.marketsConnection?.edges
|
||||||
.filter((edge) => edge.node.data)
|
.filter((edge) => edge.node.data)
|
||||||
.map((edge) => edge.node.data as MarketData) || null;
|
.map((edge) => edge.node.data as MarketData) || null;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import type { Candle } from './market-candles-provider';
|
|||||||
|
|
||||||
export type Market = MarketFieldsFragment;
|
export type Market = MarketFieldsFragment;
|
||||||
|
|
||||||
const getData = (responseData: MarketsQuery): Market[] | null =>
|
const getData = (responseData: MarketsQuery | null): Market[] | null =>
|
||||||
responseData?.marketsConnection?.edges.map((edge) => edge.node) || null;
|
responseData?.marketsConnection?.edges.map((edge) => edge.node) || null;
|
||||||
|
|
||||||
export const marketsProvider = makeDataProvider<
|
export const marketsProvider = makeDataProvider<
|
||||||
|
@ -62,7 +62,7 @@ describe('order data provider', () => {
|
|||||||
expect(updatedData && updatedData[1].node.updatedAt).toEqual(
|
expect(updatedData && updatedData[1].node.updatedAt).toEqual(
|
||||||
delta[4].updatedAt
|
delta[4].updatedAt
|
||||||
);
|
);
|
||||||
expect(update([], delta, () => null, { partyId: '0x123' }).length).toEqual(
|
expect(update([], delta, () => null, { partyId: '0x123' })?.length).toEqual(
|
||||||
4
|
4
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -71,7 +71,7 @@ const orderMatchFilters = (
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = (responseData: OrdersQuery) =>
|
const getData = (responseData: OrdersQuery | null) =>
|
||||||
responseData?.party?.ordersConnection?.edges || [];
|
responseData?.party?.ordersConnection?.edges || [];
|
||||||
|
|
||||||
const getDelta = (subscriptionData: OrdersUpdateSubscription) =>
|
const getDelta = (subscriptionData: OrdersUpdateSubscription) =>
|
||||||
@ -81,7 +81,7 @@ const getPageInfo = (responseData: OrdersQuery): PageInfo | null =>
|
|||||||
responseData.party?.ordersConnection?.pageInfo || null;
|
responseData.party?.ordersConnection?.pageInfo || null;
|
||||||
|
|
||||||
export const update = (
|
export const update = (
|
||||||
data: ReturnType<typeof getData>,
|
data: ReturnType<typeof getData> | null,
|
||||||
delta: ReturnType<typeof getDelta>,
|
delta: ReturnType<typeof getDelta>,
|
||||||
reload: () => void,
|
reload: () => void,
|
||||||
variables?: OrdersQueryVariables
|
variables?: OrdersQueryVariables
|
||||||
|
@ -14,10 +14,10 @@ import type {
|
|||||||
} from './__generated__/Positions';
|
} from './__generated__/Positions';
|
||||||
|
|
||||||
const update = (
|
const update = (
|
||||||
data: MarginFieldsFragment[],
|
data: MarginFieldsFragment[] | null,
|
||||||
delta: MarginsSubscriptionSubscription['margins']
|
delta: MarginsSubscriptionSubscription['margins']
|
||||||
) => {
|
) => {
|
||||||
return produce(data, (draft) => {
|
return produce(data || [], (draft) => {
|
||||||
const { marketId } = delta;
|
const { marketId } = delta;
|
||||||
const index = draft.findIndex((node) => node.market.id === marketId);
|
const index = draft.findIndex((node) => node.market.id === marketId);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
@ -49,8 +49,9 @@ const update = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = (responseData: MarginsQuery) =>
|
const getData = (responseData: MarginsQuery | null) =>
|
||||||
removePaginationWrapper(responseData.party?.marginsConnection?.edges) || [];
|
removePaginationWrapper(responseData?.party?.marginsConnection?.edges) || [];
|
||||||
|
|
||||||
const getDelta = (subscriptionData: MarginsSubscriptionSubscription) =>
|
const getDelta = (subscriptionData: MarginsSubscriptionSubscription) =>
|
||||||
subscriptionData.margins;
|
subscriptionData.margins;
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ import BigNumber from 'bignumber.js';
|
|||||||
import sortBy from 'lodash/sortBy';
|
import sortBy from 'lodash/sortBy';
|
||||||
import type { Account } from '@vegaprotocol/accounts';
|
import type { Account } from '@vegaprotocol/accounts';
|
||||||
import { accountsDataProvider } from '@vegaprotocol/accounts';
|
import { accountsDataProvider } from '@vegaprotocol/accounts';
|
||||||
import { toBigNum } from '@vegaprotocol/react-helpers';
|
|
||||||
import {
|
import {
|
||||||
|
toBigNum,
|
||||||
makeDataProvider,
|
makeDataProvider,
|
||||||
makeDerivedDataProvider,
|
makeDerivedDataProvider,
|
||||||
removePaginationWrapper,
|
removePaginationWrapper,
|
||||||
@ -171,10 +171,10 @@ export const getMetrics = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const update = (
|
export const update = (
|
||||||
data: PositionFieldsFragment[],
|
data: PositionFieldsFragment[] | null,
|
||||||
deltas: PositionsSubscriptionSubscription['positions']
|
deltas: PositionsSubscriptionSubscription['positions']
|
||||||
) => {
|
) => {
|
||||||
return produce(data, (draft) => {
|
return produce(data || [], (draft) => {
|
||||||
deltas.forEach((delta) => {
|
deltas.forEach((delta) => {
|
||||||
const index = draft.findIndex(
|
const index = draft.findIndex(
|
||||||
(node) => node.market.id === delta.marketId
|
(node) => node.market.id === delta.marketId
|
||||||
@ -212,8 +212,8 @@ export const positionsDataProvider = makeDataProvider<
|
|||||||
query: PositionsDocument,
|
query: PositionsDocument,
|
||||||
subscriptionQuery: PositionsSubscriptionDocument,
|
subscriptionQuery: PositionsSubscriptionDocument,
|
||||||
update,
|
update,
|
||||||
getData: (responseData: PositionsQuery) =>
|
getData: (responseData: PositionsQuery | null) =>
|
||||||
removePaginationWrapper(responseData.party?.positionsConnection?.edges) ||
|
removePaginationWrapper(responseData?.party?.positionsConnection?.edges) ||
|
||||||
[],
|
[],
|
||||||
getDelta: (subscriptionData: PositionsSubscriptionSubscription) =>
|
getDelta: (subscriptionData: PositionsSubscriptionSubscription) =>
|
||||||
subscriptionData.positions,
|
subscriptionData.positions,
|
||||||
|
@ -2,10 +2,7 @@ import { useCallback, useState } from 'react';
|
|||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { positionsDataProvider } from './positions-data-providers';
|
import { positionsDataProvider } from './positions-data-providers';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import type {
|
import type { PositionFieldsFragment } from './__generated__/Positions';
|
||||||
PositionFieldsFragment,
|
|
||||||
PositionsSubscriptionSubscription,
|
|
||||||
} from './__generated__/Positions';
|
|
||||||
|
|
||||||
export const useMarketPositionOpenVolume = (marketId: string) => {
|
export const useMarketPositionOpenVolume = (marketId: string) => {
|
||||||
const { pubKey } = useVegaWallet();
|
const { pubKey } = useVegaWallet();
|
||||||
@ -21,10 +18,7 @@ export const useMarketPositionOpenVolume = (marketId: string) => {
|
|||||||
[setOpenVolume, marketId]
|
[setOpenVolume, marketId]
|
||||||
);
|
);
|
||||||
|
|
||||||
useDataProvider<
|
useDataProvider({
|
||||||
PositionFieldsFragment[],
|
|
||||||
PositionsSubscriptionSubscription['positions']
|
|
||||||
>({
|
|
||||||
dataProvider: positionsDataProvider,
|
dataProvider: positionsDataProvider,
|
||||||
variables: { partyId: pubKey || '' },
|
variables: { partyId: pubKey || '' },
|
||||||
skip: !pubKey || !marketId,
|
skip: !pubKey || !marketId,
|
||||||
|
@ -1,20 +1,2 @@
|
|||||||
export * from './hooks';
|
export * from './hooks';
|
||||||
export * from './lib/format';
|
export * from './lib';
|
||||||
export * from './lib/generic-data-provider';
|
|
||||||
export * from './lib/get-nodes';
|
|
||||||
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';
|
|
||||||
export * from './lib/validate';
|
|
||||||
export * from './lib/links';
|
|
||||||
export * from './lib/is-asset-erc20';
|
|
||||||
export * from './lib/remove-pagination-wrapper';
|
|
||||||
export * from './lib/__generated__/ChainId';
|
|
||||||
export * from './lib/data-grid';
|
|
||||||
export * from './lib/local-logger';
|
|
||||||
export * from './lib/market-expires';
|
|
||||||
|
29
libs/react-helpers/src/lib/apollo-client.ts
Normal file
29
libs/react-helpers/src/lib/apollo-client.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import type { ApolloError } from '@apollo/client';
|
||||||
|
import type { GraphQLErrors } from '@apollo/client/errors';
|
||||||
|
|
||||||
|
const NOT_FOUND = 'NotFound';
|
||||||
|
|
||||||
|
const isApolloGraphQLError = (
|
||||||
|
error: ApolloError | Error | undefined
|
||||||
|
): error is ApolloError => {
|
||||||
|
return !!error && !!(error as ApolloError).graphQLErrors;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasNotFoundGraphQLErrors = (errors: GraphQLErrors, path?: string) => {
|
||||||
|
return errors.some(
|
||||||
|
(e) =>
|
||||||
|
e.extensions &&
|
||||||
|
e.extensions['type'] === NOT_FOUND &&
|
||||||
|
(!path || e.path?.[0] === path)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isNotFoundGraphQLError = (
|
||||||
|
error: Error | ApolloError | undefined,
|
||||||
|
path?: string
|
||||||
|
) => {
|
||||||
|
return (
|
||||||
|
isApolloGraphQLError(error) &&
|
||||||
|
hasNotFoundGraphQLErrors(error.graphQLErrors, path)
|
||||||
|
);
|
||||||
|
};
|
@ -62,7 +62,7 @@ const subscribe = makeDataProvider<QueryData, Data, SubscriptionData, Delta>({
|
|||||||
query,
|
query,
|
||||||
subscriptionQuery,
|
subscriptionQuery,
|
||||||
update,
|
update,
|
||||||
getData: (r) => r.data,
|
getData: (r) => r?.data || null,
|
||||||
getDelta: (r) => r.data,
|
getDelta: (r) => r.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ const paginatedSubscribe = makeDataProvider<
|
|||||||
query,
|
query,
|
||||||
subscriptionQuery,
|
subscriptionQuery,
|
||||||
update,
|
update,
|
||||||
getData: (r) => r.data,
|
getData: (r) => r?.data || null,
|
||||||
getDelta: (r) => r.data,
|
getDelta: (r) => r.data,
|
||||||
pagination: {
|
pagination: {
|
||||||
first,
|
first,
|
||||||
@ -215,7 +215,7 @@ describe('data provider', () => {
|
|||||||
const subscription = subscribe(callback, client);
|
const subscription = subscribe(callback, client);
|
||||||
await resolveQuery({ data });
|
await resolveQuery({ data });
|
||||||
const delta: Item[] = [];
|
const delta: Item[] = [];
|
||||||
update.mockImplementationOnce((data, delta) => [...data, ...delta]);
|
update.mockImplementationOnce((data, delta) => [...(data || []), ...delta]);
|
||||||
// calling onNext from client.subscribe({ query }).subscribe(onNext)
|
// calling onNext from client.subscribe({ query }).subscribe(onNext)
|
||||||
await clientSubscribeSubscribe.mock.calls[
|
await clientSubscribeSubscribe.mock.calls[
|
||||||
clientSubscribeSubscribe.mock.calls.length - 1
|
clientSubscribeSubscribe.mock.calls.length - 1
|
||||||
@ -234,7 +234,7 @@ describe('data provider', () => {
|
|||||||
const subscription = subscribe(callback, client);
|
const subscription = subscribe(callback, client);
|
||||||
await resolveQuery({ data });
|
await resolveQuery({ data });
|
||||||
const delta: Item[] = [];
|
const delta: Item[] = [];
|
||||||
update.mockImplementationOnce((data, delta) => data);
|
update.mockImplementationOnce((data, delta) => data || []);
|
||||||
const callbackCallsLength = callback.mock.calls.length;
|
const callbackCallsLength = callback.mock.calls.length;
|
||||||
// calling onNext from client.subscribe({ query }).subscribe(onNext)
|
// calling onNext from client.subscribe({ query }).subscribe(onNext)
|
||||||
await clientSubscribeSubscribe.mock.calls[
|
await clientSubscribeSubscribe.mock.calls[
|
||||||
@ -591,7 +591,7 @@ describe('derived data provider', () => {
|
|||||||
await resolveQuery({ data: part2 });
|
await resolveQuery({ data: part2 });
|
||||||
expect(combineData).toBeCalledTimes(1);
|
expect(combineData).toBeCalledTimes(1);
|
||||||
expect(callback).toBeCalledTimes(1);
|
expect(callback).toBeCalledTimes(1);
|
||||||
update.mockImplementation((data, delta) => [...data, ...delta]);
|
update.mockImplementation((data, delta) => [...(data || []), ...delta]);
|
||||||
combineData.mockReturnValueOnce({ ...data });
|
combineData.mockReturnValueOnce({ ...data });
|
||||||
const combinedDelta = {};
|
const combinedDelta = {};
|
||||||
combineDelta.mockReturnValueOnce(combinedDelta);
|
combineDelta.mockReturnValueOnce(combinedDelta);
|
||||||
@ -629,7 +629,7 @@ describe('derived data provider', () => {
|
|||||||
await resolveQuery({ data: [] });
|
await resolveQuery({ data: [] });
|
||||||
expect(combineData).toBeCalledTimes(1);
|
expect(combineData).toBeCalledTimes(1);
|
||||||
expect(callback).toBeCalledTimes(1);
|
expect(callback).toBeCalledTimes(1);
|
||||||
update.mockImplementation((data, delta) => [...data, ...delta]);
|
update.mockImplementation((data, delta) => [...(data || []), ...delta]);
|
||||||
combineData.mockReturnValueOnce({ ...data });
|
combineData.mockReturnValueOnce({ ...data });
|
||||||
const combinedInsertionData = {};
|
const combinedInsertionData = {};
|
||||||
combineInsertionData.mockReturnValueOnce(combinedInsertionData);
|
combineInsertionData.mockReturnValueOnce(combinedInsertionData);
|
||||||
|
@ -8,6 +8,7 @@ import type {
|
|||||||
} from '@apollo/client';
|
} from '@apollo/client';
|
||||||
import type { Subscription } from 'zen-observable-ts';
|
import type { Subscription } from 'zen-observable-ts';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
import { isNotFoundGraphQLError } from './apollo-client';
|
||||||
import type * as Schema from '@vegaprotocol/types';
|
import type * as Schema from '@vegaprotocol/types';
|
||||||
interface UpdateData<Data, Delta> {
|
interface UpdateData<Data, Delta> {
|
||||||
delta?: Delta;
|
delta?: Delta;
|
||||||
@ -71,7 +72,12 @@ export interface Update<
|
|||||||
Delta,
|
Delta,
|
||||||
Variables extends OperationVariables = OperationVariables
|
Variables extends OperationVariables = OperationVariables
|
||||||
> {
|
> {
|
||||||
(data: Data, delta: Delta, reload: Reload, variables?: Variables): Data;
|
(
|
||||||
|
data: Data | null,
|
||||||
|
delta: Delta,
|
||||||
|
reload: Reload,
|
||||||
|
variables?: Variables
|
||||||
|
): Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Append<Data> {
|
export interface Append<Data> {
|
||||||
@ -88,7 +94,7 @@ export interface Append<Data> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface GetData<QueryData, Data, Variables> {
|
interface GetData<QueryData, Data, Variables> {
|
||||||
(queryData: QueryData, variables?: Variables): Data | null;
|
(queryData: QueryData | null, variables?: Variables): Data | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetPageInfo<QueryData> {
|
interface GetPageInfo<QueryData> {
|
||||||
@ -160,7 +166,7 @@ interface DataProviderParams<
|
|||||||
> {
|
> {
|
||||||
query: Query<QueryData>;
|
query: Query<QueryData>;
|
||||||
subscriptionQuery?: Query<SubscriptionData>;
|
subscriptionQuery?: Query<SubscriptionData>;
|
||||||
update?: Update<Data, Delta, Variables>;
|
update?: Update<Data | null, Delta, Variables>;
|
||||||
getData: GetData<QueryData, Data, Variables>;
|
getData: GetData<QueryData, Data, Variables>;
|
||||||
getDelta?: GetDelta<SubscriptionData, Delta, Variables>;
|
getDelta?: GetDelta<SubscriptionData, Delta, Variables>;
|
||||||
pagination?: {
|
pagination?: {
|
||||||
@ -349,6 +355,11 @@ function makeDataProviderInternal<
|
|||||||
}
|
}
|
||||||
loaded = true;
|
loaded = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (isNotFoundGraphQLError(e as Error, 'party')) {
|
||||||
|
data = getData(null, variables);
|
||||||
|
loaded = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
// if error will occur data provider stops subscription
|
// if error will occur data provider stops subscription
|
||||||
error = e as Error;
|
error = e as Error;
|
||||||
if (subscription) {
|
if (subscription) {
|
||||||
@ -384,7 +395,7 @@ function makeDataProviderInternal<
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const delta = getDelta(subscriptionData, variables);
|
const delta = getDelta(subscriptionData, variables);
|
||||||
if (loading || !data) {
|
if (loading) {
|
||||||
updateQueue.push(delta);
|
updateQueue.push(delta);
|
||||||
} else {
|
} else {
|
||||||
const updatedData = update(data, delta, reload, variables);
|
const updatedData = update(data, delta, reload, variables);
|
||||||
@ -409,7 +420,6 @@ function makeDataProviderInternal<
|
|||||||
if (!client) {
|
if (!client) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subscriptionQuery && getDelta && update) {
|
if (subscriptionQuery && getDelta && update) {
|
||||||
subscription = client
|
subscription = client
|
||||||
.subscribe<SubscriptionData>({
|
.subscribe<SubscriptionData>({
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
export * from './format';
|
export * from './__generated__/ChainId';
|
||||||
export * from './grid';
|
export * from './ag-grid-update';
|
||||||
export * from './storage';
|
export * from './apollo-client';
|
||||||
export * from './validate';
|
|
||||||
export * from './generic-data-provider';
|
|
||||||
export * from './get-nodes';
|
|
||||||
export * from './get-events';
|
|
||||||
export * from './i18n';
|
|
||||||
export * from './pagination';
|
|
||||||
export * from './remove-0x';
|
|
||||||
export * from './time';
|
|
||||||
export * from './links';
|
|
||||||
export * from './remove-pagination-wrapper';
|
|
||||||
export * from './data-grid';
|
export * from './data-grid';
|
||||||
|
export * from './format';
|
||||||
|
export * from './generic-data-provider';
|
||||||
|
export * from './get-events';
|
||||||
|
export * from './get-nodes';
|
||||||
|
export * from './grid';
|
||||||
|
export * from './i18n';
|
||||||
|
export * from './is-asset-erc20';
|
||||||
|
export * from './links';
|
||||||
export * from './local-logger';
|
export * from './local-logger';
|
||||||
export * from './market-expires';
|
export * from './market-expires';
|
||||||
|
export * from './pagination';
|
||||||
|
export * from './remove-0x';
|
||||||
|
export * from './remove-pagination-wrapper';
|
||||||
|
export * from './storage';
|
||||||
|
export * from './time';
|
||||||
|
export * from './validate';
|
||||||
|
@ -20,7 +20,7 @@ import produce from 'immer';
|
|||||||
export const MAX_TRADES = 50;
|
export const MAX_TRADES = 50;
|
||||||
|
|
||||||
const getData = (
|
const getData = (
|
||||||
responseData: TradesQuery
|
responseData: TradesQuery | null
|
||||||
): ({
|
): ({
|
||||||
cursor: string;
|
cursor: string;
|
||||||
node: TradeFieldsFragment;
|
node: TradeFieldsFragment;
|
||||||
@ -30,7 +30,7 @@ const getDelta = (subscriptionData: TradesUpdateSubscription) =>
|
|||||||
subscriptionData?.trades || [];
|
subscriptionData?.trades || [];
|
||||||
|
|
||||||
const update = (
|
const update = (
|
||||||
data: ReturnType<typeof getData>,
|
data: ReturnType<typeof getData> | null,
|
||||||
delta: ReturnType<typeof getDelta>
|
delta: ReturnType<typeof getDelta>
|
||||||
) => {
|
) => {
|
||||||
return produce(data, (draft) => {
|
return produce(data, (draft) => {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Splash } from '../splash';
|
import { Splash } from '../splash';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { t } from '@vegaprotocol/react-helpers';
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
import { isNotFoundGraphQLError } from '@vegaprotocol/apollo-client';
|
|
||||||
|
|
||||||
interface AsyncRendererProps<T> {
|
interface AsyncRendererProps<T> {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@ -26,7 +25,7 @@ export function AsyncRenderer<T = object>({
|
|||||||
children,
|
children,
|
||||||
render,
|
render,
|
||||||
}: AsyncRendererProps<T>) {
|
}: AsyncRendererProps<T>) {
|
||||||
if (error && !isNotFoundGraphQLError(error)) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<Splash>
|
<Splash>
|
||||||
{errorMessage
|
{errorMessage
|
||||||
|
@ -8,6 +8,6 @@ export * from './lib/withdrawal-feedback';
|
|||||||
export * from './lib/use-complete-withdraw';
|
export * from './lib/use-complete-withdraw';
|
||||||
export * from './lib/use-create-withdraw';
|
export * from './lib/use-create-withdraw';
|
||||||
export * from './lib/use-verify-withdrawal';
|
export * from './lib/use-verify-withdrawal';
|
||||||
export * from './lib/use-withdrawals';
|
export * from './lib/withdrawals-provider';
|
||||||
export * from './lib/__generated__/Withdrawal';
|
export * from './lib/__generated__/Withdrawal';
|
||||||
export * from './lib/__generated__/Erc20Approval';
|
export * from './lib/__generated__/Erc20Approval';
|
||||||
|
@ -1,170 +0,0 @@
|
|||||||
import * as Schema from '@vegaprotocol/types';
|
|
||||||
import { generateWithdrawal } from './test-helpers';
|
|
||||||
import { updateQuery } from './use-withdrawals';
|
|
||||||
import type {
|
|
||||||
WithdrawalsQuery,
|
|
||||||
WithdrawalEventSubscription,
|
|
||||||
WithdrawalFieldsFragment,
|
|
||||||
} from './__generated__/Withdrawal';
|
|
||||||
|
|
||||||
describe('updateQuery', () => {
|
|
||||||
it('updates existing withdrawals', () => {
|
|
||||||
const withdrawal = generateWithdrawal({
|
|
||||||
id: '1',
|
|
||||||
status: Schema.WithdrawalStatus.STATUS_OPEN,
|
|
||||||
});
|
|
||||||
const withdrawalUpdate = generateWithdrawal({
|
|
||||||
id: '1',
|
|
||||||
status: Schema.WithdrawalStatus.STATUS_FINALIZED,
|
|
||||||
});
|
|
||||||
const prev = mockQuery([withdrawal]);
|
|
||||||
const incoming = mockSub([withdrawalUpdate]);
|
|
||||||
|
|
||||||
expect(updateQuery(prev, incoming)).toEqual({
|
|
||||||
party: {
|
|
||||||
__typename: 'Party',
|
|
||||||
id: 'party-id',
|
|
||||||
withdrawalsConnection: {
|
|
||||||
__typename: 'WithdrawalsConnection',
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: withdrawalUpdate,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Adds new withdrawals', () => {
|
|
||||||
const withdrawal = generateWithdrawal({
|
|
||||||
id: '1',
|
|
||||||
amount: '100',
|
|
||||||
});
|
|
||||||
const withdrawalUpdate = generateWithdrawal({
|
|
||||||
id: '2',
|
|
||||||
amount: '200',
|
|
||||||
});
|
|
||||||
const prev = mockQuery([withdrawal]);
|
|
||||||
const incoming = mockSub([withdrawalUpdate]);
|
|
||||||
|
|
||||||
expect(updateQuery(prev, incoming)).toEqual({
|
|
||||||
party: {
|
|
||||||
__typename: 'Party',
|
|
||||||
id: 'party-id',
|
|
||||||
withdrawalsConnection: {
|
|
||||||
__typename: 'WithdrawalsConnection',
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: withdrawalUpdate,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
node: withdrawal,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates new party if not present', () => {
|
|
||||||
const partyId = 'party-id';
|
|
||||||
const withdrawalUpdate = generateWithdrawal({
|
|
||||||
id: '2',
|
|
||||||
});
|
|
||||||
const incoming = mockSub([withdrawalUpdate]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
updateQuery({ party: null }, { ...incoming, variables: { partyId } })
|
|
||||||
).toEqual({
|
|
||||||
party: {
|
|
||||||
__typename: 'Party',
|
|
||||||
id: partyId,
|
|
||||||
withdrawalsConnection: {
|
|
||||||
__typename: 'WithdrawalsConnection',
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: withdrawalUpdate,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Handles updates and inserts simultaneously', () => {
|
|
||||||
const withdrawal1 = generateWithdrawal({
|
|
||||||
id: '1',
|
|
||||||
status: Schema.WithdrawalStatus.STATUS_OPEN,
|
|
||||||
});
|
|
||||||
const withdrawal2 = generateWithdrawal({
|
|
||||||
id: '2',
|
|
||||||
});
|
|
||||||
const withdrawalUpdate = generateWithdrawal({
|
|
||||||
id: '1',
|
|
||||||
status: Schema.WithdrawalStatus.STATUS_FINALIZED,
|
|
||||||
});
|
|
||||||
const withdrawalNew = generateWithdrawal({
|
|
||||||
id: '3',
|
|
||||||
});
|
|
||||||
|
|
||||||
const prev = mockQuery([withdrawal1, withdrawal2]);
|
|
||||||
const incoming = mockSub([withdrawalUpdate, withdrawalNew]);
|
|
||||||
expect(updateQuery(prev, incoming)).toEqual({
|
|
||||||
party: {
|
|
||||||
__typename: 'Party',
|
|
||||||
id: 'party-id',
|
|
||||||
withdrawalsConnection: {
|
|
||||||
__typename: 'WithdrawalsConnection',
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: withdrawalUpdate,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
node: withdrawalNew,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
node: withdrawal2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const mockQuery = (
|
|
||||||
withdrawals: WithdrawalFieldsFragment[]
|
|
||||||
): WithdrawalsQuery => {
|
|
||||||
return {
|
|
||||||
party: {
|
|
||||||
__typename: 'Party',
|
|
||||||
id: 'party-id',
|
|
||||||
withdrawalsConnection: {
|
|
||||||
__typename: 'WithdrawalsConnection',
|
|
||||||
edges: withdrawals.map((w) => ({
|
|
||||||
node: w,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockSub = (
|
|
||||||
withdrawals: WithdrawalFieldsFragment[]
|
|
||||||
): {
|
|
||||||
subscriptionData: {
|
|
||||||
data: WithdrawalEventSubscription;
|
|
||||||
};
|
|
||||||
} => {
|
|
||||||
return {
|
|
||||||
subscriptionData: {
|
|
||||||
data: {
|
|
||||||
busEvents: withdrawals.map((w) => ({
|
|
||||||
__typename: 'BusEvent',
|
|
||||||
event: w,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,111 +0,0 @@
|
|||||||
import type { UpdateQueryFn } from '@apollo/client/core/watchQueryOptions';
|
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
|
||||||
import uniqBy from 'lodash/uniqBy';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import {
|
|
||||||
useWithdrawalsQuery,
|
|
||||||
WithdrawalEventDocument,
|
|
||||||
} from './__generated__/Withdrawal';
|
|
||||||
import type {
|
|
||||||
WithdrawalsQuery,
|
|
||||||
WithdrawalFieldsFragment,
|
|
||||||
WithdrawalEventSubscription,
|
|
||||||
WithdrawalEventSubscriptionVariables,
|
|
||||||
} from './__generated__/Withdrawal';
|
|
||||||
import { removePaginationWrapper } from '@vegaprotocol/react-helpers';
|
|
||||||
|
|
||||||
type WithdrawalEdges = { node: WithdrawalFieldsFragment }[];
|
|
||||||
|
|
||||||
export const useWithdrawals = () => {
|
|
||||||
const { pubKey } = useVegaWallet();
|
|
||||||
const { data, loading, error, subscribeToMore } = useWithdrawalsQuery({
|
|
||||||
variables: { partyId: pubKey || '' },
|
|
||||||
skip: !pubKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!pubKey) return;
|
|
||||||
|
|
||||||
const unsubscribe = subscribeToMore<
|
|
||||||
WithdrawalEventSubscription,
|
|
||||||
WithdrawalEventSubscriptionVariables
|
|
||||||
>({
|
|
||||||
document: WithdrawalEventDocument,
|
|
||||||
variables: { partyId: pubKey },
|
|
||||||
updateQuery,
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unsubscribe();
|
|
||||||
};
|
|
||||||
}, [pubKey, subscribeToMore]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: removePaginationWrapper(
|
|
||||||
data?.party?.withdrawalsConnection?.edges ?? []
|
|
||||||
).sort((a, b) => {
|
|
||||||
if (!b.txHash !== !a.txHash) {
|
|
||||||
return b.txHash ? -1 : 1;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
b.txHash ? b.withdrawnTimestamp : b.createdTimestamp
|
|
||||||
).localeCompare(a.txHash ? a.withdrawnTimestamp : a.createdTimestamp);
|
|
||||||
}),
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateQuery: UpdateQueryFn<
|
|
||||||
WithdrawalsQuery,
|
|
||||||
WithdrawalEventSubscriptionVariables,
|
|
||||||
WithdrawalEventSubscription
|
|
||||||
> = (prev, { subscriptionData, variables }) => {
|
|
||||||
if (!subscriptionData.data.busEvents?.length) {
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
const curr = prev.party?.withdrawalsConnection?.edges || [];
|
|
||||||
const incoming = subscriptionData.data.busEvents.reduce<WithdrawalEdges>(
|
|
||||||
(acc, event) => {
|
|
||||||
if (event.event.__typename === 'Withdrawal') {
|
|
||||||
acc.push({
|
|
||||||
node: {
|
|
||||||
...event.event,
|
|
||||||
pendingOnForeignChain: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const edges = uniqBy([...incoming, ...curr], 'node.id');
|
|
||||||
|
|
||||||
// Write new party to cache if not present
|
|
||||||
if (!prev.party) {
|
|
||||||
return {
|
|
||||||
...prev,
|
|
||||||
party: {
|
|
||||||
id: variables?.partyId,
|
|
||||||
__typename: 'Party',
|
|
||||||
withdrawalsConnection: {
|
|
||||||
__typename: 'WithdrawalsConnection',
|
|
||||||
edges,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as WithdrawalsQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...prev,
|
|
||||||
party: {
|
|
||||||
...prev.party,
|
|
||||||
withdrawalsConnection: {
|
|
||||||
__typename: 'WithdrawalsConnection',
|
|
||||||
edges,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
56
libs/withdraws/src/lib/withdrawals-provider.ts
Normal file
56
libs/withdraws/src/lib/withdrawals-provider.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import uniqBy from 'lodash/uniqBy';
|
||||||
|
import { makeDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
import {
|
||||||
|
WithdrawalsDocument,
|
||||||
|
WithdrawalEventDocument,
|
||||||
|
} from './__generated__/Withdrawal';
|
||||||
|
import type {
|
||||||
|
WithdrawalsQuery,
|
||||||
|
WithdrawalFieldsFragment,
|
||||||
|
WithdrawalEventSubscription,
|
||||||
|
WithdrawalEventSubscriptionVariables,
|
||||||
|
} from './__generated__/Withdrawal';
|
||||||
|
import {
|
||||||
|
removePaginationWrapper,
|
||||||
|
getEvents,
|
||||||
|
} from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
|
const sortWithdrawals = (data: WithdrawalFieldsFragment[]) =>
|
||||||
|
data.sort((a, b) => {
|
||||||
|
if (!b.txHash !== !a.txHash) {
|
||||||
|
return b.txHash ? -1 : 1;
|
||||||
|
}
|
||||||
|
return (b.txHash ? b.withdrawnTimestamp : b.createdTimestamp).localeCompare(
|
||||||
|
a.txHash ? a.withdrawnTimestamp : a.createdTimestamp
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const withdrawalProvider = makeDataProvider<
|
||||||
|
WithdrawalsQuery,
|
||||||
|
WithdrawalFieldsFragment[],
|
||||||
|
WithdrawalEventSubscription,
|
||||||
|
WithdrawalEventSubscription,
|
||||||
|
WithdrawalEventSubscriptionVariables
|
||||||
|
>({
|
||||||
|
query: WithdrawalsDocument,
|
||||||
|
subscriptionQuery: WithdrawalEventDocument,
|
||||||
|
getData: (data: WithdrawalsQuery | null) =>
|
||||||
|
sortWithdrawals(
|
||||||
|
removePaginationWrapper(data?.party?.withdrawalsConnection?.edges || [])
|
||||||
|
),
|
||||||
|
getDelta: (data: WithdrawalEventSubscription) => data,
|
||||||
|
update: (
|
||||||
|
data: WithdrawalFieldsFragment[] | null,
|
||||||
|
delta: WithdrawalEventSubscription
|
||||||
|
) => {
|
||||||
|
if (!delta.busEvents?.length) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
const incoming = getEvents<WithdrawalFieldsFragment>(
|
||||||
|
Schema.BusEventType.Withdrawal,
|
||||||
|
delta.busEvents
|
||||||
|
);
|
||||||
|
return uniqBy([...incoming, ...(data || [])], 'id');
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user