Compare commits

...
Author SHA1 Message Date
Madalina Raicu fbcb7fc996 chore: update head 2023-08-16 12:14:43 +03:00
Madalina Raicu bb77e95c85 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into fix/metadata-console-try 2023-08-15 19:48:08 +03:00
Madalina Raicu b3b4ac36ab fix: remove manifest add title 2023-08-15 19:46:27 +03:00
Matthew Russell e4eedf5ccd feat(trading,datagrid): datagrid improvements (#4524) 2023-08-15 12:26:13 +01:00
Ben 20cbcb8302 chore(trading): remove home tests (#4551) 2023-08-14 18:06:36 +01:00
Joe Tsang cd3acf8ff9 test(explorer): successor market explorer (#4544) 2023-08-14 16:17:29 +01:00
Ben 30735388e8 chore(trading): remove asset tests (#4548) 2023-08-14 15:35:24 +01:00
Madalina Raicu 652ff66a13 fix: metadata console try 2023-08-14 14:34:36 +03:00
Madalina Raicu ccddfd3576 fix: metadata console try 2023-08-14 14:33:53 +03:00
Madalina Raicu 2efb6ab32f fix: metadata console try 2023-08-14 14:33:37 +03:00
Ben 478c4f83bb chore(trading): remove markets test (#4545) 2023-08-14 12:20:53 +01:00
Madalina Raicu 67ce576bc8 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into develop 2023-08-14 12:27:47 +03:00
JonRay15 431fab8824 chore(trading,governance): update feature-epic.md (#4528) 2023-08-14 09:43:00 +01:00
m.ray 83b6d3d295 feat(trading): metadata console (#4515) 2023-08-11 16:12:43 +00:00
Matthew Russell 98fd79bc35 fix(trading): prevent overflow in deal ticket if market fails to load (#4535) 2023-08-11 17:03:17 +01:00
Ben 39aa27f332 chore(trading): remove iceberg side order details (#4540) 2023-08-11 16:33:34 +01:00
Sam Keen bf4fb29fe6 fix(governance): fixes settlement oracle display in governance (#4534) 2023-08-11 10:08:31 +01:00
Maciek 5ed1befc53 fix(trading): remove redundant connect wallet button (#4538) 2023-08-11 10:34:32 +02:00
m.ray 1b311a8b36 fix(trading): order single view side (#4526) 2023-08-11 09:12:13 +01:00
Madalina Raicu ab1a2cb222 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into develop 2023-08-07 16:22:11 +01:00
Madalina Raicu e1a1ae0fa1 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into develop 2023-08-07 10:16:03 +01:00
82 changed files with 648 additions and 869 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: Feature Epic
about: A template to capture and scope user requirements, high level process, and basic mockups for an upcoming feature as part of the initial core spec review process.
title: 'Epic: '
title: 'FEATURE EPIC: '
labels: feature-epic
---
+1 -1
View File
@@ -137,7 +137,7 @@ jobs:
secrets: inherit
with:
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
tags: '@smoke @regression'
tags: '@smoke'
publish-dist:
needs: lint-test-build
+1
View File
@@ -23,6 +23,7 @@ module.exports = defineConfig({
viewportWidth: 1440,
viewportHeight: 900,
testIsolation: false,
experimentalMemoryManagement: true,
},
env: {
environment: 'CUSTOM',
+50 -6
View File
@@ -1,8 +1,8 @@
import { createSuccessorMarketProposal } from '../support/governance.functions';
context('Market page', { tags: '@regression' }, function () {
describe('Verify elements on page', function () {
const marketHeaders = 'markets-heading';
const createdMarketId =
'2eab0e66545a789047561bc5a2e5cbc3b19eb708da41104e3cac2474ee36c4d4';
before('Create market', function () {
cy.visit('/');
@@ -11,7 +11,7 @@ context('Market page', { tags: '@regression' }, function () {
beforeEach('Get market id', function () {
cy.navigate_to('markets');
cy.get('[col-id="id"]').eq(1).invoke('text').as('createdMarketId');
cy.get('[col-id="id"]').last().invoke('text').as('createdMarketId');
});
it('Market displayed on market page', function () {
@@ -106,6 +106,7 @@ context('Market page', { tags: '@regression' }, function () {
// Able to view Json
cy.contains('View JSON').click();
cy.get('.language-json').should('exist');
cy.getByTestId('icon-cross').click();
});
// Skipping due to resize observer loop limit error
@@ -113,17 +114,60 @@ context('Market page', { tags: '@regression' }, function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.navigate_to('markets', true);
cy.getByTestId(marketHeaders).should('be.visible');
cy.get(`[row-id="${createdMarketId}"]`)
cy.get(`[row-id="${this.createdMarketId}"]`)
.should('be.visible')
.within(() => {
cy.get_element_by_col_id('code').should('have.text', 'TEST.24h');
cy.get_element_by_col_id('name').should('have.text', 'Test market 1');
cy.get_element_by_col_id('state').should('have.text', 'Pending');
cy.get_element_by_col_id('asset').should('have.text', 'fUSDC');
cy.get_element_by_col_id('id').should('have.text', createdMarketId);
cy.get_element_by_col_id('id').should(
'have.text',
this.createdMarketId
);
cy.get_element_by_col_id('actions')
.find('a')
.should('have.attr', 'href', `/markets/${createdMarketId}`);
.should('have.attr', 'href', `/markets/${this.createdMarketId}`);
});
});
it('Able to go to market details page for successor market', function () {
const successionLineItem = 'succession-line-item';
const successionLineMarketId = 'succession-line-item-market-id';
createSuccessorMarketProposal(this.createdMarketId);
cy.navigate_to('markets');
cy.reload();
cy.contains('Token test market', { timeout: 8000 }).should('be.visible');
cy.get('[row-index="0"]')
.invoke('attr', 'row-id')
.as('successorMarketId');
cy.contains('Token test market').click();
cy.getByTestId(marketHeaders).should('have.text', 'Token test market');
cy.validate_proposal_change_type('Triggering Ratio', 'Added');
cy.validate_element_from_table('Triggering Ratio', '0.7');
cy.validate_proposal_change_type('Time Window', 'Added');
cy.validate_element_from_table('Time Window', '3,600');
cy.validate_proposal_change_type('Scaling Factor', 'Added');
cy.validate_element_from_table('Scaling Factor', '10');
cy.getByTestId(successionLineItem)
.first()
.within(() => {
cy.contains('Test market 1');
cy.getByTestId(successionLineMarketId).should(
'have.text',
this.createdMarketId
);
});
cy.getByTestId(successionLineItem)
.eq(1)
.within(() => {
cy.contains('Token test market');
cy.getByTestId(successionLineMarketId).should(
'have.text',
this.successorMarketId
);
});
});
});
@@ -13,28 +13,31 @@ context('Proposal page', { tags: '@smoke' }, function () {
it('Able to view proposal', function () {
cy.navigate_to('governanceProposals');
cy.getByTestId(proposalHeading).should('be.visible');
// get first proposal in list
cy.get('[row-index="0"]').within(() => {
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
cy.get_element_by_col_id('type').should('have.text', 'NewMarket');
cy.get_element_by_col_id('state').should('have.text', 'Enacted');
cy.getByTestId('vote-progress').should('be.visible');
cy.get('[col-id="cDate"]')
.invoke('text')
.should('match', dateTimeRegex);
cy.get('[col-id="eDate"]')
.invoke('text')
.should('match', dateTimeRegex);
cy.getByTestId('external-link')
.should('have.attr', 'href')
.and('contains', 'https://governance.fairground.wtf/proposals/');
cy.contains('View terms').should('exist').click();
});
cy.contains(proposalTitle)
.parent()
.parent()
.parent()
.within(() => {
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
cy.get_element_by_col_id('type').should('have.text', 'NewMarket');
cy.get_element_by_col_id('state').should('have.text', 'Enacted');
cy.getByTestId('vote-progress').should('be.visible');
cy.get('[col-id="cDate"]')
.invoke('text')
.should('match', dateTimeRegex);
cy.get('[col-id="eDate"]')
.invoke('text')
.should('match', dateTimeRegex);
cy.getByTestId('external-link')
.should('have.attr', 'href')
.and('contains', 'https://governance.fairground.wtf/proposals/');
cy.contains('View terms').should('exist').click();
});
cy.getByTestId('dialog-title').should('have.text', proposalTitle);
cy.get('.language-json').should('exist');
});
it('Proposal page displayed on mobile', function () {
it.skip('Proposal page displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.navigate_to('governanceProposals', true);
cy.getByTestId(proposalHeading).should('be.visible');
@@ -127,3 +127,10 @@ Cypress.Commands.add(
.should('have.text', tableRowValue);
}
);
Cypress.Commands.add(
'validate_proposal_change_type',
(tableRowName, changeType) => {
cy.contains(tableRowName).siblings().should('have.text', changeType);
}
);
@@ -0,0 +1,130 @@
export function createSuccessorMarketProposal(parentMarketId) {
cy.VegaWalletSubmitProposal(getSuccessorTxBody(parentMarketId));
}
function getSuccessorTxBody(parentMarketId) {
return {
proposalSubmission: {
rationale: {
title: 'Test successor market proposal details',
description: 'E2E test for successor market',
},
terms: {
newMarket: {
changes: {
decimalPlaces: '5',
positionDecimalPlaces: '5',
linearSlippageFactor: '0.001',
quadraticSlippageFactor: '0',
lpPriceRange: '10',
instrument: {
name: 'Token test market',
code: 'TEST.24h',
future: {
settlementAsset:
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc',
quoteName: 'fUSDC',
dataSourceSpecForSettlementData: {
external: {
oracle: {
signers: [
{
pubKey: {
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
},
},
],
filters: [
{
key: {
name: 'prices.BTC.value',
type: 'TYPE_INTEGER',
numberDecimalPlaces: '0',
},
conditions: [
{
operator: 'OPERATOR_GREATER_THAN',
value: '0',
},
],
},
],
},
},
},
dataSourceSpecForTradingTermination: {
external: {
oracle: {
signers: [
{
pubKey: {
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
},
},
],
filters: [
{
key: {
name: 'trading.terminated.ETH5',
type: 'TYPE_BOOLEAN',
},
conditions: [
{
operator: 'OPERATOR_EQUALS',
value: 'true',
},
],
},
],
},
},
},
dataSourceSpecBinding: {
settlementDataProperty: 'prices.BTC.value',
tradingTerminationProperty: 'trading.terminated.ETH5',
},
},
},
metadata: [
'sector:food',
'sector:materials',
'source:docs.vega.xyz',
],
priceMonitoringParameters: {
triggers: [
{
horizon: '43200',
probability: '0.9999999',
auctionExtension: '600',
},
],
},
liquidityMonitoringParameters: {
targetStakeParameters: {
timeWindow: '3600',
scalingFactor: 10,
},
triggeringRatio: '0.7',
auctionExtension: '1',
},
logNormal: {
tau: 0.0001140771161,
riskAversionParameter: 0.01,
params: {
mu: 0,
r: 0.016,
sigma: 0.5,
},
},
successor: {
parentMarketId: parentMarketId,
insurancePoolFraction: '0.75',
},
},
},
closingTimestamp: 1695666618,
enactmentTimestamp: 1695666618,
},
},
};
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

+20
View File
@@ -0,0 +1,20 @@
{
"short_name": "Mainnet Stats",
"name": "Vega Mainnet statistics",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
+3
View File
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
+27 -11
View File
@@ -1,23 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Explorer</title>
<base href="/" />
<link
rel="preload"
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="utf-8" />
<link
rel="icon"
type="image/x-icon"
href="https://static.vega.xyz/favicon.ico"
/>
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Vega Protocol - VEGA Explorer" />
<meta name="og:type" content="website" />
<meta name="og:url" content="https://explorer.vega.xyz/" />
<meta name="og:title" content="Vega Protocol - Explorer" />
<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="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" />
<meta name="twitter:image:alt" content="VEGA logo" />
<meta name="twitter:site" content="@vegaprotocol" />
<meta name="description" content="Vega Protocol - Explorer" />
<link rel="apple-touch-icon" href="assets/apple-touch-icon.png" />
<link rel="manifest" href="assets/manifest.json" />
<link
rel="preload"
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
as="font"
type="font/woff2"
/>
<title>VEGA Explorer</title>
<script src="./assets/env-config.js"></script>
</head>
<body class="dark:bg-black h-full w-full">
+1
View File
@@ -28,6 +28,7 @@ module.exports = defineConfig({
numTestsKeptInMemory: 5,
downloadsFolder: 'cypress/downloads',
testIsolation: false,
experimentalMemoryManagement: true,
},
env: {
ethProviderUrl: 'http://localhost:8545/',
@@ -55,12 +55,12 @@ describe(
before('connect wallets and set approval limit', function () {
cy.visit('/');
ethereumWalletConnect();
// cy.associateTokensToVegaWallet('1');
});
beforeEach('visit proposals tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.mockChainId();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -42,6 +42,7 @@ context(
beforeEach('visit proposals', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.mockChainId();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -82,6 +82,7 @@ context(
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
cy.mockChainId();
waitForSpinner();
cy.connectVegaWallet();
ethereumWalletConnect();
@@ -74,6 +74,7 @@ context(
beforeEach('visit governance tab', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.mockChainId();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -42,6 +42,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
cy.mockChainId();
waitForSpinner();
cy.connectVegaWallet();
ethereumWalletConnect();
@@ -26,6 +26,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
before('set up environment to allow rewards', function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.mockChainId();
cy.visit('/');
waitForSpinner();
ethereumWalletConnect();
@@ -25,8 +25,6 @@ import {
vegaWalletSetSpecifiedApprovalAmount,
vegaWalletTeardown,
} from '../../support/wallet-functions';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
const stakeValidatorListTotalStake = 'total-stake';
const stakeValidatorListTotalShare = 'total-stake-share';
@@ -58,10 +56,6 @@ context(
function () {
// 1002-STKE-002, 1002-STKE-032
before('visit staking tab and connect vega wallet', function () {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
cy.visit('/');
ethereumWalletConnect();
cy.connectVegaWallet();
@@ -72,12 +66,9 @@ context(
beforeEach(
'teardown wallet & drill into a specific validator',
function () {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
cy.clearLocalStorage();
turnTelemetryOff();
cy.mockChainId();
// Go to homepage to allow wallet teardown without epoch timer refreshing page
navigateTo(navigation.home);
vegaWalletTeardown();
@@ -56,6 +56,7 @@ context(
function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.mockChainId();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
@@ -6,8 +6,6 @@ import {
} from '../../support/common.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { depositAsset } from '../../support/wallet-functions';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
const withdraw = 'withdraw';
const withdrawalForm = 'withdraw-form';
@@ -44,22 +42,15 @@ context(
{ tags: '@slow' },
function () {
before('visit withdrawals and connect vega wallet', function () {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
cy.visit('/');
ethereumWalletConnect();
depositAsset(usdcEthAddress, '1000', 5);
});
beforeEach('Navigate to withdrawal page', function () {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
cy.clearLocalStorage();
turnTelemetryOff();
cy.mockChainId();
cy.reload();
waitForSpinner();
navigateTo(navigation.withdraw);
@@ -106,7 +97,8 @@ context(
});
});
it(
// eslint-disable-next-line
it.skip(
'Able to withdraw asset: -eth wallet connected -withdraw funds button',
{ tags: '@smoke' },
function () {
@@ -231,7 +231,7 @@ context(
});
// 3009-NTWU-001 3009-NTWU-002 3009-NTWU-006 3009-NTWU-009
it('should display network upgrade banner with estimate', function () {
it.skip('should display network upgrade banner with estimate', function () {
mockNetworkUpgradeProposal();
cy.visit('/');
cy.getByTestId('banners').within(() => {
+1
View File
@@ -9,6 +9,7 @@ NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","STAGNET1":"https:
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
+20 -13
View File
@@ -1,8 +1,8 @@
<!DOCTYPE html>
<html lang="en" class="dark bg-black w-full h-full">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="utf-8" />
<link rel="stylesheet" href="//static.vega.xyz/fonts.css" />
<link
rel="icon"
type="image/x-icon"
@@ -10,35 +10,42 @@
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Vega Protocol - VEGA Token Vesting" />
<meta name="description" content="Vega Protocol - VEGA Governance" />
<meta name="og:type" content="website" />
<meta name="og:url" content="https://governance.vega.xyz/" />
<meta name="og:title" content="Vega Protocol - Governance" />
<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="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" />
<meta name="twitter:image:alt" content="VEGA logo" />
<meta name="twitter:site" content="@vegaprotocol" />
<meta name="description" content="Vega Protocol - Governance" />
<link rel="apple-touch-icon" href="assets/apple-touch-icon.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="assets/manifest.json" />
<link
rel="preload"
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
/>
<title>Vega Governance dApp</title>
<title>VEGA Governance</title>
<script src="./assets/env-config.js"></script>
</head>
<body class="h-full">
<noscript>You need to enable JavaScript to run this app.</noscript>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root" class="h-full"></div>
<!--
This HTML file is a template.
<!-- This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
To create a production bundle, use `npm run build` or `yarn build`. -->
</body>
</html>
@@ -25,7 +25,7 @@ import {
} from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import type { MarketInfoWithData } from '@vegaprotocol/markets';
import type { MarketInfo } from '@vegaprotocol/markets';
import type { DataSourceDefinition } from '@vegaprotocol/types';
import { create } from 'zustand';
@@ -47,8 +47,8 @@ export const ProposalMarketData = ({
marketData,
parentMarketData,
}: {
marketData: MarketInfoWithData;
parentMarketData?: MarketInfoWithData;
marketData: MarketInfo;
parentMarketData?: MarketInfo;
}) => {
const { t } = useTranslation();
const { isOpen, open, close } = useMarketDataDialogStore();
@@ -13,7 +13,7 @@ import Routes from '../../../routes';
import { ProposalMarketData } from '../proposal-market-data';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { MarketInfoWithData } from '@vegaprotocol/markets';
import type { MarketInfo } from '@vegaprotocol/markets';
import type { AssetQuery } from '@vegaprotocol/assets';
import { removePaginationWrapper } from '@vegaprotocol/utils';
import { ProposalState } from '@vegaprotocol/types';
@@ -31,8 +31,8 @@ export enum ProposalType {
export interface ProposalProps {
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
networkParams: Partial<NetworkParamsResult>;
newMarketData?: MarketInfoWithData | null;
parentMarketData?: MarketInfoWithData | null;
newMarketData?: MarketInfo | null;
parentMarketData?: MarketInfo | null;
assetData?: AssetQuery | null;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
restData: any;
@@ -8,7 +8,7 @@ import { useProposalQuery } from './__generated__/Proposal';
import { useFetch } from '@vegaprotocol/react-helpers';
import { ENV } from '../../../config';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { marketInfoWithDataProvider } from '@vegaprotocol/markets';
import { marketInfoProvider } from '@vegaprotocol/markets';
import { useAssetQuery } from '@vegaprotocol/assets';
import {
NetworkParams,
@@ -95,7 +95,7 @@ export const ProposalContainer = () => {
loading: newMarketLoading,
error: newMarketError,
} = useDataProvider({
dataProvider: marketInfoWithDataProvider,
dataProvider: marketInfoProvider,
skipUpdates: true,
variables: {
marketId: data?.proposal?.id || '',
@@ -109,12 +109,9 @@ export const ProposalContainer = () => {
error: parentMarketIdError,
} = useParentMarketIdQuery({
variables: {
marketId: newMarketData?.data?.market?.id || '',
marketId: newMarketData?.id || '',
},
skip:
!FLAGS.SUCCESSOR_MARKETS ||
!isSuccessor ||
!newMarketData?.data?.market?.id,
skip: !FLAGS.SUCCESSOR_MARKETS || !isSuccessor || !newMarketData?.id,
});
const {
@@ -122,7 +119,7 @@ export const ProposalContainer = () => {
loading: parentMarketLoading,
error: parentMarketError,
} = useDataProvider({
dataProvider: marketInfoWithDataProvider,
dataProvider: marketInfoProvider,
skipUpdates: true,
variables: {
marketId: parentMarketId?.market?.parentMarketID || '',
+1
View File
@@ -26,6 +26,7 @@ module.exports = defineConfig({
requestTimeout: 20000,
retries: 1,
testIsolation: false,
experimentalMemoryManagement: true,
},
env: {
ETHERSCAN_URL: 'https://sepolia.etherscan.io',
@@ -1,177 +0,0 @@
// #region consts
const assetColId = '[col-id="asset.symbol"]';
const assetDetailsDialog = 'dialog-content';
const assetRow = 'key-value-table-row';
const contractAddress = '7_value';
const dialogCloseBtn = 'close-asset-details-dialog';
const dialogCloseX = 'dialog-close';
const dialogTitle = 'dialog-title';
const indicesWithLabelTooltips = [4, 5, 6, 7, 8, 9, 11, 12, 13, 14];
const indicesWithValueTooltips = [1, 6];
const labelValueToolTipPairs = [
{
label: 'ID',
value: 'asset-id',
},
{
label: 'Type',
value: 'ERC20',
valueToolTip: 'An asset originated from an Ethereum ERC20 Token',
},
{
label: 'Name',
value: 'Euro',
},
{
label: 'Symbol',
value: 'tEURO',
},
{
label: 'Decimals',
value: '5',
labelTooltip: 'Number of decimal / precision handled by this asset',
},
{
label: 'Quantum',
value: '0.00001',
labelTooltip: 'The minimum economically meaningful amount of the asset',
},
{
label: 'Status',
value: 'Enabled',
labelTooltip: 'The status of the asset in the Vega network',
valueToolTip: 'Asset can be used on the Vega network',
},
{
label: 'Contract address',
value: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4 ',
labelTooltip:
'The address of the contract for the token, on the ethereum network',
},
{
label: 'Withdrawal threshold',
value: '0.0005',
labelTooltip:
"The maximum you can withdraw instantly. There's no limit on the size of a withdrawal, but all withdrawals over the threshold will have a delay time added to them",
},
{
label: 'Lifetime limit',
value: '1,230.00',
labelTooltip:
'The lifetime deposit limit per address. Note: this is a temporary measure that can be changed or removed through governance',
},
{ label: '', value: '' },
{
label: 'Infrastructure fee account balance',
value: '0.00001',
labelTooltip: 'The infrastructure fee account in this asset',
},
{
label: 'Global reward pool account balance',
value: '0.00002',
labelTooltip: 'The global rewards acquired in this asset',
},
{
label: 'Maker paid fees account balance',
value: '0.00003',
labelTooltip:
'The rewards acquired based on the fees paid to makers in this asset',
},
{
label: 'Maker received fees account balance',
value: '0.00004',
labelTooltip:
'The rewards acquired based on fees received for being a maker on trades',
},
{
label: 'Liquidity provision fee reward account balance',
value: '0.00005',
labelTooltip:
'The rewards acquired based on the liquidity provision fees in this asset',
},
{
label: 'Market proposer reward account balance',
value: '0.00006',
labelTooltip:
'The rewards acquired based on the market proposer reward in this asset',
},
];
//endregion
beforeEach(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
});
const visitPortfolioAndClickAsset = (assetName: string) => {
cy.visit('/#/portfolio');
cy.get(assetColId).contains(assetName).click();
};
const testTooltip = (index: number, testId: string, tooltip: string) => {
cy.getByTestId(`${index}_${testId}`).realHover();
cy.get('[role="tooltip"]').find('div').should('have.text', tooltip);
cy.getByTestId(dialogTitle).click();
};
describe('assets', { tags: '@smoke', testIsolation: true }, () => {
it('asset details', () => {
visitPortfolioAndClickAsset('tBTC');
cy.getByTestId(assetRow).each((element, index) => {
if (index === 10) {
return;
}
const { label, value, labelTooltip, valueToolTip } =
labelValueToolTipPairs[index];
// 6501-ASSE-001
// 6501-ASSE-002
// 6501-ASSE-003
// 6501-ASSE-004
// 6501-ASSE-005
// 6501-ASSE-006
// 6501-ASSE-007
// 6501-ASSE-008
// 6501-ASSE-009
// 6501-ASSE-010
// 6501-ASSE-011
cy.getByTestId(`${index}_label`).should('have.text', label);
cy.getByTestId(`${index}_value`).should('have.text', value);
// 6501-ASSE-012
if (indicesWithLabelTooltips.includes(index)) {
if (labelTooltip) {
testTooltip(index, 'label', labelTooltip);
}
}
if (indicesWithValueTooltips.includes(index)) {
if (valueToolTip) {
testTooltip(index, 'value', valueToolTip);
}
}
});
// 6501-ASSE-013
cy.getByTestId(dialogCloseX).click();
cy.document().then((doc) => {
expect(doc.querySelector(assetDetailsDialog)).to.not.exist;
});
});
it('ERC20 Contract address', () => {
visitPortfolioAndClickAsset('tBTC');
cy.getByTestId(contractAddress).within(() => {
// 6501-ASSE-014
cy.getByTestId('external-link')
.should('have.attr', 'target', '_blank')
.should('have.text', '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4');
});
// 6501-ASSE-013
cy.getByTestId(dialogCloseBtn).click();
cy.document().then((doc) => {
expect(doc.querySelector(assetDetailsDialog)).to.not.exist;
});
});
});
-207
View File
@@ -1,207 +0,0 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
import * as Schema from '@vegaprotocol/types';
const dialogContent = 'welcome-dialog';
const generateProposal = (code: string): ProposalListFieldsFragment => ({
__typename: 'Proposal',
reference: '',
state: Schema.ProposalState.STATE_OPEN,
datetime: '',
votes: {
__typename: undefined,
yes: {
__typename: undefined,
totalTokens: '',
totalNumber: '',
totalWeight: '',
},
no: {
__typename: undefined,
totalTokens: '',
totalNumber: '',
totalWeight: '',
},
},
requiredMajority: '',
party: {
__typename: 'Party',
id: '',
},
rationale: {
__typename: 'ProposalRationale',
description: '',
title: '',
},
requiredParticipation: '',
errorDetails: '',
rejectionReason: null,
requiredLpMajority: '',
requiredLpParticipation: '',
terms: {
__typename: 'ProposalTerms',
closingDatetime: '',
enactmentDatetime: undefined,
change: {
__typename: 'NewMarket',
decimalPlaces: 1,
lpPriceRange: '',
riskParameters: {
__typename: 'SimpleRiskModel',
params: {
__typename: 'SimpleRiskModelParams',
factorLong: 0,
factorShort: 1,
},
},
metadata: [],
instrument: {
__typename: 'InstrumentConfiguration',
code: code,
name: code,
futureProduct: {
__typename: 'FutureProduct',
settlementAsset: {
__typename: 'Asset',
id: 'A',
name: 'A',
symbol: 'A',
decimals: 1,
quantum: '',
},
quoteName: '',
dataSourceSpecBinding: {
__typename: 'DataSourceSpecToFutureBinding',
settlementDataProperty: '',
tradingTerminationProperty: '',
},
dataSourceSpecForSettlementData: {
__typename: 'DataSourceDefinition',
sourceType: {
__typename: 'DataSourceDefinitionInternal',
},
},
dataSourceSpecForTradingTermination: {
__typename: 'DataSourceDefinition',
sourceType: {
__typename: 'DataSourceDefinitionInternal',
},
},
},
},
},
},
});
describe('home', { tags: '@regression' }, () => {
beforeEach(() => {
cy.clearLocalStorage();
cy.mockTradingPage();
cy.mockSubscription();
});
describe('default market found', () => {
it('redirects to a default market with the landing dialog open', () => {
cy.visit('/');
cy.wait('@Markets');
cy.get('[data-testid^="pathname-/markets/"]');
// the choose market overlay is no longer showing
cy.contains('Loading...').should('not.exist');
cy.url().should('eq', Cypress.config().baseUrl + '/#/markets/market-0');
});
});
describe('no markets found', () => {
beforeEach(() => {
cy.mockGQL((req) => {
const data = {
marketsConnection: {
__typename: 'MarketConnection',
edges: [],
},
};
const proposalA: ProposalListFieldsFragment =
generateProposal('AAAZZZ');
aliasGQLQuery(req, 'Markets', data);
aliasGQLQuery(req, 'MarketsData', data);
aliasGQLQuery(req, 'ProposalsList', {
proposalsConnection: {
__typename: 'ProposalsConnection',
edges: [{ __typename: 'ProposalEdge', node: proposalA }],
},
});
});
cy.visit('/');
cy.wait('@Markets');
cy.wait('@MarketsData');
});
it('close welcome dialog should redirect to market/all', () => {
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
cy.getByTestId('welcome-dialog').should('be.visible');
cy.getByTestId('welcome-title').should('contain.text', 'Console CUSTOM');
cy.getByTestId('browse-markets-button').should('not.be.disabled');
cy.getByTestId('get-started-banner').should('be.visible');
cy.getByTestId('get-started-button').should('not.be.disabled');
cy.getByTestId('dialog-close').click();
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
cy.window().then((window) => {
expect(window.localStorage.getItem('vega_onboarding_viewed')).to.equal(
'true'
);
});
});
it('click browse markets button should redirect to market/all', () => {
cy.getByTestId('welcome-dialog').should('be.visible');
cy.getByTestId('browse-markets-button').click();
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
cy.window().then((window) => {
expect(window.localStorage.getItem('vega_onboarding_viewed')).to.equal(
'true'
);
});
});
it('click get started button should open connect dialog', () => {
cy.getByTestId('welcome-dialog').should('be.visible');
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
cy.window().then((window) => {
// @ts-ignore stub it out just for test case
window.vega = {};
cy.getByTestId('get-started-button').click();
cy.getByTestId('wallet-dialog-title').should('contain.text', 'Connect');
});
});
});
describe('redirect should take last visited market into consideration', () => {
it('marketId comes from existing market', () => {
cy.window().then((window) => {
window.localStorage.setItem('marketId', 'market-1');
cy.visit('/');
cy.getByTestId('dialog-close').click();
cy.location('hash').should('equal', '#/markets/market-1');
cy.getByTestId(dialogContent).should('not.exist');
});
});
it('marketId comes from not-existing market', () => {
cy.window().then((window) => {
window.localStorage.setItem('marketId', 'market-not-existing');
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Market', null);
});
cy.visit('/');
cy.wait('@Markets');
cy.getByTestId('dialog-close').click();
cy.location('hash').should('equal', '#/markets/market-not-existing');
cy.getByTestId(dialogContent).should('not.exist');
});
});
});
});
@@ -1,73 +0,0 @@
import * as Schema from '@vegaprotocol/types';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { marketsQuery } from '@vegaprotocol/mock';
import { getDateTimeFormat } from '@vegaprotocol/utils';
describe('markets table', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.clearLocalStorage().then(() => {
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/#/markets/all');
});
});
it('opening auction subsets should be properly displayed', () => {
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION
);
cy.mockGQL((req) => {
const override = {
marketsConnection: {
edges: [
{
node: {
tradableInstrument: {
instrument: {
name: `opening auction MARKET`,
},
},
state: Schema.MarketState.STATE_ACTIVE,
tradingMode:
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
},
},
],
},
};
// @ts-ignore partial deep check failing
const market = marketsQuery(override);
aliasGQLQuery(req, 'Market', market);
aliasGQLQuery(req, 'ProposalOfMarket', {
proposal: { terms: { enactmentDatetime: '2023-01-31 12:00:01' } },
});
});
cy.visit('#/markets/market-0');
cy.url().should('contain', 'market-0');
cy.getByTestId('item-value').contains('Opening auction').realHover();
cy.getByTestId('opening-auction-sub-status').should(
'contain.text',
'Opening auction: Not enough liquidity to open'
);
const now = new Date(Date.parse('2023-01-30 12:00:01')).getTime();
cy.clock(now, ['Date']); // Set "now" to BEFORE reservation
cy.reload();
cy.getByTestId('item-value').contains('Opening auction').realHover();
cy.getByTestId('opening-auction-sub-status').should(
'contain.text',
`Opening auction: Closing on ${getDateTimeFormat().format(
new Date('2023-01-31 12:00:01')
)}`
);
cy.clock().then((clock) => {
clock.restore();
});
});
});
@@ -27,7 +27,8 @@ describe('positions', { tags: '@smoke', testIsolation: true }, () => {
validatePositionsDisplayed();
});
it('renders positions on portfolio page', () => {
// TODO: move this to sim, its flakey
it.skip('renders positions on portfolio page', () => {
cy.mockGQL((req) => {
const positions = positionsQuery();
if (positions.positions?.edges) {
@@ -230,7 +231,7 @@ describe('positions', { tags: '@regression', testIsolation: true }, () => {
deltaX: 500,
});
// 7004-POSI-004
cy.get('[col-id="updatedAt"]').should('be.visible');
cy.get('[col-id="unrealisedPNL"]').should('be.visible');
});
it('Drag and drop columns', () => {
@@ -59,8 +59,7 @@ describe('trades', { tags: '@smoke' }, () => {
cy.getByTestId(tradesTable) // order table shares identical col id
.find(`${colIdCreatedAt} ${colHeader}`)
.should('have.text', 'Created at');
const dateTimeRegex =
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
const dateTimeRegex = /(\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
cy.getByTestId(tradesTable)
.get(`.ag-center-cols-container ${colIdCreatedAt}`)
.each(($tradeDateTime) => {
@@ -87,6 +86,7 @@ describe('trades', { tags: '@smoke' }, () => {
});
it('copy price to deal ticket form', () => {
cy.getByTestId('Order').click();
// 6005-THIS-007
cy.get(colIdPrice).last().should('be.visible').click();
cy.getByTestId('order-price').should('have.value', '171.16898');
-1
View File
@@ -1,4 +1,3 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+1
View File
@@ -0,0 +1 @@
window._env_ = {};
Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

+20
View File
@@ -0,0 +1,20 @@
{
"short_name": "Mainnet Stats",
"name": "Vega Mainnet statistics",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
+3
View File
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
@@ -1,6 +1,5 @@
import type { ComponentProps } from 'react';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { TradesContainer } from '@vegaprotocol/trades';
import { DepthChartContainer } from '@vegaprotocol/market-depth';
import {
CandlesChartContainer,
@@ -8,6 +7,7 @@ import {
} from '@vegaprotocol/candles-chart';
import { Filter, OpenOrdersMenu } from '@vegaprotocol/orders';
import { NO_MARKET } from './constants';
import { TradesContainer } from '../../components/trades-container';
import { OrderbookContainer } from '../../components/orderbook-container';
import { FillsContainer } from '../../components/fills-container';
import { PositionsContainer } from '../../components/positions-container';
@@ -276,15 +276,9 @@ const ClosedMarketsDataGrid = ({
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
rowData={rowData}
columnDefs={colDefs}
getRowId={({ data }) => data.id}
defaultColDef={{
resizable: true,
minWidth: 100,
flex: 1,
}}
components={{ SuccessorMarketRenderer }}
overlayNoRowsTemplate={error ? error.message : t('No markets')}
/>
@@ -15,9 +15,7 @@ export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => {
const gridStore = usePositionsStore((store) => store.gridStore);
const updateGridStore = usePositionsStore((store) => store.updateGridStore);
const gridStoreCallbacks = useDataGridEvents(gridStore, (colState) => {
updateGridStore(colState);
});
const gridStoreCallbacks = useDataGridEvents(gridStore, updateGridStore);
if (!pubKey) {
return (
@@ -0,0 +1 @@
export * from './trades-container';
@@ -0,0 +1,24 @@
import { TradesManager } from '@vegaprotocol/trades';
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { useDataGridEvents } from '@vegaprotocol/datagrid';
interface TradesContainerProps {
marketId: string;
}
export const TradesContainer = ({ marketId }: TradesContainerProps) => {
const gridStore = useTradesStore((store) => store.gridStore);
const updateGridStore = useTradesStore((store) => store.updateGridStore);
const gridStoreCallbacks = useDataGridEvents(gridStore, updateGridStore);
return <TradesManager marketId={marketId} gridProps={gridStoreCallbacks} />;
};
const useTradesStore = create<DataGridSlice>()(
persist(createDataGridSlice, {
name: 'vega_trades_store',
})
);
+34 -1
View File
@@ -5,12 +5,45 @@ export default function Document() {
<Html>
<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"
type="image/x-icon"
href="https://static.vega.xyz/favicon.ico"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<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" />
<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"
crossOrigin="anonymous"
/>
{/* eslint-disable-next-line @next/next/no-css-tags */}
<link rel="stylesheet" href="/preloader.css" media="all" />
+10
View File
@@ -142,12 +142,19 @@ html [data-theme='dark'] {
border-width: 0;
}
.vega-ag-grid .ag-cell .ag-cell-wrapper {
height: 100%;
}
.vega-ag-grid .ag-header-row {
@apply font-alpha font-normal;
}
/* Light variables */
.ag-theme-balham {
--ag-grid-size: 2px; /* Used for compactness */
--ag-row-height: 36px;
--ag-header-height: 36px;
--ag-background-color: theme(colors.white);
--ag-border-color: theme(colors.vega.clight.600);
--ag-header-background-color: theme(colors.vega.clight.700);
@@ -160,6 +167,9 @@ html [data-theme='dark'] {
/* Dark variables */
.ag-theme-balham-dark {
--ag-grid-size: 2px; /* Used for compactness */
--ag-row-height: 36px;
--ag-header-height: 36px;
--ag-background-color: theme(colors.vega.cdark.900);
--ag-border-color: theme(colors.vega.cdark.600);
--ag-header-background-color: theme(colors.vega.cdark.700);
+7 -7
View File
@@ -58,6 +58,12 @@ export const accountValuesComparator = (
return valueA > valueB ? 1 : -1;
};
const defaultColDef = {
resizable: true,
sortable: true,
tooltipComponent: TooltipCellComponent,
comparator: accountValuesComparator,
};
export interface GetRowsParams extends Omit<IGetRowsParams, 'successCallback'> {
successCallback(rowsThisBlock: AccountFields[], lastRow?: number): void;
}
@@ -306,16 +312,10 @@ export const AccountTable = ({
return (
<AgGrid
{...props}
style={{ width: '100%', height: '100%' }}
getRowId={({ data }: { data: AccountFields }) => data.asset.id}
tooltipShowDelay={500}
rowData={data}
defaultColDef={{
resizable: true,
tooltipComponent: TooltipCellComponent,
sortable: true,
comparator: accountValuesComparator,
}}
defaultColDef={defaultColDef}
columnDefs={colDefs}
getRowHeight={getPinnedAssetRowHeight}
pinnedTopRowData={pinnedRow ? [pinnedRow] : undefined}
+5 -9
View File
@@ -20,6 +20,10 @@ import { MarginHealthChart } from './margin-health-chart';
import { MarketNameCell } from '@vegaprotocol/datagrid';
import { AccountType } from '@vegaprotocol/types';
const defaultColDef = {
resizable: true,
sortable: true,
};
interface BreakdownTableProps extends AgGridReactProps {
data: AccountFields[] | null;
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
@@ -41,7 +45,6 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
if (!value) return 'None';
return value;
},
minWidth: 200,
},
{
headerName: t('Account type'),
@@ -58,7 +61,6 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
{
headerName: t('Balance'),
field: 'used',
flex: 2,
maxWidth: 500,
type: 'rightAligned',
tooltipComponent: TooltipCellComponent,
@@ -97,7 +99,6 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
{
headerName: t('Margin health'),
field: 'market.id',
flex: 2,
maxWidth: 500,
sortable: false,
cellRenderer: ({
@@ -118,7 +119,6 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
overlayNoRowsTemplate={t('Collateral not used')}
rowData={data}
getRowId={({ data }: { data: AccountFields }) =>
@@ -128,11 +128,7 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
rowHeight={34}
components={{ PriceCell, MarketNameCell, ProgressBarCell }}
tooltipShowDelay={500}
defaultColDef={{
flex: 1,
resizable: true,
sortable: true,
}}
defaultColDef={defaultColDef}
columnDefs={coldefs}
/>
);
+2 -37
View File
@@ -7,21 +7,12 @@ import {
} from '@vegaprotocol/network-parameters';
import { useDataProvider } from '@vegaprotocol/data-provider';
import type { Transfer } from '@vegaprotocol/wallet';
import {
useVegaTransactionStore,
useVegaWallet,
useVegaWalletDialogStore,
} from '@vegaprotocol/wallet';
import { useVegaTransactionStore, useVegaWallet } from '@vegaprotocol/wallet';
import { useCallback, useMemo } from 'react';
import { accountsDataProvider } from './accounts-data-provider';
import { TransferForm } from './transfer-form';
import sortBy from 'lodash/sortBy';
import {
ExternalLink,
Intent,
Lozenge,
Notification,
} from '@vegaprotocol/ui-toolkit';
import { Lozenge } from '@vegaprotocol/ui-toolkit';
export const TransferContainer = ({ assetId }: { assetId?: string }) => {
const { pubKey, pubKeys } = useVegaWallet();
@@ -32,10 +23,6 @@ export const TransferContainer = ({ assetId }: { assetId?: string }) => {
skip: !pubKey,
});
const openVegaWalletDialog = useVegaWalletDialogStore(
(store) => store.openVegaWalletDialog
);
const create = useVegaTransactionStore((store) => store.create);
const transfer = useCallback(
@@ -74,28 +61,6 @@ export const TransferContainer = ({ assetId }: { assetId?: string }) => {
)}
{t('. If you are at all unsure, stop and seek advice.')}
</p>
{!pubKey && (
<div className="mb-4">
<Notification
intent={Intent.Warning}
message={
<p className="text-sm pb-2">
You need a{' '}
<ExternalLink href="https://vega.xyz/wallet">
Vega wallet
</ExternalLink>{' '}
to make a transfer.
</p>
}
buttonProps={{
text: t('Connect wallet'),
action: openVegaWalletDialog,
dataTestId: 'order-connect-wallet',
size: 'small',
}}
/>
</div>
)}
<TransferForm
pubKey={pubKey}
pubKeys={pubKeys ? pubKeys?.map((pk) => pk.publicKey) : null}
+2
View File
@@ -24,6 +24,7 @@ import { addVegaWalletSubmitLiquidityProvision } from './lib/commands/vega-walle
import { addImportNodeWallets } from './lib/commands/import-node-wallets';
import { addVegaWalletTopUpRewardsPool } from './lib/commands/vega-wallet-top-up-rewards-pool';
import { addAssociateTokensToVegaWallet } from './lib/commands/associate-tokens-to-vega-wallet';
import { addMockChainId } from './lib/commands/mock-chain-id';
addGetTestIdcommand();
addMockGQLCommand();
@@ -49,6 +50,7 @@ addVegaWalletSubmitLiquidityProvision();
addImportNodeWallets();
addVegaWalletTopUpRewardsPool();
addAssociateTokensToVegaWallet();
addMockChainId();
export {
mockConnectWallet,
@@ -0,0 +1,22 @@
import { aliasGQLQuery } from '../mock-gql';
// eslint-disable-next-line @nx/enforce-module-boundaries
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chainable<Subject> {
mockChainId(): void;
}
}
}
export function addMockChainId() {
Cypress.Commands.add('mockChainId', () => {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
});
}
@@ -3,6 +3,20 @@ import { AgGridReact } from 'ag-grid-react';
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
import { t } from '@vegaprotocol/i18n';
import classNames from 'classnames';
import type { ColDef } from 'ag-grid-community';
const defaultProps: AgGridReactProps = {
enableCellTextSelection: true,
overlayLoadingTemplate: t('Loading...'),
overlayNoRowsTemplate: t('No data'),
suppressCellFocus: true,
suppressColumnMoveAnimation: true,
};
const defaultColDef: ColDef = {
resizable: true,
sortable: true,
};
export const AgGridThemed = ({
style,
@@ -13,23 +27,20 @@ export const AgGridThemed = ({
gridRef?: React.ForwardedRef<AgGridReact>;
}) => {
const { theme } = useThemeSwitcher();
const defaultProps = {
rowHeight: 22,
headerHeight: 22,
enableCellTextSelection: true,
overlayLoadingTemplate: t('Loading...'),
overlayNoRowsTemplate: t('No data'),
suppressCellFocus: true,
};
const wrapperClasses = classNames('vega-ag-grid', {
const wrapperClasses = classNames('vega-ag-grid', 'w-full h-full', {
'ag-theme-balham': theme === 'light',
'ag-theme-balham-dark': theme === 'dark',
});
return (
<div className={wrapperClasses} style={style}>
<AgGridReact {...defaultProps} {...props} ref={gridRef} />
<div className={wrapperClasses}>
<AgGridReact
defaultColDef={defaultColDef}
ref={gridRef}
{...defaultProps}
{...props}
/>
</div>
);
};
@@ -29,7 +29,11 @@ export const MarketNameCell = ({
);
if (!value || !data) return null;
return onMarketClick ? (
<button onClick={handleOnClick} tabIndex={0}>
<button
onClick={handleOnClick}
tabIndex={0}
className="block text-left text-ellipsis overflow-hidden whitespace-nowrap w-full"
>
{value}
</button>
) : (
+2 -2
View File
@@ -4,8 +4,8 @@ export const COL_DEFS = {
sortable: false,
resizable: false,
filter: false,
minWidth: 45,
maxWidth: 45,
minWidth: 30,
maxWidth: 30,
type: 'rightAligned',
pinned: 'right' as const,
},
@@ -14,7 +14,6 @@ const gridProps = {
{
field: 'id',
width: 100,
resizable: true,
filter: 'agNumberColumnFilter',
},
],
@@ -50,7 +49,7 @@ describe('useDataGridEvents', () => {
console.warn = originalWarn;
});
it('default state is set and callback is called on column or filter event', async () => {
it('default state is set and callback is called on filter event', async () => {
const callback = jest.fn();
const initialState = {
filterModel: undefined,
@@ -67,45 +66,6 @@ describe('useDataGridEvents', () => {
// no filters set
expect(result.current.api.getFilterModel()).toEqual({});
const newWidth = 400;
// Set col width
await act(async () => {
result.current.columnApi.setColumnWidth('id', newWidth);
});
act(() => {
jest.advanceTimersByTime(GRID_EVENT_DEBOUNCE_TIME);
});
expect(callback).toHaveBeenCalledWith({
columnState: [expect.objectContaining({ colId: 'id', width: newWidth })],
filterModel: {},
});
callback.mockClear();
expect(result.current.columnApi.getColumnState()[0].width).toEqual(
newWidth
);
// Set filter
await act(async () => {
result.current.columnApi.applyColumnState({
state: [{ colId: 'id', sort: 'asc' }],
applyOrder: true,
});
});
act(() => {
jest.advanceTimersByTime(GRID_EVENT_DEBOUNCE_TIME);
});
expect(callback).toHaveBeenCalledWith({
columnState: [expect.objectContaining({ colId: 'id', sort: 'asc' })],
filterModel: {},
});
callback.mockClear();
expect(result.current.columnApi.getColumnState()[0].sort).toEqual('asc');
// Set filter
const idFilter = {
filter: 1,
@@ -123,7 +83,7 @@ describe('useDataGridEvents', () => {
});
expect(callback).toHaveBeenCalledWith({
columnState: expect.any(Object),
columnState: undefined,
filterModel: {
id: idFilter,
},
@@ -138,7 +98,7 @@ describe('useDataGridEvents', () => {
filterType: 'number',
type: 'equals',
};
const colState = { colId: 'id', width: 300, sort: 'desc' as const };
const colState = { colId: 'id', sort: 'desc' as const };
const initialState = {
filterModel: {
id: idFilter,
@@ -156,7 +116,7 @@ describe('useDataGridEvents', () => {
});
});
it('debounces events', async () => {
it('ignores events that were not made via the UI', async () => {
const callback = jest.fn();
const initialState = {
filterModel: undefined,
@@ -170,8 +130,6 @@ describe('useDataGridEvents', () => {
// Set col width multiple times
await act(async () => {
result.current.columnApi.setColumnWidth('id', newWidth);
result.current.columnApi.setColumnWidth('id', newWidth);
result.current.columnApi.setColumnWidth('id', newWidth);
});
expect(callback).not.toHaveBeenCalled();
@@ -180,6 +138,6 @@ describe('useDataGridEvents', () => {
jest.advanceTimersByTime(GRID_EVENT_DEBOUNCE_TIME);
});
expect(callback).toHaveBeenCalledTimes(1);
expect(callback).toHaveBeenCalledTimes(0);
});
});
+67 -23
View File
@@ -1,12 +1,13 @@
import debounce from 'lodash/debounce';
import type {
ColumnMovedEvent,
ColumnResizedEvent,
ColumnState,
ColumnVisibleEvent,
FilterChangedEvent,
GridReadyEvent,
FirstDataRenderedEvent,
SortChangedEvent,
} from 'ag-grid-community';
import { useCallback, useMemo } from 'react';
import { useCallback } from 'react';
type State = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -14,30 +15,70 @@ type State = {
columnState?: ColumnState[];
};
type Event = ColumnResizedEvent | FilterChangedEvent | SortChangedEvent;
export const GRID_EVENT_DEBOUNCE_TIME = 300;
export const useDataGridEvents = (
state: State,
callback: (data: State) => void
) => {
// This function can be called very frequently by the onColumnResized
// grid callback, so its memoized to only update after resizing is finished
const onGridChange = useMemo(
() =>
debounce(({ api, columnApi }: Event) => {
if (!api || !columnApi) return;
const columnState = columnApi.getColumnState();
const filterModel = api.getFilterModel();
callback({ columnState, filterModel });
}, GRID_EVENT_DEBOUNCE_TIME),
/**
* Callback for filter events
*/
const onFilterChanged = useCallback(
({ api }: FilterChangedEvent) => {
if (!api) return;
const filterModel = api.getFilterModel();
callback({ filterModel });
},
[callback]
);
// check if we have stored column states or filter models and apply if we do
/**
* Callback for column resized and column moved events, which can be
* triggered in quick succession. Uses the finished flag to not call the
* store callback unnecessarily
*/
const onDebouncedColumnChange = useCallback(
({
columnApi,
source,
finished,
}: ColumnResizedEvent | ColumnMovedEvent) => {
if (!finished) return;
// only call back on user interactions, and not events triggered from the api
const permittedEvents = [
'uiColumnResized',
'uiColumnDragged',
'uiColumnMoved',
];
if (!permittedEvents.includes(source)) {
return;
}
const columnState = columnApi.getColumnState();
callback({ columnState });
},
[callback]
);
/**
* Callback for sort and visible events
*/
const onColumnChange = useCallback(
({ columnApi }: SortChangedEvent | ColumnVisibleEvent) => {
const columnState = columnApi.getColumnState();
callback({ columnState });
},
[callback]
);
/**
* Callback for grid startup to apply stored column and filter states.
* State only applied if found, otherwise columns sized to fit available space
*/
const onGridReady = useCallback(
({ api, columnApi }: GridReadyEvent) => {
({ api, columnApi }: FirstDataRenderedEvent) => {
if (!api || !columnApi) return;
if (state.columnState) {
@@ -46,7 +87,6 @@ export const useDataGridEvents = (
applyOrder: true,
});
} else {
// ensure columns fit available space if no widths are set
api.sizeColumnsToFit();
}
@@ -59,8 +99,12 @@ export const useDataGridEvents = (
return {
onGridReady,
onColumnResized: onGridChange,
onFilterChanged: onGridChange,
onSortChanged: onGridChange,
// these events don't use the 'finished' flag
onFilterChanged,
onSortChanged: onColumnChange,
onColumnVisible: onColumnChange,
// these trigger a lot so this callback uses the 'finished' flag
onColumnMoved: onDebouncedColumnChange,
onColumnResized: onDebouncedColumnChange,
};
};
@@ -9,7 +9,7 @@ import {
useMarket,
useMarketPrice,
} from '@vegaprotocol/markets';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import { AsyncRendererInline } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
import { DealTicket } from './deal-ticket';
import { FLAGS } from '@vegaprotocol/environment';
@@ -42,7 +42,7 @@ export const DealTicketContainer = ({
const { data: marketPrice } = useMarketPrice(market?.id);
const create = useVegaTransactionStore((state) => state.create);
return (
<AsyncRenderer
<AsyncRendererInline
data={market && marketData}
loading={marketLoading || marketDataLoading}
error={marketError || marketDataError}
@@ -65,10 +65,8 @@ export const DealTicketContainer = ({
/>
)
) : (
<Splash>
<p>{t('Could not load market')}</p>
</Splash>
<p>{t('Could not load market')}</p>
)}
</AsyncRenderer>
</AsyncRendererInline>
);
};
+1 -9
View File
@@ -70,17 +70,9 @@ export const DepositsTable = (
</EtherscanLink>
);
},
flex: 1,
},
],
[]
);
return (
<AgGrid
defaultColDef={{ flex: 1 }}
columnDefs={columnDefs}
style={{ width: '100%', height: '100%' }}
{...props}
/>
);
return <AgGrid columnDefs={columnDefs} {...props} />;
};
-2
View File
@@ -124,8 +124,6 @@ export const FillsTable = forwardRef<AgGridReact, Props>(
ref={ref}
columnDefs={columnDefs}
overlayNoRowsTemplate={t('No fills')}
defaultColDef={{ resizable: true }}
style={{ width: '100%', height: '100%' }}
getRowId={({ data }) => data?.id}
tooltipShowDelay={0}
tooltipHideDelay={2000}
+11 -11
View File
@@ -42,6 +42,16 @@ const dateRangeFilterParams = {
maxNextDays: 0,
defaultValue,
};
const defaultColDef = {
resizable: true,
sortable: true,
tooltipComponent: TransferTooltipCellComponent,
filterParams: {
...dateRangeFilterParams,
buttons: ['reset'],
},
};
type LedgerEntryProps = TypedDataAgGrid<LedgerEntry>;
export const LedgerTable = (props: LedgerEntryProps) => {
@@ -177,24 +187,14 @@ export const LedgerTable = (props: LedgerEntryProps) => {
value ? getDateTimeFormat().format(fromNanoSeconds(value)) : '-',
filterParams: dateRangeFilterParams,
filter: DateRangeFilter,
flex: 1,
},
],
[]
);
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
tooltipShowDelay={500}
defaultColDef={{
resizable: true,
sortable: true,
tooltipComponent: TransferTooltipCellComponent,
filterParams: {
...dateRangeFilterParams,
buttons: ['reset'],
},
}}
defaultColDef={defaultColDef}
columnDefs={columnDefs}
{...props}
/>
+7 -8
View File
@@ -31,6 +31,12 @@ const dateValueFormatter = ({ value }: { value?: string | null }) => {
return getDateTimeFormat().format(new Date(value));
};
const defaultColDef = {
resizable: true,
sortable: true,
tooltipComponent: TooltipCellComponent,
};
export interface LiquidityTableProps
extends TypedDataAgGrid<LiquidityProvisionData> {
symbol?: string;
@@ -124,7 +130,6 @@ export const LiquidityTable = ({
headerTooltip: t(
'The valuation of the market at the time the liquidity commitment was made. Commitments made at a lower valuation earlier in the lifetime of the market would be expected to have a higher equity-like share if the market has grown. If a commitment is amended, value will reflect the average of the market valuations across the lifetime of the commitment.'
),
minWidth: 160,
valueFormatter: assetDecimalsQuantumFormatter,
tooltipValueGetter: assetDecimalsFormatter,
},
@@ -183,16 +188,10 @@ export const LiquidityTable = ({
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
overlayNoRowsTemplate={t('No liquidity provisions')}
getRowId={({ data }: { data: LiquidityProvisionData }) => data.id || ''}
tooltipShowDelay={500}
defaultColDef={{
resizable: true,
minWidth: 100,
tooltipComponent: TooltipCellComponent,
sortable: true,
}}
defaultColDef={defaultColDef}
{...props}
columnDefs={colDefs}
/>
@@ -35,11 +35,9 @@ const MarketName = (props: MarketNameCellProps) => (
);
const defaultColDef = {
resizable: true,
sortable: true,
filter: true,
filterParams: { buttons: ['reset'] },
minWidth: 100,
};
type Props = TypedDataAgGrid<MarketMaybeWithData> & {
onMarketClick: (marketId: string, metaKey?: boolean) => void;
@@ -58,7 +56,6 @@ export const MarketListTable = ({
};
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
getRowId={getRowId}
defaultColDef={defaultColDef}
columnDefs={columnDefs}
@@ -40,7 +40,6 @@ export const useColumnDefs = ({ onMarketClick }: Props) => {
{
headerName: t('Trading mode'),
field: 'tradingMode',
minWidth: 170,
valueFormatter: ({
data,
}: VegaValueFormatterParams<MarketMaybeWithData, 'data'>) => {
@@ -84,7 +84,6 @@ export const OrderListManager = ({
onMarketClick={onMarketClick}
onOrderTypeClick={onOrderTypeClick}
isReadOnly={isReadOnly}
suppressAutoSize
overlayNoRowsTemplate={error ? error.message : t('No orders')}
{...gridProps}
/>
@@ -37,6 +37,12 @@ import type { Order } from '../order-data-provider';
import { Filter } from '../order-list-manager';
import type { ColDef } from 'ag-grid-community';
const defaultColDef = {
resizable: true,
sortable: true,
filterParams: { buttons: ['reset'] },
};
export type OrderListTableProps = TypedDataAgGrid<Order> & {
marketId?: string;
onCancel: (order: Order) => void;
@@ -76,7 +82,6 @@ export const OrderListTable = memo<
field: 'market.tradableInstrument.instrument.code',
cellRenderer: 'MarketNameCell',
cellRendererParams: { idPath: 'market.id', onMarketClick },
minWidth: 150,
},
{
headerName: t('Filled'),
@@ -110,9 +115,6 @@ export const OrderListTable = memo<
data.market.positionDecimalPlaces ?? 0
);
},
minWidth: 50,
width: 90,
flex: 0,
},
{
headerName: t('Size'),
@@ -154,9 +156,6 @@ export const OrderListTable = memo<
)
);
},
minWidth: 50,
width: 80,
flex: 0,
},
{
field: 'type',
@@ -168,7 +167,6 @@ export const OrderListTable = memo<
cellRendererParams: {
onClick: onOrderTypeClick,
},
minWidth: 80,
},
{
field: 'status',
@@ -201,7 +199,6 @@ export const OrderListTable = memo<
{valueFormatted}
</span>
),
minWidth: 100,
},
{
field: 'price',
@@ -223,7 +220,6 @@ export const OrderListTable = memo<
}
return addDecimalsFormatNumber(value, data.market.decimalPlaces);
},
minWidth: 100,
},
{
field: 'timeInForce',
@@ -252,7 +248,6 @@ export const OrderListTable = memo<
return label;
},
minWidth: 150,
},
{
field: 'updatedAt',
@@ -272,13 +267,12 @@ export const OrderListTable = memo<
</span>
);
},
minWidth: 150,
},
{
colId: 'amend',
...COL_DEFS.actions,
minWidth: showAllActions ? 120 : COL_DEFS.actions.minWidth,
maxWidth: showAllActions ? 120 : COL_DEFS.actions.minWidth,
minWidth: showAllActions ? 110 : COL_DEFS.actions.minWidth,
maxWidth: showAllActions ? 110 : COL_DEFS.actions.minWidth,
cellRenderer: ({ data }: { data?: Order }) => {
if (!data) return null;
@@ -336,16 +330,8 @@ export const OrderListTable = memo<
return (
<AgGrid
ref={ref}
defaultColDef={{
resizable: true,
sortable: true,
filterParams: { buttons: ['reset'] },
}}
defaultColDef={defaultColDef}
columnDefs={columnDefs}
style={{
width: '100%',
height: '100%',
}}
getRowId={({ data }) => data.id}
components={{ MarketNameCell, OrderTypeCell }}
{...props}
@@ -18,6 +18,7 @@ import {
import type { Order } from '../order-data-provider';
import CopyToClipboard from 'react-copy-to-clipboard';
import { useCopyTimeout } from '@vegaprotocol/react-helpers';
import classNames from 'classnames';
interface OrderViewDialogProps {
isOpen: boolean;
@@ -50,6 +51,21 @@ export const OrderViewDialog = ({
)}
</div>
</KeyValueTableRow>
<KeyValueTableRow key={'order-side'}>
<div data-testid={'order-side-label'}>{t('Side')}</div>
<div
data-testid={`order-side-value`}
className={classNames({
// BUY
'text-market-green-600 dark:text-market-green':
order.side === Schema.Side.SIDE_BUY,
// SELL
'text-market-red': order.side === Schema.Side.SIDE_SELL,
})}
>
{Schema.SideMapping[order.side as Schema.Side]}
</div>
</KeyValueTableRow>
<KeyValueTableRow key={'order-type'}>
<div data-testid={'order-type-label'}>{t('Type')}</div>
<div data-testid={`order-type-value`}>
@@ -223,7 +239,6 @@ export const OrderViewDialog = ({
<div data-testid={`order-iceberg-order-peak-size-value`}>
<Size
value={order.icebergOrder.peakSize}
side={order.side}
positionDecimalPlaces={
order.market?.positionDecimalPlaces as number
}
@@ -248,7 +263,6 @@ export const OrderViewDialog = ({
<div data-testid={`order-iceberg-order-minimum-visible-size-value`}>
<Size
value={order.icebergOrder.minimumVisibleSize}
side={order.side}
positionDecimalPlaces={
order.market?.positionDecimalPlaces as number
}
@@ -267,7 +281,6 @@ export const OrderViewDialog = ({
<div data-testid={`order-iceberg-order-reserved-remaining-value`}>
<Size
value={order.icebergOrder.reservedRemaining}
side={order.side}
positionDecimalPlaces={
order.market?.positionDecimalPlaces as number
}
@@ -29,6 +29,12 @@ import type { AgGridReact } from 'ag-grid-react';
import type { StopOrder } from '../order-data-provider/stop-orders-data-provider';
import type { ColDef } from 'ag-grid-community';
const defaultColDef = {
resizable: true,
sortable: true,
filterParams: { buttons: ['reset'] },
};
export type StopOrdersTableProps = TypedDataAgGrid<StopOrder> & {
onCancel: (order: StopOrder) => void;
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
@@ -46,7 +52,6 @@ export const StopOrdersTable = memo<
field: 'market.tradableInstrument.instrument.code',
cellRenderer: 'MarketNameCell',
cellRendererParams: { idPath: 'market.id', onMarketClick },
minWidth: 150,
},
{
headerName: t('Trigger'),
@@ -58,7 +63,6 @@ export const StopOrdersTable = memo<
data,
}: VegaValueFormatterParams<StopOrder, 'trigger'>): string =>
data ? formatTrigger(data, data.market.decimalPlaces) : '',
minWidth: 100,
},
{
field: 'expiresAt',
@@ -82,7 +86,6 @@ export const StopOrdersTable = memo<
}
return '';
},
minWidth: 150,
},
{
headerName: t('Size'),
@@ -129,7 +132,6 @@ export const StopOrdersTable = memo<
)
);
},
minWidth: 80,
},
{
field: 'submission.type',
@@ -141,7 +143,6 @@ export const StopOrdersTable = memo<
value,
}: VegaICellRendererParams<StopOrder, 'submission.type'>) =>
value ? Schema.OrderTypeMapping[value] : '',
minWidth: 80,
},
{
field: 'status',
@@ -163,7 +164,6 @@ export const StopOrdersTable = memo<
}) => (
<span data-testid={`order-status-${data?.id}`}>{valueFormatted}</span>
),
minWidth: 100,
},
{
field: 'submission.price',
@@ -185,7 +185,6 @@ export const StopOrdersTable = memo<
}
return addDecimalsFormatNumber(value, data.market.decimalPlaces);
},
minWidth: 100,
},
{
field: 'submission.timeInForce',
@@ -198,7 +197,6 @@ export const StopOrdersTable = memo<
}: VegaValueFormatterParams<StopOrder, 'submission.timeInForce'>) => {
return value ? Schema.OrderTimeInForceCode[value] : '';
},
minWidth: 150,
},
{
field: 'updatedAt',
@@ -218,7 +216,6 @@ export const StopOrdersTable = memo<
</span>
);
},
minWidth: 150,
},
{
colId: 'actions',
@@ -249,16 +246,8 @@ export const StopOrdersTable = memo<
return (
<AgGrid
defaultColDef={{
resizable: true,
sortable: true,
filterParams: { buttons: ['reset'] },
}}
defaultColDef={defaultColDef}
columnDefs={columnDefs}
style={{
width: '100%',
height: '100%',
}}
getRowId={({ data }) => data.id}
components={{ MarketNameCell }}
{...props}
+11 -13
View File
@@ -65,18 +65,16 @@ export const PositionsManager = ({
});
return (
<div className="h-full relative">
<PositionsTable
pubKey={pubKey}
pubKeys={pubKeys}
rowData={error ? [] : data}
onMarketClick={onMarketClick}
onClose={onClose}
isReadOnly={isReadOnly}
multipleKeys={partyIds.length > 1}
overlayNoRowsTemplate={error ? error.message : t('No positions')}
{...gridProps}
/>
</div>
<PositionsTable
pubKey={pubKey}
pubKeys={pubKeys}
rowData={error ? [] : data}
onMarketClick={onMarketClick}
onClose={onClose}
isReadOnly={isReadOnly}
multipleKeys={partyIds.length > 1}
overlayNoRowsTemplate={error ? error.message : t('No positions')}
{...gridProps}
/>
);
};
@@ -57,7 +57,7 @@ describe('Positions', () => {
});
const headers = screen.getAllByRole('columnheader');
expect(headers).toHaveLength(12);
expect(headers).toHaveLength(11);
expect(
headers.map((h) => h.querySelector('[ref="eText"]')?.textContent?.trim())
).toEqual([
@@ -66,13 +66,12 @@ describe('Positions', () => {
'Open volume',
'Mark price',
'Liquidation price',
'Settlement asset',
'Asset',
'Entry price',
'Leverage',
'Margin allocated',
'Margin',
'Realised PNL',
'Unrealised PNL',
'Updated',
]);
});
@@ -212,7 +211,7 @@ describe('Positions', () => {
);
});
const cells = screen.getAllByRole('gridcell');
expect(cells[12].textContent).toEqual('Close');
expect(cells[11].textContent).toEqual('Close');
});
it('do not display close button if openVolume is zero', async () => {
@@ -228,7 +227,7 @@ describe('Positions', () => {
);
});
const cells = screen.getAllByRole('gridcell');
expect(cells[12].textContent).toEqual('');
expect(cells[11].textContent).toEqual('');
});
describe('PNLCell', () => {
+15 -41
View File
@@ -12,7 +12,6 @@ import { COL_DEFS } from '@vegaprotocol/datagrid';
import { ProgressBarCell } from '@vegaprotocol/datagrid';
import {
AgGridLazy as AgGrid,
DateRangeFilter,
PriceFlashCell,
signedNumberCssClass,
signedNumberCssClassRules,
@@ -29,7 +28,6 @@ import {
volumePrefix,
toBigNum,
formatNumber,
getDateTimeFormat,
addDecimalsFormatNumber,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
@@ -86,6 +84,14 @@ AmountCell.displayName = 'AmountCell';
export const getRowId = ({ data }: { data: Position }) =>
`${data.partyId}-${data.marketId}`;
const defaultColDef = {
sortable: true,
filter: true,
filterParams: { buttons: ['reset'] },
tooltipComponent: TooltipCellComponent,
resizable: true,
};
export const PositionsTable = ({
onClose,
onMarketClick,
@@ -98,24 +104,16 @@ export const PositionsTable = ({
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
overlayNoRowsTemplate={t('No positions')}
getRowId={getRowId}
tooltipShowDelay={500}
defaultColDef={{
resizable: true,
sortable: true,
filter: true,
filterParams: { buttons: ['reset'] },
tooltipComponent: TooltipCellComponent,
}}
defaultColDef={defaultColDef}
components={{
AmountCell,
PriceFlashCell,
ProgressBarCell,
MarketNameCell,
}}
{...props}
columnDefs={useMemo<ColDef[]>(() => {
const columnDefs: (ColDef | null)[] = [
multipleKeys
@@ -128,7 +126,6 @@ export const PositionsTable = ({
pubKeys.find((key) => key.publicKey === data.partyId)
?.name) ||
data?.partyId,
minWidth: 190,
}
: null,
{
@@ -136,7 +133,6 @@ export const PositionsTable = ({
field: 'marketName',
cellRenderer: 'MarketNameCell',
cellRendererParams: { idPath: 'marketId', onMarketClick },
minWidth: 190,
},
{
headerName: t('Notional'),
@@ -160,7 +156,6 @@ export const PositionsTable = ({
data.marketDecimalPlaces
);
},
minWidth: 80,
},
{
headerName: t('Open volume'),
@@ -190,7 +185,6 @@ export const PositionsTable = ({
);
},
cellRenderer: OpenVolumeCell,
minWidth: 100,
},
{
headerName: t('Mark price'),
@@ -224,12 +218,12 @@ export const PositionsTable = ({
data.marketDecimalPlaces
);
},
minWidth: 100,
},
{
headerName: t('Liquidation price'),
colId: 'liquidationPrice',
type: 'rightAligned',
cellClass: 'font-mono text-right',
cellRenderer: ({ data }: VegaICellRendererParams<Position>) => {
if (!data) return null;
return (
@@ -244,10 +238,9 @@ export const PositionsTable = ({
},
},
{
headerName: t('Settlement asset'),
headerName: t('Asset'),
field: 'assetSymbol',
colId: 'asset',
minWidth: 100,
cellRenderer: ({ data }: VegaICellRendererParams<Position>) => {
if (!data) return null;
return (
@@ -293,7 +286,6 @@ export const PositionsTable = ({
data.marketDecimalPlaces
);
},
minWidth: 100,
},
multipleKeys
? null
@@ -307,12 +299,11 @@ export const PositionsTable = ({
value,
}: VegaValueFormatterParams<Position, 'currentLeverage'>) =>
value === undefined ? '' : formatNumber(value.toString(), 1),
minWidth: 100,
},
multipleKeys
? null
: {
headerName: t('Margin allocated'),
headerName: t('Margin'),
field: 'marginAccountBalance',
type: 'rightAligned',
filter: 'agNumberColumnFilter',
@@ -339,7 +330,6 @@ export const PositionsTable = ({
data.decimals
);
},
minWidth: 100,
},
{
headerName: t('Realised PNL'),
@@ -364,7 +354,6 @@ export const PositionsTable = ({
'Profit or loss is realised whenever your position is reduced to zero and the margin is released back to your collateral balance. P&L excludes any fees paid.'
),
cellRenderer: PNLCell,
minWidth: 100,
},
{
headerName: t('Unrealised PNL'),
@@ -388,22 +377,6 @@ export const PositionsTable = ({
'Unrealised profit is the current profit on your open position. Margin is still allocated to your position.'
),
cellRenderer: PNLCell,
minWidth: 100,
},
{
headerName: t('Updated'),
field: 'updatedAt',
type: 'rightAligned',
filter: DateRangeFilter,
valueFormatter: ({
value,
}: VegaValueFormatterParams<Position, 'updatedAt'>) => {
if (!value) {
return '';
}
return getDateTimeFormat().format(new Date(value));
},
minWidth: 150,
},
onClose && !isReadOnly
? {
@@ -427,8 +400,8 @@ export const PositionsTable = ({
</div>
);
},
minWidth: 90,
maxWidth: 90,
minWidth: 75,
maxWidth: 75,
}
: null,
];
@@ -444,6 +417,7 @@ export const PositionsTable = ({
pubKey,
pubKeys,
])}
{...props}
/>
);
};
@@ -42,7 +42,6 @@ export const ProposalsList = ({
rowData={filteredData}
defaultColDef={defaultColDef}
getRowId={({ data }) => data.id}
style={{ width: '100%', height: '100%' }}
overlayNoRowsTemplate={t('No markets')}
components={{ SuccessorMarketRenderer }}
/>
@@ -42,7 +42,6 @@ export const useColumnDefs = () => {
colId: 'market',
headerName: t('Market'),
field: 'terms.change.instrument.code',
minWidth: 150,
cellStyle: { lineHeight: '14px' },
cellRenderer: ({
data,
@@ -144,7 +143,6 @@ export const useColumnDefs = () => {
'terms.enactmentDatetime'
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
filter: DateRangeFilter,
flex: 1,
},
{
colId: 'proposal-actions',
@@ -155,7 +153,6 @@ export const useColumnDefs = () => {
if (!data?.id) return null;
return <ProposalActionsDropdown id={data.id} />;
},
flex: 1,
},
]);
}, [VEGA_TOKEN_URL, requiredMajorityPercentage]);
@@ -163,10 +160,8 @@ export const useColumnDefs = () => {
const defaultColDef: ColDef = useMemo(() => {
return {
sortable: true,
resizable: true,
filter: true,
filterParams: { buttons: ['reset'] },
minWidth: 100,
};
}, []);
+1 -1
View File
@@ -1,2 +1,2 @@
export * from './lib/trades-container';
export * from './lib/trades-manager';
export * from './lib/__generated__/Trades';
@@ -3,12 +3,17 @@ import { tradesWithMarketProvider } from './trades-data-provider';
import { TradesTable } from './trades-table';
import { useDealTicketFormValues } from '@vegaprotocol/deal-ticket';
import { t } from '@vegaprotocol/i18n';
import type { useDataGridEvents } from '@vegaprotocol/datagrid';
interface TradesContainerProps {
marketId: string;
gridProps?: ReturnType<typeof useDataGridEvents>;
}
export const TradesContainer = ({ marketId }: TradesContainerProps) => {
export const TradesManager = ({
marketId,
gridProps,
}: TradesContainerProps) => {
const update = useDealTicketFormValues((state) => state.updateAll);
const { data, error } = useDataProvider({
@@ -23,6 +28,7 @@ export const TradesContainer = ({ marketId }: TradesContainerProps) => {
update(marketId, { price });
}}
overlayNoRowsTemplate={error ? error.message : t('No trades')}
{...gridProps}
/>
);
};
+2 -2
View File
@@ -1,5 +1,5 @@
import { act, render, screen } from '@testing-library/react';
import { getDateTimeFormat } from '@vegaprotocol/utils';
import { getTimeFormat } from '@vegaprotocol/utils';
import { SELL_CLASS, TradesTable, BUY_CLASS } from './trades-table';
import type { Trade } from './trades-data-provider';
import { Side } from '@vegaprotocol/types';
@@ -39,7 +39,7 @@ describe('TradesTable', () => {
const expectedValues = [
'1,111,222.00',
'20.00',
getDateTimeFormat().format(new Date(trade.createdAt)),
getTimeFormat().format(new Date(trade.createdAt)),
];
cells.forEach((cell, i) => {
expect(cell).toHaveTextContent(expectedValues[i]);
+4 -9
View File
@@ -8,7 +8,7 @@ import { AgGridLazy as AgGrid, NumericCell } from '@vegaprotocol/datagrid';
import {
addDecimal,
addDecimalsFormatNumber,
getDateTimeFormat,
getTimeFormat,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import type { IDatasource, IGetRowsParams } from 'ag-grid-community';
@@ -53,7 +53,6 @@ export const TradesTable = ({ onClick, ...props }: Props) => {
headerName: t('Price'),
field: 'price',
type: 'rightAligned',
width: 130,
cellClass: changeCellClass,
valueFormatter: ({
value,
@@ -87,7 +86,6 @@ export const TradesTable = ({ onClick, ...props }: Props) => {
{
headerName: t('Size'),
field: 'size',
width: 125,
type: 'rightAligned',
valueFormatter: ({
value,
@@ -107,12 +105,12 @@ export const TradesTable = ({ onClick, ...props }: Props) => {
headerName: t('Created at'),
field: 'createdAt',
type: 'rightAligned',
width: 170,
cellClass: 'text-right',
flex: 1, // make created at always fill remaining space
valueFormatter: ({
value,
}: VegaValueFormatterParams<Trade, 'createdAt'>) => {
return value && getDateTimeFormat().format(new Date(value));
return value && getTimeFormat().format(new Date(value));
},
},
],
@@ -120,12 +118,9 @@ export const TradesTable = ({ onClick, ...props }: Props) => {
);
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
getRowId={({ data }) => data.id}
defaultColDef={{
flex: 1,
}}
columnDefs={columnDefs}
rowHeight={22}
{...props}
/>
);
@@ -7,10 +7,7 @@ import {
export const ActionsDropdownTrigger = () => {
return (
<TradingDropdownTrigger
className='hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 [&[aria-expanded="true"]]:bg-vega-light-200 dark:[&[aria-expanded="true"]]:bg-vega-dark-200 p-0.5 rounded-full'
data-testid="dropdown-menu"
>
<TradingDropdownTrigger data-testid="dropdown-menu">
<button type="button">
<VegaIcon name={VegaIconNames.KEBAB} />
</button>
@@ -115,7 +115,6 @@ export const WithdrawalsTable = ({
{
headerName: t('Transaction'),
field: 'txHash',
flex: 2,
type: 'rightAligned',
cellRendererParams: {
complete: (withdrawal: WithdrawalFieldsFragment) => {
@@ -135,8 +134,6 @@ export const WithdrawalsTable = ({
<AgGrid
overlayNoRowsTemplate={t('No withdrawals')}
columnDefs={columnDefs}
defaultColDef={{ flex: 1 }}
style={{ width: '100%', height: '100%' }}
components={{
RecipientCell,
StatusCell,
+1 -1
View File
@@ -69,7 +69,7 @@ When looking at a list of orders, I...
- **must** see if any execution flags (aka conditions. e.g. Post only, Reduce only) were applied to the order (<a name="7003-MORD-019" href="#7003-MORD-019">7003-MORD-019</a>)
- **should** see "created at" [time](9001-DATA-data_display.md#time)
- **could** see updated at (this is used by the system when an order is amended, or repriced (in pegged and LP) not sure this in needed)
- **must** be able to see a single order view dialog with all the fields present above
- **should** see time priority (how many orders are before mine at this price)
- if the order is `Active` &amp; **not** part of a liquidity or peg shape: **must** see an option to [amend](#amend-order---price) the individual order (<a name="7003-MORD-007" href="#7003-MORD-007">7003-MORD-007</a>)
- if the order is `Active` &amp; is part of a liquidity or peg shape: **must** **not** see an option to amend the individual order (<a name="7003-MORD-008" href="#7003-MORD-008">7003-MORD-008</a>)