feat(proposals): generic proposal toasts (#5134)
This commit is contained in:
parent
dac7142a98
commit
9838efa00e
@ -1,5 +1,5 @@
|
|||||||
import { ToastsContainer, useToasts } from '@vegaprotocol/ui-toolkit';
|
import { ToastsContainer, useToasts } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useUpdateNetworkParametersToasts } from '@vegaprotocol/proposals';
|
import { useProposalToasts } from '@vegaprotocol/proposals';
|
||||||
import { useVegaTransactionToasts } from '@vegaprotocol/web3';
|
import { useVegaTransactionToasts } from '@vegaprotocol/web3';
|
||||||
import { useEthereumTransactionToasts } from '@vegaprotocol/web3';
|
import { useEthereumTransactionToasts } from '@vegaprotocol/web3';
|
||||||
import { useEthereumWithdrawApprovalsToasts } from '@vegaprotocol/web3';
|
import { useEthereumWithdrawApprovalsToasts } from '@vegaprotocol/web3';
|
||||||
@ -7,7 +7,7 @@ import { useReadyToWithdrawalToasts } from '@vegaprotocol/withdraws';
|
|||||||
import { Links } from '../lib/links';
|
import { Links } from '../lib/links';
|
||||||
|
|
||||||
export const ToastsManager = () => {
|
export const ToastsManager = () => {
|
||||||
useUpdateNetworkParametersToasts();
|
useProposalToasts();
|
||||||
useVegaTransactionToasts();
|
useVegaTransactionToasts();
|
||||||
useEthereumTransactionToasts();
|
useEthereumTransactionToasts();
|
||||||
useEthereumWithdrawApprovalsToasts();
|
useEthereumWithdrawApprovalsToasts();
|
||||||
|
@ -12,10 +12,15 @@ subscription ProposalEvent($partyId: ID!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment UpdateNetworkParameterProposal on Proposal {
|
fragment OnProposalFragment on Proposal {
|
||||||
id
|
id
|
||||||
state
|
state
|
||||||
datetime
|
datetime
|
||||||
|
rationale {
|
||||||
|
title
|
||||||
|
description
|
||||||
|
}
|
||||||
|
rejectionReason
|
||||||
terms {
|
terms {
|
||||||
enactmentDatetime
|
enactmentDatetime
|
||||||
change {
|
change {
|
||||||
@ -26,9 +31,9 @@ fragment UpdateNetworkParameterProposal on Proposal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subscription OnUpdateNetworkParameters {
|
subscription OnProposal {
|
||||||
proposals {
|
proposals {
|
||||||
...UpdateNetworkParameterProposal
|
...OnProposalFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,12 +13,12 @@ export type ProposalEventSubscriptionVariables = Types.Exact<{
|
|||||||
|
|
||||||
export type ProposalEventSubscription = { __typename?: 'Subscription', proposals: { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null } };
|
export type ProposalEventSubscription = { __typename?: 'Subscription', proposals: { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null } };
|
||||||
|
|
||||||
export type UpdateNetworkParameterProposalFragment = { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, datetime: any, terms: { __typename?: 'ProposalTerms', enactmentDatetime?: any | null, change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } };
|
export type OnProposalFragmentFragment = { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string }, terms: { __typename?: 'ProposalTerms', enactmentDatetime?: any | null, change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } };
|
||||||
|
|
||||||
export type OnUpdateNetworkParametersSubscriptionVariables = Types.Exact<{ [key: string]: never; }>;
|
export type OnProposalSubscriptionVariables = Types.Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type OnUpdateNetworkParametersSubscription = { __typename?: 'Subscription', proposals: { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, datetime: any, terms: { __typename?: 'ProposalTerms', enactmentDatetime?: any | null, change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } } };
|
export type OnProposalSubscription = { __typename?: 'Subscription', proposals: { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string }, terms: { __typename?: 'ProposalTerms', enactmentDatetime?: any | null, change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } } };
|
||||||
|
|
||||||
export type ProposalOfMarketQueryVariables = Types.Exact<{
|
export type ProposalOfMarketQueryVariables = Types.Exact<{
|
||||||
marketId: Types.Scalars['ID'];
|
marketId: Types.Scalars['ID'];
|
||||||
@ -64,11 +64,16 @@ export const ProposalEventFieldsFragmentDoc = gql`
|
|||||||
errorDetails
|
errorDetails
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const UpdateNetworkParameterProposalFragmentDoc = gql`
|
export const OnProposalFragmentFragmentDoc = gql`
|
||||||
fragment UpdateNetworkParameterProposal on Proposal {
|
fragment OnProposalFragment on Proposal {
|
||||||
id
|
id
|
||||||
state
|
state
|
||||||
datetime
|
datetime
|
||||||
|
rationale {
|
||||||
|
title
|
||||||
|
description
|
||||||
|
}
|
||||||
|
rejectionReason
|
||||||
terms {
|
terms {
|
||||||
enactmentDatetime
|
enactmentDatetime
|
||||||
change {
|
change {
|
||||||
@ -109,35 +114,35 @@ export function useProposalEventSubscription(baseOptions: Apollo.SubscriptionHoo
|
|||||||
}
|
}
|
||||||
export type ProposalEventSubscriptionHookResult = ReturnType<typeof useProposalEventSubscription>;
|
export type ProposalEventSubscriptionHookResult = ReturnType<typeof useProposalEventSubscription>;
|
||||||
export type ProposalEventSubscriptionResult = Apollo.SubscriptionResult<ProposalEventSubscription>;
|
export type ProposalEventSubscriptionResult = Apollo.SubscriptionResult<ProposalEventSubscription>;
|
||||||
export const OnUpdateNetworkParametersDocument = gql`
|
export const OnProposalDocument = gql`
|
||||||
subscription OnUpdateNetworkParameters {
|
subscription OnProposal {
|
||||||
proposals {
|
proposals {
|
||||||
...UpdateNetworkParameterProposal
|
...OnProposalFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
${UpdateNetworkParameterProposalFragmentDoc}`;
|
${OnProposalFragmentFragmentDoc}`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __useOnUpdateNetworkParametersSubscription__
|
* __useOnProposalSubscription__
|
||||||
*
|
*
|
||||||
* To run a query within a React component, call `useOnUpdateNetworkParametersSubscription` and pass it any options that fit your needs.
|
* To run a query within a React component, call `useOnProposalSubscription` and pass it any options that fit your needs.
|
||||||
* When your component renders, `useOnUpdateNetworkParametersSubscription` returns an object from Apollo Client that contains loading, error, and data properties
|
* When your component renders, `useOnProposalSubscription` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
* you can use to render your UI.
|
* you can use to render your UI.
|
||||||
*
|
*
|
||||||
* @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
* @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const { data, loading, error } = useOnUpdateNetworkParametersSubscription({
|
* const { data, loading, error } = useOnProposalSubscription({
|
||||||
* variables: {
|
* variables: {
|
||||||
* },
|
* },
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
export function useOnUpdateNetworkParametersSubscription(baseOptions?: Apollo.SubscriptionHookOptions<OnUpdateNetworkParametersSubscription, OnUpdateNetworkParametersSubscriptionVariables>) {
|
export function useOnProposalSubscription(baseOptions?: Apollo.SubscriptionHookOptions<OnProposalSubscription, OnProposalSubscriptionVariables>) {
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
return Apollo.useSubscription<OnUpdateNetworkParametersSubscription, OnUpdateNetworkParametersSubscriptionVariables>(OnUpdateNetworkParametersDocument, options);
|
return Apollo.useSubscription<OnProposalSubscription, OnProposalSubscriptionVariables>(OnProposalDocument, options);
|
||||||
}
|
}
|
||||||
export type OnUpdateNetworkParametersSubscriptionHookResult = ReturnType<typeof useOnUpdateNetworkParametersSubscription>;
|
export type OnProposalSubscriptionHookResult = ReturnType<typeof useOnProposalSubscription>;
|
||||||
export type OnUpdateNetworkParametersSubscriptionResult = Apollo.SubscriptionResult<OnUpdateNetworkParametersSubscription>;
|
export type OnProposalSubscriptionResult = Apollo.SubscriptionResult<OnProposalSubscription>;
|
||||||
export const ProposalOfMarketDocument = gql`
|
export const ProposalOfMarketDocument = gql`
|
||||||
query ProposalOfMarket($marketId: ID!) {
|
query ProposalOfMarket($marketId: ID!) {
|
||||||
proposal(id: $marketId) {
|
proposal(id: $marketId) {
|
||||||
|
@ -3,7 +3,7 @@ export * from './use-proposal-event';
|
|||||||
export * from './use-vega-transaction';
|
export * from './use-vega-transaction';
|
||||||
export * from './use-proposal-submit';
|
export * from './use-proposal-submit';
|
||||||
export * from './use-update-proposal';
|
export * from './use-update-proposal';
|
||||||
export * from './use-update-network-paramaters-toasts';
|
export * from './use-proposal-toasts';
|
||||||
export * from './use-successor-market-proposal-details';
|
export * from './use-successor-market-proposal-details';
|
||||||
export * from './use-new-transfer-proposal-details';
|
export * from './use-new-transfer-proposal-details';
|
||||||
export * from './use-cancel-transfer-proposal-details';
|
export * from './use-cancel-transfer-proposal-details';
|
||||||
|
@ -0,0 +1,273 @@
|
|||||||
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import type { ProposalRejectionReason } from '@vegaprotocol/types';
|
||||||
|
import {
|
||||||
|
ProposalChangeMapping,
|
||||||
|
ProposalState,
|
||||||
|
ProposalStateMapping,
|
||||||
|
} from '@vegaprotocol/types';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
import {
|
||||||
|
PROPOSAL_STATES_TO_TOAST,
|
||||||
|
ProposalToastContent,
|
||||||
|
useProposalToasts,
|
||||||
|
} from './use-proposal-toasts';
|
||||||
|
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { waitFor, renderHook, render } from '@testing-library/react';
|
||||||
|
import {
|
||||||
|
OnProposalDocument,
|
||||||
|
type OnProposalFragmentFragment,
|
||||||
|
type OnProposalSubscription,
|
||||||
|
} from './__generated__/Proposal';
|
||||||
|
import sample from 'lodash/sample';
|
||||||
|
|
||||||
|
const renderUseProposalToasts = (mocks?: MockedResponse[]) => {
|
||||||
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
|
<MockedProvider mocks={mocks}>{children}</MockedProvider>
|
||||||
|
);
|
||||||
|
return renderHook(() => useProposalToasts(), { wrapper });
|
||||||
|
};
|
||||||
|
|
||||||
|
type ProposalChange = OnProposalFragmentFragment['terms']['change'];
|
||||||
|
|
||||||
|
const NEW_MARKET_CHANGE: ProposalChange = { __typename: 'NewMarket' };
|
||||||
|
const UPDATE_MARKET_CHANGE: ProposalChange = { __typename: 'UpdateMarket' };
|
||||||
|
const UPDATE_NETWORK_PARAMETER_CHANGE: ProposalChange = {
|
||||||
|
__typename: 'UpdateNetworkParameter',
|
||||||
|
networkParameter: {
|
||||||
|
__typename: 'NetworkParameter',
|
||||||
|
key: 'abc.def',
|
||||||
|
value: '123',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const NEW_ASSET_CHANGE: ProposalChange = { __typename: 'NewAsset' };
|
||||||
|
const UPDATE_ASSET_CHANGE: ProposalChange = { __typename: 'UpdateAsset' };
|
||||||
|
const NEW_FREEFORM_CHANGE: ProposalChange = { __typename: 'NewFreeform' };
|
||||||
|
const NEW_TRANSFER_CHANGE: ProposalChange = { __typename: 'NewTransfer' };
|
||||||
|
const CANCEL_TRANSFER_CHANGE: ProposalChange = { __typename: 'CancelTransfer' };
|
||||||
|
const UPDATE_MARKET_STATE_CHANGE: ProposalChange = {
|
||||||
|
__typename: 'UpdateMarketState',
|
||||||
|
};
|
||||||
|
const NEW_SPOT_MARKET_CHANGE: ProposalChange = { __typename: 'NewSpotMarket' };
|
||||||
|
const UPDATE_SPOT_MARKET_CHANGE: ProposalChange = {
|
||||||
|
__typename: 'UpdateSpotMarket',
|
||||||
|
};
|
||||||
|
const UPDATE_VOLUME_DISCOUNT_PROGRAM_CHANGE: ProposalChange = {
|
||||||
|
__typename: 'UpdateVolumeDiscountProgram',
|
||||||
|
};
|
||||||
|
const UPDATE_REFERRAL_PROGRAM_CHANGE: ProposalChange = {
|
||||||
|
__typename: 'UpdateReferralProgram',
|
||||||
|
};
|
||||||
|
|
||||||
|
const GenericToastProposals = [
|
||||||
|
NEW_MARKET_CHANGE,
|
||||||
|
UPDATE_MARKET_CHANGE,
|
||||||
|
NEW_ASSET_CHANGE,
|
||||||
|
UPDATE_ASSET_CHANGE,
|
||||||
|
NEW_FREEFORM_CHANGE,
|
||||||
|
NEW_TRANSFER_CHANGE,
|
||||||
|
CANCEL_TRANSFER_CHANGE,
|
||||||
|
UPDATE_MARKET_STATE_CHANGE,
|
||||||
|
NEW_SPOT_MARKET_CHANGE,
|
||||||
|
UPDATE_SPOT_MARKET_CHANGE,
|
||||||
|
UPDATE_VOLUME_DISCOUNT_PROGRAM_CHANGE,
|
||||||
|
UPDATE_REFERRAL_PROGRAM_CHANGE,
|
||||||
|
];
|
||||||
|
|
||||||
|
const generateProposal = (
|
||||||
|
title: string,
|
||||||
|
state: ProposalState = ProposalState.STATE_OPEN,
|
||||||
|
change: ProposalChange = { __typename: undefined },
|
||||||
|
rejectionReason: ProposalRejectionReason | null = null
|
||||||
|
): OnProposalFragmentFragment => ({
|
||||||
|
__typename: 'Proposal',
|
||||||
|
id: Math.random().toString(),
|
||||||
|
datetime: Math.random().toString(),
|
||||||
|
rationale: {
|
||||||
|
title,
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
rejectionReason,
|
||||||
|
state,
|
||||||
|
terms: {
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
enactmentDatetime: '2022-12-09T14:40:38Z',
|
||||||
|
change,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const INITIAL = useToasts.getState();
|
||||||
|
|
||||||
|
const clear = () => {
|
||||||
|
useToasts.setState(INITIAL);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('useProposalToasts', () => {
|
||||||
|
beforeEach(clear);
|
||||||
|
afterAll(clear);
|
||||||
|
|
||||||
|
it.each(PROPOSAL_STATES_TO_TOAST)(
|
||||||
|
'renders toast for %s proposal',
|
||||||
|
async (state) => {
|
||||||
|
const mockProposal: MockedResponse<OnProposalSubscription> = {
|
||||||
|
request: {
|
||||||
|
query: OnProposalDocument,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
proposals: generateProposal(
|
||||||
|
'Things to change',
|
||||||
|
state,
|
||||||
|
NEW_MARKET_CHANGE
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const { result } = renderUseProposalToasts([mockProposal]);
|
||||||
|
expect(result.current.loading).toBe(true);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.loading).toBe(false);
|
||||||
|
expect(useToasts.getState().count).toBe(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const IGNORE_STATES = Object.keys(ProposalState).filter((state) => {
|
||||||
|
return !PROPOSAL_STATES_TO_TOAST.includes(state as ProposalState);
|
||||||
|
}) as ProposalState[];
|
||||||
|
it.each(IGNORE_STATES)(
|
||||||
|
'does not render toast for %s proposal',
|
||||||
|
async (state) => {
|
||||||
|
const mockFailedProposal: MockedResponse<OnProposalSubscription> = {
|
||||||
|
request: {
|
||||||
|
query: OnProposalDocument,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
proposals: generateProposal('Things to change but ignored', state),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const { result } = renderUseProposalToasts([mockFailedProposal]);
|
||||||
|
expect(result.current.loading).toBe(true);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.loading).toBe(false);
|
||||||
|
expect(useToasts.getState().count).toBe(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('does not render toast for empty proposal', async () => {
|
||||||
|
const error = console.error;
|
||||||
|
console.error = () => {
|
||||||
|
/* no op */
|
||||||
|
};
|
||||||
|
const mockEmptyProposal: MockedResponse<OnProposalSubscription> = {
|
||||||
|
request: {
|
||||||
|
query: OnProposalDocument,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
proposals: undefined as unknown as OnProposalFragmentFragment,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const { result } = renderUseProposalToasts([mockEmptyProposal]);
|
||||||
|
expect(result.current.loading).toBe(true);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.loading).toBe(false);
|
||||||
|
expect(useToasts.getState().count).toBe(0);
|
||||||
|
});
|
||||||
|
console.error = error;
|
||||||
|
});
|
||||||
|
|
||||||
|
const allTypes: [
|
||||||
|
ProposalChange['__typename'],
|
||||||
|
ProposalChange,
|
||||||
|
ProposalState?
|
||||||
|
][] = [...GenericToastProposals, UPDATE_NETWORK_PARAMETER_CHANGE].map(
|
||||||
|
(ch) => [ch.__typename, ch, sample(PROPOSAL_STATES_TO_TOAST)]
|
||||||
|
);
|
||||||
|
it.each(allTypes)(
|
||||||
|
'renders toast for %s proposal',
|
||||||
|
async (_, change, state) => {
|
||||||
|
const proposalData = generateProposal('Things to change', state, change);
|
||||||
|
const mockProposal: MockedResponse<OnProposalSubscription> = {
|
||||||
|
request: {
|
||||||
|
query: OnProposalDocument,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
proposals: proposalData,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const { result } = renderUseProposalToasts([mockProposal]);
|
||||||
|
expect(result.current.loading).toBe(true);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.loading).toBe(false);
|
||||||
|
expect(useToasts.getState().count).toBe(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ProposalToastContent', () => {
|
||||||
|
const genericTypes: [
|
||||||
|
ProposalChange['__typename'],
|
||||||
|
ProposalChange,
|
||||||
|
ProposalState?
|
||||||
|
][] = GenericToastProposals.map((ch) => [
|
||||||
|
ch.__typename,
|
||||||
|
ch,
|
||||||
|
sample(PROPOSAL_STATES_TO_TOAST),
|
||||||
|
]);
|
||||||
|
it.each(genericTypes)(
|
||||||
|
'renders generic toast content for %s',
|
||||||
|
async (_, change, state) => {
|
||||||
|
const proposalData = generateProposal('Things to change', state, change);
|
||||||
|
const { container } = render(
|
||||||
|
<ProposalToastContent proposal={proposalData} />
|
||||||
|
);
|
||||||
|
const title = container.querySelector(
|
||||||
|
'[data-testid="proposal-toast-title"]'
|
||||||
|
);
|
||||||
|
const rationale = container.querySelector(
|
||||||
|
'[data-testid="proposal-toast-rationale-title"]'
|
||||||
|
);
|
||||||
|
const expectedChangeName = change.__typename
|
||||||
|
? ProposalChangeMapping[change.__typename]
|
||||||
|
: '';
|
||||||
|
const expectedState =
|
||||||
|
ProposalStateMapping[proposalData.state].toLocaleLowerCase();
|
||||||
|
expect(title).toHaveTextContent(
|
||||||
|
`${expectedChangeName} proposal ${expectedState}`
|
||||||
|
);
|
||||||
|
expect(rationale).toHaveTextContent('Things to change');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('renders specific content for UpdateNetworkParameter proposal', () => {
|
||||||
|
const proposalData = generateProposal(
|
||||||
|
'Things to change',
|
||||||
|
ProposalState.STATE_OPEN,
|
||||||
|
UPDATE_NETWORK_PARAMETER_CHANGE
|
||||||
|
);
|
||||||
|
const { container } = render(
|
||||||
|
<ProposalToastContent proposal={proposalData} />
|
||||||
|
);
|
||||||
|
const title = container.querySelector(
|
||||||
|
'[data-testid="proposal-toast-title"]'
|
||||||
|
);
|
||||||
|
const rationale = container.querySelector(
|
||||||
|
'[data-testid="proposal-toast-rationale-title"]'
|
||||||
|
);
|
||||||
|
const param = container.querySelector(
|
||||||
|
'[data-testid="proposal-toast-network-param"]'
|
||||||
|
);
|
||||||
|
expect(title).toHaveTextContent('Update network parameter proposal open');
|
||||||
|
expect(rationale).toBe(null);
|
||||||
|
expect(param).toHaveTextContent('Update abc.def to 123');
|
||||||
|
});
|
||||||
|
});
|
136
libs/proposals/src/lib/proposals-hooks/use-proposal-toasts.tsx
Normal file
136
libs/proposals/src/lib/proposals-hooks/use-proposal-toasts.tsx
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
||||||
|
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import {
|
||||||
|
ProposalChangeMapping,
|
||||||
|
ProposalRejectionReasonMapping,
|
||||||
|
ProposalStateMapping,
|
||||||
|
} from '@vegaprotocol/types';
|
||||||
|
import { ProposalState } from '@vegaprotocol/types';
|
||||||
|
import type { Toast } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { ToastHeading } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { ExternalLink, Intent } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import {
|
||||||
|
useOnProposalSubscription,
|
||||||
|
type OnProposalFragmentFragment,
|
||||||
|
} from './__generated__/Proposal';
|
||||||
|
|
||||||
|
export const PROPOSAL_STATES_TO_TOAST = [
|
||||||
|
ProposalState.STATE_DECLINED,
|
||||||
|
ProposalState.STATE_ENACTED,
|
||||||
|
ProposalState.STATE_OPEN,
|
||||||
|
ProposalState.STATE_PASSED,
|
||||||
|
];
|
||||||
|
const CLOSE_AFTER = 0;
|
||||||
|
type Proposal = OnProposalFragmentFragment;
|
||||||
|
|
||||||
|
const ProposalDetails = ({ proposal }: { proposal: Proposal }) => {
|
||||||
|
const change = proposal.terms.change;
|
||||||
|
switch (change.__typename) {
|
||||||
|
case 'UpdateNetworkParameter':
|
||||||
|
return <UpdateNetworkParameterDetails proposal={proposal} />;
|
||||||
|
default:
|
||||||
|
// generic details: rationale title and rejection reason if rejected
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{proposal.rationale.title ? (
|
||||||
|
<p data-testid="proposal-toast-rationale-title" className="italic">
|
||||||
|
{proposal.rationale.title}
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
{proposal.state === ProposalState.STATE_REJECTED &&
|
||||||
|
proposal.rejectionReason ? (
|
||||||
|
<p data-testid="proposal-toast-rejection-reason">
|
||||||
|
{t('Rejection reason:')}{' '}
|
||||||
|
{ProposalRejectionReasonMapping[proposal.rejectionReason]}
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const UpdateNetworkParameterDetails = ({
|
||||||
|
proposal,
|
||||||
|
}: {
|
||||||
|
proposal: Proposal;
|
||||||
|
}) => {
|
||||||
|
const change = proposal.terms.change;
|
||||||
|
if (change.__typename !== 'UpdateNetworkParameter') return null;
|
||||||
|
return (
|
||||||
|
<p data-testid="proposal-toast-network-param" className="italic">
|
||||||
|
'{t('Update ')}
|
||||||
|
<span className="break-all">{change.networkParameter.key}</span>
|
||||||
|
{t(' to ')}
|
||||||
|
<span>{change.networkParameter.value}</span>'
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ProposalToastContent = ({ proposal }: { proposal: Proposal }) => {
|
||||||
|
const tokenLink = useLinks(DApp.Governance);
|
||||||
|
const change = proposal.terms.change;
|
||||||
|
|
||||||
|
// Generates toast's title,
|
||||||
|
// e.g. Update market proposal enacted, New transfer proposal open, ...
|
||||||
|
const title = t('%s proposal %s', [
|
||||||
|
change.__typename ? ProposalChangeMapping[change.__typename] : 'Unknown',
|
||||||
|
ProposalStateMapping[proposal.state].toLowerCase(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const enactment = Date.parse(proposal.terms.enactmentDatetime);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ToastHeading data-testid="proposal-toast-title">{title}</ToastHeading>
|
||||||
|
<ProposalDetails proposal={proposal} />
|
||||||
|
{!isNaN(enactment) && (
|
||||||
|
<p>
|
||||||
|
{t('Enactment date:')} {getDateTimeFormat().format(enactment)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<p>
|
||||||
|
<ExternalLink
|
||||||
|
href={tokenLink(TOKEN_PROPOSAL).replace(':id', proposal?.id || '')}
|
||||||
|
>
|
||||||
|
{t('View proposal details')}
|
||||||
|
</ExternalLink>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useProposalToasts = () => {
|
||||||
|
const { setToast, remove } = useToasts((store) => ({
|
||||||
|
setToast: store.setToast,
|
||||||
|
remove: store.remove,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const fromProposal = useCallback(
|
||||||
|
(proposal: Proposal): Toast => {
|
||||||
|
const id = `proposal-toast-${proposal.id}`;
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
intent: Intent.Warning,
|
||||||
|
content: <ProposalToastContent proposal={proposal} />,
|
||||||
|
onClose: () => {
|
||||||
|
remove(id);
|
||||||
|
},
|
||||||
|
closeAfter: CLOSE_AFTER,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[remove]
|
||||||
|
);
|
||||||
|
|
||||||
|
return useOnProposalSubscription({
|
||||||
|
onData: ({ data }) => {
|
||||||
|
const proposal = data.data?.proposals;
|
||||||
|
if (!proposal || !proposal.terms.change.__typename) return;
|
||||||
|
if (PROPOSAL_STATES_TO_TOAST.includes(proposal.state)) {
|
||||||
|
setToast(fromProposal(proposal));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -1,96 +0,0 @@
|
|||||||
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import type { UpdateNetworkParameter } from '@vegaprotocol/types';
|
|
||||||
import { ProposalStateMapping } from '@vegaprotocol/types';
|
|
||||||
import { ProposalState } from '@vegaprotocol/types';
|
|
||||||
import type { Toast } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { ToastHeading } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { ExternalLink, Intent } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import type { UpdateNetworkParameterProposalFragment } from './__generated__/Proposal';
|
|
||||||
import { useOnUpdateNetworkParametersSubscription } from './__generated__/Proposal';
|
|
||||||
|
|
||||||
export const PROPOSAL_STATES_TO_TOAST = [
|
|
||||||
ProposalState.STATE_DECLINED,
|
|
||||||
ProposalState.STATE_ENACTED,
|
|
||||||
ProposalState.STATE_OPEN,
|
|
||||||
ProposalState.STATE_PASSED,
|
|
||||||
];
|
|
||||||
const CLOSE_AFTER = 0;
|
|
||||||
type Proposal = UpdateNetworkParameterProposalFragment;
|
|
||||||
|
|
||||||
const UpdateNetworkParameterToastContent = ({
|
|
||||||
proposal,
|
|
||||||
}: {
|
|
||||||
proposal: Proposal;
|
|
||||||
}) => {
|
|
||||||
const tokenLink = useLinks(DApp.Governance);
|
|
||||||
const change = proposal.terms.change as UpdateNetworkParameter;
|
|
||||||
const title = t('Network change proposal %s').replace(
|
|
||||||
'%s',
|
|
||||||
ProposalStateMapping[proposal.state].toLowerCase()
|
|
||||||
);
|
|
||||||
const enactment = Date.parse(proposal.terms.enactmentDatetime);
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<ToastHeading>{title}</ToastHeading>
|
|
||||||
<p className="italic">
|
|
||||||
'{t('Update ')}
|
|
||||||
<span className="break-all">{change.networkParameter.key}</span>
|
|
||||||
{t(' to ')}
|
|
||||||
<span>{change.networkParameter.value}</span>'
|
|
||||||
</p>
|
|
||||||
{!isNaN(enactment) && (
|
|
||||||
<p>
|
|
||||||
{t('Enactment date:')} {getDateTimeFormat().format(enactment)}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<ExternalLink
|
|
||||||
href={tokenLink(TOKEN_PROPOSAL).replace(':id', proposal?.id || '')}
|
|
||||||
>
|
|
||||||
{t('View proposal details')}
|
|
||||||
</ExternalLink>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useUpdateNetworkParametersToasts = () => {
|
|
||||||
const { setToast, remove } = useToasts((store) => ({
|
|
||||||
setToast: store.setToast,
|
|
||||||
remove: store.remove,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const fromProposal = useCallback(
|
|
||||||
(proposal: Proposal): Toast => {
|
|
||||||
const id = `update-network-param-proposal-${proposal.id}`;
|
|
||||||
return {
|
|
||||||
id: `update-network-param-proposal-${proposal.id}`,
|
|
||||||
intent: Intent.Warning,
|
|
||||||
content: <UpdateNetworkParameterToastContent proposal={proposal} />,
|
|
||||||
onClose: () => {
|
|
||||||
remove(id);
|
|
||||||
},
|
|
||||||
closeAfter: CLOSE_AFTER,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
[remove]
|
|
||||||
);
|
|
||||||
|
|
||||||
return useOnUpdateNetworkParametersSubscription({
|
|
||||||
onData: ({ data }) => {
|
|
||||||
// note proposals is poorly named, it is actually a single proposal
|
|
||||||
const proposal = data.data?.proposals;
|
|
||||||
if (!proposal) return;
|
|
||||||
if (proposal.terms.change.__typename !== 'UpdateNetworkParameter') return;
|
|
||||||
|
|
||||||
// if one of the following states show a toast
|
|
||||||
if (PROPOSAL_STATES_TO_TOAST.includes(proposal.state)) {
|
|
||||||
setToast(fromProposal(proposal));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,168 +0,0 @@
|
|||||||
import merge from 'lodash/merge';
|
|
||||||
import type { MockedResponse } from '@apollo/client/testing';
|
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
|
||||||
import { ProposalState } from '@vegaprotocol/types';
|
|
||||||
import type { ReactNode } from 'react';
|
|
||||||
import {
|
|
||||||
PROPOSAL_STATES_TO_TOAST,
|
|
||||||
useUpdateNetworkParametersToasts,
|
|
||||||
} from './use-update-network-paramaters-toasts';
|
|
||||||
import type {
|
|
||||||
UpdateNetworkParameterProposalFragment,
|
|
||||||
OnUpdateNetworkParametersSubscription,
|
|
||||||
} from './__generated__/Proposal';
|
|
||||||
import { OnUpdateNetworkParametersDocument } from './__generated__/Proposal';
|
|
||||||
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { waitFor, renderHook } from '@testing-library/react';
|
|
||||||
|
|
||||||
const render = (mocks?: MockedResponse[]) => {
|
|
||||||
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
||||||
<MockedProvider mocks={mocks}>{children}</MockedProvider>
|
|
||||||
);
|
|
||||||
return renderHook(() => useUpdateNetworkParametersToasts(), { wrapper });
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateUpdateNetworkParametersProposal = (
|
|
||||||
key: string,
|
|
||||||
value: string,
|
|
||||||
state: ProposalState = ProposalState.STATE_OPEN
|
|
||||||
): UpdateNetworkParameterProposalFragment => ({
|
|
||||||
__typename: 'Proposal',
|
|
||||||
id: Math.random().toString(),
|
|
||||||
datetime: Math.random().toString(),
|
|
||||||
state,
|
|
||||||
terms: {
|
|
||||||
__typename: 'ProposalTerms',
|
|
||||||
enactmentDatetime: '2022-12-09T14:40:38Z',
|
|
||||||
change: {
|
|
||||||
__typename: 'UpdateNetworkParameter',
|
|
||||||
networkParameter: {
|
|
||||||
__typename: 'NetworkParameter',
|
|
||||||
key,
|
|
||||||
value,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const INITIAL = useToasts.getState();
|
|
||||||
|
|
||||||
const clear = () => {
|
|
||||||
useToasts.setState(INITIAL);
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('useUpdateNetworkParametersToasts', () => {
|
|
||||||
beforeEach(clear);
|
|
||||||
afterAll(clear);
|
|
||||||
|
|
||||||
it.each(PROPOSAL_STATES_TO_TOAST)(
|
|
||||||
'toasts for %s network param proposals',
|
|
||||||
async (state) => {
|
|
||||||
const mockOpenProposal: MockedResponse<OnUpdateNetworkParametersSubscription> =
|
|
||||||
{
|
|
||||||
request: {
|
|
||||||
query: OnUpdateNetworkParametersDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
proposals: generateUpdateNetworkParametersProposal(
|
|
||||||
'abc.def',
|
|
||||||
'123.456',
|
|
||||||
state
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const { result } = render([mockOpenProposal]);
|
|
||||||
expect(result.current.loading).toBe(true);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(result.current.loading).toBe(false);
|
|
||||||
expect(useToasts.getState().count).toBe(1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const IGNORE_STATES = Object.keys(ProposalState).filter((state) => {
|
|
||||||
return !PROPOSAL_STATES_TO_TOAST.includes(state as ProposalState);
|
|
||||||
}) as ProposalState[];
|
|
||||||
it.each(IGNORE_STATES)('does not toast for %s proposals', async (state) => {
|
|
||||||
const mockFailedProposal: MockedResponse<OnUpdateNetworkParametersSubscription> =
|
|
||||||
{
|
|
||||||
request: {
|
|
||||||
query: OnUpdateNetworkParametersDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
proposals: generateUpdateNetworkParametersProposal(
|
|
||||||
'abc.def',
|
|
||||||
'123.456',
|
|
||||||
state
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const { result } = render([mockFailedProposal]);
|
|
||||||
expect(result.current.loading).toBe(true);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(result.current.loading).toBe(false);
|
|
||||||
expect(useToasts.getState().count).toBe(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not return toast for empty propsal', async () => {
|
|
||||||
const error = console.error;
|
|
||||||
console.error = () => {
|
|
||||||
/* no op */
|
|
||||||
};
|
|
||||||
const mockEmptyProposal: MockedResponse<OnUpdateNetworkParametersSubscription> =
|
|
||||||
{
|
|
||||||
request: {
|
|
||||||
query: OnUpdateNetworkParametersDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
proposals:
|
|
||||||
undefined as unknown as UpdateNetworkParameterProposalFragment,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const { result } = render([mockEmptyProposal]);
|
|
||||||
expect(result.current.loading).toBe(true);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(result.current.loading).toBe(false);
|
|
||||||
expect(useToasts.getState().count).toBe(0);
|
|
||||||
});
|
|
||||||
console.error = error;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not return toast for wrong proposal type', async () => {
|
|
||||||
const wrongProposalType = merge(
|
|
||||||
generateUpdateNetworkParametersProposal('a', 'b'),
|
|
||||||
{
|
|
||||||
terms: {
|
|
||||||
change: {
|
|
||||||
__typename: 'NewMarket',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const mockWrongProposalType: MockedResponse<OnUpdateNetworkParametersSubscription> =
|
|
||||||
{
|
|
||||||
request: {
|
|
||||||
query: OnUpdateNetworkParametersDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
proposals: wrongProposalType,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const { result } = render([mockWrongProposalType]);
|
|
||||||
expect(result.current.loading).toBe(true);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(result.current.loading).toBe(false);
|
|
||||||
expect(useToasts.getState().count).toBe(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
37
libs/types/src/__generated__/types.ts
generated
37
libs/types/src/__generated__/types.ts
generated
@ -3387,6 +3387,8 @@ export type Party = {
|
|||||||
transfersConnection?: Maybe<TransferConnection>;
|
transfersConnection?: Maybe<TransferConnection>;
|
||||||
/** The current reward vesting summary of the party for the last epoch */
|
/** The current reward vesting summary of the party for the last epoch */
|
||||||
vestingBalancesSummary: PartyVestingBalancesSummary;
|
vestingBalancesSummary: PartyVestingBalancesSummary;
|
||||||
|
/** The current statistics about a party's vesting rewards for the last epoch */
|
||||||
|
vestingStats?: Maybe<PartyVestingStats>;
|
||||||
/** All votes on proposals in the Vega network by the given party */
|
/** All votes on proposals in the Vega network by the given party */
|
||||||
votesConnection?: Maybe<ProposalVoteConnection>;
|
votesConnection?: Maybe<ProposalVoteConnection>;
|
||||||
/** The list of all withdrawals initiated by the party */
|
/** The list of all withdrawals initiated by the party */
|
||||||
@ -3502,6 +3504,7 @@ export type PartytradesConnectionArgs = {
|
|||||||
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
||||||
export type PartytransfersConnectionArgs = {
|
export type PartytransfersConnectionArgs = {
|
||||||
direction?: InputMaybe<TransferDirection>;
|
direction?: InputMaybe<TransferDirection>;
|
||||||
|
isReward?: InputMaybe<Scalars['Boolean']>;
|
||||||
pagination?: InputMaybe<Pagination>;
|
pagination?: InputMaybe<Pagination>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3616,6 +3619,15 @@ export type PartyVestingBalancesSummary = {
|
|||||||
vestingBalances?: Maybe<Array<PartyVestingBalance>>;
|
vestingBalances?: Maybe<Array<PartyVestingBalance>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Statistics about a party's vesting rewards */
|
||||||
|
export type PartyVestingStats = {
|
||||||
|
__typename?: 'PartyVestingStats';
|
||||||
|
/** Epoch for which the statistics are valid */
|
||||||
|
epochSeq: Scalars['Int'];
|
||||||
|
/** The reward bonus multiplier */
|
||||||
|
rewardBonusMultiplier: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
/** Create an order linked to an index rather than a price */
|
/** Create an order linked to an index rather than a price */
|
||||||
export type PeggedOrder = {
|
export type PeggedOrder = {
|
||||||
__typename?: 'PeggedOrder';
|
__typename?: 'PeggedOrder';
|
||||||
@ -4905,6 +4917,7 @@ export type QuerytransferArgs = {
|
|||||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||||
export type QuerytransfersConnectionArgs = {
|
export type QuerytransfersConnectionArgs = {
|
||||||
direction?: InputMaybe<TransferDirection>;
|
direction?: InputMaybe<TransferDirection>;
|
||||||
|
isReward?: InputMaybe<Scalars['Boolean']>;
|
||||||
pagination?: InputMaybe<Pagination>;
|
pagination?: InputMaybe<Pagination>;
|
||||||
partyId?: InputMaybe<Scalars['ID']>;
|
partyId?: InputMaybe<Scalars['ID']>;
|
||||||
};
|
};
|
||||||
@ -5081,6 +5094,8 @@ export type ReferralSetStats = {
|
|||||||
rewardsFactorMultiplier: Scalars['String'];
|
rewardsFactorMultiplier: Scalars['String'];
|
||||||
/** The multiplier applied to the referral reward factor when calculating referral rewards due to the referrer. */
|
/** The multiplier applied to the referral reward factor when calculating referral rewards due to the referrer. */
|
||||||
rewardsMultiplier: Scalars['String'];
|
rewardsMultiplier: Scalars['String'];
|
||||||
|
/** Indicates if the referral set was eligible to be part of the referral program. */
|
||||||
|
wasEligible: Scalars['Boolean'];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Connection type for retrieving cursor-based paginated referral set statistics information */
|
/** Connection type for retrieving cursor-based paginated referral set statistics information */
|
||||||
@ -6102,11 +6117,31 @@ export enum TransferDirection {
|
|||||||
export type TransferEdge = {
|
export type TransferEdge = {
|
||||||
__typename?: 'TransferEdge';
|
__typename?: 'TransferEdge';
|
||||||
cursor: Scalars['String'];
|
cursor: Scalars['String'];
|
||||||
node: Transfer;
|
node: TransferNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A transfer fee record */
|
||||||
|
export type TransferFee = {
|
||||||
|
__typename?: 'TransferFee';
|
||||||
|
/** The fee amount */
|
||||||
|
amount: Scalars['String'];
|
||||||
|
/** The epoch when this fee was paid */
|
||||||
|
epoch: Scalars['Int'];
|
||||||
|
/** Transfer ID of the transfer for which the fee was paid */
|
||||||
|
transferId: Scalars['ID'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TransferKind = OneOffGovernanceTransfer | OneOffTransfer | RecurringGovernanceTransfer | RecurringTransfer;
|
export type TransferKind = OneOffGovernanceTransfer | OneOffTransfer | RecurringGovernanceTransfer | RecurringTransfer;
|
||||||
|
|
||||||
|
/** A transfer record with the fee payments associated with the transfer */
|
||||||
|
export type TransferNode = {
|
||||||
|
__typename?: 'TransferNode';
|
||||||
|
/** The list of fee payments made */
|
||||||
|
fees?: Maybe<Array<Maybe<TransferFee>>>;
|
||||||
|
/** The transfer record */
|
||||||
|
transfer: Transfer;
|
||||||
|
};
|
||||||
|
|
||||||
export type TransferResponse = {
|
export type TransferResponse = {
|
||||||
__typename?: 'TransferResponse';
|
__typename?: 'TransferResponse';
|
||||||
/** The balances of accounts involved in the transfer */
|
/** The balances of accounts involved in the transfer */
|
||||||
|
@ -3,6 +3,7 @@ import type {
|
|||||||
GovernanceTransferKind,
|
GovernanceTransferKind,
|
||||||
GovernanceTransferType,
|
GovernanceTransferType,
|
||||||
PeggedReference,
|
PeggedReference,
|
||||||
|
ProposalChange,
|
||||||
} from './__generated__/types';
|
} from './__generated__/types';
|
||||||
import type { AccountType } from './__generated__/types';
|
import type { AccountType } from './__generated__/types';
|
||||||
import type {
|
import type {
|
||||||
@ -299,6 +300,29 @@ export const OrderTypeMapping: {
|
|||||||
TYPE_NETWORK: 'Network',
|
TYPE_NETWORK: 'Network',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proposal change type mapping
|
||||||
|
*/
|
||||||
|
export const ProposalChangeMapping: Record<
|
||||||
|
NonNullable<ProposalChange['__typename']>,
|
||||||
|
string
|
||||||
|
> = {
|
||||||
|
NewMarket: 'New market',
|
||||||
|
UpdateMarket: 'Update market',
|
||||||
|
UpdateNetworkParameter: 'Update network parameter',
|
||||||
|
NewAsset: 'New asset',
|
||||||
|
UpdateAsset: 'Update asset',
|
||||||
|
/* cspell:disable-next-line */
|
||||||
|
NewFreeform: 'New free-form',
|
||||||
|
NewTransfer: 'New transfer',
|
||||||
|
CancelTransfer: 'Cancel transfer',
|
||||||
|
UpdateMarketState: 'Update market state',
|
||||||
|
NewSpotMarket: 'New spot market',
|
||||||
|
UpdateSpotMarket: 'Update spot market',
|
||||||
|
UpdateVolumeDiscountProgram: 'Update volume discount program',
|
||||||
|
UpdateReferralProgram: 'Update referral program',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reason for the proposal being rejected by the core node
|
* Reason for the proposal being rejected by the core node
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user