Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe8de91233 | ||
|
|
3772b624d0 | ||
|
|
35e25d9a8f | ||
|
|
86e122389c | ||
|
|
6616aceebb | ||
|
|
c937a9df0c | ||
|
|
9fcf286e4b | ||
|
|
e3ed71bec4 |
@@ -20,7 +20,7 @@ jobs:
|
||||
project: ${{ fromJSON(inputs.projects) }}
|
||||
name: ${{ matrix.project }}
|
||||
runs-on: self-hosted-runner
|
||||
timeout-minutes: 100
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
# Checks if skip cache was requested
|
||||
- name: Set skip-nx-cache flag
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
NX_VEGA_ENV=CUSTOM
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||
@@ -8,3 +6,6 @@ NX_VEGA_EXPLORER_URL=/
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_TXS_LIST=0
|
||||
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||
NX_VEGA_ENV=DEVNET
|
||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||
@@ -10,3 +8,6 @@ NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=/
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
NX_SENTRY_DSN=https://b3a56b03eda842faad731f3ea9dfd1bc@o286262.ingest.sentry.io/6242427
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
||||
NX_VEGA_URL=https://api.vega.community/graphql
|
||||
@@ -11,3 +9,6 @@ NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
||||
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
||||
@@ -10,4 +8,7 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||
|
||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||
@@ -11,3 +9,6 @@ NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
|
||||
@@ -7,9 +7,10 @@ NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
||||
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||
|
||||
@@ -22,6 +22,11 @@ import { Footer } from '../components/footer/footer';
|
||||
import { Header } from '../components/header';
|
||||
import { Routes } from './route-names';
|
||||
import { useExplorerNodeNamesLazyQuery } from './validators/__generated__/NodeNames';
|
||||
import {
|
||||
ProtocolUpgradeCountdownMode,
|
||||
ProtocolUpgradeInProgressNotification,
|
||||
ProtocolUpgradeProposalNotification,
|
||||
} from '@vegaprotocol/proposals';
|
||||
|
||||
const DialogsContainer = () => {
|
||||
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
|
||||
@@ -62,6 +67,10 @@ export const Layout = () => {
|
||||
/>
|
||||
)}
|
||||
<Header />
|
||||
<ProtocolUpgradeProposalNotification
|
||||
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
|
||||
/>
|
||||
<ProtocolUpgradeInProgressNotification />
|
||||
</div>
|
||||
<div className={fixedWidthClasses}>
|
||||
<main className="p-4">
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<meta name="og:site_name" content="Vega Protocol - Explorer" />
|
||||
<meta name="og:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:card" content="https://static.vega.xyz/favicon.ico" />
|
||||
<meta name="twitter:title" content="Vega Protocol - Explorer" />
|
||||
<meta name="twitter:description" content="Vega Protocol - Explorer" />
|
||||
<meta name="twitter:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
|
||||
@@ -29,6 +29,7 @@ const toastPanel = 'toast-panel';
|
||||
const toastClose = 'toast-close';
|
||||
const withdrawalDialogContent = 'dialog-content';
|
||||
const toastCompleteWithdrawal = 'toast-complete-withdrawal';
|
||||
const scrollBar = '.ag-body-horizontal-scroll-viewport';
|
||||
const usdtName = 'USDC (local)';
|
||||
const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
|
||||
const usdcSymbol = 'tUSDC';
|
||||
@@ -199,20 +200,17 @@ context(
|
||||
);
|
||||
cy.getByTestId(toastClose).click();
|
||||
});
|
||||
cy.get(tableTxHash)
|
||||
.eq(1)
|
||||
.should('have.text', 'Complete withdrawal')
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
|
||||
cy.get(tableAmount).should('have.text', '110.00');
|
||||
cy.get(tableReceiverAddress)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/address/');
|
||||
cy.get(tableCreatedTimeStamp).should('not.be.empty');
|
||||
});
|
||||
cy.get("[row-id='0']").within(() => {
|
||||
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
|
||||
cy.get(tableAmount).should('have.text', '110.00');
|
||||
cy.get(tableReceiverAddress)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/address/');
|
||||
cy.get(tableCreatedTimeStamp).should('not.be.empty');
|
||||
});
|
||||
ethereumWalletConnect();
|
||||
cy.get(scrollBar).scrollTo('right');
|
||||
cy.getByTestId(completeWithdrawalButton).first().click();
|
||||
cy.getByTestId(toast)
|
||||
.last(txTimeout)
|
||||
|
||||
@@ -84,9 +84,10 @@ export function stakingPageAssociateTokens(
|
||||
.length
|
||||
) {
|
||||
cy.get(tokenInputApprove, txTimeout).should('be.enabled').click();
|
||||
cy.contains('Approve $VEGA Tokens for staking on Vega').should(
|
||||
'be.visible'
|
||||
);
|
||||
cy.contains(
|
||||
'Approve $VEGA Tokens for staking on Vega',
|
||||
txTimeout
|
||||
).should('be.visible');
|
||||
cy.contains(
|
||||
'Approve $VEGA Tokens for staking on Vega',
|
||||
txTimeout
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Nav } from '../nav';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import {
|
||||
ProtocolUpgradeCountdownMode,
|
||||
ProtocolUpgradeInProgressNotification,
|
||||
ProtocolUpgradeProposalNotification,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
|
||||
@@ -49,6 +50,7 @@ const NotificationsContainer = () => {
|
||||
<ProtocolUpgradeProposalNotification
|
||||
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
|
||||
/>
|
||||
<ProtocolUpgradeInProgressNotification />
|
||||
{isReadOnly ? (
|
||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||
) : null}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<meta name="og:site_name" content="Vega Protocol - Governance" />
|
||||
<meta name="og:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:card" content="https://static.vega.xyz/favicon.ico" />
|
||||
<meta name="twitter:title" content="Vega Protocol - Governance" />
|
||||
<meta name="twitter:description" content="Vega Protocol - Governance" />
|
||||
<meta name="twitter:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
|
||||
+22
-9
@@ -24,6 +24,7 @@ import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { FLAGS } from '@vegaprotocol/environment';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { VoteState } from '../vote-details/use-user-vote';
|
||||
|
||||
jest.mock('@vegaprotocol/proposals', () => ({
|
||||
...jest.requireActual('@vegaprotocol/proposals'),
|
||||
@@ -36,7 +37,8 @@ jest.mock('@vegaprotocol/proposals', () => ({
|
||||
const renderComponent = (
|
||||
proposal: ProposalQuery['proposal'],
|
||||
isListItem = true,
|
||||
mocks: MockedResponse[] = []
|
||||
mocks: MockedResponse[] = [],
|
||||
voteState?: VoteState
|
||||
) =>
|
||||
render(
|
||||
<AppStateProvider>
|
||||
@@ -47,6 +49,7 @@ const renderComponent = (
|
||||
proposal={proposal}
|
||||
isListItem={isListItem}
|
||||
networkParams={mockNetworkParams}
|
||||
voteState={voteState}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -386,10 +389,15 @@ describe('Proposal header', () => {
|
||||
closingDatetime: nextWeek.toString(),
|
||||
},
|
||||
});
|
||||
renderComponent(proposal, true, [
|
||||
// @ts-ignore generateProposal always creates an id
|
||||
createUserVoteQueryMock(proposal.id, VoteValue.VALUE_NO),
|
||||
]);
|
||||
renderComponent(
|
||||
proposal,
|
||||
true,
|
||||
[
|
||||
// @ts-ignore generateProposal always creates an id
|
||||
createUserVoteQueryMock(proposal.id, VoteValue.VALUE_NO),
|
||||
],
|
||||
VoteState.No
|
||||
);
|
||||
expect(await screen.findByTestId('user-voted-no')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -400,10 +408,15 @@ describe('Proposal header', () => {
|
||||
closingDatetime: nextWeek.toString(),
|
||||
},
|
||||
});
|
||||
renderComponent(proposal, true, [
|
||||
// @ts-ignore generateProposal always creates an id
|
||||
createUserVoteQueryMock(proposal.id, VoteValue.VALUE_YES),
|
||||
]);
|
||||
renderComponent(
|
||||
proposal,
|
||||
true,
|
||||
[
|
||||
// @ts-ignore generateProposal always creates an id
|
||||
createUserVoteQueryMock(proposal.id, VoteValue.VALUE_YES),
|
||||
],
|
||||
VoteState.Yes
|
||||
);
|
||||
expect(await screen.findByTestId('user-voted-yes')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
+3
-2
@@ -8,25 +8,26 @@ import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import { truncateMiddle } from '../../../../lib/truncate-middle';
|
||||
import { CurrentProposalState } from '../current-proposal-state';
|
||||
import { ProposalInfoLabel } from '../proposal-info-label';
|
||||
import { useUserVote } from '../vote-details/use-user-vote';
|
||||
import { ProposalVotingStatus } from '../proposal-voting-status';
|
||||
import type { NetworkParamsResult } from '@vegaprotocol/network-parameters';
|
||||
import { useSuccessorMarketProposalDetails } from '@vegaprotocol/proposals';
|
||||
import { FLAGS } from '@vegaprotocol/environment';
|
||||
import Routes from '../../../routes';
|
||||
import { Link } from 'react-router-dom';
|
||||
import type { VoteState } from '../vote-details/use-user-vote';
|
||||
|
||||
export const ProposalHeader = ({
|
||||
proposal,
|
||||
networkParams,
|
||||
isListItem = true,
|
||||
voteState,
|
||||
}: {
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
networkParams: Partial<NetworkParamsResult>;
|
||||
isListItem?: boolean;
|
||||
voteState?: VoteState | null;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { voteState } = useUserVote(proposal?.id);
|
||||
const change = proposal?.terms.change;
|
||||
|
||||
let details: ReactNode;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { VegaWalletProvider } from '@vegaprotocol/wallet';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { generateProposal } from '../../test-helpers/generate-proposals';
|
||||
import { Proposal } from './proposal';
|
||||
@@ -44,11 +46,15 @@ jest.mock('../list-asset', () => ({
|
||||
const renderComponent = (proposal: ProposalQuery['proposal']) => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<Proposal
|
||||
restData={{}}
|
||||
proposal={proposal as ProposalQuery['proposal']}
|
||||
networkParams={mockNetworkParams}
|
||||
/>
|
||||
<MockedProvider>
|
||||
<VegaWalletProvider>
|
||||
<Proposal
|
||||
restData={{}}
|
||||
proposal={proposal as ProposalQuery['proposal']}
|
||||
networkParams={mockNetworkParams}
|
||||
/>
|
||||
</VegaWalletProvider>
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,6 +19,8 @@ import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import { ProposalMarketChanges } from '../proposal-market-changes';
|
||||
import type { NetworkParamsResult } from '@vegaprotocol/network-parameters';
|
||||
import { useVoteSubmit } from '@vegaprotocol/proposals';
|
||||
import { useUserVote } from '../vote-details/use-user-vote';
|
||||
|
||||
export enum ProposalType {
|
||||
PROPOSAL_NEW_MARKET = 'PROPOSAL_NEW_MARKET',
|
||||
@@ -53,6 +55,8 @@ export const Proposal = ({
|
||||
mostRecentlyEnactedAssociatedMarketProposal,
|
||||
}: ProposalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { submit, Dialog, finalizedVote } = useVoteSubmit();
|
||||
const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote);
|
||||
|
||||
if (!proposal) {
|
||||
return null;
|
||||
@@ -132,10 +136,12 @@ export const Proposal = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ProposalHeader
|
||||
proposal={proposal}
|
||||
isListItem={false}
|
||||
networkParams={networkParams}
|
||||
voteState={voteState}
|
||||
/>
|
||||
|
||||
<div id="details">
|
||||
@@ -207,6 +213,10 @@ export const Proposal = ({
|
||||
spamProtectionMinTokens={
|
||||
networkParams?.spam_protection_voting_min_tokens
|
||||
}
|
||||
submit={submit}
|
||||
dialog={Dialog}
|
||||
voteState={voteState}
|
||||
voteDatetime={voteDatetime}
|
||||
/>
|
||||
</RoundedWrapper>
|
||||
</div>
|
||||
|
||||
+7
-1
@@ -1,6 +1,7 @@
|
||||
import { RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
||||
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
|
||||
import { ProposalsListItemDetails } from './proposals-list-item-details';
|
||||
import { useUserVote } from '../vote-details/use-user-vote';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { NetworkParamsResult } from '@vegaprotocol/network-parameters';
|
||||
@@ -14,12 +15,17 @@ export const ProposalsListItem = ({
|
||||
proposal,
|
||||
networkParams,
|
||||
}: ProposalsListItemProps) => {
|
||||
const { voteState } = useUserVote(proposal?.id);
|
||||
if (!proposal || !proposal.id || !networkParams) return null;
|
||||
|
||||
return (
|
||||
<li id={proposal.id} data-testid="proposals-list-item">
|
||||
<RoundedWrapper paddingBottom={true} heightFull={true}>
|
||||
<ProposalHeader proposal={proposal} networkParams={networkParams} />
|
||||
<ProposalHeader
|
||||
proposal={proposal}
|
||||
networkParams={networkParams}
|
||||
voteState={voteState}
|
||||
/>
|
||||
<ProposalsListItemDetails proposal={proposal} />
|
||||
</RoundedWrapper>
|
||||
</li>
|
||||
|
||||
@@ -188,11 +188,7 @@ export const VoteButtons = ({
|
||||
(voteState === VoteState.Yes || voteState === VoteState.No) && (
|
||||
<p data-testid="you-voted">
|
||||
<span>{t('youVoted')}:</span>{' '}
|
||||
<span
|
||||
className={
|
||||
voteState === VoteState.Yes ? 'text-success' : 'text-danger'
|
||||
}
|
||||
>
|
||||
<span className="text-white font-bold">
|
||||
{t(`voteState_${voteState}`)}
|
||||
</span>{' '}
|
||||
{voteDatetime ? (
|
||||
|
||||
@@ -3,23 +3,29 @@ import { formatDistanceToNow } from 'date-fns';
|
||||
import { RoundedWrapper, Icon, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import { useVoteSubmit, VoteProgress } from '@vegaprotocol/proposals';
|
||||
import { VoteProgress } from '@vegaprotocol/proposals';
|
||||
import { formatNumber } from '../../../../lib/format-number';
|
||||
import { ConnectToVega } from '../../../../components/connect-to-vega';
|
||||
import { useVoteInformation } from '../../hooks';
|
||||
import { useUserVote } from './use-user-vote';
|
||||
import { CurrentProposalStatus } from '../current-proposal-status';
|
||||
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 { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { VoteState } from './use-user-vote';
|
||||
|
||||
interface VoteDetailsProps {
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
minVoterBalance: string | null | undefined;
|
||||
spamProtectionMinTokens: string | null | undefined;
|
||||
proposalType: ProposalType | null;
|
||||
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
|
||||
dialog: (props: DialogProps) => JSX.Element;
|
||||
voteState: VoteState | null;
|
||||
voteDatetime: Date | null;
|
||||
}
|
||||
|
||||
export const VoteDetails = ({
|
||||
@@ -27,6 +33,10 @@ export const VoteDetails = ({
|
||||
minVoterBalance,
|
||||
spamProtectionMinTokens,
|
||||
proposalType,
|
||||
submit,
|
||||
dialog,
|
||||
voteState,
|
||||
voteDatetime,
|
||||
}: VoteDetailsProps) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const {
|
||||
@@ -48,8 +58,7 @@ export const VoteDetails = ({
|
||||
} = useVoteInformation({ proposal });
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { submit, Dialog, finalizedVote } = useVoteSubmit();
|
||||
const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote);
|
||||
|
||||
const defaultDecimals = 2;
|
||||
const daysLeft = t('daysLeft', {
|
||||
daysLeft: formatDistanceToNow(new Date(proposal?.terms.closingDatetime)),
|
||||
@@ -219,7 +228,7 @@ export const VoteDetails = ({
|
||||
spamProtectionMinTokens={spamProtectionMinTokens}
|
||||
className="flex"
|
||||
submit={submit}
|
||||
dialog={Dialog}
|
||||
dialog={dialog}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
|
||||
@@ -256,6 +256,7 @@ describe('Closed markets', { tags: '@smoke' }, () => {
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="code"]')
|
||||
.find('[data-testid="market-code"]')
|
||||
.should('have.text', settledMarket.tradableInstrument.instrument.code);
|
||||
|
||||
// 6001-MARK-002
|
||||
|
||||
@@ -4,7 +4,8 @@ import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
const rowSelector =
|
||||
'[data-testid="tab-open-markets"] .ag-center-cols-container .ag-row';
|
||||
const colInstrumentCode = '[col-id="tradableInstrument.instrument.code"]';
|
||||
const colInstrumentCode =
|
||||
'[col-id="tradableInstrument.instrument.code"] [data-testid="market-code"]';
|
||||
|
||||
describe('markets all table', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -40,21 +40,25 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
code: 'SOLUSD',
|
||||
markPrice: '84.41',
|
||||
vol: '0.00',
|
||||
productType: 'Futr',
|
||||
},
|
||||
{
|
||||
code: 'ETHBTC.QM21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
productType: 'Futr',
|
||||
},
|
||||
{
|
||||
code: 'BTCUSD.MF21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
productType: 'Futr',
|
||||
},
|
||||
{
|
||||
code: 'AAPL.MF21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
productType: 'Futr',
|
||||
},
|
||||
];
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
@@ -64,7 +68,9 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
const market = data[i];
|
||||
// 6001-MARK-021
|
||||
// 6001-MARK-022
|
||||
expect(item.find('h3').text()).equals(market.code);
|
||||
expect(item.find('h3').text()).equals(
|
||||
`${market.code} ${market.productType}`
|
||||
);
|
||||
expect(
|
||||
item.find('[data-testid="market-selector-volume"]').text()
|
||||
).contains(market.vol);
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ProposalsListQuery } from '@vegaprotocol/proposals';
|
||||
|
||||
const rowSelector =
|
||||
'[data-testid="tab-proposed-markets"] .ag-center-cols-container .ag-row';
|
||||
const colMarketId = '[col-id="market"]';
|
||||
const colMarketId = '[col-id="market"] [data-testid="market-code"]';
|
||||
|
||||
describe('markets proposed table', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
@@ -155,7 +155,13 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
|
||||
'AAVEDAI.MF21',
|
||||
'AAPL.MF21',
|
||||
];
|
||||
checkSorting('market', marketColDefault, marketColAsc, marketColDesc);
|
||||
checkSorting(
|
||||
'market',
|
||||
marketColDefault,
|
||||
marketColAsc,
|
||||
marketColDesc,
|
||||
' [data-testid="market-code"]'
|
||||
);
|
||||
|
||||
const stateColDefault = [
|
||||
'Open',
|
||||
|
||||
@@ -120,7 +120,9 @@ describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
|
||||
cy.getByTestId('All').click();
|
||||
|
||||
cy.getByTestId('tab-orders')
|
||||
.get(`.ag-center-cols-container [col-id='${orderSymbol}']`)
|
||||
.get(
|
||||
`.ag-center-cols-container [col-id='${orderSymbol}'] [data-testid="market-code"]`
|
||||
)
|
||||
.should('have.length.at.least', expectedOrderList.length)
|
||||
.then(($symbols) => {
|
||||
const symbolNames: string[] = [];
|
||||
|
||||
@@ -166,7 +166,8 @@ describe('positions', { tags: '@regression', testIsolation: true }, () => {
|
||||
'marketName',
|
||||
marketsSortedDefault,
|
||||
marketsSortedAsc,
|
||||
marketsSortedDesc
|
||||
marketsSortedDesc,
|
||||
' [data-testid="market-code"]'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -20,3 +20,6 @@ NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
|
||||
@@ -20,4 +20,7 @@ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supp
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_STOP_ORDERS=false
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
|
||||
@@ -18,4 +18,7 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
|
||||
@@ -21,3 +21,6 @@ NX_SUCCESSOR_MARKETS=false
|
||||
NX_STOP_ORDERS=false
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
@@ -20,4 +20,7 @@ NX_APP_VERSION=v0.20.19-core-0.71.6
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_STOP_ORDERS=false
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||
|
||||
@@ -19,4 +19,7 @@ NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ICEBERG_ORDERS=true
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
@@ -19,4 +19,7 @@ NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_STOP_ORDERS=false
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||
|
||||
@@ -214,7 +214,6 @@ describe('Closed', () => {
|
||||
</MemoryRouter>
|
||||
);
|
||||
});
|
||||
// screen.debug(document, Infinity);
|
||||
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
const expectedHeaders = [
|
||||
@@ -434,7 +433,7 @@ describe('Closed', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByRole('button', { name: 'SuccessorCode' })
|
||||
screen.getByRole('button', { name: /^SuccessorCode/ })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
expect(
|
||||
@@ -443,6 +442,16 @@ describe('Closed', () => {
|
||||
element.getAttribute('col-id') === 'successorMarket',
|
||||
})
|
||||
).toBeInTheDocument();
|
||||
screen
|
||||
.getAllByRole('gridcell', {
|
||||
name: (_name, element) =>
|
||||
element.getAttribute('col-id') === 'successorMarket',
|
||||
})
|
||||
.forEach((element) => {
|
||||
expect(element.querySelector('[title="Future"]')?.textContent).toEqual(
|
||||
'Futr'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('feature flag should hide successors', async () => {
|
||||
|
||||
@@ -4,7 +4,11 @@ import type {
|
||||
VegaICellRendererParams,
|
||||
VegaValueFormatterParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid, COL_DEFS } from '@vegaprotocol/datagrid';
|
||||
import {
|
||||
AgGridLazy as AgGrid,
|
||||
COL_DEFS,
|
||||
MarketNameCell,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { useMemo } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { MarketState, MarketStateMapping } from '@vegaprotocol/types';
|
||||
@@ -47,6 +51,7 @@ interface Row {
|
||||
setlementDataSourceFilter: DataSourceFilterFragment | undefined;
|
||||
tradingTerminationOracleId: string;
|
||||
settlementAsset: SettlementAsset;
|
||||
productType: string;
|
||||
}
|
||||
|
||||
export const Closed = () => {
|
||||
@@ -90,6 +95,7 @@ export const Closed = () => {
|
||||
tradingTerminationOracleId:
|
||||
instrument.product.dataSourceSpecForTradingTermination.id,
|
||||
settlementAsset: instrument.product.settlementAsset,
|
||||
productType: instrument.product.__typename || '',
|
||||
};
|
||||
|
||||
return row;
|
||||
@@ -115,16 +121,7 @@ const ClosedMarketsDataGrid = ({
|
||||
{
|
||||
headerName: t('Market'),
|
||||
field: 'code',
|
||||
cellRenderer: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaICellRendererParams<Row, 'code'>) => {
|
||||
return (
|
||||
<span data-testid="market-code" data-market-id={data?.id}>
|
||||
{value}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
cellRenderer: 'MarketNameCell',
|
||||
},
|
||||
{
|
||||
headerName: t('Description'),
|
||||
@@ -279,7 +276,7 @@ const ClosedMarketsDataGrid = ({
|
||||
rowData={rowData}
|
||||
columnDefs={colDefs}
|
||||
getRowId={({ data }) => data.id}
|
||||
components={{ SuccessorMarketRenderer }}
|
||||
components={{ SuccessorMarketRenderer, MarketNameCell }}
|
||||
overlayNoRowsTemplate={error ? error.message : t('No markets')}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
import { render, screen, act, waitFor } from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import { SuccessorMarketRenderer } from './successor-market-cell';
|
||||
import {
|
||||
MarketsDocument,
|
||||
SuccessorMarketIdsDocument,
|
||||
} from '@vegaprotocol/markets';
|
||||
import { createMarketFragment } from '@vegaprotocol/mock';
|
||||
|
||||
const mockSuccessorsQuery = [
|
||||
{
|
||||
id: 'market1',
|
||||
parentMarketID: 'parentMarket1',
|
||||
successorMarketID: 'successorMarket1',
|
||||
},
|
||||
{ id: 'market2', parentMarketID: 'parentMarket2' },
|
||||
{ id: 'market3', successorMarketID: 'successorMarket3' },
|
||||
];
|
||||
const parentMarket1 = {
|
||||
id: 'parentMarket1',
|
||||
tradableInstrument: {
|
||||
instrument: { code: 'code parent 1', id: '1' },
|
||||
},
|
||||
} as unknown as Market;
|
||||
const successorMarket1 = {
|
||||
id: 'successorMarket1',
|
||||
tradableInstrument: {
|
||||
instrument: { code: 'code successor 1', id: '2' },
|
||||
},
|
||||
} as unknown as Market;
|
||||
const parentMarket2 = {
|
||||
id: 'parentMarket2',
|
||||
tradableInstrument: {
|
||||
instrument: { code: 'code parent 2', id: '3' },
|
||||
},
|
||||
} as unknown as Market;
|
||||
const successorMarket3 = {
|
||||
id: 'successorMarket3',
|
||||
tradableInstrument: {
|
||||
instrument: { code: 'code successor 3', id: '4' },
|
||||
},
|
||||
} as unknown as Market;
|
||||
|
||||
const mockMarkets = [
|
||||
parentMarket1,
|
||||
successorMarket1,
|
||||
parentMarket2,
|
||||
successorMarket3,
|
||||
];
|
||||
|
||||
const mockClickHandler = jest.fn();
|
||||
jest.mock('../../lib/hooks/use-market-click-handler', () => ({
|
||||
useMarketClickHandler: jest.fn().mockImplementation(() => mockClickHandler),
|
||||
}));
|
||||
|
||||
const marketMock = {
|
||||
request: {
|
||||
query: MarketsDocument,
|
||||
variables: undefined,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
marketsConnection: {
|
||||
edges: mockMarkets.map((item) => ({
|
||||
node: {
|
||||
...createMarketFragment(item),
|
||||
},
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const successorMock = {
|
||||
request: {
|
||||
query: SuccessorMarketIdsDocument,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
marketsConnection: {
|
||||
edges: mockSuccessorsQuery.map((item) => ({
|
||||
node: {
|
||||
...item,
|
||||
},
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mocks = [marketMock, successorMock];
|
||||
|
||||
describe('SuccessorMarketRenderer', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('should properly rendered successor market', async () => {
|
||||
const successorValue = 'market1';
|
||||
render(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} />
|
||||
</MockedProvider>
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('code successor 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
await waitFor(() => {
|
||||
expect(mockClickHandler).toHaveBeenCalledWith('successorMarket1', false);
|
||||
});
|
||||
});
|
||||
it('should properly rendered parent market', async () => {
|
||||
const successorValue = 'market1';
|
||||
render(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} parent />
|
||||
</MockedProvider>
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('code parent 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockClickHandler).toHaveBeenCalledWith('parentMarket1', false);
|
||||
});
|
||||
});
|
||||
it('should properly rendered only parent market', async () => {
|
||||
const successorValue = 'market2';
|
||||
const { rerender } = render(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} parent />
|
||||
</MockedProvider>
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('code parent 2')).toBeInTheDocument();
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockClickHandler).toHaveBeenCalledWith('parentMarket2', false);
|
||||
});
|
||||
|
||||
rerender(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} />
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(screen.getByText('-')).toBeInTheDocument();
|
||||
});
|
||||
it('should properly rendered only successor market', async () => {
|
||||
const successorValue = 'market3';
|
||||
const { rerender } = render(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} />
|
||||
</MockedProvider>
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-code')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('code successor 3')).toBeInTheDocument();
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockClickHandler).toHaveBeenCalledWith('successorMarket3', false);
|
||||
});
|
||||
|
||||
await act(() => {
|
||||
rerender(
|
||||
<MockedProvider mocks={[...mocks]}>
|
||||
<SuccessorMarketRenderer value={successorValue} parent />
|
||||
</MockedProvider>
|
||||
);
|
||||
});
|
||||
expect(screen.getByText('-')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { MarketNameCell } from '@vegaprotocol/datagrid';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { marketProvider, useSuccessorMarketIds } from '@vegaprotocol/markets';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import React from 'react';
|
||||
|
||||
export const SuccessorMarketRenderer = ({
|
||||
value,
|
||||
@@ -33,6 +33,7 @@ export const SuccessorMarketRenderer = ({
|
||||
value={data.tradableInstrument.instrument.code}
|
||||
data={data}
|
||||
onMarketClick={onMarketClick}
|
||||
productType={data.tradableInstrument.instrument?.product.__typename}
|
||||
/>
|
||||
) : (
|
||||
'-'
|
||||
|
||||
@@ -99,6 +99,7 @@ describe('MarketSelectorItem', () => {
|
||||
currentMarketId={market.id}
|
||||
style={{}}
|
||||
onSelect={jest.fn()}
|
||||
allProducts
|
||||
/>
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
@@ -181,5 +182,7 @@ describe('MarketSelectorItem', () => {
|
||||
addDecimalsFormatNumber(marketData.markPrice, market.decimalPlaces)
|
||||
);
|
||||
});
|
||||
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,17 +12,20 @@ import {
|
||||
MarketTradingModeMapping,
|
||||
} from '@vegaprotocol/types';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { MarketProductPill } from '@vegaprotocol/datagrid';
|
||||
|
||||
export const MarketSelectorItem = ({
|
||||
market,
|
||||
style,
|
||||
currentMarketId,
|
||||
onSelect,
|
||||
allProducts,
|
||||
}: {
|
||||
market: MarketMaybeWithDataAndCandles;
|
||||
style: CSSProperties;
|
||||
currentMarketId?: string;
|
||||
onSelect: (marketId: string) => void;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<div style={style} role="row">
|
||||
@@ -36,13 +39,19 @@ export const MarketSelectorItem = ({
|
||||
})}
|
||||
onClick={() => onSelect(market.id)}
|
||||
>
|
||||
<MarketData market={market} />
|
||||
<MarketData market={market} allProducts={allProducts} />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
|
||||
const MarketData = ({
|
||||
market,
|
||||
allProducts,
|
||||
}: {
|
||||
market: MarketMaybeWithDataAndCandles;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
const { data } = useMarketDataUpdateSubscription({
|
||||
variables: {
|
||||
marketId: market.id,
|
||||
@@ -84,7 +93,14 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
|
||||
<>
|
||||
<div className="w-2/5" role="gridcell">
|
||||
<h3 className="text-ellipsis text-sm lg:text-base whitespace-nowrap overflow-hidden">
|
||||
{market.tradableInstrument.instrument.code}
|
||||
{market.tradableInstrument.instrument.code}{' '}
|
||||
{allProducts && (
|
||||
<MarketProductPill
|
||||
productType={
|
||||
market.tradableInstrument.instrument.product.__typename
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</h3>
|
||||
{mode && (
|
||||
<p className="text-xs text-vega-orange-500 dark:text-vega-orange-550 whitespace-nowrap">
|
||||
|
||||
@@ -43,7 +43,7 @@ export const MarketSelector = ({
|
||||
sort: Sort.None,
|
||||
assets: [],
|
||||
});
|
||||
|
||||
const allProducts = filter.product === Product.All;
|
||||
const { markets, data, loading, error } = useMarketSelectorList(filter);
|
||||
|
||||
return (
|
||||
@@ -128,6 +128,7 @@ export const MarketSelector = ({
|
||||
? t('Spot markets coming soon.')
|
||||
: t('No markets')
|
||||
}
|
||||
allProducts={allProducts}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,6 +142,7 @@ const MarketList = ({
|
||||
currentMarketId,
|
||||
onSelect,
|
||||
noItems,
|
||||
allProducts,
|
||||
}: {
|
||||
data: MarketMaybeWithDataAndCandles[];
|
||||
error: Error | undefined;
|
||||
@@ -149,6 +151,7 @@ const MarketList = ({
|
||||
currentMarketId?: string;
|
||||
onSelect: (marketId: string) => void;
|
||||
noItems: string;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
const itemSize = 45;
|
||||
const listRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -192,6 +195,7 @@ const MarketList = ({
|
||||
currentMarketId={currentMarketId}
|
||||
onSelect={onSelect}
|
||||
noItems={noItems}
|
||||
allProducts={allProducts}
|
||||
/>
|
||||
</div>
|
||||
</TinyScroll>
|
||||
@@ -202,6 +206,7 @@ interface ListItemData {
|
||||
data: MarketMaybeWithDataAndCandles[];
|
||||
onSelect: (marketId: string) => void;
|
||||
currentMarketId?: string;
|
||||
allProducts: boolean;
|
||||
}
|
||||
|
||||
const ListItem = ({
|
||||
@@ -218,6 +223,7 @@ const ListItem = ({
|
||||
currentMarketId={data.currentMarketId}
|
||||
style={style}
|
||||
onSelect={data.onSelect}
|
||||
allProducts={data.allProducts}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -229,19 +235,21 @@ const List = ({
|
||||
onSelect,
|
||||
noItems,
|
||||
currentMarketId,
|
||||
allProducts,
|
||||
}: ListItemData & {
|
||||
loading: boolean;
|
||||
height: number;
|
||||
itemSize: number;
|
||||
noItems: string;
|
||||
allProducts: boolean;
|
||||
}) => {
|
||||
const itemKey = useCallback(
|
||||
(index: number, data: ListItemData) => data.data[index].id,
|
||||
[]
|
||||
);
|
||||
const itemData = useMemo(
|
||||
() => ({ data, onSelect, currentMarketId }),
|
||||
[data, onSelect, currentMarketId]
|
||||
() => ({ data, onSelect, currentMarketId, allProducts }),
|
||||
[data, onSelect, currentMarketId, allProducts]
|
||||
);
|
||||
if (!data || loading) {
|
||||
return (
|
||||
|
||||
@@ -43,6 +43,7 @@ import { Navbar } from '../components/navbar';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
ProtocolUpgradeCountdownMode,
|
||||
ProtocolUpgradeInProgressNotification,
|
||||
ProtocolUpgradeProposalNotification,
|
||||
} from '@vegaprotocol/proposals';
|
||||
import { ViewingBanner } from '../components/viewing-banner';
|
||||
@@ -111,6 +112,7 @@ function AppBody({ Component }: AppProps) {
|
||||
<ProtocolUpgradeProposalNotification
|
||||
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
|
||||
/>
|
||||
<ProtocolUpgradeInProgressNotification />
|
||||
<ViewingBanner />
|
||||
<UpgradeBanner showVersionChange={true} />
|
||||
</div>
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import { Html, Head, Main, NextScript } from 'next/document';
|
||||
import { Head, Html, Main, NextScript } from 'next/document';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html>
|
||||
<>
|
||||
<Head>
|
||||
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
content="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
crossOrigin="anonymous"
|
||||
/>
|
||||
{/* eslint-disable-next-line @next/next/no-css-tags */}
|
||||
<link rel="stylesheet" href="/preloader.css" media="all" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
@@ -21,10 +22,12 @@ export default function Document() {
|
||||
/>
|
||||
<script src="/theme-setter.js" type="text/javascript" async />
|
||||
</Head>
|
||||
<body className="bg-white dark:bg-vega-cdark-900 text-default font-alpha">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
<Html>
|
||||
<body className="bg-white dark:bg-vega-cdark-900 text-default font-alpha">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ export default function Index() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta charSet="utf-8" />
|
||||
<link
|
||||
rel="icon"
|
||||
@@ -18,17 +20,45 @@ export default function Index() {
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="Vega Protocol - Console" />
|
||||
<meta name="description" content="Vega Protocol - VEGA Console" />
|
||||
<meta name="og:type" content="website" />
|
||||
<meta name="og:url" content="https://console.vega.xyz/" />
|
||||
<meta name="og:title" content="Vega Protocol - Console" />
|
||||
<meta name="og:site_name" content="Vega Protocol - Console" />
|
||||
<meta name="og:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
|
||||
<link rel="apple-touch-icon" href="assets/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="assets/manifest.json" />
|
||||
<meta
|
||||
name="twitter:card"
|
||||
content="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<meta name="twitter:title" content="Vega Protocol - Console" />
|
||||
<meta name="twitter:description" content="Vega Protocol - Console" />
|
||||
<meta
|
||||
name="twitter:image"
|
||||
content="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<meta name="twitter:image:alt" content="VEGA logo" />
|
||||
<meta name="twitter:site" content="@vegaprotocol" />
|
||||
|
||||
<meta name="description" content="Vega Protocol - Console" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
content="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
/>
|
||||
<title>VEGA Console dApp</title>
|
||||
{/* eslint-disable-next-line @next/next/no-css-tags */}
|
||||
<link rel="stylesheet" href="/preloader.css" media="all" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
href="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<script src="/theme-setter.js" type="text/javascript" async />
|
||||
</Head>
|
||||
<ClientRouter />
|
||||
</>
|
||||
|
||||
@@ -24,6 +24,9 @@ const singleRow = {
|
||||
__typename: 'Instrument',
|
||||
name: 'BTCUSD Monthly (30 Jun 2022)',
|
||||
code: 'BTCUSD.MF21',
|
||||
product: {
|
||||
__typename: 'Future',
|
||||
},
|
||||
},
|
||||
},
|
||||
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
|
||||
@@ -120,6 +123,9 @@ describe('BreakdownTable', () => {
|
||||
__typename: 'Instrument',
|
||||
name: 'BTCUSD Monthly (30 Jun 2022)',
|
||||
code: 'BTCUSD.MF21',
|
||||
product: {
|
||||
__typename: 'Future',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -36,14 +36,24 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
|
||||
{
|
||||
headerName: t('Market'),
|
||||
field: 'market.tradableInstrument.instrument.code',
|
||||
valueFormatter: ({
|
||||
minWidth: 200,
|
||||
cellRenderer: ({
|
||||
value,
|
||||
}: VegaValueFormatterParams<
|
||||
data,
|
||||
}: VegaICellRendererParams<
|
||||
AccountFields,
|
||||
'market.tradableInstrument.instrument.code'
|
||||
>) => {
|
||||
if (!value) return 'None';
|
||||
return value;
|
||||
return value ? (
|
||||
<MarketNameCell
|
||||
value={value}
|
||||
productType={
|
||||
data?.market?.tradableInstrument.instrument.product.__typename
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
'None'
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -126,7 +136,7 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
|
||||
}
|
||||
ref={ref}
|
||||
rowHeight={34}
|
||||
components={{ PriceCell, MarketNameCell, ProgressBarCell }}
|
||||
components={{ PriceCell, ProgressBarCell }}
|
||||
tooltipShowDelay={500}
|
||||
defaultColDef={defaultColDef}
|
||||
columnDefs={coldefs}
|
||||
|
||||
@@ -121,9 +121,12 @@ export function createClient({
|
||||
// called on startup, NodeCheck and NodeCheckTimeUpdate are called
|
||||
// by the NodeSwitcher component and the useNodeHealth hook
|
||||
if (
|
||||
['NodeGuard', 'NodeCheck', 'NodeCheckTimeUpdate'].includes(
|
||||
operation.operationName
|
||||
)
|
||||
[
|
||||
'NodeGuard',
|
||||
'NodeCheck',
|
||||
'NodeCheckTimeUpdate',
|
||||
'BlockStatistics',
|
||||
].includes(operation.operationName)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -41,21 +41,22 @@ export const checkSorting = (
|
||||
column: string,
|
||||
orderTabDefault: string[],
|
||||
orderTabAsc: string[],
|
||||
orderTabDesc: string[]
|
||||
orderTabDesc: string[],
|
||||
additionalColumnSelector = ''
|
||||
) => {
|
||||
checkSortChange(orderTabDefault, column);
|
||||
checkSortChange(orderTabDefault, column, additionalColumnSelector);
|
||||
cy.get('.ag-header-container')
|
||||
.last()
|
||||
.within(() => {
|
||||
cy.get(`[col-id="${column}"]`).last().click();
|
||||
});
|
||||
checkSortChange(orderTabAsc, column);
|
||||
checkSortChange(orderTabAsc, column, additionalColumnSelector);
|
||||
cy.get('.ag-header-container')
|
||||
.last()
|
||||
.within(() => {
|
||||
cy.get(`[col-id="${column}"]`).click();
|
||||
});
|
||||
checkSortChange(orderTabDesc, column);
|
||||
checkSortChange(orderTabDesc, column, additionalColumnSelector);
|
||||
cy.get('.ag-header-container')
|
||||
.last()
|
||||
.within(() => {
|
||||
@@ -63,13 +64,20 @@ export const checkSorting = (
|
||||
});
|
||||
};
|
||||
|
||||
const checkSortChange = (tabsArr: string[], column: string) => {
|
||||
const checkSortChange = (
|
||||
tabsArr: string[],
|
||||
column: string,
|
||||
additionalColumnSelector = ''
|
||||
) => {
|
||||
cy.get('.ag-center-cols-container')
|
||||
.last()
|
||||
.within(() => {
|
||||
tabsArr.forEach((entry, i) => {
|
||||
cy.get(`[row-index="${i}"]`).within(() => {
|
||||
cy.get(`[col-id="${column}"]`).should('have.text', tabsArr[i]);
|
||||
cy.get(`[col-id="${column}"]${additionalColumnSelector}`).should(
|
||||
'have.text',
|
||||
tabsArr[i]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,10 @@ export const CenteredGridCellWrapper = ({
|
||||
className?: string;
|
||||
}) => (
|
||||
<div
|
||||
className={classNames('flex h-[20px] p-0 justify-items-center', className)}
|
||||
className={classNames(
|
||||
'flex h-[20px] p-0 justify-items-center items-center',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="w-full self-center">{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,39 @@
|
||||
import type { MouseEvent, ReactNode } from 'react';
|
||||
import type { MouseEvent } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { Pill } from '@vegaprotocol/ui-toolkit';
|
||||
import type { Market } from '@vegaprotocol/types';
|
||||
|
||||
const productTypeMap = {
|
||||
Future: 'Futr',
|
||||
FutureProduct: 'Futr',
|
||||
Spot: 'Spot',
|
||||
SpotProduct: 'Spot',
|
||||
Perpetual: 'Perp',
|
||||
PerpetualProduct: 'Perp',
|
||||
} as const;
|
||||
export type ProductType = keyof typeof productTypeMap | undefined;
|
||||
|
||||
export const MarketProductPill = ({
|
||||
productType,
|
||||
}: {
|
||||
productType?: ProductType;
|
||||
}) => {
|
||||
return productType ? (
|
||||
<Pill size="xxs" className="uppercase ml-0.5" title={productType}>
|
||||
{productTypeMap[productType] || productType}
|
||||
</Pill>
|
||||
) : null;
|
||||
};
|
||||
|
||||
interface MarketNameCellProps {
|
||||
value?: string | null;
|
||||
data?: { id?: string; marketId?: string; market?: { id: string } };
|
||||
data?:
|
||||
| { id?: string; marketId?: string; productType?: string; market?: Market }
|
||||
| Market;
|
||||
idPath?: string;
|
||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
defaultValue?: ReactNode;
|
||||
productType?: ProductType;
|
||||
}
|
||||
|
||||
export const MarketNameCell = ({
|
||||
@@ -15,29 +41,43 @@ export const MarketNameCell = ({
|
||||
data,
|
||||
idPath,
|
||||
onMarketClick,
|
||||
productType,
|
||||
}: MarketNameCellProps) => {
|
||||
const id = data ? get(data, idPath ?? 'id', 'all') : '';
|
||||
const handleOnClick = useCallback(
|
||||
(ev: MouseEvent<HTMLButtonElement>) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
if (onMarketClick) {
|
||||
onMarketClick(id, ev.metaKey || ev.ctrlKey);
|
||||
}
|
||||
id && onMarketClick?.(id, ev.metaKey || ev.ctrlKey);
|
||||
},
|
||||
[id, onMarketClick]
|
||||
);
|
||||
if (!value || !data) return null;
|
||||
return onMarketClick ? (
|
||||
|
||||
productType =
|
||||
productType ||
|
||||
(data as { productType?: ProductType }).productType ||
|
||||
(data as Market)?.tradableInstrument?.instrument.product.__typename ||
|
||||
(data as { market: Market })?.market?.tradableInstrument.instrument.product
|
||||
.__typename;
|
||||
|
||||
if (!value) return;
|
||||
const content = (
|
||||
<>
|
||||
<span data-testid="market-code" data-market-id={id}>
|
||||
{value}
|
||||
</span>
|
||||
<MarketProductPill productType={productType} />
|
||||
</>
|
||||
);
|
||||
return onMarketClick && id ? (
|
||||
<button
|
||||
onClick={handleOnClick}
|
||||
tabIndex={0}
|
||||
className="block text-left text-ellipsis overflow-hidden whitespace-nowrap w-full"
|
||||
>
|
||||
{value}
|
||||
{content}
|
||||
</button>
|
||||
) : (
|
||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||
<>{value}</>
|
||||
content
|
||||
);
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@ const EmptyLinks: DAppLinks = {
|
||||
|
||||
const ExplorerLinks = {
|
||||
...EmptyLinks,
|
||||
[Networks.STAGNET1]: 'https://explorer.stagnet1.vega.rocks',
|
||||
[Networks.TESTNET]: 'https://explorer.fairground.wtf',
|
||||
[Networks.VALIDATOR_TESTNET]:
|
||||
'https://explorer.validators-testnet.vega.rocks',
|
||||
@@ -40,17 +41,18 @@ const ConsoleLinks = {
|
||||
...EmptyLinks,
|
||||
[Networks.STAGNET1]: 'https://trading.stagnet1.vega.rocks',
|
||||
[Networks.TESTNET]: 'https://console.fairground.wtf',
|
||||
[Networks.MAINNET]: 'https://console.vega.xyz',
|
||||
[Networks.MAINNET_MIRROR]: 'https://console.mainnet-mirror.vega.rocks/',
|
||||
[Networks.MAINNET]: 'https://vega.trading',
|
||||
[Networks.MAINNET_MIRROR]: 'https://console.mainnet-mirror.vega.rocks',
|
||||
};
|
||||
|
||||
const TokenLinks = {
|
||||
...EmptyLinks,
|
||||
[Networks.DEVNET]: 'https://dev.governance.vega.xyz',
|
||||
[Networks.STAGNET1]: 'https://governance.stagnet1.vega.rocks',
|
||||
[Networks.TESTNET]: 'https://governance.fairground.wtf',
|
||||
[Networks.VALIDATOR_TESTNET]:
|
||||
'https://governance.validators-testnet.vega.rocks',
|
||||
[Networks.MAINNET_MIRROR]: 'https://governance.mainnet-mirror.vega.rocks/',
|
||||
[Networks.MAINNET_MIRROR]: 'https://governance.mainnet-mirror.vega.rocks',
|
||||
[Networks.MAINNET]: 'https://governance.vega.xyz',
|
||||
};
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ export const ledgerEntriesProvider = makeDerivedDataProvider<
|
||||
(partsData) => {
|
||||
const entries = partsData[0] as ReturnType<typeof getData>;
|
||||
const assets = partsData[1] as Record<string, Asset>;
|
||||
const markets = partsData[1] as Record<string, Market>;
|
||||
const markets = partsData[2] as Record<string, Market>;
|
||||
return entries.map((entry) => {
|
||||
const asset = entry.assetId
|
||||
? (assets as Record<string, Asset>)[entry.assetId]
|
||||
|
||||
@@ -12,10 +12,12 @@ import type {
|
||||
import {
|
||||
AgGridLazy as AgGrid,
|
||||
DateRangeFilter,
|
||||
MarketNameCell,
|
||||
SetFilter,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import type * as Types from '@vegaprotocol/types';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import {
|
||||
AccountTypeMapping,
|
||||
DescriptionTransferTypeMapping,
|
||||
@@ -82,10 +84,14 @@ export const LedgerTable = (props: LedgerEntryProps) => {
|
||||
field: 'marketSender.tradableInstrument.instrument.code',
|
||||
cellRenderer: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<
|
||||
LedgerEntry,
|
||||
'marketSender.tradableInstrument.instrument.code'
|
||||
>) => value || '-',
|
||||
>) =>
|
||||
value && (
|
||||
<MarketNameCell value={value} data={data?.marketSender as Market} />
|
||||
),
|
||||
},
|
||||
{
|
||||
headerName: t('Receiver'),
|
||||
@@ -112,10 +118,17 @@ export const LedgerTable = (props: LedgerEntryProps) => {
|
||||
field: 'marketReceiver.tradableInstrument.instrument.code',
|
||||
cellRenderer: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<
|
||||
LedgerEntry,
|
||||
'marketReceiver.tradableInstrument.instrument.code'
|
||||
>) => value || '-',
|
||||
>) =>
|
||||
value && (
|
||||
<MarketNameCell
|
||||
value={value}
|
||||
data={data?.marketReceiver as Market}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
headerName: t('Transfer type'),
|
||||
|
||||
@@ -80,7 +80,7 @@ describe('OrderListTable', () => {
|
||||
'-',
|
||||
Schema.OrderTimeInForceCode[marketOrder.timeInForce],
|
||||
getDateTimeFormat().format(new Date(marketOrder.createdAt)),
|
||||
'Edit',
|
||||
'',
|
||||
];
|
||||
expectedValues.forEach((expectedValue, i) =>
|
||||
expect(cells[i]).toHaveTextContent(expectedValue)
|
||||
@@ -104,7 +104,7 @@ describe('OrderListTable', () => {
|
||||
Schema.OrderTimeInForceCode[limitOrder.timeInForce]
|
||||
}: ${getDateTimeFormat().format(new Date(limitOrder.expiresAt ?? ''))}`,
|
||||
getDateTimeFormat().format(new Date(limitOrder.createdAt)),
|
||||
'Edit',
|
||||
'',
|
||||
];
|
||||
expectedValues.forEach((expectedValue, i) =>
|
||||
expect(cells[i]).toHaveTextContent(expectedValue)
|
||||
|
||||
@@ -271,8 +271,8 @@ export const OrderListTable = memo<
|
||||
{
|
||||
colId: 'amend',
|
||||
...COL_DEFS.actions,
|
||||
minWidth: showAllActions ? 110 : COL_DEFS.actions.minWidth,
|
||||
maxWidth: showAllActions ? 110 : COL_DEFS.actions.minWidth,
|
||||
minWidth: showAllActions ? 90 : COL_DEFS.actions.minWidth,
|
||||
maxWidth: showAllActions ? 90 : COL_DEFS.actions.minWidth,
|
||||
cellRenderer: ({ data }: { data?: Order }) => {
|
||||
if (!data) return null;
|
||||
|
||||
@@ -285,14 +285,14 @@ export const OrderListTable = memo<
|
||||
data-testid="edit"
|
||||
onClick={() => onEdit(data)}
|
||||
>
|
||||
{t('Edit')}
|
||||
<VegaIcon name={VegaIconNames.EDIT} size={16} />
|
||||
</ButtonLink>
|
||||
)}
|
||||
<ButtonLink
|
||||
data-testid="cancel"
|
||||
onClick={() => onCancel(data)}
|
||||
>
|
||||
{t('Cancel')}
|
||||
<VegaIcon name={VegaIconNames.CROSS} size={16} />
|
||||
</ButtonLink>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -51,6 +51,7 @@ export interface Position {
|
||||
totalBalance: string;
|
||||
unrealisedPNL: string;
|
||||
updatedAt: string | null;
|
||||
productType?: string;
|
||||
}
|
||||
|
||||
export const getMetrics = (
|
||||
@@ -135,6 +136,7 @@ export const getMetrics = (
|
||||
totalBalance: totalBalance.multipliedBy(10 ** decimals).toFixed(),
|
||||
unrealisedPNL: position.unrealisedPNL,
|
||||
updatedAt: position.updatedAt || null,
|
||||
productType: market?.tradableInstrument.instrument.product.__typename,
|
||||
});
|
||||
});
|
||||
return metrics;
|
||||
|
||||
@@ -37,6 +37,7 @@ const singleRow: Position = {
|
||||
totalBalance: '123456',
|
||||
unrealisedPNL: '456',
|
||||
updatedAt: '2022-07-27T15:02:58.400Z',
|
||||
productType: 'Future',
|
||||
};
|
||||
|
||||
const singleRowData = [singleRow];
|
||||
@@ -80,6 +81,7 @@ describe('Positions', () => {
|
||||
render(<PositionsTable rowData={singleRowData} isReadOnly={false} />);
|
||||
});
|
||||
expect(screen.getByText('ETH/BTC (31 july 2022)')).toBeTruthy();
|
||||
expect(screen.getByText('Futr')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Does not fail if the market name does not match the split pattern', async () => {
|
||||
@@ -211,7 +213,7 @@ describe('Positions', () => {
|
||||
);
|
||||
});
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
expect(cells[11].textContent).toEqual('Close');
|
||||
expect(cells[11].textContent).toEqual('');
|
||||
});
|
||||
|
||||
it('do not display close button if openVolume is zero', async () => {
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
TooltipCellComponent,
|
||||
ExternalLink,
|
||||
Icon,
|
||||
VegaIconNames,
|
||||
VegaIcon,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
volumePrefix,
|
||||
@@ -391,7 +393,7 @@ export const PositionsTable = ({
|
||||
data-testid="close-position"
|
||||
onClick={() => data && onClose(data)}
|
||||
>
|
||||
{t('Close')}
|
||||
<VegaIcon name={VegaIconNames.CROSS} size={16} />
|
||||
</ButtonLink>
|
||||
) : null}
|
||||
{data?.assetId && (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from './asset-proposal-notification';
|
||||
export * from './market-proposal-notification';
|
||||
export * from './protocol-upgrade-countdown';
|
||||
export * from './protocol-upgrade-proposal-notification';
|
||||
export * from './proposals-list';
|
||||
export * from './protocol-upgrade-countdown';
|
||||
export * from './protocol-upgrade-in-progress-notification';
|
||||
export * from './protocol-upgrade-proposal-notification';
|
||||
export * from './voting-progress';
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import { useColumnDefs } from './use-column-defs';
|
||||
import { MarketNameProposalCell, useColumnDefs } from './use-column-defs';
|
||||
import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals';
|
||||
import { useProposalsListQuery } from '../../lib/proposals-data-provider/__generated__/Proposals';
|
||||
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
@@ -43,7 +43,7 @@ export const ProposalsList = ({
|
||||
defaultColDef={defaultColDef}
|
||||
getRowId={({ data }) => data.id}
|
||||
overlayNoRowsTemplate={t('No markets')}
|
||||
components={{ SuccessorMarketRenderer }}
|
||||
components={{ SuccessorMarketRenderer, MarketNameProposalCell }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
CenteredGridCellWrapper,
|
||||
COL_DEFS,
|
||||
DateRangeFilter,
|
||||
MarketProductPill,
|
||||
SetFilter,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import compact from 'lodash/compact';
|
||||
@@ -20,13 +21,42 @@ import type {
|
||||
VegaValueFormatterParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { InstrumentConfiguration } from '@vegaprotocol/types';
|
||||
import { ProposalStateMapping } from '@vegaprotocol/types';
|
||||
import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals';
|
||||
import { VoteProgress } from '../voting-progress';
|
||||
import { ProposalActionsDropdown } from '../proposal-actions-dropdown';
|
||||
import { getMarketProductType } from '../../utils/get-market-product-type';
|
||||
|
||||
export const MarketNameProposalCell = ({
|
||||
value,
|
||||
data,
|
||||
}: VegaICellRendererParams<
|
||||
ProposalListFieldsFragment,
|
||||
'terms.change.instrument.code'
|
||||
>) => {
|
||||
const { VEGA_TOKEN_URL } = useEnvironment();
|
||||
const { change } = data?.terms || {};
|
||||
if (change?.__typename === 'NewMarket' && VEGA_TOKEN_URL) {
|
||||
const productType = getMarketProductType(
|
||||
change.instrument as InstrumentConfiguration
|
||||
);
|
||||
const content = (
|
||||
<>
|
||||
<span data-testid="market-code">{value as string}</span>
|
||||
<MarketProductPill productType={productType} />
|
||||
</>
|
||||
);
|
||||
if (data?.id) {
|
||||
const link = `${VEGA_TOKEN_URL}/proposals/${data.id}`;
|
||||
return <ExternalLink href={link}>{content}</ExternalLink>;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const useColumnDefs = () => {
|
||||
const { VEGA_TOKEN_URL } = useEnvironment();
|
||||
const { params } = useNetworkParams([
|
||||
NetworkParams.governance_proposal_market_requiredMajority,
|
||||
]);
|
||||
@@ -43,26 +73,7 @@ export const useColumnDefs = () => {
|
||||
headerName: t('Market'),
|
||||
field: 'terms.change.instrument.code',
|
||||
cellStyle: { lineHeight: '14px' },
|
||||
cellRenderer: ({
|
||||
data,
|
||||
}: VegaICellRendererParams<
|
||||
ProposalListFieldsFragment,
|
||||
'terms.change.instrument.code'
|
||||
>) => {
|
||||
const { change } = data?.terms || {};
|
||||
if (change?.__typename === 'NewMarket' && VEGA_TOKEN_URL) {
|
||||
if (data?.id) {
|
||||
const link = `${VEGA_TOKEN_URL}/proposals/${data.id}`;
|
||||
return (
|
||||
<ExternalLink href={link}>
|
||||
{change.instrument.code}
|
||||
</ExternalLink>
|
||||
);
|
||||
}
|
||||
return change.instrument.code;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
cellRenderer: 'MarketNameProposalCell',
|
||||
},
|
||||
{
|
||||
colId: 'description',
|
||||
@@ -155,7 +166,7 @@ export const useColumnDefs = () => {
|
||||
},
|
||||
},
|
||||
]);
|
||||
}, [VEGA_TOKEN_URL, requiredMajorityPercentage]);
|
||||
}, [requiredMajorityPercentage]);
|
||||
|
||||
const defaultColDef: ColDef = useMemo(() => {
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { useProtocolUpgradeProposalLink } from '@vegaprotocol/environment';
|
||||
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
ExternalLink,
|
||||
Intent,
|
||||
NotificationBanner,
|
||||
SHORT,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { StoredNextProtocolUpgradeData } from '../lib';
|
||||
import {
|
||||
NEXT_PROTOCOL_UPGRADE_PROPOSAL_SNAPSHOT,
|
||||
useNextProtocolUpgradeProposal,
|
||||
} from '../lib';
|
||||
import { useLocalStorageSnapshot } from '@vegaprotocol/react-helpers';
|
||||
import { useBlockRising } from '../lib/protocol-upgrade-proposals/use-block-rising';
|
||||
|
||||
/**
|
||||
* A flag determining whether to get the upgrade proposal data from local
|
||||
* storage if `useNextProtocolUpgradeProposal` fails.
|
||||
*/
|
||||
const ALLOW_STORED_PROPOSAL_DATA = true;
|
||||
|
||||
export const ProtocolUpgradeInProgressNotification = () => {
|
||||
const { data, error } = useNextProtocolUpgradeProposal(undefined, true);
|
||||
const [nextUpgrade] = useLocalStorageSnapshot(
|
||||
NEXT_PROTOCOL_UPGRADE_PROPOSAL_SNAPSHOT
|
||||
);
|
||||
const { blocksRising, block } = useBlockRising();
|
||||
const detailsLink = useProtocolUpgradeProposalLink();
|
||||
|
||||
let vegaReleaseTag: string | undefined;
|
||||
let upgradeBlockHeight: string | undefined;
|
||||
|
||||
if (error && !data && nextUpgrade && ALLOW_STORED_PROPOSAL_DATA) {
|
||||
try {
|
||||
const stored = JSON.parse(nextUpgrade) as StoredNextProtocolUpgradeData;
|
||||
vegaReleaseTag = stored.vegaReleaseTag;
|
||||
upgradeBlockHeight = stored.upgradeBlockHeight;
|
||||
} catch {
|
||||
// no op
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If upgrade is in progress then none of the nodes should produce blocks,
|
||||
* same should be with the tendermint block info otherwise it's a network
|
||||
* issue and not an upgrade. The upgrade usually lasts for couple of minutes.
|
||||
*
|
||||
* Once the networks is back then the notification disappears.
|
||||
*/
|
||||
const upgradeInProgress =
|
||||
vegaReleaseTag &&
|
||||
upgradeBlockHeight &&
|
||||
!blocksRising &&
|
||||
block <= Number(upgradeBlockHeight);
|
||||
|
||||
if (!upgradeInProgress) return null;
|
||||
|
||||
return (
|
||||
<NotificationBanner intent={Intent.Danger} className={SHORT}>
|
||||
<div className="uppercase">
|
||||
{t('The network is being upgraded to %s', vegaReleaseTag)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'Trading and other network activity has stopped until the upgrade is complete.'
|
||||
)}{' '}
|
||||
{vegaReleaseTag && (
|
||||
<ExternalLink href={detailsLink(vegaReleaseTag)}>
|
||||
{t('View details')}
|
||||
</ExternalLink>
|
||||
)}
|
||||
</div>
|
||||
</NotificationBanner>
|
||||
);
|
||||
};
|
||||
@@ -29,27 +29,32 @@ export const ProtocolUpgradeProposalNotification = ({
|
||||
|
||||
const { vegaReleaseTag, upgradeBlockHeight } = data;
|
||||
|
||||
let timeLeft = time;
|
||||
let blocksLeft = Number(upgradeBlockHeight) - Number(lastBlockHeight);
|
||||
if (blocksLeft < 0) {
|
||||
blocksLeft = 0;
|
||||
timeLeft = 0;
|
||||
}
|
||||
|
||||
let countdown;
|
||||
switch (mode) {
|
||||
case ProtocolUpgradeCountdownMode.IN_BLOCKS:
|
||||
countdown = (
|
||||
<>
|
||||
<span className="text-vega-orange-500">
|
||||
{Number(upgradeBlockHeight) - Number(lastBlockHeight)}
|
||||
</span>{' '}
|
||||
<span className="text-vega-orange-500">{blocksLeft}</span>{' '}
|
||||
{t('blocks')}
|
||||
</>
|
||||
);
|
||||
break;
|
||||
case ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING:
|
||||
countdown =
|
||||
time !== undefined ? (
|
||||
timeLeft !== undefined ? (
|
||||
<span
|
||||
title={t('estimated time to protocol upgrade')}
|
||||
className="text-vega-orange-500"
|
||||
data-testid="upgrade-proposal-estimate"
|
||||
>
|
||||
{convertToCountdownString(time, '0:00:00:00')}
|
||||
{convertToCountdownString(timeLeft, '0:00:00:00')}
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-vega-orange-600 lowercase italic">
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './__generated__/ProtocolUpgradeProposals';
|
||||
export * from './use-block-rising';
|
||||
export * from './use-next-protocol-upgrade-proposals';
|
||||
export * from './use-time-to-upgrade';
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import { createClient } from '@vegaprotocol/apollo-client';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { useBlockInfo } from '@vegaprotocol/tendermint';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import type { BlockStatisticsQuery } from './__generated__/BlockStatistics';
|
||||
import { BlockStatisticsDocument } from './__generated__/BlockStatistics';
|
||||
import compact from 'lodash/compact';
|
||||
import max from 'lodash/max';
|
||||
|
||||
const CHECK_INTERVAL = 5000; // ms
|
||||
|
||||
/**
|
||||
* Allows stale block height for given number of times. If stale count is
|
||||
* greater than this number then it is marked as not rising (producing blocks).
|
||||
*/
|
||||
const ALLOW_STALE = 2; // times -> MAX(this, 1) * CHECK_INTERVAL ~> min check time
|
||||
|
||||
export const useBlockRising = () => {
|
||||
const [blocksRising, setBlocksRising] = useState(true);
|
||||
const [block, setBlock] = useState(0);
|
||||
const nodes = useEnvironment((state) => state.nodes);
|
||||
const clients = useMemo(() => {
|
||||
return nodes.map(
|
||||
(n) =>
|
||||
n &&
|
||||
n.length > 0 &&
|
||||
createClient({
|
||||
url: n,
|
||||
cacheConfig: undefined,
|
||||
retry: false,
|
||||
connectToDevTools: false,
|
||||
connectToHeaderStore: true,
|
||||
})
|
||||
);
|
||||
}, [nodes]);
|
||||
|
||||
const { refetch: fetchBlockInfo } = useBlockInfo();
|
||||
useEffect(() => {
|
||||
let stale = 0;
|
||||
let prev = 0;
|
||||
const check = async () => {
|
||||
const queries = clients.map((client, index) =>
|
||||
client
|
||||
? client
|
||||
.query<BlockStatisticsQuery>({
|
||||
query: BlockStatisticsDocument,
|
||||
fetchPolicy: 'network-only',
|
||||
errorPolicy: 'ignore',
|
||||
})
|
||||
.catch((err) =>
|
||||
Promise.reject(
|
||||
`could not retrieve statistics from ${nodes[index]}`
|
||||
)
|
||||
)
|
||||
: undefined
|
||||
);
|
||||
|
||||
const blockInfo = await fetchBlockInfo();
|
||||
const results = (await Promise.allSettled(compact(queries))).map(
|
||||
(res) => {
|
||||
if (res && res.status === 'fulfilled') {
|
||||
return res.value.data.statistics;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const heights = compact([
|
||||
...results.map((r) => r?.blockHeight),
|
||||
blockInfo?.result.block.header.height,
|
||||
]);
|
||||
const current = max(heights);
|
||||
if (current && Number(current) > prev) {
|
||||
setBlock(Number(current));
|
||||
prev = Number(current);
|
||||
stale = 0;
|
||||
if (!blocksRising) setBlocksRising(true);
|
||||
} else {
|
||||
if (stale > ALLOW_STALE) setBlocksRising(false);
|
||||
stale++;
|
||||
}
|
||||
};
|
||||
const interval = setInterval(check, CHECK_INTERVAL);
|
||||
check();
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [clients, fetchBlockInfo, blocksRising, nodes]);
|
||||
|
||||
return { blocksRising, block };
|
||||
};
|
||||
+27
-2
@@ -2,6 +2,13 @@ import { useMemo, useEffect } from 'react';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { removePaginationWrapper, isTestEnv } from '@vegaprotocol/utils';
|
||||
import { useProtocolUpgradeProposalsQuery } from './__generated__/ProtocolUpgradeProposals';
|
||||
import { useLocalStorageSnapshot } from '@vegaprotocol/react-helpers';
|
||||
import pick from 'lodash/pick';
|
||||
|
||||
const POLL_INTERVAL = 5000; // ms
|
||||
|
||||
export const NEXT_PROTOCOL_UPGRADE_PROPOSAL_SNAPSHOT =
|
||||
'next_protocol_upgrade_proposal';
|
||||
|
||||
export const useNextProtocolUpgradeProposals = (since?: number) => {
|
||||
const { data, loading, error, startPolling, stopPolling } =
|
||||
@@ -22,7 +29,7 @@ export const useNextProtocolUpgradeProposals = (since?: number) => {
|
||||
}
|
||||
|
||||
if (!isTestEnv() && window.location.hostname !== 'localhost') {
|
||||
startPolling(5000);
|
||||
startPolling(POLL_INTERVAL);
|
||||
}
|
||||
}, [error, startPolling, stopPolling]);
|
||||
|
||||
@@ -51,10 +58,28 @@ export const useNextProtocolUpgradeProposals = (since?: number) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const useNextProtocolUpgradeProposal = (since?: number) => {
|
||||
export type StoredNextProtocolUpgradeData = {
|
||||
vegaReleaseTag: string;
|
||||
upgradeBlockHeight: string;
|
||||
};
|
||||
export const useNextProtocolUpgradeProposal = (
|
||||
since?: number,
|
||||
persist = false
|
||||
) => {
|
||||
const { data, lastBlockHeight, loading, error } =
|
||||
useNextProtocolUpgradeProposals(since);
|
||||
|
||||
const [, setNextUpgrade] = useLocalStorageSnapshot(
|
||||
NEXT_PROTOCOL_UPGRADE_PROPOSAL_SNAPSHOT
|
||||
);
|
||||
useEffect(() => {
|
||||
if (data && persist) {
|
||||
setNextUpgrade(
|
||||
JSON.stringify(pick(data, 'upgradeBlockHeight', 'vegaReleaseTag'))
|
||||
);
|
||||
}
|
||||
}, [data, persist, setNextUpgrade]);
|
||||
|
||||
return {
|
||||
data: !data ? undefined : data[0],
|
||||
lastBlockHeight,
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import type { InstrumentConfiguration } from '@vegaprotocol/types';
|
||||
import { getMarketProductType } from './get-market-product-type';
|
||||
|
||||
describe('getMarketProductType', () => {
|
||||
it('should resolve product type properly', () => {
|
||||
expect(
|
||||
getMarketProductType({
|
||||
futureProduct: {
|
||||
quoteName: 'Market 1',
|
||||
},
|
||||
} as InstrumentConfiguration)
|
||||
).toEqual('Future');
|
||||
expect(
|
||||
getMarketProductType({
|
||||
spotProduct: {
|
||||
quoteName: 'Market 1',
|
||||
},
|
||||
} as unknown as InstrumentConfiguration)
|
||||
).toEqual('Spot');
|
||||
expect(
|
||||
getMarketProductType({
|
||||
perpetualProduct: {
|
||||
quoteName: 'Market 1',
|
||||
},
|
||||
} as unknown as InstrumentConfiguration)
|
||||
).toEqual('Perpetual');
|
||||
expect(
|
||||
getMarketProductType({
|
||||
product: {
|
||||
__typename: 'Perpetual',
|
||||
},
|
||||
futureProduct: {
|
||||
quoteName: 'Market 1',
|
||||
},
|
||||
} as unknown as InstrumentConfiguration)
|
||||
).toEqual('Perpetual');
|
||||
expect(
|
||||
getMarketProductType({
|
||||
product: {
|
||||
__typename: 'Spot',
|
||||
},
|
||||
futureProduct: {
|
||||
quoteName: 'Market 1',
|
||||
},
|
||||
} as unknown as InstrumentConfiguration)
|
||||
).toEqual('Spot');
|
||||
expect(
|
||||
getMarketProductType({
|
||||
product: {
|
||||
__typename: 'Future',
|
||||
},
|
||||
perpetualProduct: {
|
||||
quoteName: 'Market 1',
|
||||
},
|
||||
} as unknown as InstrumentConfiguration)
|
||||
).toEqual('Future');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { InstrumentConfiguration, Product } from '@vegaprotocol/types';
|
||||
|
||||
// it needs to be adjusted after deploy this https://github.com/vegaprotocol/vega/pull/9003
|
||||
export const getMarketProductType = (
|
||||
instrumentConfiguration: InstrumentConfiguration
|
||||
) => {
|
||||
return 'product' in instrumentConfiguration
|
||||
? (instrumentConfiguration.product as Product).__typename
|
||||
: 'futureProduct' in instrumentConfiguration
|
||||
? 'Future'
|
||||
: 'spotProduct' in instrumentConfiguration
|
||||
? 'Spot'
|
||||
: 'perpetualProduct' in instrumentConfiguration
|
||||
? 'Perpetual'
|
||||
: undefined;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"name": "tendermint",
|
||||
"name": "@vegaprotocol/tendermint",
|
||||
"version": "0.0.1"
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { TendermintBlockResponse } from '../types';
|
||||
export const useBlockInfo = (blockHeight?: number, canFetch = true) => {
|
||||
const { TENDERMINT_URL } = useEnvironment();
|
||||
|
||||
const url = `${TENDERMINT_URL}/block?height=${blockHeight}`;
|
||||
const url = `${TENDERMINT_URL}/block?height=${blockHeight || ''}`;
|
||||
const canFetchData = Boolean(
|
||||
TENDERMINT_URL && blockHeight && !isNaN(blockHeight) && canFetch
|
||||
);
|
||||
|
||||
@@ -4,6 +4,8 @@ import { Intent } from '../../utils/intent';
|
||||
import { Icon } from '../icon';
|
||||
import type { HTMLAttributes } from 'react';
|
||||
|
||||
export const SHORT = '!px-1 !py-1 min-h-fit';
|
||||
|
||||
interface NotificationBannerProps {
|
||||
intent?: Intent;
|
||||
children?: React.ReactNode;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ReactNode, HTMLProps } from 'react';
|
||||
import { Intent } from '../../utils/intent';
|
||||
import classNames from 'classnames';
|
||||
|
||||
type Size = 'lg' | 'md' | 'sm' | 'xs' | 'xxs';
|
||||
interface Props {
|
||||
interface Props extends Omit<HTMLProps<HTMLSpanElement>, 'size'> {
|
||||
children: ReactNode;
|
||||
intent?: Intent;
|
||||
size?: Size;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const getClasses = (size: Size, intent?: Intent, className?: string) => {
|
||||
const getClasses = (size: Size, intent: Intent, className?: string) => {
|
||||
return classNames(
|
||||
['rounded-md', 'leading-none', 'font-alpha', 'py-1 px-2'],
|
||||
['rounded-md', 'leading-none', 'font-alpha'],
|
||||
{
|
||||
'bg-vega-yellow dark:bg-vega-yellow': intent === Intent.Primary,
|
||||
'bg-vega-clight-500 dark:bg-vega-cdark-500': intent === Intent.None,
|
||||
@@ -25,19 +25,28 @@ const getClasses = (size: Size, intent?: Intent, className?: string) => {
|
||||
intent === Intent.Primary,
|
||||
},
|
||||
{
|
||||
'text-lg': size === 'lg',
|
||||
'text-base': size === 'md',
|
||||
'text-sma': size === 'sm',
|
||||
'text-xs': size === 'xs',
|
||||
'text-[10px]': size === 'xxs',
|
||||
'text-lg py-1 px-2': size === 'lg',
|
||||
'text-base py-1 px-2': size === 'md',
|
||||
'text-sm py-1 px-1': size === 'sm',
|
||||
'text-xs py-1 px-1': size === 'xs',
|
||||
'text-[10px] py-0 px-1': size === 'xxs',
|
||||
},
|
||||
className
|
||||
);
|
||||
};
|
||||
|
||||
export const Pill = ({ intent, size, className, children }: Props) => {
|
||||
export const Pill = ({
|
||||
intent,
|
||||
size,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: Props) => {
|
||||
return (
|
||||
<span className={getClasses(size || 'md', intent, className)}>
|
||||
<span
|
||||
className={getClasses(size || 'md', intent || Intent.None, className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { NotificationBanner } from '../notification-banner';
|
||||
import { NotificationBanner, SHORT } from '../notification-banner';
|
||||
import { Intent } from '../../utils/intent';
|
||||
import { TradingButton } from '../trading-button';
|
||||
|
||||
@@ -25,7 +25,7 @@ export const ViewingAsBanner = ({
|
||||
<NotificationBanner
|
||||
data-testid="view-banner"
|
||||
intent={Intent.None}
|
||||
className="!px-1 !py-1 min-h-fit"
|
||||
className={SHORT}
|
||||
>
|
||||
<div className="flex justify-between items-baseline">
|
||||
<span>
|
||||
|
||||
Reference in New Issue
Block a user