Compare commits

..
Author SHA1 Message Date
Madalina Raicu 59ffcacb1c chore: update tests for icons 2023-08-16 12:01:09 +03:00
Madalina Raicu 3034da385e Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/use-action-icon-buttons 2023-08-16 12:00:45 +03:00
daro-maj 809f149df9 test(trading): remove charts depth test (#4557) 2023-08-16 10:20:15 +02:00
Madalina Raicu 90a8955a5b Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/use-action-icon-buttons 2023-08-15 15:26:30 +03:00
Matthew Russell e4eedf5ccd feat(trading,datagrid): datagrid improvements (#4524) 2023-08-15 12:26:13 +01:00
Madalina Raicu 9722580dde fix(trading): update min width for icons 2023-08-15 12:17:05 +03: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
Madalina Raicu ae13c15d6e chore(trading): use action icon buttons 2023-08-14 18:05:03 +03:00
Ben 30735388e8 chore(trading): remove asset tests (#4548) 2023-08-14 15:35:24 +01: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
68 changed files with 511 additions and 860 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,
},
},
};
}
+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
@@ -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;
});
});
});
@@ -1,15 +0,0 @@
describe('charts', { tags: '@smoke' }, () => {
before(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('can see market depth chart', () => {
// 6006-DEPC-001
cy.getByTestId('Depth').click();
cy.getByTestId('tab-depth').should('be.visible');
});
});
-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');
});
});
});
});
@@ -217,7 +217,7 @@ describe('no markets proposed', { tags: '@smoke', testIsolation: true }, () => {
cy.setOnBoardingViewed();
});
it('can see no markets message', () => {
it.skip('can see no markets message', () => {
cy.visit('/#/markets/all');
cy.get('[data-testid="Proposed markets"]').click();
@@ -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,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',
})
);
+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}
/>
@@ -80,7 +80,7 @@ describe('OrderListTable', () => {
'-',
Schema.OrderTimeInForceCode[marketOrder.timeInForce],
getDateTimeFormat().format(new Date(marketOrder.createdAt)),
'Edit',
'',
];
expectedValues.forEach((expectedValue, i) =>
expect(cells[i]).toHaveTextContent(expectedValue)
@@ -104,7 +104,7 @@ describe('OrderListTable', () => {
Schema.OrderTimeInForceCode[limitOrder.timeInForce]
}: ${getDateTimeFormat().format(new Date(limitOrder.expiresAt ?? ''))}`,
getDateTimeFormat().format(new Date(limitOrder.createdAt)),
'Edit',
'',
];
expectedValues.forEach((expectedValue, i) =>
expect(cells[i]).toHaveTextContent(expectedValue)
@@ -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 ? 90 : COL_DEFS.actions.minWidth,
maxWidth: showAllActions ? 90 : COL_DEFS.actions.minWidth,
cellRenderer: ({ data }: { data?: Order }) => {
if (!data) return null;
@@ -291,14 +285,14 @@ export const OrderListTable = memo<
data-testid="edit"
onClick={() => onEdit(data)}
>
{t('Edit')}
<VegaIcon name={VegaIconNames.EDIT} size={16} />
</ButtonLink>
)}
<ButtonLink
data-testid="cancel"
onClick={() => onCancel(data)}
>
{t('Cancel')}
<VegaIcon name={VegaIconNames.CROSS} size={16} />
</ButtonLink>
</>
)}
@@ -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}
@@ -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('');
});
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', () => {
+18 -42
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,
@@ -24,12 +23,13 @@ import {
TooltipCellComponent,
ExternalLink,
Icon,
VegaIconNames,
VegaIcon,
} from '@vegaprotocol/ui-toolkit';
import {
volumePrefix,
toBigNum,
formatNumber,
getDateTimeFormat,
addDecimalsFormatNumber,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
@@ -86,6 +86,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 +106,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 +128,6 @@ export const PositionsTable = ({
pubKeys.find((key) => key.publicKey === data.partyId)
?.name) ||
data?.partyId,
minWidth: 190,
}
: null,
{
@@ -136,7 +135,6 @@ export const PositionsTable = ({
field: 'marketName',
cellRenderer: 'MarketNameCell',
cellRendererParams: { idPath: 'marketId', onMarketClick },
minWidth: 190,
},
{
headerName: t('Notional'),
@@ -160,7 +158,6 @@ export const PositionsTable = ({
data.marketDecimalPlaces
);
},
minWidth: 80,
},
{
headerName: t('Open volume'),
@@ -190,7 +187,6 @@ export const PositionsTable = ({
);
},
cellRenderer: OpenVolumeCell,
minWidth: 100,
},
{
headerName: t('Mark price'),
@@ -224,12 +220,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 +240,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 +288,6 @@ export const PositionsTable = ({
data.marketDecimalPlaces
);
},
minWidth: 100,
},
multipleKeys
? null
@@ -307,12 +301,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 +332,6 @@ export const PositionsTable = ({
data.decimals
);
},
minWidth: 100,
},
{
headerName: t('Realised PNL'),
@@ -364,7 +356,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 +379,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
? {
@@ -418,7 +393,7 @@ export const PositionsTable = ({
data-testid="close-position"
onClick={() => data && onClose(data)}
>
{t('Close')}
<VegaIcon name={VegaIconNames.CROSS} size={16} />
</ButtonLink>
) : null}
{data?.assetId && (
@@ -427,8 +402,8 @@ export const PositionsTable = ({
</div>
);
},
minWidth: 90,
maxWidth: 90,
minWidth: 75,
maxWidth: 75,
}
: null,
];
@@ -444,6 +419,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,