feat(577): view new market proposals (#2078)
* feat: market proposal selector * feat: market proposal selector * feat: market proposal selector * feat: market proposal selector * feat: market proposal selector - fix linters * feat: market proposal selector - add some int tests * feat: market proposal selector - add some unit tests * feat: market proposal selector - improve union type extracting * feat: market proposal selector - fix failing on develop e2e tests * feat: market proposal selector - fix failing on develop e2e tests * feat: market proposal selector - fix failing on develop e2e tests * feat: market proposal selector - fix failing on develop e2e tests * feat: market proposal selector - fix failing on develop e2e tests
This commit is contained in:
parent
d1b45a65a0
commit
52e1757d33
@ -8,7 +8,7 @@ export const generateChainId = (
|
|||||||
const defaultResult = {
|
const defaultResult = {
|
||||||
statistics: {
|
statistics: {
|
||||||
__typename: 'Statistics',
|
__typename: 'Statistics',
|
||||||
chainId: 'test-chain-id',
|
chainId: Cypress.env('VEGA_ENV').toLowerCase() || 'test-chain-id',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ export const generateStatistics = (
|
|||||||
const defaultResult = {
|
const defaultResult = {
|
||||||
statistics: {
|
statistics: {
|
||||||
__typename: 'Statistics',
|
__typename: 'Statistics',
|
||||||
chainId: 'test-chain-id',
|
chainId: Cypress.env('VEGA_ENV').toLowerCase() || 'test-chain-id',
|
||||||
blockHeight: '11',
|
blockHeight: '11',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -2,13 +2,13 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { ProposalState } from '@vegaprotocol/types';
|
import { ProposalState } from '@vegaprotocol/types';
|
||||||
|
import { VoteProgress } from '@vegaprotocol/governance';
|
||||||
import { formatNumber } from '../../../../lib/format-number';
|
import { formatNumber } from '../../../../lib/format-number';
|
||||||
import { ConnectToVega } from '../../../../components/connect-to-vega';
|
import { ConnectToVega } from '../../../../components/connect-to-vega';
|
||||||
import { useVoteInformation } from '../../hooks';
|
import { useVoteInformation } from '../../hooks';
|
||||||
import { useUserVote } from './use-user-vote';
|
import { useUserVote } from './use-user-vote';
|
||||||
import { CurrentProposalStatus } from '../current-proposal-status';
|
import { CurrentProposalStatus } from '../current-proposal-status';
|
||||||
import { VoteButtonsContainer } from './vote-buttons';
|
import { VoteButtonsContainer } from './vote-buttons';
|
||||||
import { VoteProgress } from './vote-progress';
|
|
||||||
import { ProposalType } from '../proposal/proposal';
|
import { ProposalType } from '../proposal/proposal';
|
||||||
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
|
@ -60,6 +60,37 @@ describe('markets table', { tags: '@smoke' }, () => {
|
|||||||
.should('have.text', ExpectedSortedMarkets[i]);
|
.should('have.text', ExpectedSortedMarkets[i]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('proposed markets tab should be rendered properly', () => {
|
||||||
|
cy.getByTestId('view-market-list-link')
|
||||||
|
.should('have.attr', 'href', '#/markets')
|
||||||
|
.click();
|
||||||
|
cy.get('[data-testid="Active markets"]').should(
|
||||||
|
'have.attr',
|
||||||
|
'data-state',
|
||||||
|
'active'
|
||||||
|
);
|
||||||
|
cy.get('[data-testid="Proposed markets"]').should(
|
||||||
|
'have.attr',
|
||||||
|
'data-state',
|
||||||
|
'inactive'
|
||||||
|
);
|
||||||
|
cy.get('[data-testid="Proposed markets"]').click();
|
||||||
|
cy.get('[data-testid="Proposed markets"]').should(
|
||||||
|
'have.attr',
|
||||||
|
'data-state',
|
||||||
|
'active'
|
||||||
|
);
|
||||||
|
cy.getByTestId('tab-proposed-markets').should('be.visible');
|
||||||
|
cy.get('.ag-body-viewport .ag-center-cols-container .ag-row').should(
|
||||||
|
'have.length',
|
||||||
|
10
|
||||||
|
);
|
||||||
|
cy.getByTestId('external-link').should('have.length', 11);
|
||||||
|
cy.getByTestId('external-link')
|
||||||
|
.eq(10)
|
||||||
|
.should('have.text', 'Propose a new market');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function openMarketDropDown() {
|
function openMarketDropDown() {
|
||||||
|
@ -34,6 +34,14 @@ export const generateNetworkParameters = (
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'governance.proposal.market.requiredMajority',
|
||||||
|
value: '0.66',
|
||||||
|
__typename: 'NetworkParameter',
|
||||||
|
},
|
||||||
|
__typename: 'NetworkParameterEdge',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
625
apps/trading-e2e/src/support/mocks/generate-proposals.ts
Normal file
625
apps/trading-e2e/src/support/mocks/generate-proposals.ts
Normal file
@ -0,0 +1,625 @@
|
|||||||
|
import type { ProposalsListQuery } from '@vegaprotocol/governance';
|
||||||
|
import { Schema } from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
const marketProposals: ProposalsListQuery = {
|
||||||
|
proposalsConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'e9ec6d5c46a7e7bcabf9ba7a893fa5a5eeeec08b731f06f7a6eb7bf0e605b829',
|
||||||
|
reference: 'injected_at_runtime',
|
||||||
|
state: Schema.ProposalState.STATE_OPEN,
|
||||||
|
datetime: '2022-11-15T12:38:55.901696Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '20000000000000000000000000',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-15T12:44:34Z',
|
||||||
|
enactmentDatetime: '2022-11-15T12:44:54Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'ETHUSD',
|
||||||
|
name: 'ETHUSD',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'b340c130096819428a62e5df407fd6abe66e444b89ad64f670beb98621c9c663',
|
||||||
|
name: 'tDAI TEST',
|
||||||
|
symbol: 'tDAI',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '1cd1deb532b97fbeb9262fe94499ecec5835e60ae564b7c5af530c90a13c29cb',
|
||||||
|
reference: 'injected_at_runtime',
|
||||||
|
state: Schema.ProposalState.STATE_REJECTED,
|
||||||
|
datetime: '2022-11-15T12:38:08.810603Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '0',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '0',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-15T12:39:41Z',
|
||||||
|
enactmentDatetime: '2022-11-15T12:39:51Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'ETHUSD',
|
||||||
|
name: 'ETHUSD',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'b340c130096819428a62e5df407fd6abe66e444b89ad64f670beb98621c9c663',
|
||||||
|
name: 'tDAI TEST',
|
||||||
|
symbol: 'tDAI',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'e503cadb437861037cddfd7263d25b69102098a97573db23f8e5fc320cea1ce9',
|
||||||
|
reference: 'injected_at_runtime',
|
||||||
|
state: Schema.ProposalState.STATE_PASSED,
|
||||||
|
datetime: '2022-11-14T16:18:57.437675Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '10000000000000000000000000',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-14T16:24:24Z',
|
||||||
|
enactmentDatetime: '2022-11-14T16:24:34Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'LINKUSD',
|
||||||
|
name: 'LINKUSD',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'eb30d55e90e1f9e5c4727d6fa2a5a8cd36ab9ae9738eb8f3faf53e2bee4861ee',
|
||||||
|
name: 'mUSDT-II',
|
||||||
|
symbol: 'mUSDT-II',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'e38415b453d862c246743fa979b877d97e2c9cbe160b6174e02c5589864817a0',
|
||||||
|
reference: 'injected_at_runtime',
|
||||||
|
state: Schema.ProposalState.STATE_REJECTED,
|
||||||
|
datetime: '2022-11-14T16:17:09.605382Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '0',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '0',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-11T16:32:22Z',
|
||||||
|
enactmentDatetime: '2022-11-11T16:32:32Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'LINKUSD',
|
||||||
|
name: 'LINKUSD',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'eb30d55e90e1f9e5c4727d6fa2a5a8cd36ab9ae9738eb8f3faf53e2bee4861ee',
|
||||||
|
name: 'mUSDT-II',
|
||||||
|
symbol: 'mUSDT-II',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'e3119d341022a401cc68ba3a7ead5c431028d0060b3a49fc115025d7784c646f',
|
||||||
|
reference: 'injected_at_runtime',
|
||||||
|
state: Schema.ProposalState.STATE_WAITING_FOR_NODE_VOTE,
|
||||||
|
datetime: '2022-11-14T09:35:54.040219Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '40000000000000000000000000',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-14T09:40:57Z',
|
||||||
|
enactmentDatetime: '2022-11-14T09:41:17Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'ETHUSD',
|
||||||
|
name: 'ETHUSD',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'b340c130096819428a62e5df407fd6abe66e444b89ad64f670beb98621c9c663',
|
||||||
|
name: 'tDAI TEST',
|
||||||
|
symbol: 'tDAI',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '07549b2cf93abbf6fb8ad976af3f24876e5946df85a3b6f0a6338672c7453bfa',
|
||||||
|
reference: 'injected_at_runtime',
|
||||||
|
state: Schema.ProposalState.STATE_ENACTED,
|
||||||
|
datetime: '2022-11-11T16:29:23.46877Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '0',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-11T16:32:22Z',
|
||||||
|
enactmentDatetime: '2022-11-11T16:32:32Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'LINKUSD',
|
||||||
|
name: 'LINKUSD',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'eb30d55e90e1f9e5c4727d6fa2a5a8cd36ab9ae9738eb8f3faf53e2bee4861ee',
|
||||||
|
name: 'mUSDT-II',
|
||||||
|
symbol: 'mUSDT-II',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'de48ad0adc668a80a074e790d118b6a64fa4909fc60ebbc2c335be3b675fec93',
|
||||||
|
reference: 'zMSg0drbaFnoM1kF8YdsbH28poqdsJr33rYwyETv',
|
||||||
|
state: Schema.ProposalState.STATE_OPEN,
|
||||||
|
datetime: '2022-11-11T16:27:05.914266Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '0',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-11T16:28:25Z',
|
||||||
|
enactmentDatetime: '2022-11-11T16:30:35Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'ETHDAI.MF21',
|
||||||
|
name: 'ETHDAI Monthly (Dec 2022)',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'b340c130096819428a62e5df407fd6abe66e444b89ad64f670beb98621c9c663',
|
||||||
|
name: 'tDAI TEST',
|
||||||
|
symbol: 'tDAI',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'c80c1cc89dcc5a302e443b7fcd215cdadbb259f6b180db6253a5572ad6406253',
|
||||||
|
reference: 'NlotxzM5Jg3LfEN1vYCxxQ5wcmUwfWAqQQtad3Se',
|
||||||
|
state: Schema.ProposalState.STATE_PASSED,
|
||||||
|
datetime: '2022-11-11T16:27:05.914266Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '20000000000000000000000000',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-11T16:28:25Z',
|
||||||
|
enactmentDatetime: '2022-11-11T16:30:35Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'AAPL.MF21',
|
||||||
|
name: 'Apple Monthly (Dec 2022)',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'c9fe6fc24fce121b2cc72680543a886055abb560043fda394ba5376203b7527d',
|
||||||
|
name: 'tUSDC TEST',
|
||||||
|
symbol: 'tUSDC',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'ad2e531441c2e8a43e85423db399a4acc8f9a8a2376304a4c377d0da8eb31e80',
|
||||||
|
reference: 'rVcSDJYfk3Ni6yi9ZwVcYXFaSA6miUZucHdzdGCv',
|
||||||
|
state: Schema.ProposalState.STATE_OPEN,
|
||||||
|
datetime: '2022-11-11T16:27:05.220442Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '35000000000000000000000000',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-11T16:28:25Z',
|
||||||
|
enactmentDatetime: '2022-11-11T16:30:35Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'BTCUSD.MF21',
|
||||||
|
name: 'BTCUSD Monthly (Dec 2022)',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'b340c130096819428a62e5df407fd6abe66e444b89ad64f670beb98621c9c663',
|
||||||
|
name: 'tDAI TEST',
|
||||||
|
symbol: 'tDAI',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'acff1b95980c3355e65c7162c35917388702525c0475ba753f03d0efc9c6d6a3',
|
||||||
|
reference: 'EMRU5vhlhKUFBx9D2sr4KWSS4PZhNhWEbRr8SMf7',
|
||||||
|
state: Schema.ProposalState.STATE_PASSED,
|
||||||
|
datetime: '2022-11-11T16:27:06.008336Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '0',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-11T16:28:25Z',
|
||||||
|
enactmentDatetime: '2022-11-11T16:30:35Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'TSLA.QM21',
|
||||||
|
name: 'Tesla Quarterly (Feb 2023)',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: '177e8f6c25a955bd18475084b99b2b1d37f28f3dec393fab7755a7e69c3d8c3b',
|
||||||
|
name: 'tEURO TEST',
|
||||||
|
symbol: 'tEURO',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '90e71c52b2f40db78efc24abe4217382993868cd24e45b3dd17147be4afaf884',
|
||||||
|
reference: '1HpOzeaQhW3OgLlMS4uFIzrOJcK0zaGMN2ccWpF7',
|
||||||
|
state: Schema.ProposalState.STATE_OPEN,
|
||||||
|
datetime: '2022-11-11T16:27:05.861888Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '22000000000000000000000000',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-11T16:28:25Z',
|
||||||
|
enactmentDatetime: '2022-11-11T16:30:35Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'AAVEDAI.MF21',
|
||||||
|
name: 'AAVEDAI Monthly (Dec 2022)',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'b340c130096819428a62e5df407fd6abe66e444b89ad64f670beb98621c9c663',
|
||||||
|
name: 'tDAI TEST',
|
||||||
|
symbol: 'tDAI',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '8b4aaea9cf7cbbeee90aa6ccea21bd5b9ec15c1872d6b0b3a58e31b741dd948a',
|
||||||
|
reference: '9xlda7c2xrBTDVMNvsDdTSeVJqgCgvN3Uea7WPEN',
|
||||||
|
state: Schema.ProposalState.STATE_WAITING_FOR_NODE_VOTE,
|
||||||
|
datetime: '2022-11-11T16:27:06.076146Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '12345600000000000000000000',
|
||||||
|
totalNumber: '0',
|
||||||
|
totalWeight: '0',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-11T16:28:25Z',
|
||||||
|
enactmentDatetime: '2022-11-11T16:30:35Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'ETHBTC.QM21',
|
||||||
|
name: 'ETHBTC Quarterly (Feb 2023)',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'cee709223217281d7893b650850ae8ee8a18b7539b5658f9b4cc24de95dd18ad',
|
||||||
|
name: 'tBTC TEST',
|
||||||
|
symbol: 'tBTC',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '325dfa07e1be5192376616241d23b4d71740fe712e298130bfd35d27738f1ce4',
|
||||||
|
reference: 'WrmmmaQE4j70M0Wauh85oNpKOA1Lp8omIcn07DLS',
|
||||||
|
state: Schema.ProposalState.STATE_OPEN,
|
||||||
|
datetime: '2022-11-11T16:27:05.914266Z',
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '10000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '50000000000000000000000000',
|
||||||
|
totalNumber: '1',
|
||||||
|
totalWeight: '1',
|
||||||
|
__typename: 'ProposalVoteSide',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
},
|
||||||
|
terms: {
|
||||||
|
closingDatetime: '2022-11-11T16:28:25Z',
|
||||||
|
enactmentDatetime: '2022-11-11T16:30:35Z',
|
||||||
|
change: {
|
||||||
|
instrument: {
|
||||||
|
code: 'UNIDAI.MF21',
|
||||||
|
name: 'UNIDAI Monthly (Dec 2022)',
|
||||||
|
futureProduct: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'b340c130096819428a62e5df407fd6abe66e444b89ad64f670beb98621c9c663',
|
||||||
|
name: 'tDAI TEST',
|
||||||
|
symbol: 'tDAI',
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'FutureProduct',
|
||||||
|
},
|
||||||
|
__typename: 'InstrumentConfiguration',
|
||||||
|
},
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalTerms',
|
||||||
|
},
|
||||||
|
__typename: 'Proposal',
|
||||||
|
},
|
||||||
|
__typename: 'ProposalEdge',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
__typename: 'ProposalsConnection',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const generateMarketProposals = () => {
|
||||||
|
return { ...marketProposals };
|
||||||
|
};
|
@ -27,6 +27,7 @@ import {
|
|||||||
generatePartyBalance,
|
generatePartyBalance,
|
||||||
generatePartyMarketData,
|
generatePartyMarketData,
|
||||||
} from './mocks/generate-fees';
|
} from './mocks/generate-fees';
|
||||||
|
import { generateMarketProposals } from './mocks/generate-proposals';
|
||||||
|
|
||||||
const mockTradingPage = (
|
const mockTradingPage = (
|
||||||
req: CyHttpMessages.IncomingHttpRequest,
|
req: CyHttpMessages.IncomingHttpRequest,
|
||||||
@ -106,6 +107,7 @@ const mockTradingPage = (
|
|||||||
aliasQuery(req, 'PartyBalance', generatePartyBalance());
|
aliasQuery(req, 'PartyBalance', generatePartyBalance());
|
||||||
aliasQuery(req, 'MarketPositions', generatePositions());
|
aliasQuery(req, 'MarketPositions', generatePositions());
|
||||||
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
|
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
|
||||||
|
aliasQuery(req, 'ProposalsList', generateMarketProposals());
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
import { Markets } from './markets';
|
import { MarketsPage } from './markets-page';
|
||||||
|
|
||||||
export default Markets;
|
export default MarketsPage;
|
||||||
|
25
apps/trading/client-pages/markets/markets-page.tsx
Normal file
25
apps/trading/client-pages/markets/markets-page.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { t, titlefy } from '@vegaprotocol/react-helpers';
|
||||||
|
import { Tabs, Tab } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { Markets } from './markets';
|
||||||
|
import { Proposed } from './proposed';
|
||||||
|
import { usePageTitleStore } from '../../stores';
|
||||||
|
|
||||||
|
export const MarketsPage = () => {
|
||||||
|
const { updateTitle } = usePageTitleStore((store) => ({
|
||||||
|
updateTitle: store.updateTitle,
|
||||||
|
}));
|
||||||
|
useEffect(() => {
|
||||||
|
updateTitle(titlefy(['Markets']));
|
||||||
|
}, [updateTitle]);
|
||||||
|
return (
|
||||||
|
<Tabs>
|
||||||
|
<Tab id="active-markets" name={t('Active markets')}>
|
||||||
|
<Markets />
|
||||||
|
</Tab>
|
||||||
|
<Tab id="proposed-markets" name={t('Proposed markets')}>
|
||||||
|
<Proposed />
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
};
|
@ -1,25 +1,18 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
import { MarketsContainer } from '@vegaprotocol/market-list';
|
import { MarketsContainer } from '@vegaprotocol/market-list';
|
||||||
import { useGlobalStore, usePageTitleStore } from '../../stores';
|
import { useGlobalStore } from '../../stores';
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { titlefy } from '@vegaprotocol/react-helpers';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
export const Markets = () => {
|
export const Markets = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { update } = useGlobalStore((store) => ({ update: store.update }));
|
const { update } = useGlobalStore((store) => ({ update: store.update }));
|
||||||
const { updateTitle } = usePageTitleStore((store) => ({
|
const handleOnSelect = useCallback(
|
||||||
updateTitle: store.updateTitle,
|
(marketId: string) => {
|
||||||
}));
|
update({ marketId });
|
||||||
useEffect(() => {
|
navigate(`/markets/${marketId}`);
|
||||||
updateTitle(titlefy(['Markets']));
|
},
|
||||||
}, [updateTitle]);
|
[update, navigate]
|
||||||
|
|
||||||
return (
|
|
||||||
<MarketsContainer
|
|
||||||
onSelect={(marketId) => {
|
|
||||||
update({ marketId });
|
|
||||||
navigate(`/markets/${marketId}`);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return <MarketsContainer onSelect={handleOnSelect} />;
|
||||||
};
|
};
|
||||||
|
23
apps/trading/client-pages/markets/proposed.tsx
Normal file
23
apps/trading/client-pages/markets/proposed.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
|
import { ProposalsList } from '@vegaprotocol/governance';
|
||||||
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import {
|
||||||
|
NEW_PROPOSAL_LINK,
|
||||||
|
TOKEN_DEFAULT_DOMAIN,
|
||||||
|
} from '../../components/constants';
|
||||||
|
|
||||||
|
export const Proposed = () => {
|
||||||
|
const { VEGA_TOKEN_URL } = useEnvironment();
|
||||||
|
const externalLink = `${
|
||||||
|
VEGA_TOKEN_URL || TOKEN_DEFAULT_DOMAIN
|
||||||
|
}${NEW_PROPOSAL_LINK}`;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ProposalsList />
|
||||||
|
<ExternalLink className="py-4 px-[11px]" href={externalLink}>
|
||||||
|
{t('Propose a new market')}
|
||||||
|
</ExternalLink>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -1 +1,3 @@
|
|||||||
export const DEBOUNCE_UPDATE_TIME = 500;
|
export const DEBOUNCE_UPDATE_TIME = 500;
|
||||||
|
export const TOKEN_DEFAULT_DOMAIN = 'https://token.fairground.wtf';
|
||||||
|
export const NEW_PROPOSAL_LINK = '/governance/propose';
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
export * from './proposals-hooks';
|
export * from './proposals-hooks';
|
||||||
export * from './proposals-queries';
|
export * from './proposals-queries';
|
||||||
export * from './voting-hooks';
|
export * from './voting-hooks';
|
||||||
|
export * from './proposals-data-provider';
|
||||||
|
export * from './proposals-list';
|
||||||
|
export * from './voting-progress';
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
fragment NewMarketFields on NewMarket {
|
||||||
|
instrument {
|
||||||
|
code
|
||||||
|
name
|
||||||
|
futureProduct {
|
||||||
|
settlementAsset {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment ProposalListFields on Proposal {
|
||||||
|
id
|
||||||
|
reference
|
||||||
|
state
|
||||||
|
datetime
|
||||||
|
votes {
|
||||||
|
yes {
|
||||||
|
totalTokens
|
||||||
|
totalNumber
|
||||||
|
totalWeight
|
||||||
|
}
|
||||||
|
no {
|
||||||
|
totalTokens
|
||||||
|
totalNumber
|
||||||
|
totalWeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
terms {
|
||||||
|
closingDatetime
|
||||||
|
enactmentDatetime
|
||||||
|
change {
|
||||||
|
... on NewMarket {
|
||||||
|
...NewMarketFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query ProposalsList($proposalType: ProposalType, $inState: ProposalState) {
|
||||||
|
proposalsConnection(proposalType: $proposalType, inState: $inState) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...ProposalListFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
import { Schema as Types } from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type NewMarketFieldsFragment = { __typename?: 'NewMarket', instrument: { __typename?: 'InstrumentConfiguration', code: string, name: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string } } | null } };
|
||||||
|
|
||||||
|
export type ProposalListFieldsFragment = { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string } }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', instrument: { __typename?: 'InstrumentConfiguration', code: string, name: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string } } | null } } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateNetworkParameter' } } };
|
||||||
|
|
||||||
|
export type ProposalsListQueryVariables = Types.Exact<{
|
||||||
|
proposalType?: Types.InputMaybe<Types.ProposalType>;
|
||||||
|
inState?: Types.InputMaybe<Types.ProposalState>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ProposalsListQuery = { __typename?: 'Query', proposalsConnection?: { __typename?: 'ProposalsConnection', edges?: Array<{ __typename?: 'ProposalEdge', node: { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string } }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', instrument: { __typename?: 'InstrumentConfiguration', code: string, name: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string } } | null } } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateNetworkParameter' } } } } | null> | null } | null };
|
||||||
|
|
||||||
|
export const NewMarketFieldsFragmentDoc = gql`
|
||||||
|
fragment NewMarketFields on NewMarket {
|
||||||
|
instrument {
|
||||||
|
code
|
||||||
|
name
|
||||||
|
futureProduct {
|
||||||
|
settlementAsset {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const ProposalListFieldsFragmentDoc = gql`
|
||||||
|
fragment ProposalListFields on Proposal {
|
||||||
|
id
|
||||||
|
reference
|
||||||
|
state
|
||||||
|
datetime
|
||||||
|
votes {
|
||||||
|
yes {
|
||||||
|
totalTokens
|
||||||
|
totalNumber
|
||||||
|
totalWeight
|
||||||
|
}
|
||||||
|
no {
|
||||||
|
totalTokens
|
||||||
|
totalNumber
|
||||||
|
totalWeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
terms {
|
||||||
|
closingDatetime
|
||||||
|
enactmentDatetime
|
||||||
|
change {
|
||||||
|
... on NewMarket {
|
||||||
|
...NewMarketFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${NewMarketFieldsFragmentDoc}`;
|
||||||
|
export const ProposalsListDocument = gql`
|
||||||
|
query ProposalsList($proposalType: ProposalType, $inState: ProposalState) {
|
||||||
|
proposalsConnection(proposalType: $proposalType, inState: $inState) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...ProposalListFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${ProposalListFieldsFragmentDoc}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useProposalsListQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useProposalsListQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useProposalsListQuery` 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 } = useProposalsListQuery({
|
||||||
|
* variables: {
|
||||||
|
* proposalType: // value for 'proposalType'
|
||||||
|
* inState: // value for 'inState'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useProposalsListQuery(baseOptions?: Apollo.QueryHookOptions<ProposalsListQuery, ProposalsListQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ProposalsListQuery, ProposalsListQueryVariables>(ProposalsListDocument, options);
|
||||||
|
}
|
||||||
|
export function useProposalsListLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ProposalsListQuery, ProposalsListQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ProposalsListQuery, ProposalsListQueryVariables>(ProposalsListDocument, options);
|
||||||
|
}
|
||||||
|
export type ProposalsListQueryHookResult = ReturnType<typeof useProposalsListQuery>;
|
||||||
|
export type ProposalsListLazyQueryHookResult = ReturnType<typeof useProposalsListLazyQuery>;
|
||||||
|
export type ProposalsListQueryResult = Apollo.QueryResult<ProposalsListQuery, ProposalsListQueryVariables>;
|
2
libs/governance/src/lib/proposals-data-provider/index.ts
Normal file
2
libs/governance/src/lib/proposals-data-provider/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './proposals-data-provider';
|
||||||
|
export * from './__generated___/Proposals';
|
@ -0,0 +1,18 @@
|
|||||||
|
import { makeDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
|
import type {
|
||||||
|
ProposalsListQuery,
|
||||||
|
ProposalListFieldsFragment,
|
||||||
|
} from './__generated___/Proposals';
|
||||||
|
import { ProposalsListDocument } from './__generated___/Proposals';
|
||||||
|
|
||||||
|
const getData = (responseData: ProposalsListQuery) =>
|
||||||
|
responseData.proposalsConnection?.edges
|
||||||
|
?.filter((edge) => Boolean(edge?.node))
|
||||||
|
.map((edge) => edge?.node as ProposalListFieldsFragment) || null;
|
||||||
|
|
||||||
|
export const proposalsListDataProvider = makeDataProvider<
|
||||||
|
ProposalsListQuery,
|
||||||
|
ProposalListFieldsFragment[],
|
||||||
|
never,
|
||||||
|
never
|
||||||
|
>({ query: ProposalsListDocument, getData });
|
1
libs/governance/src/lib/proposals-list/index.ts
Normal file
1
libs/governance/src/lib/proposals-list/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './proposals-list';
|
@ -0,0 +1,96 @@
|
|||||||
|
import {
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
act,
|
||||||
|
waitFor,
|
||||||
|
getAllByRole,
|
||||||
|
} from '@testing-library/react';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { ProposalsList } from './proposals-list';
|
||||||
|
import type { ProposalListFieldsFragment } from '../proposals-data-provider';
|
||||||
|
import { Schema as Types } from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
const votesMock = {
|
||||||
|
yes: {
|
||||||
|
totalTokens: '5000',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
totalTokens: '2000',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let marketsProposalMock: ProposalListFieldsFragment[] | null = [
|
||||||
|
{
|
||||||
|
id: 'id-1',
|
||||||
|
state: Types.ProposalState.STATE_OPEN,
|
||||||
|
votes: { ...votesMock },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'id-2',
|
||||||
|
state: Types.ProposalState.STATE_PASSED,
|
||||||
|
votes: { ...votesMock },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'id-3',
|
||||||
|
state: Types.ProposalState.STATE_WAITING_FOR_NODE_VOTE,
|
||||||
|
votes: { ...votesMock },
|
||||||
|
},
|
||||||
|
] as ProposalListFieldsFragment[];
|
||||||
|
|
||||||
|
const useDataProvider = () => {
|
||||||
|
return {
|
||||||
|
data: marketsProposalMock,
|
||||||
|
loading: false,
|
||||||
|
error: false,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
jest.mock('@vegaprotocol/react-helpers', () => ({
|
||||||
|
...jest.requireActual('@vegaprotocol/react-helpers'),
|
||||||
|
useDataProvider: jest.fn(() => useDataProvider()),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('ProposalsList', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be properly rendered', async () => {
|
||||||
|
await act(() => {
|
||||||
|
render(<ProposalsList />, { wrapper: MockedProvider });
|
||||||
|
});
|
||||||
|
const container = document.querySelector('.ag-center-cols-container');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(container).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('some of states should be filtered out', async () => {
|
||||||
|
marketsProposalMock = [
|
||||||
|
{
|
||||||
|
...(marketsProposalMock as ProposalListFieldsFragment[])[0],
|
||||||
|
state: Types.ProposalState.STATE_ENACTED,
|
||||||
|
},
|
||||||
|
...(marketsProposalMock as ProposalListFieldsFragment[]).slice(1),
|
||||||
|
];
|
||||||
|
await act(() => {
|
||||||
|
render(<ProposalsList />, { wrapper: MockedProvider });
|
||||||
|
});
|
||||||
|
const container = document.querySelector('.ag-center-cols-container');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(container).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('empty response should causes no data message display', async () => {
|
||||||
|
marketsProposalMock = null;
|
||||||
|
await act(() => {
|
||||||
|
render(<ProposalsList />, { wrapper: MockedProvider });
|
||||||
|
});
|
||||||
|
const container = document.querySelector('.ag-center-cols-container');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(container).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
expect(screen.getByText('No Rows To Show')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
51
libs/governance/src/lib/proposals-list/proposals-list.tsx
Normal file
51
libs/governance/src/lib/proposals-list/proposals-list.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import {
|
||||||
|
AgGridDynamic as AgGrid,
|
||||||
|
AsyncRenderer,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
|
import { Schema as Types } from '@vegaprotocol/types';
|
||||||
|
import { proposalsListDataProvider } from '../proposals-data-provider';
|
||||||
|
import { useCallback, useMemo, useRef } from 'react';
|
||||||
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
|
import { useColumnDefs } from './use-column-defs';
|
||||||
|
import type { ProposalListFieldsFragment } from '../proposals-data-provider/__generated___/Proposals';
|
||||||
|
|
||||||
|
export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) =>
|
||||||
|
data.filter((proposal) =>
|
||||||
|
[
|
||||||
|
Types.ProposalState.STATE_OPEN,
|
||||||
|
Types.ProposalState.STATE_PASSED,
|
||||||
|
Types.ProposalState.STATE_WAITING_FOR_NODE_VOTE,
|
||||||
|
].includes(proposal.state)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ProposalsList = () => {
|
||||||
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
|
const handleOnGridReady = useCallback(() => {
|
||||||
|
gridRef.current?.api?.sizeColumnsToFit();
|
||||||
|
}, [gridRef]);
|
||||||
|
const variables = useMemo(() => {
|
||||||
|
return {
|
||||||
|
proposalType: Types.ProposalType.TYPE_NEW_MARKET,
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
const { data, loading, error } = useDataProvider({
|
||||||
|
dataProvider: proposalsListDataProvider,
|
||||||
|
variables,
|
||||||
|
});
|
||||||
|
const filteredData = getNewMarketProposals(data || []);
|
||||||
|
const { columnDefs, defaultColDef } = useColumnDefs();
|
||||||
|
return (
|
||||||
|
<AsyncRenderer loading={loading} error={error} data={filteredData}>
|
||||||
|
<AgGrid
|
||||||
|
ref={gridRef}
|
||||||
|
domLayout="autoHeight"
|
||||||
|
className="min-w-full"
|
||||||
|
columnDefs={columnDefs}
|
||||||
|
rowData={filteredData}
|
||||||
|
defaultColDef={defaultColDef}
|
||||||
|
onGridReady={handleOnGridReady}
|
||||||
|
/>
|
||||||
|
</AsyncRenderer>
|
||||||
|
);
|
||||||
|
};
|
152
libs/governance/src/lib/proposals-list/use-column-defs.tsx
Normal file
152
libs/governance/src/lib/proposals-list/use-column-defs.tsx
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import BigNumber from 'bignumber.js';
|
||||||
|
import type { ColDef } from 'ag-grid-community';
|
||||||
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
|
import {
|
||||||
|
t,
|
||||||
|
NetworkParams,
|
||||||
|
useNetworkParams,
|
||||||
|
getDateTimeFormat,
|
||||||
|
} from '@vegaprotocol/react-helpers';
|
||||||
|
import type {
|
||||||
|
VegaICellRendererParams,
|
||||||
|
VegaValueFormatterParams,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { ProposalStateMapping } from '@vegaprotocol/types';
|
||||||
|
import type {
|
||||||
|
ProposalListFieldsFragment,
|
||||||
|
NewMarketFieldsFragment,
|
||||||
|
} from '../proposals-data-provider/__generated___/Proposals';
|
||||||
|
import { VoteProgress } from '../voting-progress';
|
||||||
|
|
||||||
|
const instrumentGuard = (
|
||||||
|
change?: ProposalListFieldsFragment['terms']['change']
|
||||||
|
): change is NewMarketFieldsFragment => {
|
||||||
|
return change?.__typename === 'NewMarket';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useColumnDefs = () => {
|
||||||
|
const { VEGA_TOKEN_URL } = useEnvironment();
|
||||||
|
const { params } = useNetworkParams([
|
||||||
|
NetworkParams.governance_proposal_market_requiredMajority,
|
||||||
|
]);
|
||||||
|
const requiredMajorityPercentage = useMemo(() => {
|
||||||
|
const requiredMajority =
|
||||||
|
params?.governance_proposal_market_requiredMajority ?? 1;
|
||||||
|
return new BigNumber(requiredMajority).times(100);
|
||||||
|
}, [params?.governance_proposal_market_requiredMajority]);
|
||||||
|
|
||||||
|
const cellCss = 'grid h-full items-center';
|
||||||
|
const columnDefs: ColDef[] = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
colId: 'market',
|
||||||
|
headerName: t('Market'),
|
||||||
|
field: 'terms.change.instrument.code',
|
||||||
|
width: 150,
|
||||||
|
cellStyle: { lineHeight: '14px' },
|
||||||
|
cellRenderer: ({
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<
|
||||||
|
ProposalListFieldsFragment,
|
||||||
|
'terms.change.instrument.code'
|
||||||
|
>) => {
|
||||||
|
const { change } = data?.terms || {};
|
||||||
|
if (instrumentGuard(change) && VEGA_TOKEN_URL) {
|
||||||
|
if (data?.id) {
|
||||||
|
const link = `${VEGA_TOKEN_URL}/governance/${data.id}`;
|
||||||
|
return (
|
||||||
|
<ExternalLink href={link}>
|
||||||
|
{change.instrument.code}
|
||||||
|
</ExternalLink>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return change.instrument.code;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'description',
|
||||||
|
headerName: t('Description'),
|
||||||
|
field: 'terms.change.instrument.name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'asset',
|
||||||
|
headerName: t('Settlement asset'),
|
||||||
|
field: 'terms.change.instrument.futureProduct.settlementAsset.name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'state',
|
||||||
|
headerName: t('State'),
|
||||||
|
field: 'state',
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) =>
|
||||||
|
value ? ProposalStateMapping[value] : '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'voting',
|
||||||
|
headerName: t('Voting'),
|
||||||
|
cellClass: 'flex justify-between leading-tight font-mono',
|
||||||
|
cellRenderer: ({
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
||||||
|
if (data) {
|
||||||
|
const yesTokens = new BigNumber(data.votes.yes.totalTokens);
|
||||||
|
const noTokens = new BigNumber(data.votes.no.totalTokens);
|
||||||
|
const totalTokensVoted = yesTokens.plus(noTokens);
|
||||||
|
const yesPercentage = totalTokensVoted.isZero()
|
||||||
|
? new BigNumber(0)
|
||||||
|
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||||
|
return (
|
||||||
|
<div className="uppercase flex h-full items-center justify-center">
|
||||||
|
<VoteProgress
|
||||||
|
threshold={requiredMajorityPercentage}
|
||||||
|
progress={yesPercentage}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return '-';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'closing-date',
|
||||||
|
headerName: t('Closing date'),
|
||||||
|
field: 'terms.closingDatetime',
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<
|
||||||
|
ProposalListFieldsFragment,
|
||||||
|
'terms.closingDatetime'
|
||||||
|
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'enactment-date',
|
||||||
|
headerName: t('Enactment date'),
|
||||||
|
field: 'terms.enactmentDatetime',
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<
|
||||||
|
ProposalListFieldsFragment,
|
||||||
|
'terms.enactmentDatetime'
|
||||||
|
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}, [VEGA_TOKEN_URL, requiredMajorityPercentage]);
|
||||||
|
const defaultColDef: ColDef = useMemo(() => {
|
||||||
|
return {
|
||||||
|
sortable: false,
|
||||||
|
cellClass: cellCss,
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
return useMemo(
|
||||||
|
() => ({
|
||||||
|
columnDefs,
|
||||||
|
defaultColDef,
|
||||||
|
}),
|
||||||
|
[columnDefs, defaultColDef]
|
||||||
|
);
|
||||||
|
};
|
1
libs/governance/src/lib/voting-progress/index.ts
Normal file
1
libs/governance/src/lib/voting-progress/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './voting-progress';
|
@ -1,6 +1,6 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import { VoteProgress } from './vote-progress';
|
import { VoteProgress } from './voting-progress';
|
||||||
|
|
||||||
it('Renders with data-testid', () => {
|
it('Renders with data-testid', () => {
|
||||||
render(
|
render(
|
@ -1,4 +1,4 @@
|
|||||||
import type { BigNumber } from '../../../../lib/bignumber';
|
import type BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
export const VoteProgress = ({
|
export const VoteProgress = ({
|
||||||
progress,
|
progress,
|
||||||
@ -14,7 +14,7 @@ export const VoteProgress = ({
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
data-testid="vote-progress-indicator"
|
data-testid="vote-progress-indicator"
|
||||||
className="absolute -top-1 w-[1px] h-3 bg-white z-1"
|
className="absolute -top-1 w-[1px] h-3 bg-neutral-300 dark:bg-white z-1"
|
||||||
style={{ left: `${threshold}%` }}
|
style={{ left: `${threshold}%` }}
|
||||||
/>
|
/>
|
||||||
<div className="w-full h-2">
|
<div className="w-full h-2">
|
||||||
@ -26,7 +26,7 @@ export const VoteProgress = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="absolute left-0 bg-vega-red h-1"
|
className="absolute right-0 bg-vega-red h-1"
|
||||||
data-testid="vote-progress-bar-against"
|
data-testid="vote-progress-bar-against"
|
||||||
style={{
|
style={{
|
||||||
width: `${100 - progress.toNumber()}%`,
|
width: `${100 - progress.toNumber()}%`,
|
Loading…
Reference in New Issue
Block a user