From 5b0bd69710e407f94d55e0bd0462f338467c53b6 Mon Sep 17 00:00:00 2001 From: Sam Keen Date: Mon, 21 Aug 2023 10:05:21 +0100 Subject: [PATCH 01/14] fix(governance): better vote error handling (#4579) --- .../components/proposal/proposal.tsx | 3 +- .../vega-transaction-dialog.spec.tsx | 110 ++++++++++++++++++ .../vote-details/vote-buttons.spec.tsx | 9 +- .../components/vote-details/vote-buttons.tsx | 10 +- .../components/vote-details/vote-details.tsx | 5 +- .../vote-details/vote-transaction-dialog.tsx | 8 +- 6 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 apps/governance/src/routes/proposals/components/vote-details/vega-transaction-dialog.spec.tsx diff --git a/apps/governance/src/routes/proposals/components/proposal/proposal.tsx b/apps/governance/src/routes/proposals/components/proposal/proposal.tsx index 076ac0fd5..64790df1f 100644 --- a/apps/governance/src/routes/proposals/components/proposal/proposal.tsx +++ b/apps/governance/src/routes/proposals/components/proposal/proposal.tsx @@ -55,7 +55,7 @@ export const Proposal = ({ mostRecentlyEnactedAssociatedMarketProposal, }: ProposalProps) => { const { t } = useTranslation(); - const { submit, Dialog, finalizedVote } = useVoteSubmit(); + const { submit, Dialog, finalizedVote, transaction } = useVoteSubmit(); const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote); if (!proposal) { @@ -215,6 +215,7 @@ export const Proposal = ({ } submit={submit} dialog={Dialog} + transaction={transaction} voteState={voteState} voteDatetime={voteDatetime} /> diff --git a/apps/governance/src/routes/proposals/components/vote-details/vega-transaction-dialog.spec.tsx b/apps/governance/src/routes/proposals/components/vote-details/vega-transaction-dialog.spec.tsx new file mode 100644 index 000000000..6ef513333 --- /dev/null +++ b/apps/governance/src/routes/proposals/components/vote-details/vega-transaction-dialog.spec.tsx @@ -0,0 +1,110 @@ +import { render, screen } from '@testing-library/react'; +import { VoteTransactionDialog } from './vote-transaction-dialog'; +import { VoteState } from './use-user-vote'; +import { VegaTxStatus } from '@vegaprotocol/wallet'; + +describe('VoteTransactionDialog', () => { + const mockTransactionDialog = jest.fn(({ title, content }) => ( +
+
{title}
+
{content?.Complete}
+
+ )); + + it('renders without crashing', () => { + render( + + ); + + expect(screen.getByTestId('vote-transaction-dialog')).toBeInTheDocument(); + }); + + it('renders with txRequested title when voteState is Requested', () => { + render( + + ); + + expect(screen.getByText('txRequested')).toBeInTheDocument(); + }); + + it('renders with votePending title when voteState is Pending', () => { + render( + + ); + + expect(screen.getByText('votePending')).toBeInTheDocument(); + }); + + it('renders with no title when voteState is neither Requested nor Pending', () => { + render( + + ); + + expect(screen.queryByText('txRequested')).not.toBeInTheDocument(); + expect(screen.queryByText('votePending')).not.toBeInTheDocument(); + }); + + it('renders custom error message when voteState is Failed and error message exists', () => { + render( + + ); + + expect(screen.getByText('Custom error test message')).toBeInTheDocument(); + }); + + it('renders default error message when voteState is failed and no error message exists on the tx', () => { + render( + + ); + + expect(screen.getByText('voteError')).toBeInTheDocument(); + }); + + it('renders default ui (i.e. not error) when not in a failed state', () => { + render( + + ); + + expect(screen.queryByText('voteError')).not.toBeInTheDocument(); + }); +}); diff --git a/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.spec.tsx b/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.spec.tsx index 7f1ae36b6..9eab79c44 100644 --- a/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.spec.tsx +++ b/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.spec.tsx @@ -1,4 +1,4 @@ -import { render, screen, fireEvent } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import BigNumber from 'bignumber.js'; import { VoteButtons } from './vote-buttons'; import { VoteState } from './use-user-vote'; @@ -24,6 +24,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(1)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -47,6 +48,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(1)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -81,6 +83,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(1)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -105,6 +108,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(0)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -132,6 +136,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(1)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -159,6 +164,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(10)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> @@ -183,6 +189,7 @@ describe('Vote buttons', () => { currentStakeAvailable={new BigNumber(10)} dialog={() =>
Blah
} submit={() => Promise.resolve()} + transaction={null} /> diff --git a/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.tsx b/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.tsx index 919c6b423..7199c9365 100644 --- a/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.tsx +++ b/apps/governance/src/routes/proposals/components/vote-details/vote-buttons.tsx @@ -17,7 +17,7 @@ import { VoteState } from './use-user-vote'; import { ProposalMinRequirements, ProposalUserAction } from '../shared'; import { VoteTransactionDialog } from './vote-transaction-dialog'; import { useVoteButtonsQuery } from './__generated__/Stake'; -import type { DialogProps } from '@vegaprotocol/wallet'; +import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet'; interface VoteButtonsContainerProps { voteState: VoteState | null; @@ -27,6 +27,7 @@ interface VoteButtonsContainerProps { minVoterBalance: string | null | undefined; spamProtectionMinTokens: string | null | undefined; submit: (voteValue: VoteValue, proposalId: string | null) => Promise; + transaction: VegaTxState | null; dialog: (props: DialogProps) => JSX.Element; className?: string; } @@ -67,6 +68,7 @@ export const VoteButtons = ({ minVoterBalance, spamProtectionMinTokens, submit, + transaction, dialog: Dialog, }: VoteButtonsProps) => { const { t } = useTranslation(); @@ -208,7 +210,11 @@ export const VoteButtons = ({

) )} - + ); }; diff --git a/apps/governance/src/routes/proposals/components/vote-details/vote-details.tsx b/apps/governance/src/routes/proposals/components/vote-details/vote-details.tsx index db36adfce..b8fbb7c0a 100644 --- a/apps/governance/src/routes/proposals/components/vote-details/vote-details.tsx +++ b/apps/governance/src/routes/proposals/components/vote-details/vote-details.tsx @@ -12,7 +12,7 @@ import { VoteButtonsContainer } from './vote-buttons'; import { SubHeading } from '../../../../components/heading'; import { ProposalType } from '../proposal/proposal'; import type { VoteValue } from '@vegaprotocol/types'; -import type { DialogProps } from '@vegaprotocol/wallet'; +import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet'; import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals'; import type { ProposalQuery } from '../../proposal/__generated__/Proposal'; import type { VoteState } from './use-user-vote'; @@ -22,6 +22,7 @@ interface VoteDetailsProps { minVoterBalance: string | null | undefined; spamProtectionMinTokens: string | null | undefined; proposalType: ProposalType | null; + transaction: VegaTxState | null; submit: (voteValue: VoteValue, proposalId: string | null) => Promise; dialog: (props: DialogProps) => JSX.Element; voteState: VoteState | null; @@ -34,6 +35,7 @@ export const VoteDetails = ({ spamProtectionMinTokens, proposalType, submit, + transaction, dialog, voteState, voteDatetime, @@ -228,6 +230,7 @@ export const VoteDetails = ({ spamProtectionMinTokens={spamProtectionMinTokens} className="flex" submit={submit} + transaction={transaction} dialog={dialog} /> ) diff --git a/apps/governance/src/routes/proposals/components/vote-details/vote-transaction-dialog.tsx b/apps/governance/src/routes/proposals/components/vote-details/vote-transaction-dialog.tsx index 59f04d705..c0d9b3da9 100644 --- a/apps/governance/src/routes/proposals/components/vote-details/vote-transaction-dialog.tsx +++ b/apps/governance/src/routes/proposals/components/vote-details/vote-transaction-dialog.tsx @@ -1,9 +1,10 @@ import { t } from '@vegaprotocol/i18n'; import { VoteState } from './use-user-vote'; -import type { DialogProps } from '@vegaprotocol/wallet'; +import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet'; interface VoteTransactionDialogProps { voteState: VoteState; + transaction: VegaTxState | null; TransactionDialog: (props: DialogProps) => JSX.Element; } @@ -20,12 +21,15 @@ const dialogTitle = (voteState: VoteState): string | undefined => { export const VoteTransactionDialog = ({ voteState, + transaction, TransactionDialog, }: VoteTransactionDialogProps) => { // Render a custom message if the voting fails otherwise // pass undefined so that the default vega transaction dialog UI gets used const customMessage = - voteState === VoteState.Failed ?

{t('voteError')}

: undefined; + voteState === VoteState.Failed ? ( +

{transaction?.error?.message || t('voteError')}

+ ) : undefined; return (
From 206c6c7207d8d99d9f1348f4ceb43981fa303d30 Mon Sep 17 00:00:00 2001 From: Edd Date: Mon, 21 Aug 2023 18:38:32 +0100 Subject: [PATCH 02/14] fix(explorer): check linking type when summing stake --- .../routes/parties/id/Party-assets.graphql | 35 ++++++++++++++++++- .../parties/id/__generated__/Party-assets.ts | 6 ++-- .../id/components/party-block-stake.tsx | 12 +++++-- .../__generated__/Orders.ts | 6 ++-- libs/types/src/__generated__/types.ts | 4 ++- 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/apps/explorer/src/app/routes/parties/id/Party-assets.graphql b/apps/explorer/src/app/routes/parties/id/Party-assets.graphql index 72ae0fa38..6d30cc986 100644 --- a/apps/explorer/src/app/routes/parties/id/Party-assets.graphql +++ b/apps/explorer/src/app/routes/parties/id/Party-assets.graphql @@ -29,6 +29,37 @@ fragment ExplorerPartyAssetsAccounts on AccountBalance { } } +fragment ExplorerPartyLinks on AccountBalance { + asset { + name + id + decimals + symbol + source { + __typename + ... on ERC20 { + contractAddress + } + } + } + type + balance + market { + id + decimalPlaces + tradableInstrument { + instrument { + name + product { + ... on Future { + quoteName + } + } + } + } + } +} + query ExplorerPartyAssets($partyId: ID!) { partiesConnection(id: $partyId) { edges { @@ -48,9 +79,11 @@ query ExplorerPartyAssets($partyId: ID!) { } stakingSummary { currentStakeAvailable - linkings(pagination: { first: 100 }) { + linkings(pagination: { last: 100 }) { edges { node { + type + status amount } } diff --git a/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts b/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts index 77e334201..1f6b6262d 100644 --- a/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts +++ b/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts @@ -10,7 +10,7 @@ export type ExplorerPartyAssetsQueryVariables = Types.Exact<{ }>; -export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string, linkings: { __typename?: 'StakesConnection', edges?: Array<{ __typename?: 'StakeLinkingEdge', node: { __typename?: 'StakeLinking', amount: string } } | null> | null } }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null } } | null> | null } | null } }> } | null }; +export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string, linkings: { __typename?: 'StakesConnection', edges?: Array<{ __typename?: 'StakeLinkingEdge', node: { __typename?: 'StakeLinking', type: Types.StakeLinkingType, status: Types.StakeLinkingStatus, amount: string } } | null> | null } }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null } } | null> | null } | null } }> } | null }; export const ExplorerPartyAssetsAccountsFragmentDoc = gql` fragment ExplorerPartyAssetsAccounts on AccountBalance { @@ -67,6 +67,8 @@ export const ExplorerPartyAssetsDocument = gql` linkings(pagination: {first: 100}) { edges { node { + type + status amount } } @@ -111,4 +113,4 @@ export function useExplorerPartyAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHo } export type ExplorerPartyAssetsQueryHookResult = ReturnType; export type ExplorerPartyAssetsLazyQueryHookResult = ReturnType; -export type ExplorerPartyAssetsQueryResult = Apollo.QueryResult; \ No newline at end of file +export type ExplorerPartyAssetsQueryResult = Apollo.QueryResult; diff --git a/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx b/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx index 831c15ccc..5121f1ff1 100644 --- a/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx +++ b/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx @@ -42,9 +42,15 @@ export const PartyBlockStake = ({ linkedLength && linkedLength > 0 ? p?.stakingSummary?.linkings?.edges ?.reduce((total, e) => { - return new BigNumber(total).plus( - new BigNumber(e?.node.amount || 0) - ); + const accumulator = new BigNumber(total) + const diff = new BigNumber(e?.node.amount || 0) + if (e?.node.type === 'TYPE_LINK') { + return accumulator.plus(diff); + } else if (e?.node.type === 'TYPE_UNLINK') { + return accumulator.minus(diff); + } else { + return accumulator + } }, new BigNumber(0)) .toString() : '0'; diff --git a/libs/orders/src/lib/components/order-data-provider/__generated__/Orders.ts b/libs/orders/src/lib/components/order-data-provider/__generated__/Orders.ts index 04afda855..a4513725e 100644 --- a/libs/orders/src/lib/components/order-data-provider/__generated__/Orders.ts +++ b/libs/orders/src/lib/components/order-data-provider/__generated__/Orders.ts @@ -34,21 +34,21 @@ export type OrdersUpdateSubscription = { __typename?: 'Subscription', orders?: A export type OrderSubmissionFieldsFragment = { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null }; -export type StopOrderFieldsFragment = { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } }; +export type StopOrderFieldsFragment = { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } }; export type StopOrdersQueryVariables = Types.Exact<{ partyId: Types.Scalars['ID']; }>; -export type StopOrdersQuery = { __typename?: 'Query', stopOrders?: { __typename?: 'StopOrderConnection', edges?: Array<{ __typename?: 'StopOrderEdge', node?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null }> | null } | null }; +export type StopOrdersQuery = { __typename?: 'Query', stopOrders?: { __typename?: 'StopOrderConnection', edges?: Array<{ __typename?: 'StopOrderEdge', node?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null }> | null } | null }; export type StopOrderByIdQueryVariables = Types.Exact<{ stopOrderId: Types.Scalars['ID']; }>; -export type StopOrderByIdQuery = { __typename?: 'Query', stopOrder?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null }; +export type StopOrderByIdQuery = { __typename?: 'Query', stopOrder?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null }; export const OrderFieldsFragmentDoc = gql` fragment OrderFields on Order { diff --git a/libs/types/src/__generated__/types.ts b/libs/types/src/__generated__/types.ts index 18605c0bd..28441bfcf 100644 --- a/libs/types/src/__generated__/types.ts +++ b/libs/types/src/__generated__/types.ts @@ -4364,6 +4364,8 @@ export type StopOrder = { marketId: Scalars['ID']; /** If OCO (one-cancels-other) order, the ID of the associated order. */ ocoLinkId?: Maybe; + /** The order that was created when triggered. */ + order?: Maybe; /** Party that submitted the stop order. */ partyId: Scalars['ID']; /** Status of the stop order */ @@ -4371,7 +4373,7 @@ export type StopOrder = { /** Order to submit when the stop order is triggered. */ submission: OrderSubmission; /** Price movement that will trigger the stop order */ - trigger?: Maybe; + trigger: StopOrderTrigger; /** Direction the price is moving to trigger the stop order. */ triggerDirection: StopOrderTriggerDirection; /** Time the stop order was last updated. */ From fa1825ca64317d02171531911a198f2898d0b705 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 22 Aug 2023 08:29:13 +0100 Subject: [PATCH 03/14] chore(trading): remove settings test (#4580) --- .../src/integration/settings.cy.ts | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 apps/trading-e2e/src/integration/settings.cy.ts diff --git a/apps/trading-e2e/src/integration/settings.cy.ts b/apps/trading-e2e/src/integration/settings.cy.ts deleted file mode 100644 index a09223e5e..000000000 --- a/apps/trading-e2e/src/integration/settings.cy.ts +++ /dev/null @@ -1,30 +0,0 @@ -describe('Settings page', { tags: '@smoke' }, () => { - beforeEach(() => { - cy.clearLocalStorage(); - - cy.mockTradingPage(); - cy.mockSubscription(); - cy.setOnBoardingViewed(); - cy.visit('/'); - - // Only click if not already active otherwise sidebar will close - cy.get('[data-testid="sidebar-content"]').then(($sidebarContent) => { - if ($sidebarContent.find('h2').text() !== 'Settings') { - cy.get('[data-testid="sidebar"] [data-testid="Settings"]').click(); - } - }); - }); - - it('telemetry checkbox should work well', () => { - const telemetrySwitch = '#switch-settings-telemetry-switch'; - cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked'); - cy.get(telemetrySwitch).click(); - cy.get(telemetrySwitch).should('have.attr', 'data-state', 'checked'); - cy.reload(); - cy.get(telemetrySwitch).should('have.attr', 'data-state', 'checked'); - cy.get(telemetrySwitch).click(); - cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked'); - cy.reload(); - cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked'); - }); -}); From ab4f4e9084be8c466bd0ad2f72a409b80ef6f9c5 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 22 Aug 2023 08:29:47 +0100 Subject: [PATCH 04/14] chore(trading): remove trading chart tests (#4582) --- .../src/integration/trading-chart.cy.ts | 186 ------------------ 1 file changed, 186 deletions(-) delete mode 100644 apps/trading-e2e/src/integration/trading-chart.cy.ts diff --git a/apps/trading-e2e/src/integration/trading-chart.cy.ts b/apps/trading-e2e/src/integration/trading-chart.cy.ts deleted file mode 100644 index 152ba334d..000000000 --- a/apps/trading-e2e/src/integration/trading-chart.cy.ts +++ /dev/null @@ -1,186 +0,0 @@ -interface ItemInfoType { - name: string; - infoText: string; -} - -type CheckMenuItemsFnType = ( - triggerSelector: string, - validTexts: string[], - clickItem?: string -) => void; -type CheckMenuItemCheckboxFnType = ( - buttonText: string, - items: ItemInfoType[] -) => void; - -const menuItemRadio = 'div[role="menuitemradio"]'; -const menuItemCheckbox = 'div[role="menuitemcheckbox"]'; -const button = 'button'; -const indicatorInfo = '.indicator-info-wrapper'; - -const checkMenuItems: CheckMenuItemsFnType = ( - triggerSelector, - validTexts, - clickItem -) => { - cy.get(triggerSelector).click(); - - cy.get(menuItemRadio) - .should('have.length', validTexts.length) - .each(($el, index) => { - const text = $el.text().trim(); - expect(text).to.equal(validTexts[index]); - }); - - if (clickItem) { - cy.contains(menuItemRadio, clickItem).click(); - cy.get(triggerSelector).click(); - cy.get(`${menuItemRadio}[data-state="checked"]`) - .invoke('text') - .then((text: string) => { - expect(text.trim()).to.equal(clickItem); - }); - } -}; - -const checkMenuItemCheckbox: CheckMenuItemCheckboxFnType = ( - buttonText, - items -) => { - items.forEach((item) => { - cy.contains(button, buttonText).click(); - cy.contains(menuItemCheckbox, item.name).click(); - }); - - cy.contains(button, buttonText).click(); - cy.get(menuItemCheckbox) - .should('have.length', items.length) - .each(($el, index) => { - const text = $el.text(); - expect(text).to.equal(items[index].name); - }); - - items.forEach((item, index) => { - cy.get(indicatorInfo) - .eq(index + 1) - .invoke('text') - .should('eq', item.infoText); - }); - - cy.contains(button, buttonText).click({ force: true }); -}; - -function getButtonSelectorByText(text: string): string { - return `${button}[aria-haspopup="menu"]:contains(${text})`; -} - -beforeEach(() => { - cy.mockTradingPage(); - cy.mockSubscription(); - cy.setOnBoardingViewed(); - cy.visit('/#/markets/market-0'); - cy.wait('@Markets'); -}); - -describe( - 'chart display options', - { tags: '@smoke', testIsolation: true }, - () => { - it('change time interval', () => { - // 6004-CHAR-001 - checkMenuItems( - getButtonSelectorByText('Interval:'), - ['1m', '5m', '15m', '1H', '6H', '1D'], - '1m' - ); - }); - - it('change display type', () => { - // 6004-CHAR-002 - // 6004-CHAR-003 - checkMenuItems( - '[aria-label$="chart icon"]', - ['Mountain', 'Candlestick', 'Line', 'OHLC'], - 'Mountain' - ); - }); - - it('Overlays', () => { - // 6004-CHAR-004 - // 6004-CHAR-008 - // 6004-CHAR-009 - // 6004-CHAR-034 - // 6004-CHAR-037 - // 6004-CHAR-039 - // 6004-CHAR-041 - - const overlayInfo: ItemInfoType[] = [ - { - name: 'Bollinger bands', - infoText: 'Bollinger: Upper 174.78590Lower 173.38014', - }, - { - name: 'Envelope', - infoText: 'Envelope: Upper 191.29000Lower 156.51000', - }, - { name: 'EMA', infoText: 'EMA: 174.06793' }, - { name: 'Moving average', infoText: 'Moving average: 174.08302' }, - { - name: 'Price monitoring bounds', - infoText: - 'Price Monitoring Bounds 1: Min 162.56291Max 182.96869Reference 172.47489', - }, - ]; - - checkMenuItemCheckbox('Overlays', overlayInfo); - }); - - it('Studies', () => { - // 6004-CHAR-005 - // 6004-CHAR-006 - // 6004-CHAR-007 - // 6004-CHAR-042 - // 6004-CHAR-045 - // 6004-CHAR-047 - // 6004-CHAR-049 - // 6004-CHAR-051 - const studyInfo: ItemInfoType[] = [ - { - name: 'Eldar-ray', - infoText: 'Eldar-ray: Bull -0.08376Bear -0.58376', - }, - { name: 'Force index', infoText: 'Force index: 987.48858' }, - { name: 'MACD', infoText: 'MACD: S -0.06420D 0.00359MACD -0.06062' }, - { name: 'RSI', infoText: 'RSI: 47.08648' }, - { name: 'Volume', infoText: 'Volume: 55,000' }, - ]; - cy.get(indicatorInfo).eq(1).realHover(); - cy.get('.chart__wrapper [data-testid="split-view-view"]') - .last() - .find('[role="button"][title="Close"]') - .click({ force: true }); - cy.get(indicatorInfo).should('have.length', 1); - - checkMenuItemCheckbox('Studies', studyInfo); - }); - - it('price details', () => { - // 6004-CHAR-010 - const expectedDateRegex = new RegExp( - /^\d{2}:\d{2} \d{2} [A-Za-z]{3} \d{4}$/ - ); - const expectedOhlc = `O 173.60000H 174.00000L 173.50000C 173.90000Change −0.60000(−0.34%)`; - cy.get(indicatorInfo) - .eq(0) - .invoke('text') - .then((text) => { - const actualDate = text.slice(0, -67); - // eslint-disable-next-line no-console - console.log(actualDate); - const actualOhlc = text.slice(-67); - assert.isTrue(expectedDateRegex.test(actualDate)); - assert.strictEqual(actualOhlc, expectedOhlc); - }); - }); - } -); From 6d130c9cfc6b19c384cb1f35e91e2d04f57ff1c0 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Tue, 22 Aug 2023 11:17:10 +0200 Subject: [PATCH 05/14] feat(positions): filter closed markets in positions table (#4569) --- .../client-pages/market/trade-grid.tsx | 6 +++- .../client-pages/market/trade-views.tsx | 7 +++- .../positions-container.tsx | 33 ++++++++++++++++--- .../components/positions-menu/index.ts | 1 + .../positions-menu/positions-menu.tsx | 18 ++++++++++ .../src/lib/positions-data-providers.spec.ts | 32 +++++++++++++++++- .../src/lib/positions-data-providers.ts | 28 ++++++++++++++-- libs/positions/src/lib/positions-manager.tsx | 6 ++-- .../src/lib/positions-table.spec.tsx | 1 + libs/positions/src/lib/positions-table.tsx | 4 +-- specs/7004-POSI-positions.md | 6 +++- 11 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 apps/trading/components/positions-menu/index.ts create mode 100644 apps/trading/components/positions-menu/positions-menu.tsx diff --git a/apps/trading/client-pages/market/trade-grid.tsx b/apps/trading/client-pages/market/trade-grid.tsx index b316a3f54..ab64f77b1 100644 --- a/apps/trading/client-pages/market/trade-grid.tsx +++ b/apps/trading/client-pages/market/trade-grid.tsx @@ -94,7 +94,11 @@ const MainGrid = memo( > - + } + > ( diff --git a/apps/trading/components/positions-container/positions-container.tsx b/apps/trading/components/positions-container/positions-container.tsx index 518f7c2d6..f830d4666 100644 --- a/apps/trading/components/positions-container/positions-container.tsx +++ b/apps/trading/components/positions-container/positions-container.tsx @@ -5,6 +5,7 @@ import { Splash } from '@vegaprotocol/ui-toolkit'; import { useVegaWallet } from '@vegaprotocol/wallet'; import type { DataGridSlice } from '../../stores/datagrid-store-slice'; import { createDataGridSlice } from '../../stores/datagrid-store-slice'; +import type { StateCreator } from 'zustand'; import { create } from 'zustand'; import { persist } from 'zustand/middleware'; import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler'; @@ -13,6 +14,7 @@ export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => { const onMarketClick = useMarketClickHandler(true); const { pubKey, pubKeys, isReadOnly } = useVegaWallet(); + const showClosed = usePositionsStore((store) => store.showClosedMarkets); const gridStore = usePositionsStore((store) => store.gridStore); const updateGridStore = usePositionsStore((store) => store.updateGridStore); const gridStoreCallbacks = useDataGridEvents(gridStore, updateGridStore); @@ -40,12 +42,35 @@ export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => { onMarketClick={onMarketClick} isReadOnly={isReadOnly} gridProps={gridStoreCallbacks} + showClosed={showClosed} /> ); }; -const usePositionsStore = create()( - persist(createDataGridSlice, { - name: 'vega_positions_store', - }) +type PositionsStoreSlice = { + showClosedMarkets: boolean; + toggleClosedMarkets: () => void; +}; + +const createPositionStoreSlice: StateCreator = (set) => ({ + showClosedMarkets: false, + toggleClosedMarkets: () => { + set((curr) => { + return { + showClosedMarkets: !curr.showClosedMarkets, + }; + }); + }, +}); + +export const usePositionsStore = create()( + persist( + (...args) => ({ + ...createPositionStoreSlice(...args), + ...createDataGridSlice(...args), + }), + { + name: 'vega_positions_store', + } + ) ); diff --git a/apps/trading/components/positions-menu/index.ts b/apps/trading/components/positions-menu/index.ts new file mode 100644 index 000000000..12fc9ea53 --- /dev/null +++ b/apps/trading/components/positions-menu/index.ts @@ -0,0 +1 @@ +export * from './positions-menu'; diff --git a/apps/trading/components/positions-menu/positions-menu.tsx b/apps/trading/components/positions-menu/positions-menu.tsx new file mode 100644 index 000000000..58dddee7b --- /dev/null +++ b/apps/trading/components/positions-menu/positions-menu.tsx @@ -0,0 +1,18 @@ +import { t } from '@vegaprotocol/i18n'; +import { Intent, TradingButton } from '@vegaprotocol/ui-toolkit'; +import { usePositionsStore } from '../positions-container'; + +export const PositionsMenu = () => { + const showClosed = usePositionsStore((store) => store.showClosedMarkets); + const toggle = usePositionsStore((store) => store.toggleClosedMarkets); + return ( + + {showClosed ? t('Hide closed markets') : t('Show closed markets')} + + ); +}; diff --git a/libs/positions/src/lib/positions-data-providers.spec.ts b/libs/positions/src/lib/positions-data-providers.spec.ts index a8ca0aaa9..6c1f67093 100644 --- a/libs/positions/src/lib/positions-data-providers.spec.ts +++ b/libs/positions/src/lib/positions-data-providers.spec.ts @@ -2,7 +2,12 @@ import * as Schema from '@vegaprotocol/types'; import type { Account } from '@vegaprotocol/accounts'; import type { MarketWithData } from '@vegaprotocol/markets'; import type { PositionFieldsFragment } from './__generated__/Positions'; -import { getMetrics, rejoinPositionData } from './positions-data-providers'; +import type { Position } from './positions-data-providers'; +import { + getMetrics, + preparePositions, + rejoinPositionData, +} from './positions-data-providers'; import { PositionStatus } from '@vegaprotocol/types'; const accounts = [ @@ -223,4 +228,29 @@ describe('getMetrics && rejoinPositionData', () => { ); expect(metrics[1].status).toEqual(positions[1].positionStatus); }); + + it('sorts and filters positions', () => { + const createPosition = (override?: Partial) => + ({ + marketState: Schema.MarketState.STATE_ACTIVE, + marketCode: 'a', + ...override, + } as Position); + + const data = [ + createPosition(), + createPosition({ + marketCode: 'c', + marketState: Schema.MarketState.STATE_CANCELLED, + }), + createPosition({ marketCode: 'd' }), + createPosition({ marketCode: 'b' }), + ]; + + const withoutClosed = preparePositions(data, false); + expect(withoutClosed.map((p) => p.marketCode)).toEqual(['a', 'b', 'd']); + + const withClosed = preparePositions(data, true); + expect(withClosed.map((p) => p.marketCode)).toEqual(['a', 'b', 'c', 'd']); + }); }); diff --git a/libs/positions/src/lib/positions-data-providers.ts b/libs/positions/src/lib/positions-data-providers.ts index 8d44c0941..d5c533b83 100644 --- a/libs/positions/src/lib/positions-data-providers.ts +++ b/libs/positions/src/lib/positions-data-providers.ts @@ -41,6 +41,7 @@ export interface Position { marketId: string; marketCode: string; marketTradingMode: Schema.MarketTradingMode; + marketState: Schema.MarketState; markPrice: string | undefined; notional: string | undefined; openVolume: string; @@ -119,6 +120,7 @@ export const getMetrics = ( marketId: market.id, marketCode: market.tradableInstrument.instrument.code, marketTradingMode: market.tradingMode, + marketState: market.state, markPrice: marketData ? marketData.markPrice : undefined, notional: notional ? notional.multipliedBy(10 ** marketDecimalPlaces).toFixed(0) @@ -248,6 +250,26 @@ export const rejoinPositionData = ( return null; }; +export const preparePositions = (metrics: Position[], showClosed: boolean) => { + return sortBy(metrics, 'marketCode').filter((p) => { + if (showClosed) { + return true; + } + + if ( + [ + Schema.MarketState.STATE_ACTIVE, + Schema.MarketState.STATE_PENDING, + Schema.MarketState.STATE_SUSPENDED, + ].includes(p.marketState) + ) { + return true; + } + + return false; + }); +}; + export const positionsMarketsProvider = makeDerivedDataProvider< string[], never, @@ -265,7 +287,7 @@ export const positionsMarketsProvider = makeDerivedDataProvider< export const positionsMetricsProvider = makeDerivedDataProvider< Position[], Position[], - PositionsQueryVariables & { marketIds: string[] } + PositionsQueryVariables & { marketIds: string[]; showClosed: boolean } >( [ (callback, client, variables) => @@ -281,10 +303,10 @@ export const positionsMetricsProvider = makeDerivedDataProvider< marketIds: variables.marketIds, }), ], - ([positions, accounts, marketsData]) => { + ([positions, accounts, marketsData], variables) => { const positionsData = rejoinPositionData(positions, marketsData); const metrics = getMetrics(positionsData, accounts as Account[] | null); - return sortBy(metrics, 'marketCode'); + return preparePositions(metrics, variables.showClosed); }, (data, delta, previousData) => data.filter((row) => { diff --git a/libs/positions/src/lib/positions-manager.tsx b/libs/positions/src/lib/positions-manager.tsx index f01f71cfa..521ae1b45 100644 --- a/libs/positions/src/lib/positions-manager.tsx +++ b/libs/positions/src/lib/positions-manager.tsx @@ -16,6 +16,7 @@ interface PositionsManagerProps { onMarketClick?: (marketId: string) => void; isReadOnly: boolean; gridProps?: ReturnType; + showClosed?: boolean; } export const PositionsManager = ({ @@ -23,6 +24,7 @@ export const PositionsManager = ({ onMarketClick, isReadOnly, gridProps, + showClosed = false, }: PositionsManagerProps) => { const { pubKeys, pubKey } = useVegaWallet(); const create = useVegaTransactionStore((store) => store.create); @@ -60,7 +62,7 @@ export const PositionsManager = ({ const { data, error } = useDataProvider({ dataProvider: positionsMetricsProvider, - variables: { partyIds, marketIds: marketIds || [] }, + variables: { partyIds, marketIds: marketIds || [], showClosed }, skip: !marketIds, }); @@ -68,7 +70,7 @@ export const PositionsManager = ({ ); }, - minWidth: 75, - maxWidth: 75, + minWidth: 55, + maxWidth: 55, } : null, ]; diff --git a/specs/7004-POSI-positions.md b/specs/7004-POSI-positions.md index 3bcb69493..5965f24f8 100644 --- a/specs/7004-POSI-positions.md +++ b/specs/7004-POSI-positions.md @@ -51,4 +51,8 @@ - **Must** be able to see if your realised PnL was affected by loss socialisation (7004-POSI-018) -- **Must** Must be able to see what type of product the position was opened on (7004-POSI-019) +- **Must** be able to see what type of product the position was opened on (7004-POSI-019) + +- **Must** not see positions on markets which are closed (7004-POSI-020) + +- **Must** be able to show closed markets (7004-POSI-021) From d2854b6e90cdf9c1a2436eb54a77d9783d36bfa2 Mon Sep 17 00:00:00 2001 From: Joe Tsang <30622993+jtsang586@users.noreply.github.com> Date: Tue, 22 Aug 2023 12:06:41 +0100 Subject: [PATCH 06/14] chore(governance): add acs for network nodes (#4577) --- .../src/integration/view/home.cy.ts | 33 +++++++++++++++++++ specs/1005-VEST-vesting.md | 1 - 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/governance-e2e/src/integration/view/home.cy.ts b/apps/governance-e2e/src/integration/view/home.cy.ts index a84b15846..dc080b0ad 100644 --- a/apps/governance-e2e/src/integration/view/home.cy.ts +++ b/apps/governance-e2e/src/integration/view/home.cy.ts @@ -119,6 +119,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () { }); }); + // 0006-NETW-001 0006-NETW-002 it('should display network data', function () { cy.getByTestId('git-network-data') .should('contain.text', 'Reading network data from') @@ -130,6 +131,37 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () { }); }); + // 0006-NETW-003 0006-NETW-008 0006-NETW-009 0006-NETW-010 0006-NETW-012 0006-NETW-013 0006-NETW-017 0006-NETW-018 0006-NETW-019 0006-NETW-020 + it('should have option to switch to different network node', function () { + cy.getByTestId('git-network-data').within(() => { + cy.getByTestId('link').click(); + }); + cy.getByTestId('node-row').within(() => { + cy.getByTestId('node-url-0') + .parent() + .should('have.text', 'http://localhost:3008/graphql'); + cy.getByTestId('response-time-cell') + .invoke('text') + .should('not.be.empty') + .and('not.eq', 'Checking'); + cy.getByTestId('block-height-cell') + .invoke('text') + .should('not.be.empty') + .then((currentBlockHeight) => { + // Check that block height updates automatically + cy.getByTestId('block-height-cell') + .invoke('text') + .should('not.eq', currentBlockHeight); + }); + cy.getByTestId('subscription-cell').should('have.text', 'Yes'); + }); + cy.getByTestId('connect').should('be.disabled'); + cy.getByTestId('node-url-custom').click(); + cy.get('input').should('exist'); + cy.getByTestId('connect').should('be.disabled'); + cy.getByTestId('icon-cross').click(); + }); + it('should display eth data', function () { cy.getByTestId('git-eth-data') .should('contain.text', 'Reading Ethereum data from') @@ -138,6 +170,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () { }); }); + // 0006-NETW-011 it('should contain link for known issues on Github', function () { cy.getByTestId('git-info').within(() => { cy.contains('Known issues and feedback on') diff --git a/specs/1005-VEST-vesting.md b/specs/1005-VEST-vesting.md index 819c4d4b2..23157e85b 100644 --- a/specs/1005-VEST-vesting.md +++ b/specs/1005-VEST-vesting.md @@ -53,7 +53,6 @@ for the a given Ethereum wallet/address/key: - **must** see how many tokens in each tranche are locked 1005-VEST-025 - **must** see how many tokens in each tranche are redeemable 1005-VEST-026 - **must** see an option to redeem from tranche 1005-VEST-027 - - **must** be warned if amount that can be redeemed from that tranche is greater than the un-associated balance for that Eth key (because this will cause the redeem function to fail) 1005-VEST-028 - **should** see how many tokens I'd need to disassociate to be able to run the redeem function (this should be rounded up to avoid the transaction failing due to more tokens having unlocked since the user looked at the form) - **should** see link to [disassociate](1004-ASSO-associate.md) From 3e627ff849ab38f9ef6b4f507e12322b6757c55a Mon Sep 17 00:00:00 2001 From: Edd Date: Tue, 22 Aug 2023 14:08:00 +0100 Subject: [PATCH 07/14] fix(explorer): check linking type when summing stake (#4585) --- .../routes/parties/id/Party-assets.graphql | 31 ------------------- .../parties/id/__generated__/Party-assets.ts | 4 +-- .../id/components/party-block-stake.tsx | 6 ++-- 3 files changed, 5 insertions(+), 36 deletions(-) diff --git a/apps/explorer/src/app/routes/parties/id/Party-assets.graphql b/apps/explorer/src/app/routes/parties/id/Party-assets.graphql index 6d30cc986..1021cfc78 100644 --- a/apps/explorer/src/app/routes/parties/id/Party-assets.graphql +++ b/apps/explorer/src/app/routes/parties/id/Party-assets.graphql @@ -29,37 +29,6 @@ fragment ExplorerPartyAssetsAccounts on AccountBalance { } } -fragment ExplorerPartyLinks on AccountBalance { - asset { - name - id - decimals - symbol - source { - __typename - ... on ERC20 { - contractAddress - } - } - } - type - balance - market { - id - decimalPlaces - tradableInstrument { - instrument { - name - product { - ... on Future { - quoteName - } - } - } - } - } -} - query ExplorerPartyAssets($partyId: ID!) { partiesConnection(id: $partyId) { edges { diff --git a/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts b/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts index 1f6b6262d..dfe632305 100644 --- a/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts +++ b/apps/explorer/src/app/routes/parties/id/__generated__/Party-assets.ts @@ -64,7 +64,7 @@ export const ExplorerPartyAssetsDocument = gql` } stakingSummary { currentStakeAvailable - linkings(pagination: {first: 100}) { + linkings(pagination: {last: 100}) { edges { node { type @@ -113,4 +113,4 @@ export function useExplorerPartyAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHo } export type ExplorerPartyAssetsQueryHookResult = ReturnType; export type ExplorerPartyAssetsLazyQueryHookResult = ReturnType; -export type ExplorerPartyAssetsQueryResult = Apollo.QueryResult; +export type ExplorerPartyAssetsQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx b/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx index 5121f1ff1..6b45e73a5 100644 --- a/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx +++ b/apps/explorer/src/app/routes/parties/id/components/party-block-stake.tsx @@ -42,14 +42,14 @@ export const PartyBlockStake = ({ linkedLength && linkedLength > 0 ? p?.stakingSummary?.linkings?.edges ?.reduce((total, e) => { - const accumulator = new BigNumber(total) - const diff = new BigNumber(e?.node.amount || 0) + const accumulator = new BigNumber(total); + const diff = new BigNumber(e?.node.amount || 0); if (e?.node.type === 'TYPE_LINK') { return accumulator.plus(diff); } else if (e?.node.type === 'TYPE_UNLINK') { return accumulator.minus(diff); } else { - return accumulator + return accumulator; } }, new BigNumber(0)) .toString() From 80f7a08765c61b706c627404b05f23b77c27bb13 Mon Sep 17 00:00:00 2001 From: Joe Tsang <30622993+jtsang586@users.noreply.github.com> Date: Tue, 22 Aug 2023 16:15:33 +0100 Subject: [PATCH 08/14] test(governance): vote error test (#4588) --- .../integration/flow/proposal-details.cy.ts | 28 +++++++++++++++++++ .../src/support/staking.functions.ts | 5 ++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts b/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts index cef462d61..13b7e19bb 100644 --- a/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts +++ b/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts @@ -361,6 +361,34 @@ describe( stakingPageDisassociateAllTokens(); }); + it('Error message should be displayed if error returned from wallet when voting', function () { + const errorMsg = + 'Application error: party has already submitted the maximum number of transactions of this type per epoch (3)'; + + createRawProposal(); + cy.get('@rawProposal').then((rawProposal) => { + getProposalFromTitle(rawProposal.rationale.title).within(() => + cy.getByTestId(viewProposalButton).click() + ); + cy.intercept('POST', '/api/v2/requests', { + jsonrpc: '2.0', + error: { + code: 2001, + message: 'Application error', + data: 'party has already submitted the maximum number of transactions of this type per epoch (3)', + }, + id: '-PK5EGmErnjLhAmzMeclC', + }); + cy.contains('Vote breakdown').should('be.visible', { timeout: 10000 }); + cy.getByTestId('vote-buttons').contains('for').click(); + cy.getByTestId('dialog-title').should( + 'have.text', + 'Transaction failed' + ); + cy.getByTestId('Error').should('have.text', errorMsg); + }); + }); + it('Able to see successor market details with new and updated values', function () { cy.createMarket(); cy.reload(); diff --git a/apps/governance-e2e/src/support/staking.functions.ts b/apps/governance-e2e/src/support/staking.functions.ts index 4f99e0964..cd198783d 100644 --- a/apps/governance-e2e/src/support/staking.functions.ts +++ b/apps/governance-e2e/src/support/staking.functions.ts @@ -183,9 +183,8 @@ export function clickOnValidatorFromList( cy.get(`[row-id="${validatorNumber}"]`) .should('be.visible') .first() - .within(() => { - cy.get(stakeValidatorListName).click(); - }); + .as('validatorOnList'); + cy.get('@validatorOnList').click(); } } From e0a91b3850b71d3dcddf02d1f118eca398547925 Mon Sep 17 00:00:00 2001 From: "m.ray" <16125548+MadalinaRaicu@users.noreply.github.com> Date: Tue, 22 Aug 2023 19:23:24 +0300 Subject: [PATCH 09/14] chore(trading): revert metadata update - viewport meta tags should not be used in _document.js's (#4591) --- apps/trading/pages/_document.page.tsx | 48 +++++----------------- apps/trading/pages/index.page.tsx | 58 ++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 40 deletions(-) diff --git a/apps/trading/pages/_document.page.tsx b/apps/trading/pages/_document.page.tsx index 9a2552e07..53c42fb1a 100644 --- a/apps/trading/pages/_document.page.tsx +++ b/apps/trading/pages/_document.page.tsx @@ -1,40 +1,10 @@ -import { Html, Head, Main, NextScript } from 'next/document'; +import { Head, Html, Main, NextScript } from 'next/document'; export default function Document() { return ( - + <> - - - - - - - - - - - - - - - - - - - - - {/* eslint-disable-next-line @next/next/no-css-tags */} -