From de48ffa56337f598558c5603414898209424a669 Mon Sep 17 00:00:00 2001 From: Sam Keen Date: Tue, 2 May 2023 11:10:03 +0100 Subject: [PATCH] feat(governance): update market proposal only available for enacted markets (#3542) --- .../update-market/UpdateMarket.graphql | 3 + .../__generated__/UpdateMarket.ts | 5 +- .../__generated___/UpdateMarket.ts | 94 --------------- .../propose-update-market.spec.tsx | 112 ++++++++++++++++-- .../update-market/propose-update-market.tsx | 16 ++- 5 files changed, 122 insertions(+), 108 deletions(-) delete mode 100644 apps/governance/src/routes/proposals/propose/update-market/__generated___/UpdateMarket.ts diff --git a/apps/governance/src/routes/proposals/propose/update-market/UpdateMarket.graphql b/apps/governance/src/routes/proposals/propose/update-market/UpdateMarket.graphql index a338ec489..4c24091ca 100644 --- a/apps/governance/src/routes/proposals/propose/update-market/UpdateMarket.graphql +++ b/apps/governance/src/routes/proposals/propose/update-market/UpdateMarket.graphql @@ -9,6 +9,9 @@ query ProposalMarketsQuery { code } } + proposal { + state + } } } } diff --git a/apps/governance/src/routes/proposals/propose/update-market/__generated__/UpdateMarket.ts b/apps/governance/src/routes/proposals/propose/update-market/__generated__/UpdateMarket.ts index e9e984537..ce50d970a 100644 --- a/apps/governance/src/routes/proposals/propose/update-market/__generated__/UpdateMarket.ts +++ b/apps/governance/src/routes/proposals/propose/update-market/__generated__/UpdateMarket.ts @@ -6,7 +6,7 @@ const defaultOptions = {} as const; export type ProposalMarketsQueryQueryVariables = Types.Exact<{ [key: string]: never; }>; -export type ProposalMarketsQueryQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string } } } }> } | null }; +export type ProposalMarketsQueryQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string } }, proposal?: { __typename?: 'Proposal', state: Types.ProposalState } | null } }> } | null }; export const ProposalMarketsQueryDocument = gql` @@ -21,6 +21,9 @@ export const ProposalMarketsQueryDocument = gql` code } } + proposal { + state + } } } } diff --git a/apps/governance/src/routes/proposals/propose/update-market/__generated___/UpdateMarket.ts b/apps/governance/src/routes/proposals/propose/update-market/__generated___/UpdateMarket.ts deleted file mode 100644 index 1454716f4..000000000 --- a/apps/governance/src/routes/proposals/propose/update-market/__generated___/UpdateMarket.ts +++ /dev/null @@ -1,94 +0,0 @@ -import * as Types from '@vegaprotocol/types'; - -import { gql } from '@apollo/client'; -import * as Apollo from '@apollo/client'; -const defaultOptions = {} as const; -export type ProposalMarketsQueryQueryVariables = Types.Exact<{ - [key: string]: never; -}>; - -export type ProposalMarketsQueryQuery = { - __typename?: 'Query'; - marketsConnection?: { - __typename?: 'MarketConnection'; - edges: Array<{ - __typename?: 'MarketEdge'; - node: { - __typename?: 'Market'; - id: string; - tradableInstrument: { - __typename?: 'TradableInstrument'; - instrument: { __typename?: 'Instrument'; name: string; code: string }; - }; - }; - }>; - } | null; -}; - -export const ProposalMarketsQueryDocument = gql` - query ProposalMarketsQuery { - marketsConnection { - edges { - node { - id - tradableInstrument { - instrument { - name - code - } - } - } - } - } - } -`; - -/** - * __useProposalMarketsQueryQuery__ - * - * To run a query within a React component, call `useProposalMarketsQueryQuery` and pass it any options that fit your needs. - * When your component renders, `useProposalMarketsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useProposalMarketsQueryQuery({ - * variables: { - * }, - * }); - */ -export function useProposalMarketsQueryQuery( - baseOptions?: Apollo.QueryHookOptions< - ProposalMarketsQueryQuery, - ProposalMarketsQueryQueryVariables - > -) { - const options = { ...defaultOptions, ...baseOptions }; - return Apollo.useQuery< - ProposalMarketsQueryQuery, - ProposalMarketsQueryQueryVariables - >(ProposalMarketsQueryDocument, options); -} -export function useProposalMarketsQueryLazyQuery( - baseOptions?: Apollo.LazyQueryHookOptions< - ProposalMarketsQueryQuery, - ProposalMarketsQueryQueryVariables - > -) { - const options = { ...defaultOptions, ...baseOptions }; - return Apollo.useLazyQuery< - ProposalMarketsQueryQuery, - ProposalMarketsQueryQueryVariables - >(ProposalMarketsQueryDocument, options); -} -export type ProposalMarketsQueryQueryHookResult = ReturnType< - typeof useProposalMarketsQueryQuery ->; -export type ProposalMarketsQueryLazyQueryHookResult = ReturnType< - typeof useProposalMarketsQueryLazyQuery ->; -export type ProposalMarketsQueryQueryResult = Apollo.QueryResult< - ProposalMarketsQueryQuery, - ProposalMarketsQueryQueryVariables ->; diff --git a/apps/governance/src/routes/proposals/propose/update-market/propose-update-market.spec.tsx b/apps/governance/src/routes/proposals/propose/update-market/propose-update-market.spec.tsx index 2b8f6776f..23506cc0f 100644 --- a/apps/governance/src/routes/proposals/propose/update-market/propose-update-market.spec.tsx +++ b/apps/governance/src/routes/proposals/propose/update-market/propose-update-market.spec.tsx @@ -1,15 +1,16 @@ import type { MockedResponse } from '@apollo/client/testing'; import { MockedProvider } from '@apollo/client/testing'; import { MemoryRouter as Router } from 'react-router-dom'; -import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { VegaWalletContext } from '@vegaprotocol/wallet'; import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider'; import { mockWalletContext } from '../../test-helpers/mocks'; import { ProposeUpdateMarket } from './propose-update-market'; import type { NetworkParamsQuery } from '@vegaprotocol/react-helpers'; import { NetworkParamsDocument } from '@vegaprotocol/react-helpers'; -import type { ProposalMarketsQueryQuery } from './__generated___/UpdateMarket'; -import { ProposalMarketsQueryDocument } from './__generated___/UpdateMarket'; +import type { ProposalMarketsQueryQuery } from './__generated__/UpdateMarket'; +import { ProposalMarketsQueryDocument } from './__generated__/UpdateMarket'; +import { ProposalState } from '@vegaprotocol/types'; const updateMarketNetworkParamsQueryMock: MockedResponse = { request: { @@ -89,6 +90,10 @@ const marketQueryMock: MockedResponse = { code: 'ETHiUSDT', }, }, + proposal: { + __typename: 'Proposal', + state: ProposalState.STATE_ENACTED, + }, }, }, { @@ -101,11 +106,16 @@ const marketQueryMock: MockedResponse = { instrument: { __typename: 'Instrument', name: 'Las Vegas nuggets', - code: 'Nuggets2', + code: 'Nuggets', }, }, + proposal: { + __typename: 'Proposal', + state: ProposalState.STATE_OPEN, + }, }, }, + { __typename: 'MarketEdge', node: { @@ -115,10 +125,14 @@ const marketQueryMock: MockedResponse = { __typename: 'TradableInstrument', instrument: { __typename: 'Instrument', - name: 'Nuggets', - code: 'Nuggets', + name: 'California Nuggets', + code: 'Nuggets2', }, }, + proposal: { + __typename: 'Proposal', + state: ProposalState.STATE_WAITING_FOR_NODE_VOTE, + }, }, }, { @@ -130,10 +144,71 @@ const marketQueryMock: MockedResponse = { __typename: 'TradableInstrument', instrument: { __typename: 'Instrument', - name: 'CELUSD (June 2022)', - code: 'CELUSD', + name: 'Nevada Nuggets', + code: 'Nugetts3', }, }, + proposal: { + __typename: 'Proposal', + state: ProposalState.STATE_REJECTED, + }, + }, + }, + { + __typename: 'MarketEdge', + node: { + __typename: 'Market', + id: 'asdfe1755208914b6f258a28babd19ae8dfbaf4084d8867d8a120c50dca1e17f', + tradableInstrument: { + __typename: 'TradableInstrument', + instrument: { + __typename: 'Instrument', + name: 'NZ Nuggets', + code: 'Nugetts4', + }, + }, + proposal: { + __typename: 'Proposal', + state: ProposalState.STATE_DECLINED, + }, + }, + }, + { + __typename: 'MarketEdge', + node: { + __typename: 'Market', + id: 'asdfe1755208914b6f258a28babd19ae8dfbaf4084d8867d8a120c50dca1e17f', + tradableInstrument: { + __typename: 'TradableInstrument', + instrument: { + __typename: 'Instrument', + name: 'Aussie Nuggets', + code: 'Nugetts5', + }, + }, + proposal: { + __typename: 'Proposal', + state: ProposalState.STATE_PASSED, + }, + }, + }, + { + __typename: 'MarketEdge', + node: { + __typename: 'Market', + id: 'xcvbe1755208914b6f258a28babd19ae8dfbaf4084d8867d8a120c50dca1e17f', + tradableInstrument: { + __typename: 'TradableInstrument', + instrument: { + __typename: 'Instrument', + name: 'Tasmanian Nuggets', + code: 'Nugetts6', + }, + }, + proposal: { + __typename: 'Proposal', + state: ProposalState.STATE_FAILED, + }, }, }, ], @@ -199,6 +274,27 @@ describe('Propose Update Market', () => { expect(screen.getByTestId('proposal-market-select')).toHaveValue(''); }); + it('should only render enacted markets', async () => { + renderComponent(); + expect( + await screen.findByText('Update market proposal') + ).toBeInTheDocument(); + // (state enacted) + expect(screen.getByText('ETHUSD (September Market)')).toBeInTheDocument(); + // (state open) + expect(screen.queryByText('Las Vegas nuggets')).not.toBeInTheDocument(); + // (state waiting for node vote) + expect(screen.queryByText('California nuggets')).not.toBeInTheDocument(); + // (state rejected) + expect(screen.queryByText('Nevada nuggets')).not.toBeInTheDocument(); + // (state declined) + expect(screen.queryByText('NZ nuggets')).not.toBeInTheDocument(); + // (state passed) + expect(screen.queryByText('Aussie nuggets')).not.toBeInTheDocument(); + // (state failed) + expect(screen.queryByText('Tasmanian nuggets')).not.toBeInTheDocument(); + }); + it('should render the correct market details when the market select is used', async () => { renderComponent(); expect( diff --git a/apps/governance/src/routes/proposals/propose/update-market/propose-update-market.tsx b/apps/governance/src/routes/proposals/propose/update-market/propose-update-market.tsx index 8e5d99018..08732f8fb 100644 --- a/apps/governance/src/routes/proposals/propose/update-market/propose-update-market.tsx +++ b/apps/governance/src/routes/proposals/propose/update-market/propose-update-market.tsx @@ -2,25 +2,28 @@ import { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useForm } from 'react-hook-form'; import { + doesValueEquateToParam, getClosingTimestamp, getEnactmentTimestamp, useProposalSubmit, - doesValueEquateToParam, } from '@vegaprotocol/proposals'; import { useEnvironment } from '@vegaprotocol/environment'; import { createDocsLinks, validateJson } from '@vegaprotocol/utils'; import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers'; import { ProposalFormDescription, + ProposalFormDownloadJson, ProposalFormSubheader, ProposalFormSubmit, ProposalFormTerms, ProposalFormTitle, ProposalFormTransactionDialog, - ProposalFormDownloadJson, ProposalFormVoteAndEnactmentDeadline, } from '../../components/propose'; -import { ProposalMinRequirements } from '../../components/shared'; +import { + ProposalMinRequirements, + ProposalUserAction, +} from '../../components/shared'; import { AsyncRenderer, ExternalLink, @@ -31,9 +34,9 @@ import { Select, } from '@vegaprotocol/ui-toolkit'; import { Heading } from '../../../../components/heading'; -import { ProposalUserAction } from '../../components/shared'; -import { useProposalMarketsQueryQuery } from './__generated___/UpdateMarket'; +import { useProposalMarketsQueryQuery } from './__generated__/UpdateMarket'; import { downloadJson } from '../../../../lib/download-json'; +import { ProposalState } from '@vegaprotocol/types'; export interface UpdateMarketProposalFormFields { proposalVoteDeadline: string; @@ -73,6 +76,9 @@ export const ProposeUpdateMarket = () => { return marketsData.marketsConnection.edges .map((edge) => edge.node) + .filter( + (market) => market.proposal?.state === ProposalState.STATE_ENACTED + ) .sort((a, b) => { const aName = a.tradableInstrument.instrument.name; const bName = b.tradableInstrument.instrument.name;