Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
400a30d707 | ||
|
|
06bf382b60 | ||
|
|
3d8ebbfaa5 | ||
|
|
b061d193a1 | ||
|
|
72e0cb76aa | ||
|
|
ca64516a52 | ||
|
|
55d692ea6f | ||
|
|
f235c03abe | ||
|
|
546deb0e1c | ||
|
|
042919eca9 |
@@ -1,7 +1,7 @@
|
||||
import { getNewAssetTxBody } from '../support/governance.functions';
|
||||
|
||||
context('Proposal page', { tags: '@smoke' }, function () {
|
||||
describe('Verify elements on page', function () {
|
||||
describe.skip('Verify elements on page', function () {
|
||||
const proposalHeading = 'proposals-heading';
|
||||
const dateTimeRegex =
|
||||
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
|
||||
|
||||
@@ -7,7 +7,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
|
||||
describe('Links and buttons', function () {
|
||||
it.skip('should have link for proposal page', function () {
|
||||
it('should have link for proposal page', function () {
|
||||
cy.getByTestId('home-proposals').within(() => {
|
||||
cy.get('[href="/proposals"]')
|
||||
.should('exist')
|
||||
@@ -51,7 +51,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should have external link for governance', function () {
|
||||
it('should have external link for governance', function () {
|
||||
cy.getByTestId('home-proposals').within(() => {
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
@@ -59,7 +59,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should have link for validator page', function () {
|
||||
it('should have link for validator page', function () {
|
||||
cy.getByTestId('home-validators').within(() => {
|
||||
cy.get('[href="/validators"]')
|
||||
.first()
|
||||
@@ -68,7 +68,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should have external link for validators', function () {
|
||||
it('should have external link for validators', function () {
|
||||
cy.getByTestId('home-validators').within(() => {
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
@@ -79,29 +79,29 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should have information on active nodes', function () {
|
||||
it('should have information on active nodes', function () {
|
||||
cy.getByTestId('node-information')
|
||||
.first()
|
||||
.should('contain.text', '2')
|
||||
.should('contain.text', '1')
|
||||
.and('contain.text', 'active nodes');
|
||||
});
|
||||
|
||||
it.skip('should have information on consensus nodes', function () {
|
||||
it('should have information on consensus nodes', function () {
|
||||
cy.getByTestId('node-information')
|
||||
.last()
|
||||
.should('contain.text', '2')
|
||||
.should('contain.text', '1')
|
||||
.and('contain.text', 'consensus nodes');
|
||||
});
|
||||
|
||||
it.skip('should contain link to specific validators', function () {
|
||||
it('should contain link to specific validators', function () {
|
||||
cy.getByTestId('validators')
|
||||
.should('have.length', '2')
|
||||
.should('have.length', '1')
|
||||
.each(($validator) => {
|
||||
cy.wrap($validator).find('a').should('have.attr', 'href');
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should have link for rewards page', function () {
|
||||
it('should have link for rewards page', function () {
|
||||
cy.getByTestId('home-rewards').within(() => {
|
||||
cy.get('[href="/rewards"]')
|
||||
.first()
|
||||
@@ -110,7 +110,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should have link for withdrawal page', function () {
|
||||
it('should have link for withdrawal page', function () {
|
||||
cy.getByTestId('home-vega-token').within(() => {
|
||||
cy.get('[href="/token/withdraw"]')
|
||||
.first()
|
||||
@@ -132,7 +132,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
|
||||
// 0006-NETW-003 0006-NETW-008 0006-NETW-009 0006-NETW-010 0006-NETW-012 0006-NETW-013 0006-NETW-017 0006-NETW-018 0006-NETW-019 0006-NETW-020
|
||||
it.skip('should have option to switch to different network node', function () {
|
||||
it('should have option to switch to different network node', function () {
|
||||
cy.getByTestId('git-network-data').within(() => {
|
||||
cy.getByTestId('link').click();
|
||||
});
|
||||
@@ -159,7 +159,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
cy.getByTestId('node-url-custom').click({ force: true });
|
||||
cy.get('input').should('exist');
|
||||
cy.getByTestId('connect').should('be.disabled');
|
||||
cy.getByTestId('icon-cross').click();
|
||||
cy.getByTestId('dialog-close').click();
|
||||
});
|
||||
|
||||
it('should display eth data', function () {
|
||||
|
||||
@@ -33,12 +33,12 @@ context(
|
||||
verifyTabHighlighted(navigation.proposals);
|
||||
});
|
||||
|
||||
it.skip('should have GOVERNANCE header visible', function () {
|
||||
it('should have GOVERNANCE header visible', function () {
|
||||
verifyPageHeader('Proposals');
|
||||
});
|
||||
|
||||
// 3002-PROP-023 3004-PMAC-002 3005-PASN-002 3006-PASC-002 3007-PNEC-002 3008-PFRO-003
|
||||
it.skip('new proposal page should have button for link to more information on proposals', function () {
|
||||
it('new proposal page should have button for link to more information on proposals', function () {
|
||||
cy.getByTestId('new-proposal-link').click();
|
||||
cy.url().should('include', '/proposals/propose/raw');
|
||||
cy.contains('To see Explorer data on proposals visit').within(() => {
|
||||
@@ -73,7 +73,7 @@ context(
|
||||
navigateTo(navigation.proposals);
|
||||
});
|
||||
|
||||
it.skip('should be able to see a working link for - find out more about Vega governance', function () {
|
||||
it('should be able to see a working link for - find out more about Vega governance', function () {
|
||||
// 3001-VOTE-001 // 3002-PROP-001
|
||||
cy.getByTestId(proposalDocumentationLink)
|
||||
.should('be.visible')
|
||||
|
||||
@@ -40,10 +40,10 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
|
||||
verifyConnectedToPubKey();
|
||||
});
|
||||
|
||||
it('Able to connect public key via wallet and view assets in wallet', function () {
|
||||
it.skip('Able to connect public key via wallet and view assets in wallet', function () {
|
||||
verifyConnectedToPubKey();
|
||||
cy.getByTestId('currency-title', { timeout: 10000 })
|
||||
.should('have.length.at.least', 4)
|
||||
.should('have.length.at.least', 2)
|
||||
.and('contain.text', 'USDC (fake)');
|
||||
});
|
||||
|
||||
|
||||
@@ -46,11 +46,11 @@ context('Validators Page - verify elements on page', function () {
|
||||
|
||||
// @ts-ignore clash between jest and cypress
|
||||
describe('with wallets disconnected', { tags: '@smoke' }, function () {
|
||||
it.skip('Should have validators tab highlighted', function () {
|
||||
it('Should have validators tab highlighted', function () {
|
||||
verifyTabHighlighted(navigation.validators);
|
||||
});
|
||||
|
||||
it.skip('Should have validators ON VEGA header visible', function () {
|
||||
it('Should have validators ON VEGA header visible', function () {
|
||||
verifyPageHeader('Validators');
|
||||
});
|
||||
|
||||
@@ -192,7 +192,7 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
// 1002-STKE-006
|
||||
it.skip('Should be able to see validator name', function () {
|
||||
it('Should be able to see validator name', function () {
|
||||
cy.getByTestId(validatorTitle).should('not.be.empty');
|
||||
});
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ LC_ALL="en_US.UTF-8"
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_METAMASK_SNAPS=true
|
||||
NX_PRODUCT_PERPETUALS=false
|
||||
NX_UPDATE_MARKET_STATE=false
|
||||
NX_PRODUCT_PERPETUALS=true
|
||||
NX_UPDATE_MARKET_STATE=true
|
||||
NX_REFERRALS=true
|
||||
NX_GOVERNANCE_TRANSFERS=false
|
||||
NX_GOVERNANCE_TRANSFERS=true
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import classNames from 'classnames';
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
interface HeadingProps {
|
||||
title?: string;
|
||||
title?: ReactNode;
|
||||
centerContent?: boolean;
|
||||
marginTop?: boolean;
|
||||
marginBottom?: boolean;
|
||||
|
||||
+3
-6
@@ -54,11 +54,8 @@ const ProposalTypeTags = ({
|
||||
|
||||
if (proposal.__typename === 'BatchProposal') {
|
||||
return (
|
||||
<div data-testid="proposal-type" className="flex gap-1">
|
||||
{proposal.subProposals?.map((subProposal, i) => {
|
||||
if (!subProposal?.terms) return null;
|
||||
return <ProposalTypeTag key={i} terms={subProposal.terms} />;
|
||||
})}
|
||||
<div data-testid="proposal-type">
|
||||
<ProposalInfoLabel variant="secondary">BatchProposal</ProposalInfoLabel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -315,7 +312,7 @@ const ProposalDetails = ({
|
||||
{proposal.subProposals.map((p, i) => {
|
||||
if (!p?.terms) return null;
|
||||
return (
|
||||
<li key={i} className="flex gap-3">
|
||||
<li key={i} className="flex gap-3 items-center">
|
||||
<span className={getIndicatorStyle(i + 1)}>{i + 1}</span>
|
||||
<span>
|
||||
<div>{renderDetails(p.terms)}</div>
|
||||
|
||||
@@ -3,16 +3,8 @@ import { useTranslation } from 'react-i18next';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
import {
|
||||
type BatchProposalFieldsFragment,
|
||||
type ProposalFieldsFragment,
|
||||
} from '../../__generated__/Proposals';
|
||||
|
||||
export const ProposalJson = ({
|
||||
proposal,
|
||||
}: {
|
||||
proposal: ProposalFieldsFragment | BatchProposalFieldsFragment;
|
||||
}) => {
|
||||
export const ProposalJson = ({ proposal }: { proposal?: unknown }) => {
|
||||
const { t } = useTranslation();
|
||||
const [showDetails, setShowDetails] = useState(false);
|
||||
|
||||
|
||||
+8
-3
@@ -5,6 +5,11 @@ import {
|
||||
} from './proposal-market-changes';
|
||||
import type { JsonValue } from '../../../../components/json-diff';
|
||||
|
||||
jest.mock('../proposal/market-name.tsx', () => ({
|
||||
...jest.requireActual('../proposal/market-name.tsx'),
|
||||
MarketName: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('applyImmutableKeysFromEarlierVersion', () => {
|
||||
it('returns an empty object if any argument is not an object or null', () => {
|
||||
const earlierVersion: JsonValue = null;
|
||||
@@ -57,21 +62,21 @@ describe('applyImmutableKeysFromEarlierVersion', () => {
|
||||
describe('ProposalMarketChanges', () => {
|
||||
it('renders correctly', () => {
|
||||
const { getByTestId } = render(
|
||||
<ProposalMarketChanges marketId="market-id" updatedProposal={{}} />
|
||||
<ProposalMarketChanges marketId="market-id" updateProposalNode={null} />
|
||||
);
|
||||
expect(getByTestId('proposal-market-changes')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('JsonDiff is not visible when showChanges is false', () => {
|
||||
const { queryByTestId } = render(
|
||||
<ProposalMarketChanges marketId="market-id" updatedProposal={{}} />
|
||||
<ProposalMarketChanges marketId="market-id" updateProposalNode={null} />
|
||||
);
|
||||
expect(queryByTestId('json-diff')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('JsonDiff is visible when showChanges is true', async () => {
|
||||
const { getByTestId } = render(
|
||||
<ProposalMarketChanges marketId="market-id" updatedProposal={{}} />
|
||||
<ProposalMarketChanges marketId="market-id" updateProposalNode={null} />
|
||||
);
|
||||
fireEvent.click(getByTestId('proposal-market-changes-toggle'));
|
||||
expect(getByTestId('json-diff')).toBeInTheDocument();
|
||||
|
||||
+91
-52
@@ -1,14 +1,24 @@
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import set from 'lodash/set';
|
||||
import get from 'lodash/get';
|
||||
import { JsonDiff } from '../../../../components/json-diff';
|
||||
import compact from 'lodash/compact';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { JsonDiff, type JsonValue } from '../../../../components/json-diff';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useState } from 'react';
|
||||
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import type { JsonValue } from '../../../../components/json-diff';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { ENV } from '../../../../config';
|
||||
import {
|
||||
useFetchProposal,
|
||||
useFetchProposals,
|
||||
flatten,
|
||||
isBatchProposalNode,
|
||||
isSingleProposalNode,
|
||||
type ProposalNode,
|
||||
type SingleProposalData,
|
||||
type SubProposalData,
|
||||
} from '../proposal/proposal-utils';
|
||||
import { MarketName } from '../proposal/market-name';
|
||||
|
||||
const immutableKeys = [
|
||||
'decimalPlaces',
|
||||
@@ -18,8 +28,8 @@ const immutableKeys = [
|
||||
];
|
||||
|
||||
export const applyImmutableKeysFromEarlierVersion = (
|
||||
earlierVersion: JsonValue,
|
||||
updatedVersion: JsonValue
|
||||
earlierVersion: unknown,
|
||||
updatedVersion: unknown
|
||||
) => {
|
||||
if (
|
||||
typeof earlierVersion !== 'object' ||
|
||||
@@ -35,7 +45,8 @@ export const applyImmutableKeysFromEarlierVersion = (
|
||||
|
||||
// Overwrite the immutable keys in the updatedVersionCopy with the earlier values
|
||||
immutableKeys.forEach((key) => {
|
||||
set(updatedVersionCopy, key, get(earlierVersion, key));
|
||||
const earlier = get(earlierVersion, key);
|
||||
if (earlier) set(updatedVersionCopy, key, earlier);
|
||||
});
|
||||
|
||||
return updatedVersionCopy;
|
||||
@@ -43,49 +54,84 @@ export const applyImmutableKeysFromEarlierVersion = (
|
||||
|
||||
interface ProposalMarketChangesProps {
|
||||
marketId: string;
|
||||
updatedProposal: JsonValue;
|
||||
/** This are the changes from proposal */
|
||||
updateProposalNode: ProposalNode | null;
|
||||
indicator?: number;
|
||||
}
|
||||
|
||||
export const ProposalMarketChanges = ({
|
||||
marketId,
|
||||
updatedProposal,
|
||||
updateProposalNode,
|
||||
indicator,
|
||||
}: ProposalMarketChangesProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [showChanges, setShowChanges] = useState(false);
|
||||
|
||||
const {
|
||||
state: { data },
|
||||
} = useFetch(`${ENV.rest}governance?proposalId=${marketId}`, undefined, true);
|
||||
const { data: originalProposalData } = useFetchProposal({
|
||||
proposalId: marketId,
|
||||
});
|
||||
|
||||
const {
|
||||
state: { data: enactedProposalData },
|
||||
} = useFetch(
|
||||
`${ENV.rest}governances?proposalState=STATE_ENACTED&proposalType=TYPE_UPDATE_MARKET`,
|
||||
undefined,
|
||||
true
|
||||
const { data: enactedProposalsData } = useFetchProposals({
|
||||
proposalState: 'STATE_ENACTED',
|
||||
proposalType: 'TYPE_UPDATE_MARKET',
|
||||
});
|
||||
|
||||
let updateProposal: SingleProposalData | SubProposalData | undefined;
|
||||
if (isBatchProposalNode(updateProposalNode)) {
|
||||
updateProposal = updateProposalNode.proposals.find(
|
||||
(p, i) =>
|
||||
p.terms.updateMarket?.marketId === marketId &&
|
||||
(indicator != null ? i === indicator - 1 : true)
|
||||
);
|
||||
}
|
||||
if (isSingleProposalNode(updateProposalNode)) {
|
||||
updateProposal = updateProposalNode.proposal;
|
||||
}
|
||||
|
||||
// this should get the proposal before the current one
|
||||
const enactedUpdateMarketProposals = orderBy(
|
||||
compact(
|
||||
flatten(enactedProposalsData).filter((enacted) => {
|
||||
const related = enacted.terms.updateMarket?.marketId === marketId;
|
||||
const notCurrent =
|
||||
enacted.id !== updateProposal?.id ||
|
||||
('batchId' in enacted && enacted.batchId !== updateProposal.id);
|
||||
const beforeCurrent =
|
||||
Number(enacted.terms.enactmentTimestamp) <
|
||||
Number(updateProposal?.terms.enactmentTimestamp);
|
||||
return related && notCurrent && beforeCurrent;
|
||||
})
|
||||
),
|
||||
[(proposal) => Number(proposal.terms.enactmentTimestamp)],
|
||||
'desc'
|
||||
);
|
||||
|
||||
// @ts-ignore no types here :-/
|
||||
const enacted = enactedProposalData?.connection?.edges
|
||||
.filter(
|
||||
// @ts-ignore no type here
|
||||
({ node }) => node?.proposal?.terms?.updateMarket?.marketId === marketId
|
||||
)
|
||||
// @ts-ignore no type here
|
||||
.sort((a, b) => {
|
||||
return (
|
||||
new Date(a?.node?.terms?.enactmentTimestamp).getTime() -
|
||||
new Date(b?.node?.terms?.enactmentTimestamp).getTime()
|
||||
);
|
||||
});
|
||||
const latestEnactedProposal =
|
||||
enactedUpdateMarketProposals.length > 0
|
||||
? enactedUpdateMarketProposals[0]
|
||||
: undefined;
|
||||
|
||||
const latestEnactedProposal = enacted?.length
|
||||
? enacted[enacted.length - 1]
|
||||
: undefined;
|
||||
let originalProposal;
|
||||
if (isBatchProposalNode(originalProposalData)) {
|
||||
originalProposal = originalProposalData.proposals.find(
|
||||
(proposal) => proposal.id === marketId && proposal.terms.newMarket != null
|
||||
);
|
||||
}
|
||||
if (isSingleProposalNode(originalProposalData)) {
|
||||
originalProposal = originalProposalData.proposal;
|
||||
}
|
||||
|
||||
const originalProposal =
|
||||
// @ts-ignore no types with useFetch TODO: check this is good
|
||||
data?.data?.proposal?.terms?.newMarket?.changes;
|
||||
// LEFT SIDE: update market proposal enacted just before this one
|
||||
// or original new market proposal
|
||||
const left =
|
||||
latestEnactedProposal?.terms.updateMarket?.changes ||
|
||||
originalProposal?.terms.newMarket?.changes;
|
||||
|
||||
// RIGHT SIDE: this update market proposal
|
||||
const right = applyImmutableKeysFromEarlierVersion(
|
||||
left,
|
||||
updateProposal?.terms.updateMarket?.changes
|
||||
);
|
||||
|
||||
return (
|
||||
<section data-testid="proposal-market-changes">
|
||||
@@ -94,25 +140,18 @@ export const ProposalMarketChanges = ({
|
||||
setToggleState={setShowChanges}
|
||||
dataTestId={'proposal-market-changes-toggle'}
|
||||
>
|
||||
<SubHeading title={t('updatesToMarket')} />
|
||||
<SubHeading
|
||||
title={
|
||||
<>
|
||||
{t('UpdateToMarket')}: <MarketName marketId={marketId} />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</CollapsibleToggle>
|
||||
|
||||
{showChanges && (
|
||||
<div className="mb-6">
|
||||
<JsonDiff
|
||||
left={latestEnactedProposal || originalProposal}
|
||||
right={
|
||||
latestEnactedProposal
|
||||
? applyImmutableKeysFromEarlierVersion(
|
||||
latestEnactedProposal,
|
||||
updatedProposal
|
||||
)
|
||||
: applyImmutableKeysFromEarlierVersion(
|
||||
originalProposal,
|
||||
updatedProposal
|
||||
)
|
||||
}
|
||||
/>
|
||||
<JsonDiff left={left as JsonValue} right={right as JsonValue} />
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
+5
@@ -2,6 +2,11 @@ import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { ProposalUpdateMarketState } from './proposal-update-market-state';
|
||||
import { MarketUpdateType } from '@vegaprotocol/types';
|
||||
|
||||
jest.mock('../proposal/market-name.tsx', () => ({
|
||||
...jest.requireActual('../proposal/market-name.tsx'),
|
||||
MarketName: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('<ProposalUpdateMarketState />', () => {
|
||||
const suspendProposal = {
|
||||
__typename: 'UpdateMarketState' as const,
|
||||
|
||||
+16
-7
@@ -10,6 +10,7 @@ import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { type UpdateMarketStatesFragment } from '../../__generated__/Proposals';
|
||||
import { MarketUpdateTypeMapping } from '@vegaprotocol/types';
|
||||
import { MarketName } from '../proposal/market-name';
|
||||
|
||||
interface ProposalUpdateMarketStateProps {
|
||||
change: UpdateMarketStatesFragment | null;
|
||||
@@ -20,16 +21,18 @@ export const ProposalUpdateMarketState = ({
|
||||
}: ProposalUpdateMarketStateProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [showDetails, setShowDetails] = useState(false);
|
||||
let market;
|
||||
let isTerminate = false;
|
||||
|
||||
if (!change) {
|
||||
if (!change || change.__typename !== 'UpdateMarketState') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (change.__typename === 'UpdateMarketState') {
|
||||
market = change?.market;
|
||||
isTerminate = change?.updateType === 'MARKET_STATE_UPDATE_TYPE_TERMINATE';
|
||||
const market = change?.market;
|
||||
const isTerminate =
|
||||
change?.updateType === 'MARKET_STATE_UPDATE_TYPE_TERMINATE';
|
||||
|
||||
let toggleTitle = t(change.updateType);
|
||||
if (toggleTitle.length === 0) {
|
||||
toggleTitle = t('MarketDetails');
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -39,7 +42,13 @@ export const ProposalUpdateMarketState = ({
|
||||
setToggleState={setShowDetails}
|
||||
dataTestId="proposal-market-data-toggle"
|
||||
>
|
||||
<SubHeading title={t('MarketDetails')} />
|
||||
<SubHeading
|
||||
title={
|
||||
<>
|
||||
{toggleTitle}: <MarketName marketId={market?.id} />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</CollapsibleToggle>
|
||||
|
||||
{showDetails && (
|
||||
|
||||
@@ -16,18 +16,31 @@ const getColour = (indicator: number, max = COLOURS.length) => {
|
||||
|
||||
export const getStyle = (indicator: number, max = COLOURS.length) =>
|
||||
classNames({
|
||||
'bg-vega-yellow-400': 'yellow' === getColour(indicator, max),
|
||||
'bg-vega-green-400': 'green' === getColour(indicator, max),
|
||||
'bg-vega-blue-400': 'blue' === getColour(indicator, max),
|
||||
'bg-vega-purple-400': 'purple' === getColour(indicator, max),
|
||||
'bg-vega-pink-400': 'pink' === getColour(indicator, max),
|
||||
'bg-vega-orange-400': 'orange' === getColour(indicator, max),
|
||||
'bg-vega-red-400': 'red' === getColour(indicator, max),
|
||||
'bg-vega-clight-600': 'none' === getColour(indicator, max),
|
||||
'bg-vega-yellow-400 after:bg-vega-yellow-400':
|
||||
'yellow' === getColour(indicator, max),
|
||||
'bg-vega-green-400 after:bg-vega-green-400':
|
||||
'green' === getColour(indicator, max),
|
||||
'bg-vega-blue-400 after:bg-vega-blue-400':
|
||||
'blue' === getColour(indicator, max),
|
||||
'bg-vega-purple-400 after:bg-vega-purple-400':
|
||||
'purple' === getColour(indicator, max),
|
||||
'bg-vega-pink-400 after:bg-vega-pink-400':
|
||||
'pink' === getColour(indicator, max),
|
||||
'bg-vega-orange-400 after:bg-vega-orange-400':
|
||||
'orange' === getColour(indicator, max),
|
||||
'bg-vega-red-400 after:bg-vega-red-400':
|
||||
'red' === getColour(indicator, max),
|
||||
'bg-vega-clight-600 after:bg-vega-clight-600':
|
||||
'none' === getColour(indicator, max),
|
||||
});
|
||||
|
||||
export const getIndicatorStyle = (indicator: number) =>
|
||||
classNames(
|
||||
'rounded-sm text-black inline-block px-1 py-1 font-alpha calt h-8',
|
||||
getStyle(indicator)
|
||||
'rounded-sm text-black inline-block px-1 py-1 font-alpha calt h-8 w-7 text-center',
|
||||
'text-border-1',
|
||||
getStyle(indicator),
|
||||
// Comment below if you want to remove the "chevron"
|
||||
'relative mr-[11px]',
|
||||
'after:absolute after:z-[-1] after:top-1 after:right-[-11px] after:rounded-sm',
|
||||
"after:w-[22.62px] after:h-[22.62px] after:rotate-45 after:content-['']"
|
||||
);
|
||||
|
||||
+4
-21
@@ -13,6 +13,7 @@ import { ProposalUpdateBenefitTiers } from '../proposal-update-benefit-tiers';
|
||||
import { ProposalUpdateMarketState } from '../proposal-update-market-state';
|
||||
import { ProposalVolumeDiscountProgramDetails } from '../proposal-volume-discount-program-details';
|
||||
import { getIndicatorStyle } from './colours';
|
||||
import { type ProposalNode } from './proposal-utils';
|
||||
|
||||
export const ProposalChangeDetails = ({
|
||||
proposal,
|
||||
@@ -22,8 +23,7 @@ export const ProposalChangeDetails = ({
|
||||
}: {
|
||||
proposal: Proposal | BatchProposal;
|
||||
terms: ProposalTermsFieldsFragment;
|
||||
// eslint-disable-next-line
|
||||
restData: any;
|
||||
restData: ProposalNode | null;
|
||||
indicator?: number;
|
||||
}) => {
|
||||
let details = null;
|
||||
@@ -63,30 +63,13 @@ export const ProposalChangeDetails = ({
|
||||
}
|
||||
case 'UpdateMarket': {
|
||||
if (proposal.id) {
|
||||
const marketId = terms.change.marketId;
|
||||
const proposalData = restData?.data?.proposal;
|
||||
let updatedProposal = null;
|
||||
// single proposal
|
||||
if ('terms' in proposalData) {
|
||||
updatedProposal = proposalData?.terms?.updateMarket?.changes;
|
||||
}
|
||||
// batch proposal - need to fish for the actual changes
|
||||
if (
|
||||
'batchTerms' in proposalData &&
|
||||
Array.isArray(proposalData.batchTerms?.changes)
|
||||
) {
|
||||
updatedProposal = proposalData?.batchTerms?.changes.find(
|
||||
(ch: { updateMarket?: { marketId: string } }) =>
|
||||
ch?.updateMarket?.marketId === marketId
|
||||
)?.updateMarket?.changes;
|
||||
}
|
||||
|
||||
details = (
|
||||
<div className="flex flex-col gap-4">
|
||||
<ProposalMarketData proposalId={proposal.id} />
|
||||
<ProposalMarketChanges
|
||||
indicator={indicator}
|
||||
marketId={terms.change.marketId}
|
||||
updatedProposal={updatedProposal}
|
||||
updateProposalNode={restData}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
import compact from 'lodash/compact';
|
||||
import { ENV } from '../../../../config';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
type Maybe<T> = T | null | undefined;
|
||||
|
||||
type ProposalState =
|
||||
| 'STATE_UNSPECIFIED'
|
||||
| 'STATE_FAILED'
|
||||
| 'STATE_OPEN'
|
||||
| 'STATE_PASSED'
|
||||
| 'STATE_REJECTED'
|
||||
| 'STATE_DECLINED'
|
||||
| 'STATE_ENACTED'
|
||||
| 'STATE_WAITING_FOR_NODE_VOTE';
|
||||
|
||||
type ProposalType =
|
||||
| 'TYPE_UNSPECIFIED'
|
||||
| 'TYPE_ALL'
|
||||
| 'TYPE_NEW_MARKET'
|
||||
| 'TYPE_UPDATE_MARKET'
|
||||
| 'TYPE_NETWORK_PARAMETERS'
|
||||
| 'TYPE_NEW_ASSET'
|
||||
| 'TYPE_NEW_FREE_FORM'
|
||||
| 'TYPE_UPDATE_ASSET'
|
||||
| 'TYPE_NEW_SPOT_MARKET'
|
||||
| 'TYPE_UPDATE_SPOT_MARKET'
|
||||
| 'TYPE_NEW_TRANSFER'
|
||||
| 'TYPE_CANCEL_TRANSFER'
|
||||
| 'TYPE_UPDATE_MARKET_STATE'
|
||||
| 'TYPE_UPDATE_REFERRAL_PROGRAM'
|
||||
| 'TYPE_UPDATE_VOLUME_DISCOUNT_PROGRAM';
|
||||
|
||||
type ProposalNodeType = 'TYPE_SINGLE_OR_UNSPECIFIED' | 'TYPE_BATCH';
|
||||
|
||||
type ProposalData = {
|
||||
id: string;
|
||||
rationale: {
|
||||
description: string;
|
||||
title: string;
|
||||
};
|
||||
state: ProposalState;
|
||||
timestamp: string;
|
||||
};
|
||||
|
||||
type Terms = {
|
||||
cancelTransfer?: { changes: unknown };
|
||||
enactmentTimestamp: string;
|
||||
newAsset?: { changes: unknown };
|
||||
newFreeform: object;
|
||||
newMarket?: { changes: unknown };
|
||||
newSpotMarket?: { changes: unknown };
|
||||
newTransfer?: { changes: unknown };
|
||||
updateAsset?: { assetId: string; changes: unknown };
|
||||
updateMarket?: { marketId: string; changes: unknown };
|
||||
updateMarketState?: {
|
||||
changes: {
|
||||
marketId: string;
|
||||
price: string;
|
||||
updateType:
|
||||
| 'MARKET_STATE_UPDATE_TYPE_UNSPECIFIED'
|
||||
| 'MARKET_STATE_UPDATE_TYPE_TERMINATE'
|
||||
| 'MARKET_STATE_UPDATE_TYPE_SUSPEND'
|
||||
| 'MARKET_STATE_UPDATE_TYPE_RESUME';
|
||||
};
|
||||
};
|
||||
updateNetworkParameter?: { changes: unknown };
|
||||
updateReferralProgram?: { changes: unknown };
|
||||
updateSpotMarket?: { marketId: string; changes: unknown };
|
||||
updateVolumeDiscountProgram?: { changes: unknown };
|
||||
};
|
||||
|
||||
export type SingleProposalData = ProposalData & {
|
||||
terms: Terms & {
|
||||
closingTimestamp: string;
|
||||
validationTimestamp: string;
|
||||
};
|
||||
};
|
||||
|
||||
type BatchProposalData = ProposalData & {
|
||||
batchTerms: {
|
||||
changes: Terms[];
|
||||
};
|
||||
};
|
||||
|
||||
export type SubProposalData = SingleProposalData & {
|
||||
batchId: string;
|
||||
};
|
||||
|
||||
export type ProposalNode = {
|
||||
proposal: ProposalData;
|
||||
proposalType: ProposalNodeType;
|
||||
proposals: SubProposalData[];
|
||||
};
|
||||
|
||||
type SingleProposalNode = ProposalNode & {
|
||||
proposal: SingleProposalData;
|
||||
proposalType: 'TYPE_SINGLE_OR_UNSPECIFIED';
|
||||
proposals: [];
|
||||
};
|
||||
|
||||
type BatchProposalNode = ProposalNode & {
|
||||
proposal: BatchProposalData;
|
||||
proposalType: 'TYPE_BATCH';
|
||||
};
|
||||
|
||||
export const isProposalNode = (node: unknown): node is ProposalNode =>
|
||||
Boolean(
|
||||
typeof node === 'object' &&
|
||||
node &&
|
||||
'proposal' in node &&
|
||||
typeof node.proposal === 'object' &&
|
||||
node?.proposal &&
|
||||
'id' in node.proposal &&
|
||||
node?.proposal?.id
|
||||
);
|
||||
|
||||
export const isSingleProposalNode = (
|
||||
node: Maybe<ProposalNode>
|
||||
): node is SingleProposalNode =>
|
||||
Boolean(
|
||||
node &&
|
||||
node?.proposalType === 'TYPE_SINGLE_OR_UNSPECIFIED' &&
|
||||
node?.proposal
|
||||
);
|
||||
|
||||
export const isBatchProposalNode = (
|
||||
node: Maybe<ProposalNode>
|
||||
): node is BatchProposalNode =>
|
||||
Boolean(
|
||||
node &&
|
||||
node?.proposalType === 'TYPE_BATCH' &&
|
||||
node?.proposal &&
|
||||
'batchTerms' in node.proposal &&
|
||||
node?.proposals?.length > 0
|
||||
);
|
||||
|
||||
// this includes also batch proposals with `updateMarket`s 👍
|
||||
const PROPOSALS_ENDPOINT = `${ENV.rest}governances?proposalState=:proposalState&proposalType=:proposalType`;
|
||||
|
||||
// this can be queried also by sub proposal id as `proposalId` and it will
|
||||
// return full batch proposal data with all of its sub proposals including
|
||||
// the requested one inside `proposals` array.
|
||||
const PROPOSAL_ENDPOINT = `${ENV.rest}governance?proposalId=:proposalId`;
|
||||
|
||||
export const getProposals = async ({
|
||||
proposalState,
|
||||
proposalType,
|
||||
}: {
|
||||
proposalState: ProposalState;
|
||||
proposalType: ProposalType;
|
||||
}) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
PROPOSALS_ENDPOINT.replace(':proposalState', proposalState).replace(
|
||||
':proposalType',
|
||||
proposalType
|
||||
)
|
||||
);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if (
|
||||
data &&
|
||||
'connection' in data &&
|
||||
data.connection &&
|
||||
'edges' in data.connection &&
|
||||
data.connection.edges?.length > 0
|
||||
) {
|
||||
const nodes = compact(
|
||||
data.connection.edges.map((e: { node?: object }) => e?.node)
|
||||
).filter(isProposalNode);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// NOOP - ignore errors
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
export const getProposal = async ({ proposalId }: { proposalId: string }) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
PROPOSAL_ENDPOINT.replace(':proposalId', proposalId)
|
||||
);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if (data && 'data' in data && isProposalNode(data.data)) {
|
||||
return data.data as ProposalNode;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// NOOP - ignore errors
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const useFetchProposal = ({ proposalId }: { proposalId?: string }) => {
|
||||
const [data, setData] = useState<ProposalNode | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const cb = async () => {
|
||||
if (!proposalId) return;
|
||||
|
||||
setLoading(true);
|
||||
const data = await getProposal({ proposalId });
|
||||
setLoading(false);
|
||||
if (data) {
|
||||
setData(data);
|
||||
}
|
||||
};
|
||||
cb();
|
||||
}, [proposalId]);
|
||||
|
||||
return { data, loading };
|
||||
};
|
||||
|
||||
export const useFetchProposals = ({
|
||||
proposalState,
|
||||
proposalType,
|
||||
}: {
|
||||
proposalState: ProposalState;
|
||||
proposalType: ProposalType;
|
||||
}) => {
|
||||
const [data, setData] = useState<ProposalNode[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const cb = async () => {
|
||||
setLoading(true);
|
||||
const data = await getProposals({ proposalState, proposalType });
|
||||
setLoading(false);
|
||||
if (data) {
|
||||
setData(data);
|
||||
}
|
||||
};
|
||||
cb();
|
||||
}, [proposalState, proposalType]);
|
||||
|
||||
return { data, loading };
|
||||
};
|
||||
|
||||
export const flatten = (
|
||||
nodes: ProposalNode[]
|
||||
): (SingleProposalData | SubProposalData)[] => {
|
||||
const flattenNodes = [];
|
||||
for (const node of nodes) {
|
||||
if (isSingleProposalNode(node)) {
|
||||
flattenNodes.push(node.proposal);
|
||||
}
|
||||
if (isBatchProposalNode(node)) {
|
||||
for (const sub of node.proposals) {
|
||||
flattenNodes.push(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
return flattenNodes;
|
||||
};
|
||||
@@ -61,7 +61,7 @@ const renderComponent = (proposal: IProposal) => {
|
||||
<MemoryRouter>
|
||||
<MockedProvider>
|
||||
<VegaWalletProvider config={vegaWalletConfig}>
|
||||
<Proposal restData={{}} proposal={proposal} />
|
||||
<Proposal restData={null} proposal={proposal} />
|
||||
</VegaWalletProvider>
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
|
||||
@@ -8,15 +8,17 @@ import { ProposalJson } from '../proposal-json';
|
||||
import { UserVote } from '../vote-details';
|
||||
import Routes from '../../../routes';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import { type ProposalNode } from './proposal-utils';
|
||||
import { useVoteSubmit } from '@vegaprotocol/proposals';
|
||||
import { useUserVote } from '../vote-details/use-user-vote';
|
||||
import { type Proposal as IProposal, type BatchProposal } from '../../types';
|
||||
import { ProposalChangeDetails } from './proposal-change-details';
|
||||
import { type JsonValue } from 'type-fest';
|
||||
|
||||
export interface ProposalProps {
|
||||
proposal: IProposal | BatchProposal;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
restData: any;
|
||||
restData: ProposalNode | null;
|
||||
}
|
||||
|
||||
export const Proposal = ({ proposal, restData }: ProposalProps) => {
|
||||
@@ -95,7 +97,7 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
<ProposalJson proposal={restData?.data?.proposal} />
|
||||
<ProposalJson proposal={restData?.proposal as unknown as JsonValue} />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
+154
-120
@@ -16,6 +16,7 @@ import {
|
||||
} from '../../__generated__/Proposals';
|
||||
import { useBatchVoteInformation } from '../../hooks/use-vote-information';
|
||||
import { getIndicatorStyle } from '../proposal/colours';
|
||||
import { MarketName } from '../proposal/market-name';
|
||||
|
||||
export const CompactVotes = ({ number }: { number: BigNumber }) => (
|
||||
<CompactNumber
|
||||
@@ -40,8 +41,9 @@ const VoteProgress = ({
|
||||
children,
|
||||
}: VoteProgressProps) => {
|
||||
const containerClasses = classNames(
|
||||
'relative h-10 rounded-md border border-vega-dark-300 overflow-hidden',
|
||||
colourfulBg ? 'bg-vega-pink' : 'bg-vega-dark-400'
|
||||
'relative h-2 rounded-md overflow-hidden',
|
||||
// 'border border-vega-dark-300',
|
||||
colourfulBg ? 'bg-vega-red' : 'bg-vega-dark-200'
|
||||
);
|
||||
|
||||
const progressClasses = classNames(
|
||||
@@ -50,17 +52,19 @@ const VoteProgress = ({
|
||||
);
|
||||
|
||||
const textClasses = classNames(
|
||||
'absolute top-0 left-0 w-full h-full flex items-center justify-start px-3 text-black'
|
||||
'w-full flex items-center justify-start text-white text-sm pb-1'
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={containerClasses}>
|
||||
<div
|
||||
className={progressClasses}
|
||||
style={{ width: `${percentageFor}%` }}
|
||||
data-testid={testId}
|
||||
/>
|
||||
<div>
|
||||
<div className={textClasses}>{children}</div>
|
||||
<div className={containerClasses}>
|
||||
<div
|
||||
className={progressClasses}
|
||||
style={{ width: `${percentageFor}%` }}
|
||||
data-testid={testId}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -79,14 +83,22 @@ const Status = ({ reached, threshold, text, testId }: StatusProps) => {
|
||||
<div data-testid={testId}>
|
||||
{reached ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<VegaIcon name={VegaIconNames.TICK} size={20} />
|
||||
<VegaIcon
|
||||
name={VegaIconNames.TICK}
|
||||
className="text-vega-green"
|
||||
size={20}
|
||||
/>
|
||||
<span>
|
||||
{threshold.toString()}% {text} {t('met')}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2">
|
||||
<VegaIcon name={VegaIconNames.CROSS} size={20} />
|
||||
<VegaIcon
|
||||
name={VegaIconNames.CROSS}
|
||||
className="text-vega-red"
|
||||
size={20}
|
||||
/>
|
||||
<span>
|
||||
{threshold.toString()}% {text} {t('not met')}
|
||||
</span>
|
||||
@@ -152,7 +164,7 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => {
|
||||
<p className="flex gap-2 m-0 items-center">
|
||||
<VegaIcon
|
||||
name={VegaIconNames.CROSS}
|
||||
className="text-vega-pink"
|
||||
className="text-vega-red"
|
||||
size={20}
|
||||
/>
|
||||
{t(
|
||||
@@ -215,7 +227,7 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => {
|
||||
<p className="flex gap-2 m-0 items-center">
|
||||
<VegaIcon
|
||||
name={VegaIconNames.CROSS}
|
||||
className="text-vega-pink"
|
||||
className="text-vega-red"
|
||||
size={20}
|
||||
/>
|
||||
{t('Proposal failed: {{count}} of {{total}} proposals passed', {
|
||||
@@ -237,6 +249,7 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => {
|
||||
if (!p?.terms) return null;
|
||||
return (
|
||||
<VoteBreakdownBatchSubProposal
|
||||
indicator={i + 1}
|
||||
key={i}
|
||||
proposal={proposal}
|
||||
votes={proposal.votes}
|
||||
@@ -273,21 +286,39 @@ const VoteBreakdownBatchSubProposal = ({
|
||||
const isProposalOpen = proposal?.state === ProposalState.STATE_OPEN;
|
||||
const isUpdateMarket = terms?.change?.__typename === 'UpdateMarket';
|
||||
|
||||
let marketId = undefined;
|
||||
if (terms?.change?.__typename === 'UpdateMarket') {
|
||||
marketId = terms.change.marketId;
|
||||
}
|
||||
if (terms?.change?.__typename === 'UpdateMarketState') {
|
||||
marketId = terms.change.market.id;
|
||||
}
|
||||
|
||||
const marketName = marketId ? (
|
||||
<>
|
||||
: <MarketName marketId={marketId} />
|
||||
</>
|
||||
) : null;
|
||||
|
||||
const indicatorElement = indicator && (
|
||||
<span className={getIndicatorStyle(indicator)}>{indicator}</span>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-baseline gap-3">
|
||||
<div className="mb-6">
|
||||
<div className="flex items-baseline gap-3 mb-3">
|
||||
{indicatorElement}
|
||||
<h4>{t(terms.change.__typename)}</h4>
|
||||
<h4>
|
||||
{t(terms.change.__typename)} {marketName}
|
||||
</h4>
|
||||
</div>
|
||||
<div className="rounded-sm bg-vega-dark-100 p-3">
|
||||
<VoteBreakDownUI
|
||||
voteInfo={voteInfo}
|
||||
isProposalOpen={isProposalOpen}
|
||||
isUpdateMarket={isUpdateMarket}
|
||||
/>
|
||||
</div>
|
||||
<VoteBreakDownUI
|
||||
voteInfo={voteInfo}
|
||||
isProposalOpen={isProposalOpen}
|
||||
isUpdateMarket={isUpdateMarket}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -302,11 +333,13 @@ const VoteBreakdownNormal = ({ proposal }: { proposal: Proposal }) => {
|
||||
const isUpdateMarket = proposal?.terms?.change?.__typename === 'UpdateMarket';
|
||||
|
||||
return (
|
||||
<VoteBreakDownUI
|
||||
voteInfo={voteInfo}
|
||||
isProposalOpen={isProposalOpen}
|
||||
isUpdateMarket={isUpdateMarket}
|
||||
/>
|
||||
<div className="mb-6">
|
||||
<VoteBreakDownUI
|
||||
voteInfo={voteInfo}
|
||||
isProposalOpen={isProposalOpen}
|
||||
isUpdateMarket={isUpdateMarket}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -370,13 +403,13 @@ const VoteBreakDownUI = ({
|
||||
'flex justify-between flex-wrap gap-6'
|
||||
);
|
||||
const sectionClasses = classNames('min-w-[300px] flex-1 flex-grow');
|
||||
const headingClasses = classNames('mb-2 text-vega-dark-400');
|
||||
const headingClasses = classNames('mb-2 text-sm text-white font-bold');
|
||||
const progressDetailsClasses = classNames(
|
||||
'flex justify-between flex-wrap mt-2 text-sm'
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mb-6">
|
||||
<div>
|
||||
{isProposalOpen && (
|
||||
<div
|
||||
data-testid="vote-status"
|
||||
@@ -393,7 +426,7 @@ const VoteBreakDownUI = ({
|
||||
<VegaIcon
|
||||
name={VegaIconNames.CROSS}
|
||||
size={20}
|
||||
className="text-vega-pink"
|
||||
className="text-vega-red"
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
@@ -409,103 +442,13 @@ const VoteBreakDownUI = ({
|
||||
<p className="m-0">
|
||||
<Trans
|
||||
i18nKey={'Currently expected to <0>fail</0>'}
|
||||
components={[<span className="text-vega-pink" />]}
|
||||
components={[<span className="text-vega-red" />]}
|
||||
/>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isUpdateMarket && (
|
||||
<div className="mb-4">
|
||||
<h3 className={headingClasses}>{t('liquidityProviderVote')}</h3>
|
||||
<div className={sectionWrapperClasses}>
|
||||
<section
|
||||
className={sectionClasses}
|
||||
data-testid="lp-majority-breakdown"
|
||||
>
|
||||
<VoteProgress
|
||||
percentageFor={lpVoteWeight}
|
||||
colourfulBg={true}
|
||||
testId="lp-majority-progress"
|
||||
>
|
||||
<Status
|
||||
reached={majorityLPMet}
|
||||
threshold={requiredMajorityLPPercentage}
|
||||
text={t('majorityThreshold')}
|
||||
testId={
|
||||
majorityLPMet ? 'lp-majority-met' : 'lp-majority-not-met'
|
||||
}
|
||||
/>
|
||||
</VoteProgress>
|
||||
|
||||
<div className={progressDetailsClasses}>
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{t('liquidityProviderVotesFor')}:</span>
|
||||
<Tooltip
|
||||
description={
|
||||
<span>{lpVoteWeight.toFixed(defaultDP)}%</span>
|
||||
}
|
||||
>
|
||||
<button>{lpVoteWeight.toFixed(1)}%</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{t('liquidityProviderVotesAgainst')}:</span>
|
||||
<span>
|
||||
<Tooltip
|
||||
description={
|
||||
<span>{noLPPercentage.toFixed(defaultDP)}%</span>
|
||||
}
|
||||
>
|
||||
<button>{noLPPercentage.toFixed(1)}%</button>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
className={sectionClasses}
|
||||
data-testid="lp-participation-breakdown"
|
||||
>
|
||||
<VoteProgress
|
||||
percentageFor={
|
||||
lpParticipationThresholdProgress || new BigNumber(0)
|
||||
}
|
||||
testId="lp-participation-progress"
|
||||
>
|
||||
<Status
|
||||
reached={participationLPMet}
|
||||
threshold={requiredParticipationLP || new BigNumber(1)}
|
||||
text={t('participationThreshold')}
|
||||
testId={
|
||||
participationLPMet
|
||||
? 'lp-participation-met'
|
||||
: 'lp-participation-not-met'
|
||||
}
|
||||
/>
|
||||
</VoteProgress>
|
||||
|
||||
<div className="flex mt-2 text-sm">
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{t('totalLiquidityProviderTokensVoted')}:</span>
|
||||
<Tooltip
|
||||
description={formatNumber(
|
||||
totalEquityLikeShareWeight,
|
||||
defaultDP
|
||||
)}
|
||||
>
|
||||
<span>{totalEquityLikeShareWeight.toFixed(1)}%</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isUpdateMarket && <h3 className={headingClasses}>{t('tokenVote')}</h3>}
|
||||
<div className={sectionWrapperClasses}>
|
||||
<section
|
||||
@@ -605,6 +548,97 @@ const VoteBreakDownUI = ({
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{/** Liquidity provider vote */}
|
||||
{isUpdateMarket && (
|
||||
<div className="mt-3">
|
||||
<h3 className={headingClasses}>{t('liquidityProviderVote')}</h3>
|
||||
<div className={sectionWrapperClasses}>
|
||||
<section
|
||||
className={sectionClasses}
|
||||
data-testid="lp-majority-breakdown"
|
||||
>
|
||||
<VoteProgress
|
||||
percentageFor={lpVoteWeight}
|
||||
colourfulBg={true}
|
||||
testId="lp-majority-progress"
|
||||
>
|
||||
<Status
|
||||
reached={majorityLPMet}
|
||||
threshold={requiredMajorityLPPercentage}
|
||||
text={t('majorityThreshold')}
|
||||
testId={
|
||||
majorityLPMet ? 'lp-majority-met' : 'lp-majority-not-met'
|
||||
}
|
||||
/>
|
||||
</VoteProgress>
|
||||
|
||||
<div className={progressDetailsClasses}>
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{t('liquidityProviderVotesFor')}:</span>
|
||||
<Tooltip
|
||||
description={
|
||||
<span>{lpVoteWeight.toFixed(defaultDP)}%</span>
|
||||
}
|
||||
>
|
||||
<button>{lpVoteWeight.toFixed(1)}%</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{t('liquidityProviderVotesAgainst')}:</span>
|
||||
<span>
|
||||
<Tooltip
|
||||
description={
|
||||
<span>{noLPPercentage.toFixed(defaultDP)}%</span>
|
||||
}
|
||||
>
|
||||
<button>{noLPPercentage.toFixed(1)}%</button>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
className={sectionClasses}
|
||||
data-testid="lp-participation-breakdown"
|
||||
>
|
||||
<VoteProgress
|
||||
percentageFor={
|
||||
lpParticipationThresholdProgress || new BigNumber(0)
|
||||
}
|
||||
testId="lp-participation-progress"
|
||||
>
|
||||
<Status
|
||||
reached={participationLPMet}
|
||||
threshold={requiredParticipationLP || new BigNumber(1)}
|
||||
text={t('participationThreshold')}
|
||||
testId={
|
||||
participationLPMet
|
||||
? 'lp-participation-met'
|
||||
: 'lp-participation-not-met'
|
||||
}
|
||||
/>
|
||||
</VoteProgress>
|
||||
|
||||
<div className="flex mt-2 text-sm">
|
||||
<div className="flex items-center gap-1">
|
||||
<span>{t('totalLiquidityProviderTokensVoted')}:</span>
|
||||
<Tooltip
|
||||
description={formatNumber(
|
||||
totalEquityLikeShareWeight,
|
||||
defaultDP
|
||||
)}
|
||||
>
|
||||
<span>{totalEquityLikeShareWeight.toFixed(1)}%</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { ENV } from '../../../config';
|
||||
import { Proposal } from '../components/proposal';
|
||||
import { ProposalNotFound } from '../components/proposal-not-found';
|
||||
import { useProposalQuery } from '../__generated__/Proposals';
|
||||
import { useFetchProposal } from '../components/proposal/proposal-utils';
|
||||
|
||||
export const ProposalContainer = () => {
|
||||
const params = useParams<{ proposalId: string }>();
|
||||
|
||||
const {
|
||||
state: { data: restData, loading: restLoading, error: restError },
|
||||
} = useFetch(`${ENV.rest}governance?proposalId=${params.proposalId}`);
|
||||
const { data: restData, loading: restLoading } = useFetchProposal({
|
||||
proposalId: params.proposalId,
|
||||
});
|
||||
|
||||
const { data, loading, error } = useProposalQuery({
|
||||
fetchPolicy: 'network-only',
|
||||
@@ -26,7 +25,7 @@ export const ProposalContainer = () => {
|
||||
return (
|
||||
<AsyncRenderer
|
||||
loading={Boolean(loading || restLoading)}
|
||||
error={error || restError}
|
||||
error={error}
|
||||
data={{
|
||||
...data,
|
||||
...(restData ? { restData } : {}),
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
lpAggregatedDataProvider,
|
||||
type Filter,
|
||||
LiquidityTable,
|
||||
liquidityProvisionsDataProvider,
|
||||
} from '@vegaprotocol/liquidity';
|
||||
import { getAsset, useMarket } from '@vegaprotocol/markets';
|
||||
import {
|
||||
@@ -71,7 +70,7 @@ export const LiquidityContainer = ({
|
||||
|
||||
const useReloadLiquidityData = (marketId: string | undefined) => {
|
||||
const { reload } = useDataProvider({
|
||||
dataProvider: liquidityProvisionsDataProvider,
|
||||
dataProvider: lpAggregatedDataProvider,
|
||||
variables: { marketId: marketId || '' },
|
||||
update: () => true,
|
||||
skip: !marketId,
|
||||
|
||||
@@ -182,7 +182,27 @@ def vega(request):
|
||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
||||
yield vega_instance
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def shared_vega(request):
|
||||
with init_vega(request) as vega_instance:
|
||||
try:
|
||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
||||
yield vega_instance
|
||||
finally:
|
||||
cleanup_container(vega_instance)
|
||||
|
||||
@pytest.fixture
|
||||
def page_shared_vega(shared_vega, browser, request):
|
||||
with init_page(shared_vega, browser, request) as page_instance:
|
||||
yield page_instance
|
||||
|
||||
@pytest.fixture
|
||||
def auth_shared_vega(shared_vega: VegaServiceNull, page_shared_vega: Page):
|
||||
return auth_setup(shared_vega, page_shared_vega)
|
||||
|
||||
@pytest.fixture
|
||||
def risk_accepted_shared_vega(page_shared_vega: Page):
|
||||
risk_accepted_setup(page_shared_vega)
|
||||
|
||||
def cleanup_container(vega_instance):
|
||||
try:
|
||||
@@ -283,6 +303,10 @@ def opening_auction_market(vega):
|
||||
return setup_opening_auction_market(vega)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def shared_continuous_market(shared_vega:VegaServiceNull):
|
||||
return setup_continuous_market(shared_vega)
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def continuous_market(vega):
|
||||
return setup_continuous_market(vega)
|
||||
|
||||
@@ -2,35 +2,62 @@ import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.null_service import VegaServiceNull
|
||||
from datetime import datetime, timedelta
|
||||
from conftest import init_vega, cleanup_container
|
||||
from conftest import init_page, risk_accepted_setup, auth_setup
|
||||
from fixtures.market import setup_continuous_market
|
||||
from actions.utils import wait_for_toast_confirmation
|
||||
from wallet_config import WalletConfig, MM_WALLET2
|
||||
|
||||
from actions.utils import (
|
||||
change_keys,
|
||||
create_and_faucet_wallet,
|
||||
)
|
||||
|
||||
order_size = "order-size"
|
||||
order_price = "order-price"
|
||||
place_order = "place-order"
|
||||
order_side_sell = "order-side-SIDE_SELL"
|
||||
order_side_buy = "order-side-SIDE_BUY"
|
||||
market_order = "order-type-Market"
|
||||
limit_order = "order-type-Limit"
|
||||
tif = "order-tif"
|
||||
expire = "expire"
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
with init_vega(request) as vega_instance:
|
||||
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
|
||||
yield vega_instance
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def page(shared_vega, browser, request, continuous_market):
|
||||
with init_page(shared_vega, browser, request) as page:
|
||||
risk_accepted_setup(page)
|
||||
auth_setup(shared_vega, page)
|
||||
basic_key = WalletConfig("basic_key", "basic_key")
|
||||
create_and_faucet_wallet(vega=shared_vega, wallet=basic_key)
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
change_keys(page, shared_vega, "basic_key")
|
||||
yield page
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def continuous_market(vega):
|
||||
return setup_continuous_market(vega)
|
||||
def continuous_market(shared_vega:VegaServiceNull):
|
||||
keypairs = shared_vega.wallet.get_keypairs("MarketSim")
|
||||
proposal_key = keypairs.get('market_maker')
|
||||
termination_key=keypairs.get('FJMKnwfZdd48C8NqvYrG')
|
||||
mm_2_key=keypairs.get('market_maker_2')
|
||||
|
||||
kwargs = {}
|
||||
if proposal_key is not None:
|
||||
kwargs['proposal_key'] = proposal_key
|
||||
if termination_key is not None:
|
||||
kwargs['termination_key'] = termination_key
|
||||
if mm_2_key is not None:
|
||||
kwargs['mm_2_key'] = mm_2_key
|
||||
|
||||
return setup_continuous_market(shared_vega, **kwargs)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_limit_buy_order_GTT(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
|
||||
def test_limit_buy_order_GTT( shared_vega: VegaServiceNull, page: Page):
|
||||
page.get_by_test_id(limit_order).click()
|
||||
page.get_by_test_id(order_side_buy).click()
|
||||
page.get_by_test_id(tif).select_option("Good 'til Time (GTT)")
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_price).fill("120")
|
||||
@@ -47,30 +74,31 @@ def test_limit_buy_order_GTT(continuous_market, vega: VegaServiceNull, page: Pag
|
||||
)
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
shared_vega.wait_fn(1)
|
||||
shared_vega.wait_for_total_catchup()
|
||||
page.get_by_test_id("All").click()
|
||||
page.reload()
|
||||
# 7002-SORD-017
|
||||
expect(page.get_by_role("row").nth(5)).to_contain_text("10+10LimitFilled120.00GTT:")
|
||||
expect(page.get_by_role("row").nth(4)).to_contain_text("10+10LimitFilled120.00GTT:")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_limit_buy_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
def test_limit_buy_order(shared_vega: VegaServiceNull, page: Page):
|
||||
page.get_by_test_id(limit_order).click()
|
||||
page.get_by_test_id(order_side_buy).click()
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_price).fill("120")
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.wait_fn(2)
|
||||
vega.wait_for_total_catchup()
|
||||
shared_vega.wait_fn(2)
|
||||
shared_vega.wait_for_total_catchup()
|
||||
page.get_by_test_id("All").click()
|
||||
page.reload()
|
||||
# 7002-SORD-017
|
||||
expect(page.get_by_role("row").nth(6)).to_contain_text("10+10LimitFilled120.00GTC")
|
||||
expect(page.get_by_role("row").nth(5)).to_contain_text("10+10LimitFilled120.00GTT")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_limit_sell_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
def test_limit_sell_order(shared_vega: VegaServiceNull, page: Page):
|
||||
page.get_by_test_id(limit_order).click()
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_price).fill("100")
|
||||
page.get_by_test_id(order_side_sell).click()
|
||||
@@ -84,15 +112,15 @@ def test_limit_sell_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
)
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
shared_vega.wait_fn(1)
|
||||
shared_vega.wait_for_total_catchup()
|
||||
page.get_by_test_id("All").click()
|
||||
expect(page.get_by_role("row").nth(7)).to_contain_text("10-10LimitFilled100.00GFN")
|
||||
page.reload()
|
||||
expect(page.get_by_role("row").nth(6)).to_contain_text("10-10LimitFilled100.00GFN")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_market_sell_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
|
||||
def test_market_sell_order(shared_vega: VegaServiceNull, page: Page):
|
||||
page.get_by_test_id(market_order).click()
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_side_sell).click()
|
||||
@@ -105,32 +133,32 @@ def test_market_sell_order(continuous_market, vega: VegaServiceNull, page: Page)
|
||||
)
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
shared_vega.wait_fn(1)
|
||||
shared_vega.wait_for_total_catchup()
|
||||
|
||||
page.get_by_test_id("All").click()
|
||||
expect(page.get_by_role("row").nth(8)).to_contain_text("10-10MarketFilled-IOC")
|
||||
page.reload()
|
||||
expect(page.get_by_role("row").nth(7)).to_contain_text("10-10MarketFilled-IOC")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_market_buy_order(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
def test_market_buy_order(shared_vega: VegaServiceNull, page: Page):
|
||||
page.get_by_test_id(market_order).click()
|
||||
page.get_by_test_id(order_side_buy).click()
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(tif).select_option("Fill or Kill (FOK)")
|
||||
page.get_by_test_id(place_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
shared_vega.wait_fn(1)
|
||||
shared_vega.wait_for_total_catchup()
|
||||
page.get_by_test_id("All").click()
|
||||
page.reload()
|
||||
# 7002-SORD-010
|
||||
# 0003-WTXN-012
|
||||
# 0003-WTXN-003
|
||||
expect(page.get_by_role("row").nth(9)).to_contain_text("10+10MarketFilled-FOK")
|
||||
expect(page.get_by_role("row").nth(8)).to_contain_text("10+10MarketFilled-FOK")
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_sidebar_should_be_open_after_reload(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
|
||||
def test_sidebar_should_be_open_after_reload(page: Page):
|
||||
expect(page.get_by_test_id("deal-ticket-form")).to_be_visible()
|
||||
page.get_by_test_id("Order").click()
|
||||
expect(page.get_by_test_id("deal-ticket-form")).not_to_be_visible()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import pytest
|
||||
""" import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.null_service import VegaServiceNull
|
||||
from actions.vega import submit_order
|
||||
@@ -87,3 +87,4 @@ def test_margin_and_fees_estimations(continuous_market, vega: VegaServiceNull, p
|
||||
# expect(page.get_by_test_id("toast-content")).to_contain_text(
|
||||
# "Your transaction has been confirmed"
|
||||
# )
|
||||
"""
|
||||
@@ -44,25 +44,25 @@ def create_position(vega: VegaServiceNull, market_id):
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_stop_order_form_error_validation(continuous_market, page: Page):
|
||||
@pytest.mark.usefixtures("auth_shared_vega", "risk_accepted_shared_vega")
|
||||
def test_stop_order_form_error_validation(shared_continuous_market, page_shared_vega: Page):
|
||||
# 7002-SORD-032
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(stop_order_btn).click()
|
||||
page.get_by_test_id(stop_limit_order_btn).is_visible()
|
||||
page.get_by_test_id(stop_limit_order_btn).click()
|
||||
page.get_by_test_id(order_side_sell).click()
|
||||
page.get_by_test_id(submit_stop_order).click()
|
||||
expect(page.get_by_test_id("stop-order-error-message-trigger-price")).to_have_text(
|
||||
page_shared_vega.goto(f"/#/markets/{shared_continuous_market}")
|
||||
page_shared_vega.get_by_test_id(stop_order_btn).click()
|
||||
page_shared_vega.get_by_test_id(stop_limit_order_btn).is_visible()
|
||||
page_shared_vega.get_by_test_id(stop_limit_order_btn).click()
|
||||
page_shared_vega.get_by_test_id(order_side_sell).click()
|
||||
page_shared_vega.get_by_test_id(submit_stop_order).click()
|
||||
expect(page_shared_vega.get_by_test_id("stop-order-error-message-trigger-price")).to_have_text(
|
||||
"You need provide a price"
|
||||
)
|
||||
expect(page.get_by_test_id("stop-order-error-message-size")).to_have_text(
|
||||
expect(page_shared_vega.get_by_test_id("stop-order-error-message-size")).to_have_text(
|
||||
"Size cannot be lower than 1"
|
||||
)
|
||||
|
||||
page.get_by_test_id(order_size).fill("1")
|
||||
page.get_by_test_id(order_price).fill("0.0000001")
|
||||
expect(page.get_by_test_id("stop-order-error-message-price")).to_have_text(
|
||||
page_shared_vega.get_by_test_id(order_size).fill("1")
|
||||
page_shared_vega.get_by_test_id(order_price).fill("0.0000001")
|
||||
expect(page_shared_vega.get_by_test_id("stop-order-error-message-price")).to_have_text(
|
||||
"Price cannot be lower than 0.00001"
|
||||
)
|
||||
|
||||
@@ -257,7 +257,7 @@ def test_submit_stop_limit_order_cancel(
|
||||
).to_have_text("Cancelled")
|
||||
|
||||
|
||||
class TestStopOcoValidation:
|
||||
""" class TestStopOcoValidation:
|
||||
@pytest.fixture(scope="class")
|
||||
def vega(request):
|
||||
with init_vega(request) as vega_instance:
|
||||
@@ -296,3 +296,4 @@ class TestStopOcoValidation:
|
||||
expect(page.get_by_test_id("stop-order-warning-limit")).to_have_text(
|
||||
"There is a limit of 4 active stop orders per market. Orders submitted above the limit will be immediately rejected."
|
||||
)
|
||||
"""
|
||||
@@ -235,7 +235,7 @@ def test_submit_stop_oco_market_order_pending(
|
||||
"PendingOCO"
|
||||
)
|
||||
|
||||
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_submit_stop_oco_limit_order_pending(
|
||||
continuous_market, vega: VegaServiceNull, page: Page
|
||||
):
|
||||
|
||||
@@ -1,39 +1,30 @@
|
||||
import pytest
|
||||
from playwright.sync_api import Page, expect, Locator
|
||||
|
||||
from conftest import init_page, init_vega, cleanup_container
|
||||
from conftest import init_page, risk_accepted_setup
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
with init_vega(request) as vega_instance:
|
||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
||||
yield vega_instance
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def page(vega, browser, request):
|
||||
with init_page(vega, browser, request) as page:
|
||||
def page(shared_vega, browser, request):
|
||||
with init_page(shared_vega, browser, request) as page:
|
||||
risk_accepted_setup(page)
|
||||
page.goto("/#/disclaimer")
|
||||
yield page
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
|
||||
def test_network_switcher(page: Page):
|
||||
page.goto("/#/disclaimer")
|
||||
navbar = page.locator('nav[aria-label="Main"]')
|
||||
assert_network_switcher(navbar)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
|
||||
def test_navbar_pages(page: Page):
|
||||
page.goto("/#/disclaimer")
|
||||
navbar = page.locator('nav[aria-label="Main"]')
|
||||
assert_links(navbar)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
|
||||
def test_navigation_mobile(page: Page):
|
||||
page.goto("/#/disclaimer")
|
||||
page.set_viewport_size({"width": 800, "height": 1040})
|
||||
navbar = page.locator('nav[aria-label="Main"]')
|
||||
|
||||
@@ -108,4 +99,4 @@ def assert_network_switcher(container: Locator):
|
||||
expect(mainnet_link).to_be_visible()
|
||||
# 0006-NETW-003
|
||||
expect(mainnet_link).to_have_attribute("href", "https://console.vega.xyz")
|
||||
expect(container.get_by_role("link", name="Fairground testnet")).to_be_visible()
|
||||
expect(container.get_by_role("link", name="Fairground testnet")).to_be_visible()
|
||||
@@ -49,7 +49,7 @@ def markets(vega: VegaServiceNull):
|
||||
price=130,
|
||||
)
|
||||
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -63,7 +63,7 @@ def markets(vega: VegaServiceNull):
|
||||
price=88,
|
||||
)
|
||||
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -77,7 +77,7 @@ def markets(vega: VegaServiceNull):
|
||||
price=88,
|
||||
)
|
||||
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -92,7 +92,7 @@ def markets(vega: VegaServiceNull):
|
||||
wait=False,
|
||||
)
|
||||
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -105,7 +105,7 @@ def markets(vega: VegaServiceNull):
|
||||
volume=100,
|
||||
price=104,
|
||||
)
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -120,7 +120,7 @@ def markets(vega: VegaServiceNull):
|
||||
expires_at=vega.get_blockchain_time() + 5 * 1e9,
|
||||
)
|
||||
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -134,7 +134,7 @@ def markets(vega: VegaServiceNull):
|
||||
volume=20,
|
||||
)
|
||||
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -148,7 +148,7 @@ def markets(vega: VegaServiceNull):
|
||||
volume=40,
|
||||
)
|
||||
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -162,7 +162,7 @@ def markets(vega: VegaServiceNull):
|
||||
volume=60,
|
||||
)
|
||||
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -177,7 +177,7 @@ def markets(vega: VegaServiceNull):
|
||||
volume=60,
|
||||
)
|
||||
|
||||
vega.forward("2s")
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -190,7 +190,7 @@ def markets(vega: VegaServiceNull):
|
||||
volume=10,
|
||||
price=150,
|
||||
)
|
||||
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -203,7 +203,7 @@ def markets(vega: VegaServiceNull):
|
||||
volume=10,
|
||||
price=160,
|
||||
)
|
||||
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
@@ -216,7 +216,7 @@ def markets(vega: VegaServiceNull):
|
||||
volume=10,
|
||||
price=60,
|
||||
)
|
||||
|
||||
vega.forward("5s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ def setup_market_and_referral_scheme(vega: VegaServiceNull, continuous_market: s
|
||||
forward_time(vega)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_can_traverse_up_and_down_through_tiers(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
setup_market_and_referral_scheme(vega, continuous_market, page)
|
||||
change_keys(page, vega, PARTY_B.name)
|
||||
@@ -163,7 +163,7 @@ def test_can_traverse_up_and_down_through_tiers(continuous_market, vega: VegaSer
|
||||
"1%", "1", "1%", "0", "1", "1"))
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_does_not_move_up_tiers_when_not_enough_epochs(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
setup_market_and_referral_scheme(vega, continuous_market, page)
|
||||
change_keys(page, vega, PARTY_B.name)
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import pytest
|
||||
from playwright.sync_api import expect, Page
|
||||
from conftest import init_vega, cleanup_container
|
||||
from conftest import init_page, risk_accepted_setup
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
with init_vega(request) as vega_instance:
|
||||
request.addfinalizer(lambda: cleanup_container(vega_instance))
|
||||
yield vega_instance
|
||||
def page(shared_vega, browser, request):
|
||||
with init_page(shared_vega, browser, request) as page:
|
||||
risk_accepted_setup(page)
|
||||
yield page
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_share_usage_data(page: Page):
|
||||
page.goto("/")
|
||||
page.get_by_test_id("Settings").click()
|
||||
@@ -41,7 +40,6 @@ ICON_TO_TOAST = {
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_toast_positions(page: Page):
|
||||
page.goto("/")
|
||||
page.get_by_test_id("Settings").click()
|
||||
@@ -52,10 +50,10 @@ def test_toast_positions(page: Page):
|
||||
expect(page.locator(f"[{toast_selector}]")).to_be_visible()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
|
||||
def test_dark_mode(page: Page):
|
||||
page.goto("/")
|
||||
page.get_by_test_id("Settings").click()
|
||||
expect(page.locator("html")).not_to_have_attribute("class", "dark")
|
||||
page.locator("#switch-settings-theme-switch").click()
|
||||
expect(page.locator("html")).to_have_attribute("class", "dark")
|
||||
expect(page.locator("html")).to_have_attribute("class", "dark")
|
||||
@@ -0,0 +1,8 @@
|
||||
import { ENV, Networks } from '@vegaprotocol/environment';
|
||||
|
||||
const TEAMS_STATS_EPOCHS_MAINNET = 30;
|
||||
const TEAMS_STATS_EPOCHS_TESTNET = 192;
|
||||
export const TEAMS_STATS_EPOCHS =
|
||||
ENV.VEGA_ENV === Networks.MAINNET
|
||||
? TEAMS_STATS_EPOCHS_MAINNET
|
||||
: TEAMS_STATS_EPOCHS_TESTNET;
|
||||
@@ -7,8 +7,7 @@ import orderBy from 'lodash/orderBy';
|
||||
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import { useEpochInfoQuery } from './__generated__/Epoch';
|
||||
import { type ApolloError } from '@apollo/client';
|
||||
|
||||
const TAKE_EPOCHS = 30; // TODO: should this be DEFAULT_AGGREGATION_EPOCHS?
|
||||
import { TEAMS_STATS_EPOCHS } from './constants';
|
||||
|
||||
const findTeam = (entities: GameFieldsFragment['entities'], teamId: string) => {
|
||||
const team = entities.find(
|
||||
@@ -45,7 +44,7 @@ export const useGames = (teamId?: string, epochFrom?: number): GamesData => {
|
||||
|
||||
let from = epochFrom;
|
||||
if (!from && epochData) {
|
||||
from = Number(epochData.epoch.id) - TAKE_EPOCHS;
|
||||
from = Number(epochData.epoch.id) - TEAMS_STATS_EPOCHS;
|
||||
if (from < 1) from = 1; // make sure it's not negative
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
type TeamRefereeFieldsFragment,
|
||||
type TeamMemberStatsFieldsFragment,
|
||||
} from './__generated__/Team';
|
||||
import { DEFAULT_AGGREGATION_EPOCHS } from './use-teams';
|
||||
import { TEAMS_STATS_EPOCHS } from './constants';
|
||||
|
||||
export type Team = TeamFieldsFragment;
|
||||
export type TeamStats = TeamStatsFieldsFragment;
|
||||
@@ -22,7 +22,7 @@ export const useTeam = (teamId?: string, partyId?: string) => {
|
||||
variables: {
|
||||
teamId: teamId || '',
|
||||
partyId,
|
||||
aggregationEpochs: DEFAULT_AGGREGATION_EPOCHS,
|
||||
aggregationEpochs: TEAMS_STATS_EPOCHS,
|
||||
},
|
||||
skip: !teamId,
|
||||
fetchPolicy: 'cache-and-network',
|
||||
|
||||
@@ -4,9 +4,7 @@ import { useTeamsQuery } from './__generated__/Teams';
|
||||
import { useTeamsStatisticsQuery } from './__generated__/TeamsStatistics';
|
||||
import compact from 'lodash/compact';
|
||||
import { type TeamStatsFieldsFragment } from './__generated__/Team';
|
||||
|
||||
// 192
|
||||
export const DEFAULT_AGGREGATION_EPOCHS = 192;
|
||||
import { TEAMS_STATS_EPOCHS } from './constants';
|
||||
|
||||
const EMPTY_STATS: Partial<TeamStatsFieldsFragment> = {
|
||||
totalQuantumVolume: '0',
|
||||
@@ -16,7 +14,7 @@ const EMPTY_STATS: Partial<TeamStatsFieldsFragment> = {
|
||||
quantumRewards: [],
|
||||
};
|
||||
|
||||
export const useTeams = (aggregationEpochs = DEFAULT_AGGREGATION_EPOCHS) => {
|
||||
export const useTeams = (aggregationEpochs = TEAMS_STATS_EPOCHS) => {
|
||||
const {
|
||||
data: teamsData,
|
||||
loading: teamsLoading,
|
||||
|
||||
@@ -71,7 +71,7 @@ function waitForStake(vegaPublicKey: string) {
|
||||
let tick = 1;
|
||||
const interval = setInterval(async () => {
|
||||
log(`confirming stake (attempt: ${tick})`);
|
||||
if (tick >= 30) {
|
||||
if (tick >= 90) {
|
||||
clearInterval(interval);
|
||||
reject(new Error('stake link never seen'));
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export const addCreateMarket = () => {
|
||||
cy.highlight('creating market on capsule environment');
|
||||
|
||||
cy.wrap(createMarket(config), {
|
||||
timeout: 5 * 60 * 1000,
|
||||
timeout: 9 * 60 * 1000,
|
||||
})
|
||||
// register market list result so it can be retrieved in tests later
|
||||
.as('markets');
|
||||
|
||||
@@ -111,7 +111,7 @@ export const addValidatorsSelfDelegate = () => {
|
||||
String(node0ApiToken),
|
||||
String(node0Id)
|
||||
),
|
||||
{ timeout: 60000 }
|
||||
{ timeout: 90000 }
|
||||
);
|
||||
// Self delegating Node 1 wallet
|
||||
cy.get('@node1PubKey').then((node1PubKey) => {
|
||||
@@ -124,7 +124,7 @@ export const addValidatorsSelfDelegate = () => {
|
||||
String(node1ApiToken),
|
||||
String(node1Id)
|
||||
),
|
||||
{ timeout: 60000 }
|
||||
{ timeout: 90000 }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -175,6 +175,7 @@
|
||||
},
|
||||
"network_parameters": {
|
||||
"blockchains.ethereumConfig": "{\"network_id\": \"{{ .NetworkID }}\", \"chain_id\": \"{{ .ChainID }}\", \"collateral_bridge_contract\": { \"address\": \"{{.GetEthContractAddr "erc20_bridge_1"}}\" }, \"confirmations\": 3, \"staking_bridge_contract\": { \"address\": \"{{.GetEthContractAddr "staking_bridge"}}\", \"deployment_block_height\": 0}, \"token_vesting_contract\": { \"address\": \"{{.GetEthContractAddr "erc20_vesting"}}\", \"deployment_block_height\": 0 }, \"multisig_control_contract\": { \"address\": \"{{.GetEthContractAddr "MultisigControl"}}\", \"deployment_block_height\": 0 }}",
|
||||
"blockchains.ethereumRpcAndEvmCompatDataSourcesConfig": "{\"configs\": []}",
|
||||
"governance.proposal.asset.minClose": "2s",
|
||||
"governance.proposal.asset.minEnact": "2s",
|
||||
"governance.proposal.asset.requiredParticipation": "0.00000000000000000000000015",
|
||||
|
||||
Reference in New Issue
Block a user