import { type Update } from '@vegaprotocol/data-provider'; import { makeDataProvider } from '@vegaprotocol/data-provider'; import produce from 'immer'; import * as Types from '@vegaprotocol/types'; import { MarketViewLiveProposalsDocument, MarketViewProposalsDocument, ProposalsListDocument, type ProposalsListQuery, type ProposalsListQueryVariables, type ProposalListFieldsFragment, type MarketViewLiveProposalsSubscription, type MarketViewProposalFieldsFragment, type MarketViewProposalsQuery, type MarketViewProposalsQueryVariables, type MarketViewLiveProposalsSubscriptionVariables, } from './__generated__/Proposals'; import { removePaginationWrapper } from '@vegaprotocol/utils'; const getData = (responseData: ProposalsListQuery | null) => responseData?.proposalsConnection?.edges ?.filter((edge) => Boolean(edge?.node)) .map((edge) => edge?.node as ProposalListFieldsFragment) || null; export const proposalsDataProvider = makeDataProvider< ProposalsListQuery, ProposalListFieldsFragment[], never, never, ProposalsListQueryVariables >({ query: ProposalsListDocument, getData, /** * Ignores errors for not found settlement asset for NewMarket proposals. * * It can happen that a NewMarket proposal is incomplete and does not contain * `futureProduct` details. This guard protects against that. * * GQL Path: `terms.change.instrument.futureProduct.settlementAsset` */ errorPolicyGuard: (errors) => errors.every((e) => e.message.match(/failed to get asset for ID/)), }); const ProposalTypeMap: Record< Types.ProposalType, Types.ProposalChange['__typename'] > = { [Types.ProposalType.TYPE_CANCEL_TRANSFER]: 'CancelTransfer', [Types.ProposalType.TYPE_NETWORK_PARAMETERS]: 'UpdateNetworkParameter', [Types.ProposalType.TYPE_NEW_ASSET]: 'NewAsset', [Types.ProposalType.TYPE_NEW_FREE_FORM]: 'NewFreeform', [Types.ProposalType.TYPE_NEW_MARKET]: 'NewMarket', [Types.ProposalType.TYPE_NEW_SPOT_MARKET]: 'NewSpotMarket', [Types.ProposalType.TYPE_NEW_TRANSFER]: 'NewTransfer', [Types.ProposalType.TYPE_UPDATE_ASSET]: 'UpdateAsset', [Types.ProposalType.TYPE_UPDATE_MARKET]: 'UpdateMarket', [Types.ProposalType.TYPE_UPDATE_MARKET_STATE]: 'UpdateMarketState', [Types.ProposalType.TYPE_UPDATE_REFERRAL_PROGRAM]: 'UpdateReferralProgram', [Types.ProposalType.TYPE_UPDATE_SPOT_MARKET]: 'UpdateSpotMarket', [Types.ProposalType.TYPE_UPDATE_VOLUME_DISCOUNT_PROGRAM]: 'UpdateVolumeDiscountProgram', }; const matchFilter = ( data: MarketViewProposalFieldsFragment, variables: MarketViewProposalsQueryVariables ) => { return ( (!variables.inState || data.state === variables.inState) && (!variables.proposalType || data.terms.change.__typename === ProposalTypeMap[variables.proposalType]) ); }; export const update: Update< MarketViewProposalFieldsFragment[] | null, MarketViewProposalFieldsFragment, MarketViewProposalsQueryVariables > = ( data: MarketViewProposalFieldsFragment[] | null, delta: MarketViewProposalFieldsFragment, reload, variables ) => { const updateData = produce(data || [], (draft) => { const { id } = delta; const index = draft.findIndex((item) => item.id === id); const match = matchFilter(delta, variables); if (index === -1) { if (match) { draft.unshift(delta); } } else { if (match) { draft[index] = delta; } else { draft.splice(index, 1); } } }); return updateData; }; const getMarketProposalsData = ( responseData: MarketViewProposalsQuery | null ) => removePaginationWrapper(responseData?.proposalsConnection?.edges) || []; const subscriptionVariables: MarketViewLiveProposalsSubscriptionVariables = {}; export const marketViewProposalsDataProvider = makeDataProvider< MarketViewProposalsQuery, MarketViewProposalFieldsFragment[], MarketViewLiveProposalsSubscription, MarketViewProposalFieldsFragment, MarketViewProposalsQueryVariables, MarketViewLiveProposalsSubscriptionVariables >({ query: MarketViewProposalsDocument, subscriptionQuery: MarketViewLiveProposalsDocument, update, getDelta: (subscriptionData: MarketViewLiveProposalsSubscription) => subscriptionData.proposals, getData: getMarketProposalsData, getSubscriptionVariables: () => subscriptionVariables, });