Compare commits
51
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eba8e3ca8b | ||
|
|
6894fe1264 | ||
|
|
93e4b5fdb9 | ||
|
|
1566fc3984 | ||
|
|
39962a0246 | ||
|
|
8d31510d5e | ||
|
|
26d5a67604 | ||
|
|
9cc8f5a377 | ||
|
|
2e11cf4dfa | ||
|
|
9e4ba9f275 | ||
|
|
aac0c25d09 | ||
|
|
d20c2a08ae | ||
|
|
4e6ba5fe3d | ||
|
|
276d1d7c7b | ||
|
|
4990c5808d | ||
|
|
cdd91c24f2 | ||
|
|
e3eb13ca72 | ||
|
|
3f0ebbf33d | ||
|
|
026aa3964b | ||
|
|
aa4c5a4a57 | ||
|
|
0874314d2a | ||
|
|
a70a7bcc8e | ||
|
|
4461a6a497 | ||
|
|
1041864ad8 | ||
|
|
015e0188ec | ||
|
|
228236c152 | ||
|
|
cd6e906dc6 | ||
|
|
8a47a92dbd | ||
|
|
af14c27df9 | ||
|
|
38edcd88c0 | ||
|
|
a74cf02030 | ||
|
|
6686755763 | ||
|
|
79cf8163be | ||
|
|
1688e26f4b | ||
|
|
5e101a8eaf | ||
|
|
65071f57d0 | ||
|
|
b87c981a90 | ||
|
|
b509e5b347 | ||
|
|
bb9fce4831 | ||
|
|
918825aca8 | ||
|
|
74bf183fad | ||
|
|
674baa1ee3 | ||
|
|
d18a0c7e15 | ||
|
|
76a6005b77 | ||
|
|
79414614c2 | ||
|
|
fde49e5446 | ||
|
|
45283161aa | ||
|
|
375d447fa8 | ||
|
|
1dd97a2bce | ||
|
|
d4a1a9b193 | ||
|
|
376c5241a8 |
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
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: 'FEATURE EPIC: '
|
||||||
|
labels: feature-epic
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Feature
|
||||||
|
|
||||||
|
<Name>
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
- [ ] Define high level requirements
|
||||||
|
- [ ] Create basic mockups
|
||||||
|
- [ ] Update "API Requirements" in core spec
|
||||||
|
- [ ] Update "User-Interface Spec" in relevant front end repo
|
||||||
|
- [ ] Create detailed user stories using normal template
|
||||||
|
|
||||||
|
## High Level Requirements
|
||||||
|
|
||||||
|
## Basic Mockups
|
||||||
|
|
||||||
|
## Link to API Requirements in Core spec
|
||||||
|
|
||||||
|
## Link to User Interface Specs
|
||||||
|
|
||||||
|
## Linked User Stories
|
||||||
@@ -10,8 +10,8 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
run-tests:
|
run-tests:
|
||||||
name: run-tests
|
name: run-tests
|
||||||
runs-on: ubuntu-22.04
|
runs-on: 8-cores
|
||||||
timeout-minutes: 25
|
timeout-minutes: 20
|
||||||
steps:
|
steps:
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# check-out frontend-monorepo
|
# check-out frontend-monorepo
|
||||||
@@ -125,7 +125,7 @@ jobs:
|
|||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
working-directory: ./console-test
|
working-directory: ./console-test
|
||||||
run: poetry run pytest --numprocesses auto
|
run: poetry run pytest -s --numprocesses auto
|
||||||
- name: Check files
|
- name: Check files
|
||||||
run: |
|
run: |
|
||||||
ls -al .
|
ls -al .
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ jobs:
|
|||||||
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
||||||
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
||||||
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
||||||
|
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is dev image
|
||||||
|
if: ${{ contains(github.ref, 'develop') && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||||
|
run: |
|
||||||
|
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Is PR
|
- name: Is PR
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
@@ -75,7 +81,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
- name: Log in to the Container registry (docker hub)
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
@@ -173,7 +179,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
id: dockerhub-push
|
id: dockerhub-push
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -183,7 +189,7 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || '' }}
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr - retry)
|
- name: Publish dist as docker image (ghcr - retry)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
context('Proposal page', { tags: '@smoke' }, function () {
|
||||||
|
describe('Verify elements on page', function () {
|
||||||
|
const proposalHeading = 'proposals-heading';
|
||||||
|
const dateTimeRegex =
|
||||||
|
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
|
||||||
|
const proposalTitle = 'Add Lorem Ipsum market';
|
||||||
|
|
||||||
|
before('Create market proposal', function () {
|
||||||
|
cy.visit('/');
|
||||||
|
cy.createMarket();
|
||||||
|
});
|
||||||
|
|
||||||
|
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.getByTestId('dialog-title').should('have.text', proposalTitle);
|
||||||
|
cy.get('.language-json').should('exist');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('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');
|
||||||
|
cy.get('[row-index="0"]').within(() => {
|
||||||
|
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -23,7 +23,7 @@ export const Footer = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="grid grid-rows-2 lg:grid-cols-[1fr_auto] text-xs md:text-md lg:flex md:col-span-2 px-4 py-2 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200">
|
<footer className="grid grid-cols-[1fr_auto] items-center text-xs md:text-md lg:flex md:col-span-2 px-4 pt-2 pb-3 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200">
|
||||||
<div className="flex justify-between gap-2 align-middle">
|
<div className="flex justify-between gap-2 align-middle">
|
||||||
{GIT_COMMIT_HASH && (
|
{GIT_COMMIT_HASH && (
|
||||||
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
||||||
@@ -43,9 +43,12 @@ export const Footer = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="content-center flex pl-2 md:border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
<div className="content-center flex pr-4 md:border-r border-neutral-700 dark:border-neutral-300">
|
||||||
{VEGA_URL && <NodeUrl url={VEGA_URL} />}
|
<span className="pr-2">{VEGA_URL && <NodeUrl url={VEGA_URL} />}</span>
|
||||||
<Link className="ml-2" onClick={() => setNodeSwitcherOpen(true)}>
|
<Link
|
||||||
|
className="ml-2 underline-offset-4"
|
||||||
|
onClick={() => setNodeSwitcherOpen(true)}
|
||||||
|
>
|
||||||
{t('Change')}
|
{t('Change')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,7 +62,10 @@ export const Footer = () => {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="pl-2 align-center lg:align-right lg:flex lg:justify-end gap-2 align-middle lg:max-w-xs lg:ml-auto">
|
<div className="pl-2 align-center lg:align-right lg:flex lg:justify-end gap-2 align-middle lg:max-w-xs lg:ml-auto">
|
||||||
<RouteLink to={`/${Routes.DISCLAIMER}`} className="underline">
|
<RouteLink
|
||||||
|
to={`/${Routes.DISCLAIMER}`}
|
||||||
|
className="underline underline-offset-4"
|
||||||
|
>
|
||||||
Disclaimer
|
Disclaimer
|
||||||
</RouteLink>
|
</RouteLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
import { PriceMonitoringBoundsInfoPanel } from '@vegaprotocol/markets';
|
import {
|
||||||
|
PriceMonitoringBoundsInfoPanel,
|
||||||
|
SuccessionLineInfoPanel,
|
||||||
|
} from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
LiquidityInfoPanel,
|
LiquidityInfoPanel,
|
||||||
LiquidityMonitoringParametersInfoPanel,
|
LiquidityMonitoringParametersInfoPanel,
|
||||||
@@ -103,6 +106,8 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
<OracleInfoPanel market={market} type="settlementData" />
|
<OracleInfoPanel market={market} type="settlementData" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<h2 className={`${headerClassName} mb-4`}>{t('Succession line')}</h2>
|
||||||
|
<SuccessionLineInfoPanel market={market} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import Hash from '../../links/hash';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ProposalSignatureBundleNewAsset } from './proposal/signature-bundle-new';
|
import { ProposalSignatureBundleNewAsset } from './proposal/signature-bundle-new';
|
||||||
import { ProposalSignatureBundleUpdateAsset } from './proposal/signature-bundle-update';
|
import { ProposalSignatureBundleUpdateAsset } from './proposal/signature-bundle-update';
|
||||||
|
import { MarketLink } from '../../links';
|
||||||
|
import { formatNumber } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
export type Proposal = components['schemas']['v1ProposalSubmission'];
|
export type Proposal = components['schemas']['v1ProposalSubmission'];
|
||||||
export type ProposalTerms = components['schemas']['vegaProposalTerms'];
|
export type ProposalTerms = components['schemas']['vegaProposalTerms'];
|
||||||
@@ -53,7 +55,11 @@ export function proposalTypeLabel(terms?: ProposalTerms): string {
|
|||||||
} else if (has(terms, 'updateAsset')) {
|
} else if (has(terms, 'updateAsset')) {
|
||||||
return t('Update asset proposal');
|
return t('Update asset proposal');
|
||||||
} else if (has(terms, 'newMarket')) {
|
} else if (has(terms, 'newMarket')) {
|
||||||
return t('New market proposal');
|
if (terms?.newMarket?.changes?.successor) {
|
||||||
|
return t('Successor market proposal');
|
||||||
|
} else {
|
||||||
|
return t('New market proposal');
|
||||||
|
}
|
||||||
} else if (has(terms, 'updateMarket')) {
|
} else if (has(terms, 'updateMarket')) {
|
||||||
return t('Update market proposal');
|
return t('Update market proposal');
|
||||||
} else if (has(terms, 'updateNetworkParameter')) {
|
} else if (has(terms, 'updateNetworkParameter')) {
|
||||||
@@ -85,6 +91,13 @@ export const TxProposal = ({ txData, pubKey, blockData }: TxProposalProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tx = proposal.terms?.newAsset || proposal.terms?.updateAsset;
|
const tx = proposal.terms?.newAsset || proposal.terms?.updateAsset;
|
||||||
|
const isSuccessorMarketProposal =
|
||||||
|
proposal?.terms?.newMarket?.changes?.successor;
|
||||||
|
const parentMarketId =
|
||||||
|
isSuccessorMarketProposal &&
|
||||||
|
proposal?.terms.newMarket?.changes?.successor?.parentMarketId;
|
||||||
|
const insurancePoolFraction =
|
||||||
|
proposal?.terms?.newMarket?.changes?.successor?.insurancePoolFraction;
|
||||||
|
|
||||||
// This component is not rendered if no bundle is required
|
// This component is not rendered if no bundle is required
|
||||||
const SignatureBundleComponent = proposal.terms?.newAsset
|
const SignatureBundleComponent = proposal.terms?.newAsset
|
||||||
@@ -111,6 +124,30 @@ export const TxProposal = ({ txData, pubKey, blockData }: TxProposalProps) => {
|
|||||||
<Hash text={deterministicId} />
|
<Hash text={deterministicId} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
{isSuccessorMarketProposal ? (
|
||||||
|
<>
|
||||||
|
{parentMarketId ? (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Previous market')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<MarketLink
|
||||||
|
id={
|
||||||
|
proposal.terms?.newMarket.changes.successor.parentMarketId
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
|
{insurancePoolFraction ? (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Insurance pool fraction')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{formatNumber(Number(insurancePoolFraction) * 100, 0)}%
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</TableWithTbody>
|
</TableWithTbody>
|
||||||
<ProposalSummary
|
<ProposalSummary
|
||||||
id={deterministicId}
|
id={deterministicId}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
DropdownMenuSubContent,
|
DropdownMenuSubContent,
|
||||||
Icon,
|
Icon,
|
||||||
Button,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import type { Dispatch, SetStateAction } from 'react';
|
import type { Dispatch, SetStateAction } from 'react';
|
||||||
import { FilterLabel } from './tx-filter-label';
|
import { FilterLabel } from './tx-filter-label';
|
||||||
@@ -100,15 +99,13 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
|
|||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
modal={false}
|
modal={false}
|
||||||
trigger={
|
trigger={
|
||||||
<DropdownMenuTrigger className="ml-0">
|
<DropdownMenuTrigger>
|
||||||
<Button size="xs" data-testid="filter-trigger">
|
<FilterLabel filters={filters} />
|
||||||
<FilterLabel filters={filters} />
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
{filters.size > 0 ? null : (
|
{filters.size > 1 ? null : (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuCheckboxItem
|
<DropdownMenuCheckboxItem
|
||||||
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
|
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export const TxsListNavigation = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="xs"
|
||||||
disabled={!hasMoreTxs || loading}
|
disabled={!hasMoreTxs}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
nextPage();
|
nextPage();
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -78,7 +78,11 @@ export function getLabelForProposal(
|
|||||||
} else if (proposal.terms?.updateAsset) {
|
} else if (proposal.terms?.updateAsset) {
|
||||||
return t('Proposal: Update asset');
|
return t('Proposal: Update asset');
|
||||||
} else if (proposal.terms?.newMarket) {
|
} else if (proposal.terms?.newMarket) {
|
||||||
return t('Proposal: New market');
|
if (proposal.terms?.newMarket.changes?.successor) {
|
||||||
|
return t('Proposal: Successor market');
|
||||||
|
} else {
|
||||||
|
return t('Proposal: New market');
|
||||||
|
}
|
||||||
} else if (proposal.terms?.updateMarket) {
|
} else if (proposal.terms?.updateMarket) {
|
||||||
return t('Proposal: Update market');
|
return t('Proposal: Update market');
|
||||||
} else if (proposal.terms?.updateNetworkParameter) {
|
} else if (proposal.terms?.updateNetworkParameter) {
|
||||||
|
|||||||
@@ -86,14 +86,18 @@ describe('Txs infinite list item', () => {
|
|||||||
render(
|
render(
|
||||||
<MockedProvider>
|
<MockedProvider>
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<TxsInfiniteListItem
|
<table>
|
||||||
type="testType"
|
<tbody>
|
||||||
submitter="testPubKey"
|
<TxsInfiniteListItem
|
||||||
hash="testTxHash"
|
type="testType"
|
||||||
block="1"
|
submitter="testPubKey"
|
||||||
code={0}
|
hash="testTxHash"
|
||||||
command={{}}
|
block="1"
|
||||||
/>
|
code={0}
|
||||||
|
command={{}}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ const DEFAULT_TRUNCATE_LENGTH = 7;
|
|||||||
|
|
||||||
export function getIdTruncateLength(screen: Screen): number {
|
export function getIdTruncateLength(screen: Screen): number {
|
||||||
if (['xxxl', 'xxl'].includes(screen)) {
|
if (['xxxl', 'xxl'].includes(screen)) {
|
||||||
return 64;
|
|
||||||
} else if (['xl', 'lg', 'md'].includes(screen)) {
|
|
||||||
return 32;
|
return 32;
|
||||||
|
} else if (['xl', 'lg', 'md'].includes(screen)) {
|
||||||
|
return 16;
|
||||||
}
|
}
|
||||||
return DEFAULT_TRUNCATE_LENGTH;
|
return DEFAULT_TRUNCATE_LENGTH;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,17 @@ import type { BlockExplorerTransactionResult } from '../../routes/types/block-ex
|
|||||||
import { Side } from '@vegaprotocol/types';
|
import { Side } from '@vegaprotocol/types';
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
|
||||||
|
const generateHash = (): string =>
|
||||||
|
Array.from(
|
||||||
|
{ length: 64 },
|
||||||
|
() => '0123456789ABCDEF'[Math.floor(Math.random() * 16)]
|
||||||
|
).join('');
|
||||||
|
|
||||||
const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
|
const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
|
||||||
return Array.from(Array(number)).map((_) => ({
|
return Array.from(Array(number)).map((_) => ({
|
||||||
block: '87901',
|
block: '87901',
|
||||||
index: 2,
|
index: 2,
|
||||||
hash: '0F8B98DA0923A50786B852D9CA11E051CACC4C733E1DB93D535C7D81DBD10F6F',
|
hash: generateHash(),
|
||||||
submitter:
|
submitter:
|
||||||
'4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964',
|
'4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964',
|
||||||
type: 'Submit Order',
|
type: 'Submit Order',
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Table, TableRow } from '../table';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||||
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
|
||||||
import { getTxsDataUrl } from '../../hooks/use-txs-data';
|
import { getTxsDataUrl } from '../../hooks/get-txs-data-url';
|
||||||
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
|
||||||
import EmptyList from '../empty-list/empty-list';
|
import EmptyList from '../empty-list/empty-list';
|
||||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||||
@@ -14,7 +14,7 @@ interface TxsPerBlockProps {
|
|||||||
|
|
||||||
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||||
const filters = `filters[block.height]=${blockHeight}`;
|
const filters = `filters[block.height]=${blockHeight}`;
|
||||||
const url = getTxsDataUrl({ limit: txCount.toString(), filters });
|
const url = getTxsDataUrl({ filters, count: txCount });
|
||||||
const {
|
const {
|
||||||
state: { data, loading, error },
|
state: { data, loading, error },
|
||||||
} = useFetch<BlockExplorerTransactions>(url);
|
} = useFetch<BlockExplorerTransactions>(url);
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { DATA_SOURCES } from '../config';
|
||||||
|
|
||||||
|
type IGetTxsDataFirstPage = {
|
||||||
|
baseUrl?: string;
|
||||||
|
count?: number;
|
||||||
|
party?: string;
|
||||||
|
filters?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IGetTxsDataPrevious extends IGetTxsDataFirstPage {
|
||||||
|
before: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGetTxsDataNext extends IGetTxsDataFirstPage {
|
||||||
|
after: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IGetTxsDataUrl =
|
||||||
|
| IGetTxsDataPrevious
|
||||||
|
| IGetTxsDataNext
|
||||||
|
| IGetTxsDataFirstPage;
|
||||||
|
|
||||||
|
export const BE_TXS_PER_REQUEST = 25;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properly encodes the filters and parameters for a request to the block explorer
|
||||||
|
* API for transactions. As the API uses a slightly less common format for encoding
|
||||||
|
* filters, some of it is more manual than you might expect.
|
||||||
|
*
|
||||||
|
* @param params An object containing the pagination and filters
|
||||||
|
* @returns string URL to call
|
||||||
|
*/
|
||||||
|
export const getTxsDataUrl = (params: IGetTxsDataUrl) => {
|
||||||
|
const baseUrl =
|
||||||
|
params.baseUrl || `${DATA_SOURCES.blockExplorerUrl}/transactions`;
|
||||||
|
const url = new URL(baseUrl);
|
||||||
|
const count = `${params.count || BE_TXS_PER_REQUEST}`;
|
||||||
|
|
||||||
|
if ('before' in params && params.before?.length > 0) {
|
||||||
|
url.searchParams.append('last', count);
|
||||||
|
url.searchParams.append('before', params.before);
|
||||||
|
} else if ('after' in params && params.after?.length > 0) {
|
||||||
|
url.searchParams.append('first', count);
|
||||||
|
url.searchParams.append('after', params.after);
|
||||||
|
} else {
|
||||||
|
url.searchParams.append('first', count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hacky fix for param as array
|
||||||
|
let urlAsString = url.toString();
|
||||||
|
if (params.filters && params.filters?.length > 0) {
|
||||||
|
urlAsString += '&' + params.filters.replaceAll(' ', '%20');
|
||||||
|
}
|
||||||
|
if (params.party && params.party?.length > 0) {
|
||||||
|
urlAsString += `&filters[tx.submitter]=${params.party}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlAsString;
|
||||||
|
};
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { getTxsDataUrl } from './get-txs-data-url'; // import the function to be tested
|
||||||
|
|
||||||
|
describe('getTxsDataUrl', () => {
|
||||||
|
it('should return the correct URL without filters and party', () => {
|
||||||
|
const params = {
|
||||||
|
count: 10,
|
||||||
|
baseUrl: 'https://example.com/transactions',
|
||||||
|
};
|
||||||
|
const expectedUrl = 'https://example.com/transactions?first=10';
|
||||||
|
|
||||||
|
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct URL with "before" in params', () => {
|
||||||
|
const params = {
|
||||||
|
count: 5,
|
||||||
|
before: '100.1',
|
||||||
|
baseUrl: 'https://example.com/transactions',
|
||||||
|
};
|
||||||
|
const expectedUrl = 'https://example.com/transactions?last=5&before=100.1';
|
||||||
|
|
||||||
|
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct URL with "after" in params', () => {
|
||||||
|
const params = {
|
||||||
|
count: 5,
|
||||||
|
after: '222.1',
|
||||||
|
baseUrl: 'https://example.com/transactions',
|
||||||
|
};
|
||||||
|
const expectedUrl = 'https://example.com/transactions?first=5&after=222.1';
|
||||||
|
|
||||||
|
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct URL with filters and party', () => {
|
||||||
|
const params = {
|
||||||
|
count: 10,
|
||||||
|
filters: 'filters[cmd.type]=Made Up Transaction',
|
||||||
|
party: '1234',
|
||||||
|
baseUrl: 'https://example.com/transactions',
|
||||||
|
};
|
||||||
|
const expectedUrl =
|
||||||
|
'https://example.com/transactions?first=10&filters[cmd.type]=Made%20Up%20Transaction&filters[tx.submitter]=1234';
|
||||||
|
|
||||||
|
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,130 +1,141 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
import type { URLSearchParamsInit } from 'react-router-dom';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||||
import type {
|
import type {
|
||||||
BlockExplorerTransactionResult,
|
BlockExplorerTransactionResult,
|
||||||
BlockExplorerTransactions,
|
BlockExplorerTransactions,
|
||||||
} from '../routes/types/block-explorer-response';
|
} from '../routes/types/block-explorer-response';
|
||||||
import { DATA_SOURCES } from '../config';
|
|
||||||
import isNumber from 'lodash/isNumber';
|
import isNumber from 'lodash/isNumber';
|
||||||
|
import { AllFilterOptions } from '../components/txs/tx-filter';
|
||||||
|
import type { FilterOption } from '../components/txs/tx-filter';
|
||||||
|
import { BE_TXS_PER_REQUEST, getTxsDataUrl } from './get-txs-data-url';
|
||||||
|
|
||||||
export interface TxsStateProps {
|
export function getTypeFilters(filters?: Set<FilterOption>) {
|
||||||
txsData: BlockExplorerTransactionResult[];
|
if (!filters) {
|
||||||
hasMoreTxs: boolean;
|
return '';
|
||||||
cursor: string;
|
} else if (filters.size > 1) {
|
||||||
previousCursors: string[];
|
return '';
|
||||||
hasPreviousPage: boolean;
|
}
|
||||||
|
|
||||||
|
const forcedSingleFilter = Array.from(filters)[0];
|
||||||
|
return `filters[cmd.type]=${forcedSingleFilter}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUseTxsData {
|
export interface IUseTxsData {
|
||||||
limit: number;
|
count?: number;
|
||||||
filters?: string;
|
before?: string;
|
||||||
|
after?: string;
|
||||||
|
party?: string;
|
||||||
|
filters?: Set<FilterOption>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IGetTxsDataUrl {
|
export const useTxsData = ({
|
||||||
limit: string;
|
count = 25,
|
||||||
filters?: string;
|
before,
|
||||||
}
|
after,
|
||||||
|
filters,
|
||||||
|
party,
|
||||||
|
}: IUseTxsData) => {
|
||||||
|
const [, setSearchParams] = useSearchParams();
|
||||||
|
let hasMoreTxs = true;
|
||||||
|
let txsData: BlockExplorerTransactionResult[] = [];
|
||||||
|
|
||||||
export const getTxsDataUrl = ({ limit, filters }: IGetTxsDataUrl) => {
|
const url = getTxsDataUrl({
|
||||||
const url = new URL(`${DATA_SOURCES.blockExplorerUrl}/transactions`);
|
filters: getTypeFilters(filters),
|
||||||
|
count,
|
||||||
if (limit) {
|
before,
|
||||||
url.searchParams.append('limit', limit);
|
after,
|
||||||
}
|
party,
|
||||||
|
|
||||||
// Hacky fix for param as array
|
|
||||||
let urlAsString = url.toString();
|
|
||||||
if (filters) {
|
|
||||||
urlAsString += '&' + filters.replace(' ', '%20');
|
|
||||||
}
|
|
||||||
|
|
||||||
return urlAsString;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useTxsData = ({ limit, filters }: IUseTxsData) => {
|
|
||||||
const [
|
|
||||||
{ txsData, hasMoreTxs, cursor, previousCursors, hasPreviousPage },
|
|
||||||
setTxsState,
|
|
||||||
] = useState<TxsStateProps>({
|
|
||||||
txsData: [],
|
|
||||||
hasMoreTxs: false,
|
|
||||||
previousCursors: [],
|
|
||||||
cursor: '',
|
|
||||||
hasPreviousPage: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const url = getTxsDataUrl({ limit: limit.toString(), filters });
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
state: { data, error, loading },
|
state: { data, error, loading },
|
||||||
refetch,
|
refetch,
|
||||||
} = useFetch<BlockExplorerTransactions>(url, {}, true);
|
} = useFetch<BlockExplorerTransactions>(url, {}, true);
|
||||||
|
|
||||||
useEffect(() => {
|
if (!loading && data && isNumber(data.transactions.length)) {
|
||||||
if (!loading && data && isNumber(data.transactions.length)) {
|
hasMoreTxs = data.transactions.length >= count;
|
||||||
setTxsState((prev) => {
|
txsData = data.transactions;
|
||||||
return {
|
}
|
||||||
...prev,
|
|
||||||
txsData: data.transactions,
|
|
||||||
hasMoreTxs: data.transactions.length >= limit,
|
|
||||||
cursor: data?.transactions.at(-1)?.cursor || '',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [loading, setTxsState, data, limit]);
|
|
||||||
|
|
||||||
const nextPage = useCallback(() => {
|
const nextPage = useCallback(() => {
|
||||||
const c = data?.transactions.at(0)?.cursor;
|
const after = data?.transactions.at(-1)?.cursor || '';
|
||||||
const newPreviousCursors = c ? [...previousCursors, c] : previousCursors;
|
const params: URLSearchParamsInit = { after };
|
||||||
|
if (filters) {
|
||||||
setTxsState((prev) => ({
|
params.filters = Array.from(filters).join(',');
|
||||||
...prev,
|
}
|
||||||
hasPreviousPage: true,
|
setSearchParams(params);
|
||||||
previousCursors: newPreviousCursors,
|
}, [filters, data, setSearchParams]);
|
||||||
}));
|
|
||||||
|
|
||||||
return refetch({
|
|
||||||
limit,
|
|
||||||
before: cursor,
|
|
||||||
});
|
|
||||||
}, [data, previousCursors, cursor, limit, refetch]);
|
|
||||||
|
|
||||||
const previousPage = useCallback(() => {
|
const previousPage = useCallback(() => {
|
||||||
const previousCursor = [...previousCursors].pop();
|
const before = data?.transactions[0]?.cursor || '';
|
||||||
const newPreviousCursors = previousCursors.slice(0, -1);
|
const params: URLSearchParamsInit = { before };
|
||||||
setTxsState((prev) => ({
|
if (filters && filters.size > 0 && filters.size === 1) {
|
||||||
...prev,
|
params.filters = Array.from(filters)[0];
|
||||||
hasPreviousPage: newPreviousCursors.length > 0,
|
}
|
||||||
previousCursors: newPreviousCursors,
|
setSearchParams(params);
|
||||||
}));
|
}, [filters, data, setSearchParams]);
|
||||||
return refetch({
|
|
||||||
limit,
|
|
||||||
before: previousCursor,
|
|
||||||
});
|
|
||||||
}, [previousCursors, limit, refetch]);
|
|
||||||
|
|
||||||
const refreshTxs = useCallback(async () => {
|
const refreshTxs = useCallback(async () => {
|
||||||
setTxsState(() => ({
|
const params: URLSearchParamsInit = {};
|
||||||
txsData: [],
|
if (filters && filters.size > 0 && filters.size === 1) {
|
||||||
cursor: '',
|
params.filters = Array.from(filters)[0];
|
||||||
previousCursors: [],
|
}
|
||||||
hasMoreTxs: false,
|
setSearchParams(params);
|
||||||
hasPreviousPage: false,
|
|
||||||
}));
|
|
||||||
|
|
||||||
refetch({ limit });
|
refetch({ count: BE_TXS_PER_REQUEST });
|
||||||
}, [setTxsState, limit, refetch, filters]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [setSearchParams, refetch, filters]);
|
||||||
|
|
||||||
|
const updateFilters = useCallback(
|
||||||
|
(newFilters: Set<FilterOption>) => {
|
||||||
|
const params: URLSearchParamsInit = {};
|
||||||
|
if (newFilters && newFilters.size === 1) {
|
||||||
|
params.filters = Array.from(newFilters)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
setSearchParams(params);
|
||||||
|
},
|
||||||
|
[setSearchParams]
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
updateFilters,
|
||||||
txsData,
|
txsData,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
hasMoreTxs,
|
hasMoreTxs,
|
||||||
hasPreviousPage,
|
|
||||||
previousCursors,
|
|
||||||
cursor,
|
|
||||||
refreshTxs,
|
refreshTxs,
|
||||||
nextPage,
|
nextPage,
|
||||||
previousPage,
|
previousPage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Set of filters based on the URLSearchParams, or
|
||||||
|
* defaults to all.
|
||||||
|
* @param params
|
||||||
|
* @returns Set
|
||||||
|
*/
|
||||||
|
export function getInitialFilters(params: URLSearchParams): Set<FilterOption> {
|
||||||
|
const defaultFilters = new Set(AllFilterOptions);
|
||||||
|
|
||||||
|
const p = params.get('filters');
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
return defaultFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filters = new Set<FilterOption>();
|
||||||
|
p.split(',').forEach((f) => {
|
||||||
|
if (AllFilterOptions.includes(f as FilterOption)) {
|
||||||
|
filters.add(f as FilterOption);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filters.size === 0) {
|
||||||
|
return defaultFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ describe('Block', () => {
|
|||||||
(useFetch as jest.Mock).mockReturnValue({
|
(useFetch as jest.Mock).mockReturnValue({
|
||||||
state: { data: createBlockResponse(1), loading: false, error: null },
|
state: { data: createBlockResponse(1), loading: false, error: null },
|
||||||
});
|
});
|
||||||
|
|
||||||
render(renderComponent(1));
|
render(renderComponent(1));
|
||||||
await waitFor(() => screen.getByTestId('block-header'));
|
await waitFor(() => screen.getByTestId('block-header'));
|
||||||
expect(screen.getByTestId('previous-block-button')).toHaveAttribute(
|
expect(screen.getByTestId('previous-block-button')).toHaveAttribute(
|
||||||
|
|||||||
@@ -15,9 +15,13 @@ import { PartyBlockAccounts } from './components/party-block-accounts';
|
|||||||
import { isValidPartyId } from './components/party-id-error';
|
import { isValidPartyId } from './components/party-id-error';
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
|
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
|
||||||
|
import type { FilterOption } from '../../../components/txs/tx-filter';
|
||||||
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
||||||
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
const Party = () => {
|
const Party = () => {
|
||||||
|
const [params] = useSearchParams();
|
||||||
|
|
||||||
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
||||||
const { party } = useParams<{ party: string }>();
|
const { party } = useParams<{ party: string }>();
|
||||||
|
|
||||||
@@ -27,24 +31,21 @@ const Party = () => {
|
|||||||
const partyId = toNonHex(party ? party : '');
|
const partyId = toNonHex(party ? party : '');
|
||||||
const { isMobile } = useScreenDimensions();
|
const { isMobile } = useScreenDimensions();
|
||||||
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
|
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
|
||||||
const baseFilters = `filters[tx.submitter]=${partyId}`;
|
|
||||||
const f =
|
|
||||||
filters && filters.size === 1
|
|
||||||
? `${baseFilters}&filters[cmd.type]=${Array.from(filters)[0]}`
|
|
||||||
: baseFilters;
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
hasMoreTxs,
|
|
||||||
nextPage,
|
nextPage,
|
||||||
|
refreshTxs,
|
||||||
previousPage,
|
previousPage,
|
||||||
error,
|
error,
|
||||||
refreshTxs,
|
|
||||||
loading,
|
loading,
|
||||||
txsData,
|
txsData,
|
||||||
hasPreviousPage,
|
hasMoreTxs,
|
||||||
|
updateFilters,
|
||||||
} = useTxsData({
|
} = useTxsData({
|
||||||
limit: 25,
|
filters: filters.size === 1 ? filters : undefined,
|
||||||
filters: f,
|
before: params.get('before') || undefined,
|
||||||
|
after: !params.get('before') ? params.get('after') || undefined : undefined,
|
||||||
|
party: partyId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||||
@@ -102,15 +103,21 @@ const Party = () => {
|
|||||||
refreshTxs={refreshTxs}
|
refreshTxs={refreshTxs}
|
||||||
nextPage={nextPage}
|
nextPage={nextPage}
|
||||||
previousPage={previousPage}
|
previousPage={previousPage}
|
||||||
hasPreviousPage={hasPreviousPage}
|
hasPreviousPage={true}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
hasMoreTxs={hasMoreTxs}
|
hasMoreTxs={hasMoreTxs}
|
||||||
>
|
>
|
||||||
<TxsFilter filters={filters} setFilters={setFilters} />
|
<TxsFilter
|
||||||
|
filters={filters}
|
||||||
|
setFilters={(f) => {
|
||||||
|
setFilters(f);
|
||||||
|
updateFilters(f as Set<FilterOption>);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</TxsListNavigation>
|
</TxsListNavigation>
|
||||||
{!error && txsData ? (
|
{!error && txsData ? (
|
||||||
<TxsInfiniteList
|
<TxsInfiniteList
|
||||||
hasMoreTxs={hasMoreTxs}
|
hasMoreTxs={true}
|
||||||
areTxsLoading={loading}
|
areTxsLoading={loading}
|
||||||
txs={txsData}
|
txs={txsData}
|
||||||
loadMoreTxs={nextPage}
|
loadMoreTxs={nextPage}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { RouteTitle } from '../../../components/route-title';
|
import { RouteTitle } from '../../../components/route-title';
|
||||||
import { TxsInfiniteList } from '../../../components/txs';
|
import { TxsInfiniteList } from '../../../components/txs';
|
||||||
import { useTxsData } from '../../../hooks/use-txs-data';
|
import { useTxsData, getInitialFilters } from '../../../hooks/use-txs-data';
|
||||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
import { TxsFilter } from '../../../components/txs/tx-filter';
|
||||||
|
import type { FilterOption } from '../../../components/txs/tx-filter';
|
||||||
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
|
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
|
||||||
|
import { useSearchParams } from 'react-router-dom';
|
||||||
const BE_TXS_PER_REQUEST = 25;
|
|
||||||
|
|
||||||
export const TxsList = () => {
|
export const TxsList = () => {
|
||||||
useDocumentTitle(['Transactions']);
|
useDocumentTitle(['Transactions']);
|
||||||
@@ -27,25 +27,22 @@ export const TxsList = () => {
|
|||||||
* @returns {JSX.Element} Transaction List and controls
|
* @returns {JSX.Element} Transaction List and controls
|
||||||
*/
|
*/
|
||||||
export const TxsListFiltered = () => {
|
export const TxsListFiltered = () => {
|
||||||
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
const [params] = useSearchParams();
|
||||||
|
const [filters, setFilters] = useState(getInitialFilters(params));
|
||||||
const f =
|
|
||||||
filters && filters.size === 1
|
|
||||||
? `filters[cmd.type]=${Array.from(filters)[0]}`
|
|
||||||
: '';
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
hasMoreTxs,
|
|
||||||
nextPage,
|
nextPage,
|
||||||
previousPage,
|
previousPage,
|
||||||
error,
|
error,
|
||||||
refreshTxs,
|
refreshTxs,
|
||||||
loading,
|
loading,
|
||||||
txsData,
|
txsData,
|
||||||
hasPreviousPage,
|
hasMoreTxs,
|
||||||
|
updateFilters,
|
||||||
} = useTxsData({
|
} = useTxsData({
|
||||||
limit: BE_TXS_PER_REQUEST,
|
filters: filters.size === 1 ? filters : undefined,
|
||||||
filters: f,
|
before: params.get('before') || undefined,
|
||||||
|
after: !params.get('before') ? params.get('after') || undefined : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -54,11 +51,17 @@ export const TxsListFiltered = () => {
|
|||||||
refreshTxs={refreshTxs}
|
refreshTxs={refreshTxs}
|
||||||
nextPage={nextPage}
|
nextPage={nextPage}
|
||||||
previousPage={previousPage}
|
previousPage={previousPage}
|
||||||
hasPreviousPage={hasPreviousPage}
|
hasPreviousPage={true}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
hasMoreTxs={hasMoreTxs}
|
hasMoreTxs={hasMoreTxs}
|
||||||
>
|
>
|
||||||
<TxsFilter filters={filters} setFilters={setFilters} />
|
<TxsFilter
|
||||||
|
filters={filters}
|
||||||
|
setFilters={(f) => {
|
||||||
|
setFilters(f);
|
||||||
|
updateFilters(f as Set<FilterOption>);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</TxsListNavigation>
|
</TxsListNavigation>
|
||||||
<TxsInfiniteList
|
<TxsInfiniteList
|
||||||
hasFilters={filters.size > 0}
|
hasFilters={filters.size > 0}
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
{
|
||||||
|
"changes": {
|
||||||
|
"decimalPlaces": "5",
|
||||||
|
"positionDecimalPlaces": "5",
|
||||||
|
"linearSlippageFactor": "0.001",
|
||||||
|
"quadraticSlippageFactor": "0",
|
||||||
|
"lpPriceRange": "10",
|
||||||
|
"instrument": {
|
||||||
|
"name": "Token test market",
|
||||||
|
"code": "Token.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.001,
|
||||||
|
"params": {
|
||||||
|
"mu": 0,
|
||||||
|
"r": 0.016,
|
||||||
|
"sigma": 0.8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"successor": {
|
||||||
|
"parentMarketId": "",
|
||||||
|
"insurancePoolFraction": "0.75"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -220,7 +220,7 @@ context(
|
|||||||
function () {
|
function () {
|
||||||
const proposalTitle = 'Test new market proposal';
|
const proposalTitle = 'Test new market proposal';
|
||||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||||
cy.getByTestId(newProposalTitle).type('Test new market proposal');
|
cy.getByTestId(newProposalTitle).type(proposalTitle);
|
||||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||||
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
||||||
const newMarketPayload = JSON.stringify(newMarketProposal);
|
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||||
@@ -606,6 +606,94 @@ context(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('able to submit successor market proposal', function () {
|
||||||
|
const proposalTitle = 'Test successor market proposal';
|
||||||
|
|
||||||
|
cy.createMarket();
|
||||||
|
cy.reload();
|
||||||
|
waitForSpinner();
|
||||||
|
cy.getByTestId('closed-proposals').within(() => {
|
||||||
|
cy.contains('Add Lorem Ipsum market')
|
||||||
|
.parentsUntil(proposalListItem)
|
||||||
|
.last()
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId(viewProposalBtn).click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
getProposalInformationFromTable('ID').invoke('text').as('parentMarketId');
|
||||||
|
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||||
|
cy.getByTestId(newProposalTitle).type(proposalTitle);
|
||||||
|
cy.getByTestId(newProposalDescription).type(
|
||||||
|
'E2E test for successor market'
|
||||||
|
);
|
||||||
|
cy.fixture('/proposals/successor-market').then((newMarketProposal) => {
|
||||||
|
newMarketProposal.changes.successor.parentMarketId =
|
||||||
|
this.parentMarketId;
|
||||||
|
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||||
|
cy.getByTestId(newProposalTerms).type(newMarketPayload, {
|
||||||
|
parseSpecialCharSequences: false,
|
||||||
|
delay: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
cy.getByTestId(proposalDownloadBtn)
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
.then(() => {
|
||||||
|
cy.wrap(
|
||||||
|
getDownloadedProposalJsonPath('vega-new-market-proposal-')
|
||||||
|
).then((filePath) => {
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
submitUniqueRawProposal({ proposalBody: filePath });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
getProposalFromTitle(proposalTitle).within(() => {
|
||||||
|
// 3003-PMAN-008
|
||||||
|
cy.getByTestId('proposal-successor-info')
|
||||||
|
.should('have.text', 'Successor market to: TEST.24h')
|
||||||
|
.find('a')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', this.parentMarketId);
|
||||||
|
cy.getByTestId('view-proposal-btn').click();
|
||||||
|
});
|
||||||
|
// #3003-PMAN-010
|
||||||
|
cy.getByTestId(proposalJsonToggle).click();
|
||||||
|
cy.get('.language-json').within(() => {
|
||||||
|
cy.get('.hljs-attr').should('contain.text', 'parentMarketId');
|
||||||
|
cy.get('.hljs-string').should('contain.text', this.parentMarketId);
|
||||||
|
cy.get('.hljs-attr').should('contain.text', 'insurancePoolFraction');
|
||||||
|
cy.get('.hljs-string').should('contain.text', '0.75');
|
||||||
|
});
|
||||||
|
cy.getByTestId('proposal-market-data').within(() => {
|
||||||
|
cy.getByTestId('proposal-market-data-toggle').click();
|
||||||
|
cy.contains('Key details').click();
|
||||||
|
// 3003-PMAN-009
|
||||||
|
getMarketProposalDetailsFromTable('Parent Market ID').should(
|
||||||
|
'have.text',
|
||||||
|
this.parentMarketId
|
||||||
|
);
|
||||||
|
getMarketProposalDetailsFromTable('Insurance Pool Fraction').should(
|
||||||
|
'have.text',
|
||||||
|
'0.75'
|
||||||
|
);
|
||||||
|
getMarketProposalDetailsFromTable('Trading Mode').should(
|
||||||
|
'have.text',
|
||||||
|
'No trading'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
// 3003-PMAN-011
|
||||||
|
cy.contains('Parent Market ID').realHover();
|
||||||
|
cy.getByTestId('tooltip-content').should(
|
||||||
|
'contain.text',
|
||||||
|
'The ID of the market this market succeeds.'
|
||||||
|
);
|
||||||
|
cy.contains('Insurance Pool Fraction').realHover();
|
||||||
|
cy.getByTestId('tooltip-content').should(
|
||||||
|
'contain.text',
|
||||||
|
'The fraction of the insurance pool balance that is carried over from the parent market to the successor.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
after('Disassociate from second wallet key if present', function () {
|
after('Disassociate from second wallet key if present', function () {
|
||||||
cy.reload();
|
cy.reload();
|
||||||
waitForSpinner();
|
waitForSpinner();
|
||||||
@@ -642,6 +730,7 @@ context(
|
|||||||
.getByTestId('key-value-table-row')
|
.getByTestId('key-value-table-row')
|
||||||
.contains(heading)
|
.contains(heading)
|
||||||
.parent()
|
.parent()
|
||||||
|
.parent()
|
||||||
.siblings();
|
.siblings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,12 +96,14 @@ context('rewards - flow', { tags: '@slow' }, function () {
|
|||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get('h2').first().should('contain.text', 'EPOCH');
|
cy.get('h2').first().should('contain.text', 'EPOCH');
|
||||||
cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega');
|
cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega');
|
||||||
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD', rewardsTimeOut)
|
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD', rewardsTimeOut).should(
|
||||||
.should('contain.text', '0.4415')
|
'contain.text',
|
||||||
.and('contain.text', '(44.15%)');
|
'0.4415'
|
||||||
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE')
|
);
|
||||||
.should('contain.text', '0.0004')
|
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE').should(
|
||||||
.and('contain.text', '(44.15%)');
|
'contain.text',
|
||||||
|
'0.0004'
|
||||||
|
);
|
||||||
cy.getByTestId('total').should('have.text', '0.4419');
|
cy.getByTestId('total').should('have.text', '0.4419');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ context(
|
|||||||
cy.getByTestId(vegaWalletCurrencyTitle)
|
cy.getByTestId(vegaWalletCurrencyTitle)
|
||||||
.contains(name)
|
.contains(name)
|
||||||
.parent()
|
.parent()
|
||||||
.siblings()
|
.siblings(txTimeout)
|
||||||
.should((elementAmount) => {
|
.should((elementAmount) => {
|
||||||
const displayedAmount = parseFloat(elementAmount.text());
|
const displayedAmount = parseFloat(elementAmount.text());
|
||||||
expect(displayedAmount).be.gte(expectedAmount);
|
expect(displayedAmount).be.gte(expectedAmount);
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export function dissociateFromSecondWalletKey() {
|
|||||||
cy.getByTestId('vega-in-wallet')
|
cy.getByTestId('vega-in-wallet')
|
||||||
.first()
|
.first()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId('eth-wallet-associated-balances')
|
cy.getByTestId('eth-wallet-associated-balances', txTimeout)
|
||||||
.last()
|
.last()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId('associated-key')
|
cy.getByTestId('associated-key')
|
||||||
|
|||||||
@@ -78,13 +78,21 @@ export function stakingPageAssociateTokens(
|
|||||||
}
|
}
|
||||||
cy.get(tokenAmountInputBox, epochTimeout).type(amount);
|
cy.get(tokenAmountInputBox, epochTimeout).type(amount);
|
||||||
if (approve) {
|
if (approve) {
|
||||||
cy.get(tokenInputApprove, txTimeout).should('be.enabled').click();
|
cy.getByTestId('wallet-associate').then((walletAssociateField) => {
|
||||||
cy.contains('Approve $VEGA Tokens for staking on Vega').should(
|
if (
|
||||||
'be.visible'
|
walletAssociateField.find('[data-testid="token-input-approve-button"]')
|
||||||
);
|
.length
|
||||||
cy.contains('Approve $VEGA Tokens for staking on Vega', txTimeout).should(
|
) {
|
||||||
'not.exist'
|
cy.get(tokenInputApprove, txTimeout).should('be.enabled').click();
|
||||||
);
|
cy.contains('Approve $VEGA Tokens for staking on Vega').should(
|
||||||
|
'be.visible'
|
||||||
|
);
|
||||||
|
cy.contains(
|
||||||
|
'Approve $VEGA Tokens for staking on Vega',
|
||||||
|
txTimeout
|
||||||
|
).should('not.exist');
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
cy.get(tokenSubmitButton, txTimeout).should('be.enabled').click();
|
cy.get(tokenSubmitButton, txTimeout).should('be.enabled').click();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { VegaConnectDialog, VegaManageDialog } from '@vegaprotocol/wallet';
|
import {
|
||||||
|
VegaConnectDialog,
|
||||||
|
VegaManageDialog,
|
||||||
|
ViewAsDialog,
|
||||||
|
} from '@vegaprotocol/wallet';
|
||||||
import {
|
import {
|
||||||
AppStateActionType,
|
AppStateActionType,
|
||||||
useAppState,
|
useAppState,
|
||||||
@@ -25,6 +29,8 @@ export const VegaWalletDialogs = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ViewAsDialog connector={Connectors.view} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { ExternalLinks } from '@vegaprotocol/environment';
|
|
||||||
|
|
||||||
export const DownloadWalletPrompt = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h3 className="mt-4 mb-2">{t('getWallet')}</h3>
|
|
||||||
<p>
|
|
||||||
<Link className="text-neutral-500" href={ExternalLinks.VEGA_WALLET_URL}>
|
|
||||||
{t('getWalletLink')}
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { ButtonLink, Link } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ExternalLinks } from '@vegaprotocol/environment';
|
||||||
|
import { useViewAsDialog } from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
|
export const VegaWalletPrompt = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const setViewAsDialog = useViewAsDialog((state) => state.setOpen);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h3 className="mt-4 mb-2">{t('getWallet')}</h3>
|
||||||
|
<div className="flex flex-row gap-4">
|
||||||
|
<Link className="text-neutral-500" href={ExternalLinks.VEGA_WALLET_URL}>
|
||||||
|
{t('getWalletLink')}
|
||||||
|
</Link>
|
||||||
|
<ButtonLink
|
||||||
|
className="text-neutral-500"
|
||||||
|
onClick={() => setViewAsDialog(true)}
|
||||||
|
>
|
||||||
|
{t('viewAsParty')}
|
||||||
|
</ButtonLink>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
WalletCardHeader,
|
WalletCardHeader,
|
||||||
WalletCardRow,
|
WalletCardRow,
|
||||||
} from '../wallet-card';
|
} from '../wallet-card';
|
||||||
import { DownloadWalletPrompt } from './download-wallet-prompt';
|
import { VegaWalletPrompt } from './vega-wallet-prompt';
|
||||||
import { usePollForDelegations } from './hooks';
|
import { usePollForDelegations } from './hooks';
|
||||||
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||||
import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
@@ -85,7 +85,7 @@ const VegaWalletNotConnected = () => {
|
|||||||
>
|
>
|
||||||
{t('connectVegaWalletToUseAssociated')}
|
{t('connectVegaWalletToUseAssociated')}
|
||||||
</Button>
|
</Button>
|
||||||
<DownloadWalletPrompt />
|
<VegaWalletPrompt />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -855,5 +855,6 @@
|
|||||||
"Estimated time to upgrade": "Estimated time to upgrade",
|
"Estimated time to upgrade": "Estimated time to upgrade",
|
||||||
"Upgraded at": "Upgraded at",
|
"Upgraded at": "Upgraded at",
|
||||||
"dataIsIdentical": "Data is identical",
|
"dataIsIdentical": "Data is identical",
|
||||||
"updatesToMarket": "Updates to market"
|
"updatesToMarket": "Updates to market",
|
||||||
|
"viewAsParty": "View as party"
|
||||||
}
|
}
|
||||||
|
|||||||
+84
-10
@@ -45,8 +45,10 @@ export const useMarketDataDialogStore = create<MarketDataDialogState>(
|
|||||||
|
|
||||||
export const ProposalMarketData = ({
|
export const ProposalMarketData = ({
|
||||||
marketData,
|
marketData,
|
||||||
|
parentMarketData,
|
||||||
}: {
|
}: {
|
||||||
marketData: MarketInfoWithData;
|
marketData: MarketInfoWithData;
|
||||||
|
parentMarketData?: MarketInfoWithData;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isOpen, open, close } = useMarketDataDialogStore();
|
const { isOpen, open, close } = useMarketDataDialogStore();
|
||||||
@@ -58,8 +60,21 @@ export const ProposalMarketData = ({
|
|||||||
|
|
||||||
const settlementData = marketData.tradableInstrument.instrument.product
|
const settlementData = marketData.tradableInstrument.instrument.product
|
||||||
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
||||||
|
const parentSettlementData =
|
||||||
|
parentMarketData?.tradableInstrument.instrument?.product
|
||||||
|
?.dataSourceSpecForSettlementData?.data;
|
||||||
const terminationData = marketData.tradableInstrument.instrument.product
|
const terminationData = marketData.tradableInstrument.instrument.product
|
||||||
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
||||||
|
const parentTerminationData =
|
||||||
|
parentMarketData?.tradableInstrument.instrument?.product
|
||||||
|
?.dataSourceSpecForTradingTermination?.data;
|
||||||
|
|
||||||
|
const isParentSettlementDataEqual =
|
||||||
|
parentSettlementData !== undefined &&
|
||||||
|
isEqual(settlementData, parentSettlementData);
|
||||||
|
const isParentTerminationDataEqual =
|
||||||
|
parentTerminationData !== undefined &&
|
||||||
|
isEqual(terminationData, parentTerminationData);
|
||||||
|
|
||||||
const getSigners = (data: DataSourceDefinition) => {
|
const getSigners = (data: DataSourceDefinition) => {
|
||||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||||
@@ -97,12 +112,22 @@ export const ProposalMarketData = ({
|
|||||||
<AccordionItem
|
<AccordionItem
|
||||||
itemId="key-details"
|
itemId="key-details"
|
||||||
title={t('Key details')}
|
title={t('Key details')}
|
||||||
content={<KeyDetailsInfoPanel market={marketData} />}
|
content={
|
||||||
|
<KeyDetailsInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
parentMarket={parentMarketData}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
itemId="instrument"
|
itemId="instrument"
|
||||||
title={t('Instrument')}
|
title={t('Instrument')}
|
||||||
content={<InstrumentInfoPanel market={marketData} />}
|
content={
|
||||||
|
<InstrumentInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
parentMarket={parentMarketData}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
{isEqual(
|
{isEqual(
|
||||||
getSigners(settlementData),
|
getSigners(settlementData),
|
||||||
@@ -115,6 +140,11 @@ export const ProposalMarketData = ({
|
|||||||
<OracleInfoPanel
|
<OracleInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
type="settlementData"
|
type="settlementData"
|
||||||
|
parentMarket={
|
||||||
|
isParentSettlementDataEqual
|
||||||
|
? undefined
|
||||||
|
: parentMarketData
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -127,6 +157,11 @@ export const ProposalMarketData = ({
|
|||||||
<OracleInfoPanel
|
<OracleInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
type="settlementData"
|
type="settlementData"
|
||||||
|
parentMarket={
|
||||||
|
isParentSettlementDataEqual
|
||||||
|
? undefined
|
||||||
|
: parentMarketData
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -135,11 +170,21 @@ export const ProposalMarketData = ({
|
|||||||
itemId="termination-oracle"
|
itemId="termination-oracle"
|
||||||
title={t('Termination Oracle')}
|
title={t('Termination Oracle')}
|
||||||
content={
|
content={
|
||||||
<OracleInfoPanel market={marketData} type="termination" />
|
<OracleInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
type="termination"
|
||||||
|
parentMarket={
|
||||||
|
isParentTerminationDataEqual
|
||||||
|
? undefined
|
||||||
|
: parentMarketData
|
||||||
|
}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{/*Note: successor markets will not differ in their settlement*/}
|
||||||
|
{/*assets, so no need to pass in parent market data for comparison.*/}
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
itemId="settlement-asset"
|
itemId="settlement-asset"
|
||||||
title={t('Settlement asset')}
|
title={t('Settlement asset')}
|
||||||
@@ -148,22 +193,42 @@ export const ProposalMarketData = ({
|
|||||||
<AccordionItem
|
<AccordionItem
|
||||||
itemId="metadata"
|
itemId="metadata"
|
||||||
title={t('Metadata')}
|
title={t('Metadata')}
|
||||||
content={<MetadataInfoPanel market={marketData} />}
|
content={
|
||||||
|
<MetadataInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
parentMarket={parentMarketData}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
itemId="risk-model"
|
itemId="risk-model"
|
||||||
title={t('Risk model')}
|
title={t('Risk model')}
|
||||||
content={<RiskModelInfoPanel market={marketData} />}
|
content={
|
||||||
|
<RiskModelInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
parentMarket={parentMarketData}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
itemId="risk-parameters"
|
itemId="risk-parameters"
|
||||||
title={t('Risk parameters')}
|
title={t('Risk parameters')}
|
||||||
content={<RiskParametersInfoPanel market={marketData} />}
|
content={
|
||||||
|
<RiskParametersInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
parentMarket={parentMarketData}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
itemId="risk-factors"
|
itemId="risk-factors"
|
||||||
title={t('Risk factors')}
|
title={t('Risk factors')}
|
||||||
content={<RiskFactorsInfoPanel market={marketData} />}
|
content={
|
||||||
|
<RiskFactorsInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
parentMarket={parentMarketData}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
{(
|
{(
|
||||||
marketData.priceMonitoringSettings?.parameters?.triggers || []
|
marketData.priceMonitoringSettings?.parameters?.triggers || []
|
||||||
@@ -174,6 +239,7 @@ export const ProposalMarketData = ({
|
|||||||
content={
|
content={
|
||||||
<PriceMonitoringBoundsInfoPanel
|
<PriceMonitoringBoundsInfoPanel
|
||||||
market={marketData}
|
market={marketData}
|
||||||
|
parentMarket={parentMarketData}
|
||||||
triggerIndex={triggerIndex}
|
triggerIndex={triggerIndex}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@@ -183,13 +249,21 @@ export const ProposalMarketData = ({
|
|||||||
itemId="liqudity-monitoring-parameters"
|
itemId="liqudity-monitoring-parameters"
|
||||||
title={t('Liquidity monitoring parameters')}
|
title={t('Liquidity monitoring parameters')}
|
||||||
content={
|
content={
|
||||||
<LiquidityMonitoringParametersInfoPanel market={marketData} />
|
<LiquidityMonitoringParametersInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
parentMarket={parentMarketData}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
itemId="liquidity-price-range"
|
itemId="liquidity-price-range"
|
||||||
title={t('Liquidity price range')}
|
title={t('Liquidity price range')}
|
||||||
content={<LiquidityPriceRangeInfoPanel market={marketData} />}
|
content={
|
||||||
|
<LiquidityPriceRangeInfoPanel
|
||||||
|
market={marketData}
|
||||||
|
parentMarket={parentMarketData}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</div>
|
</div>
|
||||||
@@ -200,7 +274,7 @@ export const ProposalMarketData = ({
|
|||||||
title={marketData.tradableInstrument.instrument.code}
|
title={marketData.tradableInstrument.instrument.code}
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
onChange={(isOpen) => (isOpen ? open() : close())}
|
onChange={(isOpen) => (isOpen ? open() : close())}
|
||||||
size="medium"
|
size="large"
|
||||||
dataTestId="market-json-dialog"
|
dataTestId="market-json-dialog"
|
||||||
>
|
>
|
||||||
<CopyWithTooltip text={JSON.stringify(marketData)}>
|
<CopyWithTooltip text={JSON.stringify(marketData)}>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export interface ProposalProps {
|
|||||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||||
networkParams: Partial<NetworkParamsResult>;
|
networkParams: Partial<NetworkParamsResult>;
|
||||||
newMarketData?: MarketInfoWithData | null;
|
newMarketData?: MarketInfoWithData | null;
|
||||||
|
parentMarketData?: MarketInfoWithData | null;
|
||||||
assetData?: AssetQuery | null;
|
assetData?: AssetQuery | null;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
restData: any;
|
restData: any;
|
||||||
@@ -46,6 +47,7 @@ export const Proposal = ({
|
|||||||
networkParams,
|
networkParams,
|
||||||
restData,
|
restData,
|
||||||
newMarketData,
|
newMarketData,
|
||||||
|
parentMarketData,
|
||||||
assetData,
|
assetData,
|
||||||
originalMarketProposalRestData,
|
originalMarketProposalRestData,
|
||||||
mostRecentlyEnactedAssociatedMarketProposal,
|
mostRecentlyEnactedAssociatedMarketProposal,
|
||||||
@@ -157,7 +159,10 @@ export const Proposal = ({
|
|||||||
|
|
||||||
{newMarketData && (
|
{newMarketData && (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<ProposalMarketData marketData={newMarketData} />
|
<ProposalMarketData
|
||||||
|
marketData={newMarketData}
|
||||||
|
parentMarketData={parentMarketData ? parentMarketData : undefined}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ import {
|
|||||||
NetworkParams,
|
NetworkParams,
|
||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
} from '@vegaprotocol/network-parameters';
|
} from '@vegaprotocol/network-parameters';
|
||||||
|
import { useParentMarketIdQuery } from '@vegaprotocol/markets';
|
||||||
|
import { FLAGS } from '@vegaprotocol/environment';
|
||||||
|
import { useSuccessorMarketProposalDetails } from '@vegaprotocol/proposals';
|
||||||
|
|
||||||
export const ProposalContainer = () => {
|
export const ProposalContainer = () => {
|
||||||
const [
|
const [
|
||||||
@@ -54,6 +57,10 @@ export const ProposalContainer = () => {
|
|||||||
skip: !params.proposalId,
|
skip: !params.proposalId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const successor = useSuccessorMarketProposalDetails(params.proposalId);
|
||||||
|
|
||||||
|
const isSuccessor = !!successor?.parentMarketId || !!successor.code;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
state: {
|
state: {
|
||||||
data: originalMarketProposalRestData,
|
data: originalMarketProposalRestData,
|
||||||
@@ -96,6 +103,36 @@ export const ProposalContainer = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: parentMarketId,
|
||||||
|
loading: parentMarketIdLoading,
|
||||||
|
error: parentMarketIdError,
|
||||||
|
} = useParentMarketIdQuery({
|
||||||
|
variables: {
|
||||||
|
marketId: newMarketData?.data?.market?.id || '',
|
||||||
|
},
|
||||||
|
skip:
|
||||||
|
!FLAGS.SUCCESSOR_MARKETS ||
|
||||||
|
!isSuccessor ||
|
||||||
|
!newMarketData?.data?.market?.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: parentMarketData,
|
||||||
|
loading: parentMarketLoading,
|
||||||
|
error: parentMarketError,
|
||||||
|
} = useDataProvider({
|
||||||
|
dataProvider: marketInfoWithDataProvider,
|
||||||
|
skipUpdates: true,
|
||||||
|
variables: {
|
||||||
|
marketId: parentMarketId?.market?.parentMarketID || '',
|
||||||
|
skip:
|
||||||
|
!FLAGS.SUCCESSOR_MARKETS ||
|
||||||
|
!isSuccessor ||
|
||||||
|
!parentMarketId?.market?.parentMarketID,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: assetData,
|
data: assetData,
|
||||||
loading: assetLoading,
|
loading: assetLoading,
|
||||||
@@ -160,6 +197,8 @@ export const ProposalContainer = () => {
|
|||||||
newMarketLoading ||
|
newMarketLoading ||
|
||||||
assetLoading ||
|
assetLoading ||
|
||||||
networkParamsLoading ||
|
networkParamsLoading ||
|
||||||
|
parentMarketIdLoading ||
|
||||||
|
parentMarketLoading ||
|
||||||
(restLoading ? (restLoading as boolean) : false) ||
|
(restLoading ? (restLoading as boolean) : false) ||
|
||||||
(originalMarketProposalRestLoading
|
(originalMarketProposalRestLoading
|
||||||
? (originalMarketProposalRestLoading as boolean)
|
? (originalMarketProposalRestLoading as boolean)
|
||||||
@@ -172,15 +211,18 @@ export const ProposalContainer = () => {
|
|||||||
error ||
|
error ||
|
||||||
newMarketError ||
|
newMarketError ||
|
||||||
assetError ||
|
assetError ||
|
||||||
|
networkParamsError ||
|
||||||
|
parentMarketIdError ||
|
||||||
|
parentMarketError ||
|
||||||
restError ||
|
restError ||
|
||||||
originalMarketProposalRestError ||
|
originalMarketProposalRestError ||
|
||||||
previouslyEnactedMarketProposalsRestError ||
|
previouslyEnactedMarketProposalsRestError
|
||||||
networkParamsError
|
|
||||||
}
|
}
|
||||||
data={{
|
data={{
|
||||||
...data,
|
...data,
|
||||||
...networkParams,
|
...networkParams,
|
||||||
...(newMarketData ? { newMarketData } : {}),
|
...(newMarketData ? { newMarketData } : {}),
|
||||||
|
...(parentMarketData ? { parentMarketData } : {}),
|
||||||
...(assetData ? { assetData } : {}),
|
...(assetData ? { assetData } : {}),
|
||||||
...(restData ? { restData } : {}),
|
...(restData ? { restData } : {}),
|
||||||
...(originalMarketProposalRestData
|
...(originalMarketProposalRestData
|
||||||
@@ -197,6 +239,7 @@ export const ProposalContainer = () => {
|
|||||||
networkParams={networkParams}
|
networkParams={networkParams}
|
||||||
restData={restData}
|
restData={restData}
|
||||||
newMarketData={newMarketData}
|
newMarketData={newMarketData}
|
||||||
|
parentMarketData={parentMarketData}
|
||||||
assetData={assetData}
|
assetData={assetData}
|
||||||
originalMarketProposalRestData={originalMarketProposalRestData}
|
originalMarketProposalRestData={originalMarketProposalRestData}
|
||||||
mostRecentlyEnactedAssociatedMarketProposal={
|
mostRecentlyEnactedAssociatedMarketProposal={
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ const ROWS = [
|
|||||||
|
|
||||||
export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
|
export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
|
||||||
return (
|
return (
|
||||||
<Dialog size="medium" open={isOpen} onChange={onChange}>
|
<Dialog size="large" open={isOpen} onChange={onChange}>
|
||||||
<h1 className="text-2xl mb-5 pr-2 font-medium font-alpha uppercase">
|
<h1 className="text-2xl mb-5 pr-2 font-medium font-alpha uppercase">
|
||||||
{t('Health')}
|
{t('Health')}
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ describe('charts', { tags: '@smoke' }, () => {
|
|||||||
before(() => {
|
before(() => {
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/#/markets/market-0');
|
cy.visit('/#/markets/market-0');
|
||||||
cy.wait('@Markets');
|
cy.wait('@Markets');
|
||||||
cy.getByTestId('Depth').click();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can see market depth chart', () => {
|
it('can see market depth chart', () => {
|
||||||
// 6006-DEPC-001
|
// 6006-DEPC-001
|
||||||
|
cy.getByTestId('Depth').click();
|
||||||
cy.getByTestId('tab-depth').should('be.visible');
|
cy.getByTestId('tab-depth').should('be.visible');
|
||||||
cy.get('.depth-chart-module_canvas__260De').should('be.visible');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ describe('Closed markets', { tags: '@smoke' }, () => {
|
|||||||
const specDataConnection = createDataConnection();
|
const specDataConnection = createDataConnection();
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.mockGQL((req) => {
|
cy.mockGQL((req) => {
|
||||||
aliasGQLQuery(req, 'ChainId', chainIdQuery());
|
aliasGQLQuery(req, 'ChainId', chainIdQuery());
|
||||||
aliasGQLQuery(req, 'Statistics', statisticsQuery());
|
aliasGQLQuery(req, 'Statistics', statisticsQuery());
|
||||||
@@ -455,6 +456,7 @@ describe('no closed markets', { tags: '@smoke', testIsolation: true }, () => {
|
|||||||
before(() => {
|
before(() => {
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/#/markets/all');
|
cy.visit('/#/markets/all');
|
||||||
cy.get('[data-testid="Closed markets"]').click();
|
cy.get('[data-testid="Closed markets"]').click();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -104,11 +104,11 @@ describe('deposit actions', { tags: '@smoke' }, () => {
|
|||||||
cy.visit('/#/markets/market-1');
|
cy.visit('/#/markets/market-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Deposit to trade is visble', () => {
|
it('Deposit to trade is visible', () => {
|
||||||
cy.getByTestId('Collateral').click();
|
cy.getByTestId('Collateral').click();
|
||||||
cy.contains('[data-testid="deposit"]', 'Deposit')
|
cy.get('[row-id="asset-id"]').contains('tEURO').should('be.visible');
|
||||||
.should('be.visible')
|
cy.contains('[data-testid="deposit"]', 'Deposit').should('be.visible');
|
||||||
.click();
|
cy.contains('[data-testid="deposit"]', 'Deposit').click();
|
||||||
cy.getByTestId('deposit-submit').should('be.visible');
|
cy.getByTestId('deposit-submit').should('be.visible');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const nodeHealthTrigger = 'node-health-trigger';
|
|||||||
|
|
||||||
describe('home', { tags: '@regression' }, () => {
|
describe('home', { tags: '@regression' }, () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
|||||||
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
|
||||||
const dialogContent = 'dialog-content';
|
const dialogContent = 'welcome-dialog';
|
||||||
|
|
||||||
const generateProposal = (code: string): ProposalListFieldsFragment => ({
|
const generateProposal = (code: string): ProposalListFieldsFragment => ({
|
||||||
__typename: 'Proposal',
|
__typename: 'Proposal',
|
||||||
@@ -140,43 +140,43 @@ describe('home', { tags: '@regression' }, () => {
|
|||||||
cy.wait('@MarketsData');
|
cy.wait('@MarketsData');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('redirects to market/all and displays welcome notice', () => {
|
it('close welcome dialog should redirect to market/all', () => {
|
||||||
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
|
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
|
||||||
cy.getByTestId('welcome-notice-title').should(
|
cy.getByTestId('welcome-dialog').should('be.visible');
|
||||||
'contain.text',
|
cy.getByTestId('welcome-title').should('contain.text', 'Console CUSTOM');
|
||||||
'Welcome to Console'
|
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`);
|
||||||
describe('no proposal nor markets found', () => {
|
cy.window().then((window) => {
|
||||||
it('there are welcome text and a link to propose market', () => {
|
expect(window.localStorage.getItem('vega_onboarding_viewed')).to.equal(
|
||||||
cy.mockGQL((req) => {
|
'true'
|
||||||
const data = {
|
);
|
||||||
marketsConnection: {
|
|
||||||
__typename: 'MarketConnection',
|
|
||||||
edges: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
aliasGQLQuery(req, 'Markets', data);
|
|
||||||
aliasGQLQuery(req, 'MarketsData', data);
|
|
||||||
aliasGQLQuery(req, 'ProposalsList', {
|
|
||||||
proposalsConnection: {
|
|
||||||
__typename: 'ProposalsConnection',
|
|
||||||
edges: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
cy.visit('/');
|
});
|
||||||
cy.wait('@Markets');
|
|
||||||
cy.wait('@MarketsData');
|
it('click browse markets button should redirect to market/all', () => {
|
||||||
cy.getByTestId('welcome-notice-title').should(
|
cy.getByTestId('welcome-dialog').should('be.visible');
|
||||||
'contain.text',
|
cy.getByTestId('browse-markets-button').click();
|
||||||
'Welcome to Console'
|
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
|
||||||
);
|
cy.window().then((window) => {
|
||||||
cy.getByTestId('external-link')
|
expect(window.localStorage.getItem('vega_onboarding_viewed')).to.equal(
|
||||||
.contains('Propose a market')
|
'true'
|
||||||
.should('exist');
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('click get started button should open connect dialog', () => {
|
||||||
|
cy.getByTestId('welcome-dialog').should('be.visible');
|
||||||
|
cy.getByTestId('get-started-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'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
cy.getByTestId('wallet-dialog-title').should('contain.text', 'Connect');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ describe('home', { tags: '@regression' }, () => {
|
|||||||
cy.window().then((window) => {
|
cy.window().then((window) => {
|
||||||
window.localStorage.setItem('marketId', 'market-1');
|
window.localStorage.setItem('marketId', 'market-1');
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.wait('@Markets');
|
cy.getByTestId('dialog-close').click();
|
||||||
cy.location('hash').should('equal', '#/markets/market-1');
|
cy.location('hash').should('equal', '#/markets/market-1');
|
||||||
cy.getByTestId(dialogContent).should('not.exist');
|
cy.getByTestId(dialogContent).should('not.exist');
|
||||||
});
|
});
|
||||||
@@ -199,6 +199,7 @@ describe('home', { tags: '@regression' }, () => {
|
|||||||
});
|
});
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.wait('@Markets');
|
cy.wait('@Markets');
|
||||||
|
cy.getByTestId('dialog-close').click();
|
||||||
cy.location('hash').should('equal', '#/markets/market-not-existing');
|
cy.location('hash').should('equal', '#/markets/market-not-existing');
|
||||||
cy.getByTestId(dialogContent).should('not.exist');
|
cy.getByTestId(dialogContent).should('not.exist');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ import type { MarketsQuery } from '@vegaprotocol/markets';
|
|||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
|
||||||
const rowSelector =
|
const rowSelector =
|
||||||
'[data-testid="tab-all-markets"] .ag-center-cols-container .ag-row';
|
'[data-testid="tab-open-markets"] .ag-center-cols-container .ag-row';
|
||||||
const colInstrumentCode = '[col-id="tradableInstrument.instrument.code"]';
|
const colInstrumentCode = '[col-id="tradableInstrument.instrument.code"]';
|
||||||
|
|
||||||
describe('markets all table', { tags: '@smoke' }, () => {
|
describe('markets all table', { tags: '@smoke' }, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.clearLocalStorage().then(() => {
|
cy.clearLocalStorage().then(() => {
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.mockTradingPage(
|
cy.mockTradingPage(
|
||||||
Schema.MarketState.STATE_ACTIVE,
|
Schema.MarketState.STATE_ACTIVE,
|
||||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||||
@@ -34,7 +35,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
|||||||
'Settlement asset',
|
'Settlement asset',
|
||||||
'',
|
'',
|
||||||
];
|
];
|
||||||
cy.getByTestId('tab-all-markets').within(($headers) => {
|
cy.getByTestId('tab-open-markets').within(($headers) => {
|
||||||
cy.wrap($headers)
|
cy.wrap($headers)
|
||||||
.get('.ag-header-cell-text')
|
.get('.ag-header-cell-text')
|
||||||
.each(($header, i) => {
|
.each(($header, i) => {
|
||||||
@@ -44,7 +45,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('markets tab should be rendered properly', () => {
|
it('markets tab should be rendered properly', () => {
|
||||||
cy.get('[data-testid="All markets"]').should(
|
cy.get('[data-testid="Open markets"]').should(
|
||||||
'have.attr',
|
'have.attr',
|
||||||
'data-state',
|
'data-state',
|
||||||
'active'
|
'active'
|
||||||
@@ -166,7 +167,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
|||||||
'ETHBTC.QM21',
|
'ETHBTC.QM21',
|
||||||
'SOLUSD',
|
'SOLUSD',
|
||||||
];
|
];
|
||||||
cy.get('[data-testid="All markets"]').click({ force: true });
|
cy.get('[data-testid="Open markets"]').click({ force: true });
|
||||||
cy.url().should('eq', Cypress.config('baseUrl') + '/#/markets/all');
|
cy.url().should('eq', Cypress.config('baseUrl') + '/#/markets/all');
|
||||||
cy.contains('AAPL.MF21').should('be.visible');
|
cy.contains('AAPL.MF21').should('be.visible');
|
||||||
cy.get('.ag-header-cell-label').contains('Market').click(); // sort by market name
|
cy.get('.ag-header-cell-label').contains('Market').click(); // sort by market name
|
||||||
@@ -191,7 +192,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('no all markets', { tags: '@smoke', testIsolation: true }, () => {
|
describe('no open markets', { tags: '@smoke', testIsolation: true }, () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
const markets: MarketsQuery = {};
|
const markets: MarketsQuery = {};
|
||||||
@@ -199,11 +200,12 @@ describe('no all markets', { tags: '@smoke', testIsolation: true }, () => {
|
|||||||
aliasGQLQuery(req, 'Markets', markets);
|
aliasGQLQuery(req, 'Markets', markets);
|
||||||
});
|
});
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/#/markets/all');
|
cy.visit('/#/markets/all');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('can see no markets message', () => {
|
it.skip('can see no markets message', () => {
|
||||||
// 6001-MARK-048
|
// 6001-MARK-048
|
||||||
cy.getByTestId('tab-all-markets').should('contain.text', 'No markets');
|
cy.getByTestId('tab-open-markets').should('contain.text', 'No markets');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.mockTradingPage(MarketState.STATE_ACTIVE);
|
cy.mockTradingPage(MarketState.STATE_ACTIVE);
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
cy.visit('/#/markets/market-0');
|
cy.visit('/#/markets/market-0');
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const headers = [
|
|||||||
|
|
||||||
describe('liquidity table - trading', { tags: '@smoke' }, () => {
|
describe('liquidity table - trading', { tags: '@smoke' }, () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
cy.mockTradingPage(
|
cy.mockTradingPage(
|
||||||
Schema.MarketState.STATE_ACTIVE,
|
Schema.MarketState.STATE_ACTIVE,
|
||||||
@@ -119,6 +120,7 @@ describe('liquidity table - trading', { tags: '@smoke' }, () => {
|
|||||||
|
|
||||||
describe('liquidity table view', { tags: '@smoke' }, () => {
|
describe('liquidity table view', { tags: '@smoke' }, () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
cy.mockTradingPage(
|
cy.mockTradingPage(
|
||||||
Schema.MarketState.STATE_ACTIVE,
|
Schema.MarketState.STATE_ACTIVE,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
|||||||
cy.window().then((window) => {
|
cy.window().then((window) => {
|
||||||
window.localStorage.setItem('marketId', 'market-1');
|
window.localStorage.setItem('marketId', 'market-1');
|
||||||
});
|
});
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.mockTradingPage(
|
cy.mockTradingPage(
|
||||||
MarketState.STATE_ACTIVE,
|
MarketState.STATE_ACTIVE,
|
||||||
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ describe('Market trading page', () => {
|
|||||||
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
||||||
);
|
);
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/#/markets/market-0');
|
cy.visit('/#/markets/market-0');
|
||||||
cy.wait('@MarketData');
|
cy.wait('@MarketData');
|
||||||
cy.getByTestId(marketSummaryBlock).should('be.visible');
|
cy.getByTestId(marketSummaryBlock).should('be.visible');
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
|
|||||||
before(() => {
|
before(() => {
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/#/markets/all');
|
cy.visit('/#/markets/all');
|
||||||
cy.get('[data-testid="Proposed markets"]').click();
|
cy.get('[data-testid="Proposed markets"]').click();
|
||||||
});
|
});
|
||||||
@@ -100,7 +101,6 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
|
|||||||
'VEGA_TOKEN_URL'
|
'VEGA_TOKEN_URL'
|
||||||
)}/proposals/e9ec6d5c46a7e7bcabf9ba7a893fa5a5eeeec08b731f06f7a6eb7bf0e605b829`
|
)}/proposals/e9ec6d5c46a7e7bcabf9ba7a893fa5a5eeeec08b731f06f7a6eb7bf0e605b829`
|
||||||
);
|
);
|
||||||
cy.getByTestId('proposal-actions-content').click();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 6001-MARK-060
|
// 6001-MARK-060
|
||||||
@@ -214,11 +214,13 @@ describe('no markets proposed', { tags: '@smoke', testIsolation: true }, () => {
|
|||||||
aliasGQLQuery(req, 'ProposalsList', proposal);
|
aliasGQLQuery(req, 'ProposalsList', proposal);
|
||||||
});
|
});
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
cy.visit('/#/markets/all');
|
cy.setOnBoardingViewed();
|
||||||
cy.get('[data-testid="Proposed markets"]').click();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can see no markets message', () => {
|
it('can see no markets message', () => {
|
||||||
|
cy.visit('/#/markets/all');
|
||||||
|
cy.get('[data-testid="Proposed markets"]').click();
|
||||||
|
|
||||||
// 6001-MARK-061
|
// 6001-MARK-061
|
||||||
cy.getByTestId('tab-proposed-markets').should('contain.text', 'No markets');
|
cy.getByTestId('tab-proposed-markets').should('contain.text', 'No markets');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ describe('markets table', { tags: '@smoke' }, () => {
|
|||||||
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
||||||
);
|
);
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/#/markets/all');
|
cy.visit('/#/markets/all');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const oracleFullProfile = 'oracle-full-profile';
|
|||||||
|
|
||||||
describe('oracle information', { tags: '@smoke' }, () => {
|
describe('oracle information', { tags: '@smoke' }, () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.mockTradingPage(
|
cy.mockTradingPage(
|
||||||
MarketState.STATE_ACTIVE,
|
MarketState.STATE_ACTIVE,
|
||||||
undefined,
|
undefined,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const resPrice = 'price-990';
|
|||||||
|
|
||||||
describe('order book', { tags: '@smoke' }, () => {
|
describe('order book', { tags: '@smoke' }, () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
cy.visit('/#/markets/market-0');
|
cy.visit('/#/markets/market-0');
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ describe('Settings page', { tags: '@smoke' }, () => {
|
|||||||
|
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
|
|
||||||
// Only click if not already active otherwise sidebar will close
|
// Only click if not already active otherwise sidebar will close
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ function getButtonSelectorByText(text: string): string {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/#/markets/market-0');
|
cy.visit('/#/markets/market-0');
|
||||||
cy.wait('@Markets');
|
cy.wait('@Markets');
|
||||||
});
|
});
|
||||||
@@ -154,7 +155,10 @@ describe(
|
|||||||
{ name: 'Volume', infoText: 'Volume: 55,000' },
|
{ name: 'Volume', infoText: 'Volume: 55,000' },
|
||||||
];
|
];
|
||||||
cy.get(indicatorInfo).eq(1).realHover();
|
cy.get(indicatorInfo).eq(1).realHover();
|
||||||
cy.get('.close-button-module_closeButton__2ifkl').click({ force: true });
|
cy.get('.chart__wrapper [data-testid="split-view-view"]')
|
||||||
|
.last()
|
||||||
|
.find('[role="button"][title="Close"]')
|
||||||
|
.click({ force: true });
|
||||||
cy.get(indicatorInfo).should('have.length', 1);
|
cy.get(indicatorInfo).should('have.length', 1);
|
||||||
|
|
||||||
checkMenuItemCheckbox('Studies', studyInfo);
|
checkMenuItemCheckbox('Studies', studyInfo);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ describe('deal ticket basics', { tags: '@smoke' }, () => {
|
|||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
cy.clearAllLocalStorage();
|
cy.clearAllLocalStorage();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/#/markets/market-0');
|
cy.visit('/#/markets/market-0');
|
||||||
cy.wait('@Markets');
|
cy.wait('@Markets');
|
||||||
});
|
});
|
||||||
@@ -21,37 +22,36 @@ describe('deal ticket basics', { tags: '@smoke' }, () => {
|
|||||||
it('must show place order button and connect wallet if wallet is not connected', () => {
|
it('must show place order button and connect wallet if wallet is not connected', () => {
|
||||||
// 0003-WTXN-001
|
// 0003-WTXN-001
|
||||||
cy.getByTestId('connect-vega-wallet'); // Not connected
|
cy.getByTestId('connect-vega-wallet'); // Not connected
|
||||||
cy.getByTestId('order-connect-wallet').should('exist');
|
|
||||||
cy.getByTestId(placeOrderBtn).should('exist');
|
cy.getByTestId(placeOrderBtn).should('exist');
|
||||||
cy.getByTestId('deal-ticket-connect-wallet').should('exist');
|
cy.getByTestId('get-started-button').should('exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('must be able to select order direction - long/short', function () {
|
it('must be able to select order direction - long/short', function () {
|
||||||
// 7002-SORD-004
|
// 7002-SORD-004
|
||||||
cy.getByTestId(toggleShort).click().children('input').should('be.checked');
|
cy.getByTestId(toggleShort).click().next('input').should('be.checked');
|
||||||
cy.getByTestId(toggleLong).click().children('input').should('be.checked');
|
cy.getByTestId(toggleLong).click().next('input').should('be.checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('must be able to select order type - limit/market', function () {
|
it('must be able to select order type - limit/market', function () {
|
||||||
// 7002-SORD-005
|
// 7002-SORD-005
|
||||||
// 7002-SORD-006
|
// 7002-SORD-006
|
||||||
// 7002-SORD-007
|
// 7002-SORD-007
|
||||||
cy.getByTestId(toggleLimit).click().children('input').should('be.checked');
|
cy.getByTestId(toggleLimit).click().next('input').should('be.checked');
|
||||||
cy.getByTestId(toggleMarket).click().children('input').should('be.checked');
|
cy.getByTestId(toggleMarket).click().next('input').should('be.checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('order connect vega wallet button should connect', () => {
|
it('order connect vega wallet button should connect', () => {
|
||||||
mockConnectWallet();
|
mockConnectWallet();
|
||||||
cy.getByTestId(toggleLimit).click();
|
cy.getByTestId(toggleLimit).click();
|
||||||
cy.getByTestId(orderPriceField).clear().type('101');
|
cy.getByTestId(orderPriceField).clear().type('101');
|
||||||
cy.getByTestId('order-connect-wallet').click();
|
cy.getByTestId('get-started-button').click();
|
||||||
cy.getByTestId('dialog-content').should('be.visible');
|
cy.getByTestId('dialog-content').should('be.visible');
|
||||||
cy.getByTestId('connectors-list')
|
cy.getByTestId('connectors-list')
|
||||||
.find('[data-testid="connector-jsonRpc"]')
|
.find('[data-testid="connector-jsonRpc"]')
|
||||||
.click();
|
.click();
|
||||||
cy.wait('@walletReq');
|
cy.wait('@walletReq');
|
||||||
cy.getByTestId(placeOrderBtn).should('be.visible');
|
cy.getByTestId(placeOrderBtn).should('be.visible');
|
||||||
cy.getByTestId(toggleLimit).children('input').should('be.checked');
|
cy.getByTestId(toggleLimit).next('input').should('be.checked');
|
||||||
cy.getByTestId(orderPriceField).should('have.value', '101');
|
cy.getByTestId(orderPriceField).should('have.value', '101');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
|||||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTC');
|
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTC');
|
||||||
cy.getByTestId(orderSizeField).clear().type('1');
|
cy.getByTestId(orderSizeField).clear().type('1');
|
||||||
cy.getByTestId(orderPriceField).clear().type('1.123456');
|
cy.getByTestId(orderPriceField).clear().type('1.123456');
|
||||||
|
cy.getByTestId(placeOrderBtn).click();
|
||||||
cy.getByTestId('deal-ticket-error-message-price-limit').should(
|
cy.getByTestId('deal-ticket-error-message-price-limit').should(
|
||||||
'have.text',
|
'have.text',
|
||||||
'Price accepts up to 5 decimal places'
|
'Price accepts up to 5 decimal places'
|
||||||
@@ -73,6 +74,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
|||||||
describe('market order', () => {
|
describe('market order', () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.getByTestId(toggleMarket).click();
|
cy.getByTestId(toggleMarket).click();
|
||||||
|
cy.getByTestId(placeOrderBtn).click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('must not see the price unit', function () {
|
it('must not see the price unit', function () {
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
|||||||
cy.getByTestId(orderPriceField).clear().type('0.1');
|
cy.getByTestId(orderPriceField).clear().type('0.1');
|
||||||
cy.getByTestId(orderSizeField).clear().type('1');
|
cy.getByTestId(orderSizeField).clear().type('1');
|
||||||
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
||||||
|
cy.getByTestId(placeOrderBtn).click();
|
||||||
cy.getByTestId('deal-ticket-warning-auction').should(
|
cy.getByTestId('deal-ticket-warning-auction').should(
|
||||||
'have.text',
|
'have.text',
|
||||||
'Any orders placed now will not trade until the auction ends'
|
'Any orders placed now will not trade until the auction ends'
|
||||||
@@ -60,6 +61,7 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
|||||||
TIFlist.filter((item) => item.code === 'FOK')[0].value
|
TIFlist.filter((item) => item.code === 'FOK')[0].value
|
||||||
);
|
);
|
||||||
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
||||||
|
cy.getByTestId(placeOrderBtn).click();
|
||||||
cy.getByTestId('deal-ticket-error-message-tif').should(
|
cy.getByTestId('deal-ticket-error-message-tif').should(
|
||||||
'have.text',
|
'have.text',
|
||||||
'This market is in auction until it reaches sufficient liquidity. Until the auction ends, you can only place GFA, GTT, or GTC limit orders'
|
'This market is in auction until it reaches sufficient liquidity. Until the auction ends, you can only place GFA, GTT, or GTC limit orders'
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ describe('time in force validation', { tags: '@smoke' }, () => {
|
|||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
cy.clearAllLocalStorage();
|
cy.clearAllLocalStorage();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.visit('/#/markets/market-0');
|
cy.visit('/#/markets/market-0');
|
||||||
cy.wait('@Markets');
|
cy.wait('@Markets');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ describe('fills', { tags: '@regression' }, () => {
|
|||||||
cy.getByTestId(tabFills).contains('Market');
|
cy.getByTestId(tabFills).contains('Market');
|
||||||
cy.getByTestId(tabFills)
|
cy.getByTestId(tabFills)
|
||||||
.get(
|
.get(
|
||||||
'[role="gridcell"][col-id="market.tradableInstrument.instrument.name"]'
|
'[role="gridcell"][col-id="market.tradableInstrument.instrument.code"]'
|
||||||
)
|
)
|
||||||
.each(($marketSymbol) => {
|
.each(($marketSymbol) => {
|
||||||
cy.wrap($marketSymbol).invoke('text').should('not.be.empty');
|
cy.wrap($marketSymbol).invoke('text').should('not.be.empty');
|
||||||
|
|||||||
@@ -142,22 +142,22 @@ describe('positions', { tags: '@regression', testIsolation: true }, () => {
|
|||||||
it('sorting by Market', () => {
|
it('sorting by Market', () => {
|
||||||
visitAndClickPositions();
|
visitAndClickPositions();
|
||||||
const marketsSortedDefault = [
|
const marketsSortedDefault = [
|
||||||
'ACTIVE MARKET',
|
'AAPL.MF21',
|
||||||
'Apple Monthly (30 Jun 2022)',
|
'BTCUSD.MF21',
|
||||||
'ETHBTC Quarterly (30 Jun 2022)',
|
'ETHBTC.QM21',
|
||||||
'SUSPENDED MARKET',
|
'SOLUSD',
|
||||||
];
|
];
|
||||||
const marketsSortedAsc = [
|
const marketsSortedAsc = [
|
||||||
'ACTIVE MARKET',
|
'AAPL.MF21',
|
||||||
'Apple Monthly (30 Jun 2022)',
|
'BTCUSD.MF21',
|
||||||
'ETHBTC Quarterly (30 Jun 2022)',
|
'ETHBTC.QM21',
|
||||||
'SUSPENDED MARKET',
|
'SOLUSD',
|
||||||
];
|
];
|
||||||
const marketsSortedDesc = [
|
const marketsSortedDesc = [
|
||||||
'SUSPENDED MARKET',
|
'SOLUSD',
|
||||||
'ETHBTC Quarterly (30 Jun 2022)',
|
'ETHBTC.QM21',
|
||||||
'Apple Monthly (30 Jun 2022)',
|
'BTCUSD.MF21',
|
||||||
'ACTIVE MARKET',
|
'AAPL.MF21',
|
||||||
];
|
];
|
||||||
cy.getByTestId(positions).click();
|
cy.getByTestId(positions).click();
|
||||||
// 7004-POSI-003
|
// 7004-POSI-003
|
||||||
@@ -251,11 +251,13 @@ describe('positions', { tags: '@regression', testIsolation: true }, () => {
|
|||||||
it('I can see warnings', () => {
|
it('I can see warnings', () => {
|
||||||
visitAndClickPositions();
|
visitAndClickPositions();
|
||||||
|
|
||||||
cy.get('[col-id="openVolume"]').within(() => {
|
cy.get('[col-id="openVolume"]')
|
||||||
cy.get('[aria-label="warning-sign icon"]')
|
.eq(3)
|
||||||
.should('be.visible')
|
.within(() => {
|
||||||
.realHover();
|
cy.get('[aria-label="warning-sign icon"]')
|
||||||
});
|
.should('be.visible')
|
||||||
|
.realHover();
|
||||||
|
});
|
||||||
// 7004-POSI-011
|
// 7004-POSI-011
|
||||||
cy.getByTestId(tooltipContent).should('be.visible');
|
cy.getByTestId(tooltipContent).should('be.visible');
|
||||||
});
|
});
|
||||||
@@ -289,9 +291,11 @@ describe('positions', { tags: '@regression', testIsolation: true }, () => {
|
|||||||
|
|
||||||
it('View settlement asset', () => {
|
it('View settlement asset', () => {
|
||||||
visitAndClickPositions();
|
visitAndClickPositions();
|
||||||
cy.get('[col-id="asset"]').within(() => {
|
cy.get('[col-id="asset"]')
|
||||||
cy.get('button[type="button"]').first().click();
|
.eq(3)
|
||||||
});
|
.within(() => {
|
||||||
|
cy.get('button[type="button"]').click();
|
||||||
|
});
|
||||||
// 7004-POSI-008
|
// 7004-POSI-008
|
||||||
cy.getByTestId(dialogContent).should('be.visible');
|
cy.getByTestId(dialogContent).should('be.visible');
|
||||||
cy.getByTestId(dialogCloseX).click();
|
cy.getByTestId(dialogCloseX).click();
|
||||||
@@ -306,7 +310,7 @@ function validatePositionsDisplayed(multiKey = false) {
|
|||||||
cy.getByTestId('tab-positions').should('be.visible');
|
cy.getByTestId('tab-positions').should('be.visible');
|
||||||
cy.getByTestId('tab-positions')
|
cy.getByTestId('tab-positions')
|
||||||
.get('.ag-center-cols-container .ag-row')
|
.get('.ag-center-cols-container .ag-row')
|
||||||
.first()
|
.eq(multiKey ? 3 : 1)
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get('[col-id="marketName"]')
|
cy.get('[col-id="marketName"]')
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ describe('trades', { tags: '@smoke' }, () => {
|
|||||||
before(() => {
|
before(() => {
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.intercept('POST', '/graphql', (req) => {
|
cy.intercept('POST', '/graphql', (req) => {
|
||||||
if (req.body.operationName === 'Trades') {
|
if (req.body.operationName === 'Trades') {
|
||||||
req.alias = '@Trades';
|
req.alias = '@Trades';
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe(
|
|||||||
cy.visit('/#/portfolio');
|
cy.visit('/#/portfolio');
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,6 +123,7 @@ describe('connect vega wallet', { tags: '@smoke', testIsolation: true }, () => {
|
|||||||
cy.visit('/#/portfolio');
|
cy.visit('/#/portfolio');
|
||||||
cy.mockTradingPage();
|
cy.mockTradingPage();
|
||||||
cy.mockSubscription();
|
cy.mockSubscription();
|
||||||
|
cy.setOnBoardingViewed();
|
||||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import { selectAsset } from '../support/helpers';
|
||||||
|
|
||||||
|
const amountField = 'input[name="amount"]';
|
||||||
|
const includeTransferFeeRadioBtn = 'include-transfer-fee';
|
||||||
|
const manageVegaWallet = 'manage-vega-wallet';
|
||||||
|
const toAddressField = '[name="toAddress"]';
|
||||||
|
const totalTransferfee = 'total-transfer-fee';
|
||||||
|
const transferAmount = 'transfer-amount';
|
||||||
|
const transferForm = 'transfer-form';
|
||||||
|
const transferFee = 'transfer-fee';
|
||||||
|
const walletTransfer = 'wallet-transfer';
|
||||||
|
|
||||||
|
const ASSET_SEPOLIA_TBTC = 2;
|
||||||
|
|
||||||
|
describe.skip(
|
||||||
|
'transfer fees',
|
||||||
|
{ tags: '@regression', testIsolation: true },
|
||||||
|
() => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.mockWeb3Provider();
|
||||||
|
cy.mockTradingPage();
|
||||||
|
cy.mockSubscription();
|
||||||
|
cy.setVegaWallet();
|
||||||
|
|
||||||
|
cy.visit('/');
|
||||||
|
cy.getByTestId(manageVegaWallet).click();
|
||||||
|
cy.getByTestId(walletTransfer).click();
|
||||||
|
|
||||||
|
cy.wait('@Assets');
|
||||||
|
cy.wait('@Accounts');
|
||||||
|
|
||||||
|
cy.mockVegaWalletTransaction();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('transfer fees tooltips', () => {
|
||||||
|
// 1003-TRAN-015
|
||||||
|
// 1003-TRAN-016
|
||||||
|
// 1003-TRAN-017
|
||||||
|
// 1003-TRAN-018
|
||||||
|
// 1003-TRAN-019
|
||||||
|
cy.getByTestId(transferForm);
|
||||||
|
cy.contains('Enter manually').click();
|
||||||
|
cy.getByTestId(transferForm)
|
||||||
|
.find(toAddressField)
|
||||||
|
.type(
|
||||||
|
'7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535'
|
||||||
|
);
|
||||||
|
selectAsset(ASSET_SEPOLIA_TBTC);
|
||||||
|
cy.getByTestId(transferForm)
|
||||||
|
.find(amountField)
|
||||||
|
.type('1', { delay: 100, force: true });
|
||||||
|
|
||||||
|
/// Check Include Transfer Fee tooltip
|
||||||
|
cy.get('label[for="include-transfer-fee"] div').realHover();
|
||||||
|
cy.get('[data-side="bottom"] div')
|
||||||
|
.should('be.visible')
|
||||||
|
.should('not.be.empty');
|
||||||
|
|
||||||
|
//Check Transfer Fee tooltip
|
||||||
|
cy.contains('div', 'Transfer fee').realHover();
|
||||||
|
cy.get('[data-side="bottom"] div')
|
||||||
|
.should('be.visible')
|
||||||
|
.should('not.be.empty');
|
||||||
|
|
||||||
|
//Check Amount to be transferred tooltip
|
||||||
|
cy.contains('div', 'Amount to be transferred').realHover();
|
||||||
|
cy.get('[data-side="bottom"] div')
|
||||||
|
.should('be.visible')
|
||||||
|
.should('not.be.empty');
|
||||||
|
|
||||||
|
//Check Total amount (with fee) tooltip
|
||||||
|
cy.contains('div', 'Total amount (with fee)').realHover();
|
||||||
|
cy.get('[data-side="bottom"] div')
|
||||||
|
.should('be.visible')
|
||||||
|
.should('not.be.empty');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('transfer fees', () => {
|
||||||
|
// 1003-TRAN-020
|
||||||
|
// 1003-TRAN-021
|
||||||
|
// 1003-TRAN-022
|
||||||
|
// 1003-TRAN-023
|
||||||
|
cy.getByTestId(transferForm);
|
||||||
|
cy.contains('Enter manually').click();
|
||||||
|
|
||||||
|
cy.getByTestId(transferForm)
|
||||||
|
.find(toAddressField)
|
||||||
|
.type(
|
||||||
|
'7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535'
|
||||||
|
);
|
||||||
|
selectAsset(ASSET_SEPOLIA_TBTC);
|
||||||
|
cy.getByTestId(includeTransferFeeRadioBtn).should('be.disabled');
|
||||||
|
|
||||||
|
cy.getByTestId(transferForm)
|
||||||
|
.find(amountField)
|
||||||
|
.type('1', { delay: 100, force: true });
|
||||||
|
|
||||||
|
cy.getByTestId(transferFee)
|
||||||
|
.should('be.visible')
|
||||||
|
.should('contain.text', '0.01');
|
||||||
|
cy.getByTestId(transferAmount)
|
||||||
|
.should('be.visible')
|
||||||
|
.should('contain.text', '1.00');
|
||||||
|
cy.getByTestId(totalTransferfee)
|
||||||
|
.should('be.visible')
|
||||||
|
.should('contain.text', '1.01');
|
||||||
|
cy.getByTestId(includeTransferFeeRadioBtn).click();
|
||||||
|
cy.getByTestId(transferFee)
|
||||||
|
.should('be.visible')
|
||||||
|
.should('contain.text', '0.01');
|
||||||
|
cy.getByTestId(transferAmount)
|
||||||
|
.should('be.visible')
|
||||||
|
.should('contain.text', '0.99');
|
||||||
|
cy.getByTestId(totalTransferfee)
|
||||||
|
.should('be.visible')
|
||||||
|
.should('contain.text', '1.00');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import { selectAsset } from '../support/helpers';
|
||||||
|
|
||||||
|
const amountField = 'input[name="amount"]';
|
||||||
|
const transferText = 'transfer-intro-text';
|
||||||
|
const errorText = 'input-error-text';
|
||||||
|
const formFieldError = 'input-error-text';
|
||||||
|
const keyID = `[data-testid="${transferText}"] > .rounded-md`;
|
||||||
|
const manageVegaWallet = 'manage-vega-wallet';
|
||||||
|
const submitTransferBtn = '[type="submit"]';
|
||||||
|
const toAddressField = '[name="toAddress"]';
|
||||||
|
const transferForm = 'transfer-form';
|
||||||
|
const walletTransfer = 'wallet-transfer';
|
||||||
|
|
||||||
|
const ASSET_EURO = 1;
|
||||||
|
const ASSET_SEPOLIA_TBTC = 2;
|
||||||
|
|
||||||
|
describe(
|
||||||
|
'transfer form validation',
|
||||||
|
{ tags: '@regression', testIsolation: true },
|
||||||
|
() => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.mockWeb3Provider();
|
||||||
|
cy.mockTradingPage();
|
||||||
|
cy.mockSubscription();
|
||||||
|
cy.setVegaWallet();
|
||||||
|
|
||||||
|
cy.visit('/#/portfolio');
|
||||||
|
cy.getByTestId(manageVegaWallet).click();
|
||||||
|
cy.getByTestId(walletTransfer).click();
|
||||||
|
|
||||||
|
cy.wait('@Accounts');
|
||||||
|
cy.wait('@Assets');
|
||||||
|
|
||||||
|
cy.mockVegaWalletTransaction();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('transfer Text', () => {
|
||||||
|
// 1003-TRAN-003
|
||||||
|
cy.getByTestId(transferText)
|
||||||
|
.should('exist')
|
||||||
|
.get(keyID)
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', /[\w.]{6}…[\w.]{6}/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('invalid vega key validation', () => {
|
||||||
|
//1003-TRAN-013
|
||||||
|
//1003-TRAN-004
|
||||||
|
cy.getByTestId(transferForm).should('be.visible');
|
||||||
|
cy.contains('Enter manually').click();
|
||||||
|
cy.getByTestId(transferForm).find(toAddressField).type('asd');
|
||||||
|
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||||
|
cy.getByTestId(formFieldError).should('contain.text', 'Invalid Vega key');
|
||||||
|
cy.contains('label', 'Vega key').should('be.visible');
|
||||||
|
cy.contains('label', 'Asset').should('be.visible');
|
||||||
|
cy.contains('label', 'Amount').should('be.visible');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('empty fields', () => {
|
||||||
|
// 1003-TRAN-012
|
||||||
|
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||||
|
cy.getByTestId(formFieldError).should('contain.text', 'Required');
|
||||||
|
cy.getByTestId(formFieldError).should('have.length', 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('min amount', () => {
|
||||||
|
// 1002-WITH-010
|
||||||
|
// 1003-TRAN-014
|
||||||
|
selectAsset(ASSET_SEPOLIA_TBTC);
|
||||||
|
cy.get(amountField).clear().type('0');
|
||||||
|
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||||
|
cy.getByTestId(errorText).should(
|
||||||
|
'contain.text',
|
||||||
|
'Value is below minimum'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('max amount', () => {
|
||||||
|
// 1003-TRAN-002
|
||||||
|
// 1003-TRAN-011
|
||||||
|
// 1003-TRAN-002
|
||||||
|
selectAsset(ASSET_EURO); // Will be above maximum because the vega wallet doesn't have any collateral
|
||||||
|
cy.get(amountField).clear().type('1001', { delay: 100 });
|
||||||
|
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||||
|
cy.getByTestId(errorText).should(
|
||||||
|
'contain.text',
|
||||||
|
'You cannot transfer more than your available collateral'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -5,205 +5,15 @@ const amountShortName = 'input[name="amount"] + div + span.text-xs';
|
|||||||
const assetSelection = 'select-asset';
|
const assetSelection = 'select-asset';
|
||||||
const assetBalance = 'asset-balance';
|
const assetBalance = 'asset-balance';
|
||||||
const assetOption = 'rich-select-option';
|
const assetOption = 'rich-select-option';
|
||||||
const transferText = 'transfer-intro-text';
|
|
||||||
const errorText = 'input-error-text';
|
|
||||||
const formFieldError = 'input-error-text';
|
|
||||||
const includeTransferFeeRadioBtn = 'include-transfer-fee';
|
|
||||||
const keyID = `[data-testid="${transferText}"] > .rounded-md`;
|
|
||||||
const manageVegaWallet = 'manage-vega-wallet';
|
|
||||||
const openTransferButton = 'open-transfer';
|
const openTransferButton = 'open-transfer';
|
||||||
const submitTransferBtn = '[type="submit"]';
|
const submitTransferBtn = '[type="submit"]';
|
||||||
const toAddressField = '[name="toAddress"]';
|
const toAddressField = '[name="toAddress"]';
|
||||||
const totalTransferfee = 'total-transfer-fee';
|
|
||||||
const transferAmount = 'transfer-amount';
|
|
||||||
const transferForm = 'transfer-form';
|
const transferForm = 'transfer-form';
|
||||||
const transferFee = 'transfer-fee';
|
|
||||||
const walletTransfer = 'wallet-transfer';
|
|
||||||
|
|
||||||
const ASSET_EURO = 1;
|
|
||||||
const ASSET_SEPOLIA_TBTC = 2;
|
const ASSET_SEPOLIA_TBTC = 2;
|
||||||
|
|
||||||
const collateralTab = 'Collateral';
|
const collateralTab = 'Collateral';
|
||||||
const toastCloseBtn = 'toast-close';
|
const toastCloseBtn = 'toast-close';
|
||||||
const toastContent = 'toast-content';
|
const toastContent = 'toast-content';
|
||||||
|
|
||||||
describe('transfer fees', { tags: '@regression', testIsolation: true }, () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.mockWeb3Provider();
|
|
||||||
cy.mockTradingPage();
|
|
||||||
cy.mockSubscription();
|
|
||||||
cy.setVegaWallet();
|
|
||||||
|
|
||||||
cy.visit('/');
|
|
||||||
|
|
||||||
cy.wait('@Assets');
|
|
||||||
cy.wait('@Accounts');
|
|
||||||
|
|
||||||
cy.mockVegaWalletTransaction();
|
|
||||||
|
|
||||||
// Only click if not already active otherwise sidebar will close
|
|
||||||
cy.get('[data-testid="sidebar-content"]').then(($sidebarContent) => {
|
|
||||||
if ($sidebarContent.find('h2').text() !== 'Transfer') {
|
|
||||||
cy.get('[data-testid="sidebar"] [data-testid="Transfer"]').click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('transfer fees tooltips', () => {
|
|
||||||
// 1003-TRAN-015
|
|
||||||
// 1003-TRAN-016
|
|
||||||
// 1003-TRAN-017
|
|
||||||
// 1003-TRAN-018
|
|
||||||
// 1003-TRAN-019
|
|
||||||
cy.getByTestId(transferForm);
|
|
||||||
cy.contains('Enter manually').click();
|
|
||||||
|
|
||||||
cy.getByTestId(transferForm)
|
|
||||||
.find(toAddressField)
|
|
||||||
.type('7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535');
|
|
||||||
selectAsset(ASSET_SEPOLIA_TBTC);
|
|
||||||
cy.getByTestId(transferForm)
|
|
||||||
.find(amountField)
|
|
||||||
.type('1', { delay: 100, force: true });
|
|
||||||
|
|
||||||
/// Check Include Transfer Fee tooltip
|
|
||||||
cy.get('label[for="include-transfer-fee"] div').realHover();
|
|
||||||
cy.get('[data-side="bottom"] div')
|
|
||||||
.should('be.visible')
|
|
||||||
.should('not.be.empty');
|
|
||||||
|
|
||||||
//Check Transfer Fee tooltip
|
|
||||||
cy.contains('div', 'Transfer fee').realHover();
|
|
||||||
cy.get('[data-side="bottom"] div')
|
|
||||||
.should('be.visible')
|
|
||||||
.should('not.be.empty');
|
|
||||||
|
|
||||||
//Check Amount to be transferred tooltip
|
|
||||||
cy.contains('div', 'Amount to be transferred').realHover();
|
|
||||||
cy.get('[data-side="bottom"] div')
|
|
||||||
.should('be.visible')
|
|
||||||
.should('not.be.empty');
|
|
||||||
|
|
||||||
//Check Total amount (with fee) tooltip
|
|
||||||
cy.contains('div', 'Total amount (with fee)').realHover();
|
|
||||||
cy.get('[data-side="bottom"] div')
|
|
||||||
.should('be.visible')
|
|
||||||
.should('not.be.empty');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('transfer fees', () => {
|
|
||||||
// 1003-TRAN-020
|
|
||||||
// 1003-TRAN-021
|
|
||||||
// 1003-TRAN-022
|
|
||||||
// 1003-TRAN-023
|
|
||||||
cy.getByTestId(transferForm);
|
|
||||||
cy.contains('Enter manually').click();
|
|
||||||
|
|
||||||
cy.getByTestId(transferForm)
|
|
||||||
.find(toAddressField)
|
|
||||||
.type('7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535');
|
|
||||||
selectAsset(ASSET_SEPOLIA_TBTC);
|
|
||||||
cy.getByTestId(includeTransferFeeRadioBtn).should('be.disabled');
|
|
||||||
|
|
||||||
cy.getByTestId(transferForm)
|
|
||||||
.find(amountField)
|
|
||||||
.type('1', { delay: 100, force: true });
|
|
||||||
|
|
||||||
cy.getByTestId(transferFee)
|
|
||||||
.should('be.visible')
|
|
||||||
.should('contain.text', '0.01');
|
|
||||||
cy.getByTestId(transferAmount)
|
|
||||||
.should('be.visible')
|
|
||||||
.should('contain.text', '1.00');
|
|
||||||
cy.getByTestId(totalTransferfee)
|
|
||||||
.should('be.visible')
|
|
||||||
.should('contain.text', '1.01');
|
|
||||||
cy.getByTestId(includeTransferFeeRadioBtn).click();
|
|
||||||
cy.getByTestId(transferFee)
|
|
||||||
.should('be.visible')
|
|
||||||
.should('contain.text', '0.01');
|
|
||||||
cy.getByTestId(transferAmount)
|
|
||||||
.should('be.visible')
|
|
||||||
.should('contain.text', '0.99');
|
|
||||||
cy.getByTestId(totalTransferfee)
|
|
||||||
.should('be.visible')
|
|
||||||
.should('contain.text', '1.00');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(
|
|
||||||
'transfer form validation',
|
|
||||||
{ tags: '@regression', testIsolation: true },
|
|
||||||
() => {
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.mockWeb3Provider();
|
|
||||||
cy.mockTradingPage();
|
|
||||||
cy.mockSubscription();
|
|
||||||
cy.setVegaWallet();
|
|
||||||
|
|
||||||
cy.visit('/#/portfolio');
|
|
||||||
cy.getByTestId(manageVegaWallet).click();
|
|
||||||
cy.getByTestId(walletTransfer).click();
|
|
||||||
|
|
||||||
cy.wait('@Accounts');
|
|
||||||
cy.wait('@Assets');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('transfer Text', () => {
|
|
||||||
// 1003-TRAN-003
|
|
||||||
cy.getByTestId(transferText)
|
|
||||||
.should('exist')
|
|
||||||
.get(keyID)
|
|
||||||
.invoke('text')
|
|
||||||
.should('match', /[\w.]{6}…[\w.]{6}/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('invalid vega key validation', () => {
|
|
||||||
//1003-TRAN-013
|
|
||||||
//1003-TRAN-004
|
|
||||||
cy.getByTestId(transferForm).should('be.visible');
|
|
||||||
cy.contains('Enter manually').click();
|
|
||||||
cy.getByTestId(transferForm).find(toAddressField).type('asd');
|
|
||||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
|
||||||
cy.getByTestId(formFieldError).should('contain.text', 'Invalid Vega key');
|
|
||||||
cy.contains('label', 'Vega key').should('be.visible');
|
|
||||||
cy.contains('label', 'Asset').should('be.visible');
|
|
||||||
cy.contains('label', 'Amount').should('be.visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('empty fields', () => {
|
|
||||||
// 1003-TRAN-012
|
|
||||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
|
||||||
cy.getByTestId(formFieldError).should('contain.text', 'Required');
|
|
||||||
cy.getByTestId(formFieldError).should('have.length', 3);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('min amount', () => {
|
|
||||||
// 1002-WITH-010
|
|
||||||
// 1003-TRAN-014
|
|
||||||
selectAsset(ASSET_SEPOLIA_TBTC);
|
|
||||||
cy.get(amountField).clear().type('0');
|
|
||||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
|
||||||
cy.getByTestId(errorText).should(
|
|
||||||
'contain.text',
|
|
||||||
'Value is below minimum'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('max amount', () => {
|
|
||||||
// 1003-TRAN-002
|
|
||||||
// 1003-TRAN-011
|
|
||||||
// 1003-TRAN-002
|
|
||||||
selectAsset(ASSET_EURO); // Will be above maximum because the vega wallet doesn't have any collateral
|
|
||||||
cy.get(amountField).clear().type('1001', { delay: 100 });
|
|
||||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
|
||||||
cy.getByTestId(errorText).should(
|
|
||||||
'contain.text',
|
|
||||||
'You cannot transfer more than your available collateral'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
describe('withdraw actions', { tags: '@smoke', testIsolation: true }, () => {
|
describe('withdraw actions', { tags: '@smoke', testIsolation: true }, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mockWeb3Provider();
|
cy.mockWeb3Provider();
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { OrderType } from '@vegaprotocol/types';
|
||||||
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
const orderSizeField = 'order-size';
|
const orderSizeField = 'order-size';
|
||||||
@@ -9,7 +10,9 @@ export const createOrder = (order: OrderSubmission): void => {
|
|||||||
cy.log('Placing order', order);
|
cy.log('Placing order', order);
|
||||||
const { type, side, size, price, timeInForce, expiresAt } = order;
|
const { type, side, size, price, timeInForce, expiresAt } = order;
|
||||||
|
|
||||||
cy.getByTestId(`order-type-${type}`).click();
|
cy.getByTestId(
|
||||||
|
`order-type-${type === OrderType.TYPE_LIMIT ? 'Limit' : 'Market'}`
|
||||||
|
).click();
|
||||||
cy.getByTestId(`order-side-${side}`).click();
|
cy.getByTestId(`order-side-${side}`).click();
|
||||||
cy.getByTestId(orderSizeField).clear().type(size);
|
cy.getByTestId(orderSizeField).clear().type(size);
|
||||||
if (price) {
|
if (price) {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ export const orderTIFDropDown = 'order-tif';
|
|||||||
export const placeOrderBtn = 'place-order';
|
export const placeOrderBtn = 'place-order';
|
||||||
export const toggleShort = 'order-side-SIDE_SELL';
|
export const toggleShort = 'order-side-SIDE_SELL';
|
||||||
export const toggleLong = 'order-side-SIDE_BUY';
|
export const toggleLong = 'order-side-SIDE_BUY';
|
||||||
export const toggleLimit = 'order-type-TYPE_LIMIT';
|
export const toggleLimit = 'order-type-Limit';
|
||||||
export const toggleMarket = 'order-type-TYPE_MARKET';
|
export const toggleMarket = 'order-type-Market';
|
||||||
|
|
||||||
export const TIFlist = Object.values(Schema.OrderTimeInForce).map((value) => {
|
export const TIFlist = Object.values(Schema.OrderTimeInForce).map((value) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
+1
-1
@@ -16,6 +16,6 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
|||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
# NX_STOP_ORDERS
|
NX_STOP_ORDERS=true
|
||||||
# NX_ICEBERG_ORDERS
|
# NX_ICEBERG_ORDERS
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
@@ -18,6 +18,6 @@ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supp
|
|||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=false
|
NX_SUCCESSOR_MARKETS=false
|
||||||
# NX_STOP_ORDERS
|
NX_STOP_ORDERS=false
|
||||||
# NX_ICEBERG_ORDERS
|
# NX_ICEBERG_ORDERS
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
@@ -16,6 +16,6 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
|||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
# NX_STOP_ORDERS
|
NX_STOP_ORDERS=true
|
||||||
# NX_ICEBERG_ORDERS
|
# NX_ICEBERG_ORDERS
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
@@ -18,6 +18,6 @@ NX_APP_VERSION=v0.20.21-core-0.71.6
|
|||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=false
|
NX_SUCCESSOR_MARKETS=false
|
||||||
# NX_STOP_ORDERS
|
NX_STOP_ORDERS=false
|
||||||
# NX_ICEBERG_ORDERS
|
# NX_ICEBERG_ORDERS
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
@@ -18,6 +18,6 @@ NX_APP_VERSION=v0.20.19-core-0.71.6
|
|||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=false
|
NX_SUCCESSOR_MARKETS=false
|
||||||
# NX_STOP_ORDERS
|
NX_STOP_ORDERS=false
|
||||||
# NX_ICEBERG_ORDERS
|
# NX_ICEBERG_ORDERS
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
@@ -16,6 +16,6 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
|||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
# NX_STOP_ORDERS
|
NX_STOP_ORDERS=true
|
||||||
# NX_ICEBERG_ORDERS
|
# NX_ICEBERG_ORDERS
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
@@ -17,6 +17,6 @@ NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
|||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
# NX_STOP_ORDERS
|
NX_STOP_ORDERS=true
|
||||||
# NX_ICEBERG_ORDERS
|
NX_ICEBERG_ORDERS=true
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
@@ -17,6 +17,6 @@ NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks
|
|||||||
|
|
||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=false
|
NX_SUCCESSOR_MARKETS=false
|
||||||
# NX_STOP_ORDERS
|
NX_STOP_ORDERS=false
|
||||||
# NX_ICEBERG_ORDERS
|
# NX_ICEBERG_ORDERS
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { DepositContainer } from '@vegaprotocol/deposits';
|
||||||
|
import { GetStarted } from '../../components/welcome-dialog';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
export const Deposit = () => {
|
||||||
|
return (
|
||||||
|
<div className="py-16 px-8 flex w-full justify-center">
|
||||||
|
<div className="lg:min-w-[700px] min-w-[300px] max-w-[700px]">
|
||||||
|
<h1 className="text-4xl xl:text-5xl uppercase font-alpha calt">
|
||||||
|
{t('Deposit')}
|
||||||
|
</h1>
|
||||||
|
<div className="mt-10">
|
||||||
|
<DepositContainer />
|
||||||
|
<GetStarted />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { Deposit } from './deposit';
|
||||||
|
|
||||||
|
export default Deposit;
|
||||||
@@ -23,7 +23,6 @@ export const Home = () => {
|
|||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
} else if (data) {
|
} else if (data) {
|
||||||
update({ shouldDisplayWelcomeDialog: true });
|
|
||||||
const marketDataId = data[0]?.id;
|
const marketDataId = data[0]?.id;
|
||||||
if (marketDataId) {
|
if (marketDataId) {
|
||||||
navigate(Links[Routes.MARKET](marketDataId), {
|
navigate(Links[Routes.MARKET](marketDataId), {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import type { Market } from '@vegaprotocol/markets';
|
|||||||
import { Filter } from '@vegaprotocol/orders';
|
import { Filter } from '@vegaprotocol/orders';
|
||||||
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
|
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
|
||||||
import {
|
import {
|
||||||
ResizableGrid,
|
ResizableGrid,
|
||||||
ResizableGridPanel,
|
ResizableGridPanel,
|
||||||
@@ -45,20 +44,24 @@ const MainGrid = memo(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ResizableGrid vertical onChange={handleOnLayoutChange}>
|
<ResizableGrid vertical onChange={handleOnLayoutChange}>
|
||||||
<ResizableGridPanel minSize={75} priority={LayoutPriority.High}>
|
<ResizableGridPanel
|
||||||
<ResizableGrid
|
preferredSize={sizes[0]}
|
||||||
proportionalLayout={false}
|
priority={LayoutPriority.High}
|
||||||
minSize={200}
|
minSize={200}
|
||||||
onChange={handleOnMiddleLayoutChange}
|
>
|
||||||
>
|
<ResizableGrid onChange={handleOnMiddleLayoutChange}>
|
||||||
<ResizableGridPanel
|
<ResizableGridPanel
|
||||||
priority={LayoutPriority.High}
|
priority={LayoutPriority.High}
|
||||||
minSize={200}
|
minSize={200}
|
||||||
preferredSize={sizesMiddle[1] || '50%'}
|
preferredSize={sizesMiddle[0] || '75%'}
|
||||||
>
|
>
|
||||||
<TradeGridChild>
|
<TradeGridChild>
|
||||||
<Tabs storageKey="console-trade-grid-main-left">
|
<Tabs storageKey="console-trade-grid-main-left">
|
||||||
<Tab id="chart" name={t('Chart')}>
|
<Tab
|
||||||
|
id="chart"
|
||||||
|
name={t('Chart')}
|
||||||
|
menu={<TradingViews.candles.menu />}
|
||||||
|
>
|
||||||
<TradingViews.candles.component marketId={marketId} />
|
<TradingViews.candles.component marketId={marketId} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="depth" name={t('Depth')}>
|
<Tab id="depth" name={t('Depth')}>
|
||||||
@@ -71,8 +74,8 @@ const MainGrid = memo(
|
|||||||
</TradeGridChild>
|
</TradeGridChild>
|
||||||
</ResizableGridPanel>
|
</ResizableGridPanel>
|
||||||
<ResizableGridPanel
|
<ResizableGridPanel
|
||||||
preferredSize={sizesMiddle[2] || 300}
|
|
||||||
minSize={200}
|
minSize={200}
|
||||||
|
preferredSize={sizesMiddle[1] || 300}
|
||||||
>
|
>
|
||||||
<TradeGridChild>
|
<TradeGridChild>
|
||||||
<Tabs storageKey="console-trade-grid-main-right">
|
<Tabs storageKey="console-trade-grid-main-right">
|
||||||
@@ -88,64 +91,55 @@ const MainGrid = memo(
|
|||||||
</ResizableGrid>
|
</ResizableGrid>
|
||||||
</ResizableGridPanel>
|
</ResizableGridPanel>
|
||||||
<ResizableGridPanel
|
<ResizableGridPanel
|
||||||
priority={LayoutPriority.Low}
|
|
||||||
preferredSize={sizes[1] || '25%'}
|
preferredSize={sizes[1] || '25%'}
|
||||||
minSize={50}
|
minSize={50}
|
||||||
|
priority={LayoutPriority.Low}
|
||||||
>
|
>
|
||||||
<TradeGridChild>
|
<TradeGridChild>
|
||||||
<Tabs storageKey="console-trade-grid-bottom">
|
<Tabs storageKey="console-trade-grid-bottom">
|
||||||
<Tab id="positions" name={t('Positions')}>
|
<Tab id="positions" name={t('Positions')}>
|
||||||
<VegaWalletContainer>
|
<TradingViews.positions.component
|
||||||
<TradingViews.positions.component
|
onMarketClick={onMarketClick}
|
||||||
onMarketClick={onMarketClick}
|
/>
|
||||||
/>
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="open-orders" name={t('Open')}>
|
<Tab id="open-orders" name={t('Open')}>
|
||||||
<VegaWalletContainer>
|
<TradingViews.orders.component
|
||||||
<TradingViews.orders.component
|
marketId={marketId}
|
||||||
marketId={marketId}
|
filter={Filter.Open}
|
||||||
filter={Filter.Open}
|
/>
|
||||||
/>
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="closed-orders" name={t('Closed')}>
|
<Tab id="closed-orders" name={t('Closed')}>
|
||||||
<VegaWalletContainer>
|
<TradingViews.orders.component
|
||||||
<TradingViews.orders.component
|
marketId={marketId}
|
||||||
marketId={marketId}
|
filter={Filter.Closed}
|
||||||
filter={Filter.Closed}
|
/>
|
||||||
/>
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="rejected-orders" name={t('Rejected')}>
|
<Tab id="rejected-orders" name={t('Rejected')}>
|
||||||
<VegaWalletContainer>
|
<TradingViews.orders.component
|
||||||
<TradingViews.orders.component
|
marketId={marketId}
|
||||||
marketId={marketId}
|
filter={Filter.Rejected}
|
||||||
filter={Filter.Rejected}
|
/>
|
||||||
/>
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="orders" name={t('All')}>
|
<Tab id="orders" name={t('All')}>
|
||||||
<VegaWalletContainer>
|
<TradingViews.orders.component marketId={marketId} />
|
||||||
<TradingViews.orders.component marketId={marketId} />
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
|
{FLAGS.STOP_ORDERS ? (
|
||||||
|
<Tab id="stop-orders" name={t('Stop orders')}>
|
||||||
|
<TradingViews.stopOrders.component />
|
||||||
|
</Tab>
|
||||||
|
) : null}
|
||||||
<Tab id="fills" name={t('Fills')}>
|
<Tab id="fills" name={t('Fills')}>
|
||||||
<VegaWalletContainer>
|
<TradingViews.fills.component
|
||||||
<TradingViews.fills.component
|
marketId={marketId}
|
||||||
marketId={marketId}
|
onMarketClick={onMarketClick}
|
||||||
onMarketClick={onMarketClick}
|
/>
|
||||||
/>
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="accounts" name={t('Collateral')}>
|
<Tab id="accounts" name={t('Collateral')}>
|
||||||
<VegaWalletContainer>
|
<TradingViews.collateral.component
|
||||||
<TradingViews.collateral.component
|
pinnedAsset={pinnedAsset}
|
||||||
pinnedAsset={pinnedAsset}
|
onMarketClick={onMarketClick}
|
||||||
onMarketClick={onMarketClick}
|
hideButtons
|
||||||
hideButtons
|
/>
|
||||||
/>
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</TradeGridChild>
|
</TradeGridChild>
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export const TradePanels = ({
|
|||||||
const onOrderTypeClick = useMarketLiquidityClickHandler();
|
const onOrderTypeClick = useMarketLiquidityClickHandler();
|
||||||
|
|
||||||
const [view, setView] = useState<TradingView>('candles');
|
const [view, setView] = useState<TradingView>('candles');
|
||||||
|
|
||||||
const renderView = () => {
|
const renderView = () => {
|
||||||
const Component = memo<{
|
const Component = memo<{
|
||||||
marketId: string;
|
marketId: string;
|
||||||
@@ -65,8 +66,23 @@ export const TradePanels = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderMenu = () => {
|
||||||
|
const viewCfg = TradingViews[view];
|
||||||
|
|
||||||
|
if ('menu' in viewCfg) {
|
||||||
|
const Menu = viewCfg.menu;
|
||||||
|
return (
|
||||||
|
<div className="flex gap-1 p-1 bg-vega-clight-800 dark:bg-vega-cdark-800 border-b border-default">
|
||||||
|
<Menu />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full grid grid-rows-[min-content_1fr_min-content]">
|
<div className="h-full grid grid-rows-[min-content_min-content_1fr_min-content]">
|
||||||
<div>
|
<div>
|
||||||
{FLAGS.SUCCESSOR_MARKETS && (
|
{FLAGS.SUCCESSOR_MARKETS && (
|
||||||
<>
|
<>
|
||||||
@@ -76,6 +92,7 @@ export const TradePanels = ({
|
|||||||
)}
|
)}
|
||||||
<OracleBanner marketId={market?.id || ''} />
|
<OracleBanner marketId={market?.id || ''} />
|
||||||
</div>
|
</div>
|
||||||
|
<div>{renderMenu()}</div>
|
||||||
<div className="h-full">
|
<div className="h-full">
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
{({ width, height }) => (
|
{({ width, height }) => (
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import type { ComponentProps } from 'react';
|
|||||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { TradesContainer } from '@vegaprotocol/trades';
|
import { TradesContainer } from '@vegaprotocol/trades';
|
||||||
import { DepthChartContainer } from '@vegaprotocol/market-depth';
|
import { DepthChartContainer } from '@vegaprotocol/market-depth';
|
||||||
import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
|
import {
|
||||||
|
CandlesChartContainer,
|
||||||
|
CandlesMenu,
|
||||||
|
} from '@vegaprotocol/candles-chart';
|
||||||
import { Filter } from '@vegaprotocol/orders';
|
import { Filter } from '@vegaprotocol/orders';
|
||||||
import { NO_MARKET } from './constants';
|
import { NO_MARKET } from './constants';
|
||||||
import { OrderbookContainer } from '../../components/orderbook-container';
|
import { OrderbookContainer } from '../../components/orderbook-container';
|
||||||
@@ -12,6 +15,7 @@ import { AccountsContainer } from '../../components/accounts-container';
|
|||||||
import { LiquidityContainer } from '../../components/liquidity-container';
|
import { LiquidityContainer } from '../../components/liquidity-container';
|
||||||
import type { OrderContainerProps } from '../../components/orders-container';
|
import type { OrderContainerProps } from '../../components/orders-container';
|
||||||
import { OrdersContainer } from '../../components/orders-container';
|
import { OrdersContainer } from '../../components/orders-container';
|
||||||
|
import { StopOrdersContainer } from '../../components/stop-orders-container';
|
||||||
|
|
||||||
type MarketDependantView =
|
type MarketDependantView =
|
||||||
| typeof CandlesChartContainer
|
| typeof CandlesChartContainer
|
||||||
@@ -34,6 +38,7 @@ export const TradingViews = {
|
|||||||
candles: {
|
candles: {
|
||||||
label: 'Candles',
|
label: 'Candles',
|
||||||
component: requiresMarket(CandlesChartContainer),
|
component: requiresMarket(CandlesChartContainer),
|
||||||
|
menu: CandlesMenu,
|
||||||
},
|
},
|
||||||
depth: {
|
depth: {
|
||||||
label: 'Depth',
|
label: 'Depth',
|
||||||
@@ -74,6 +79,10 @@ export const TradingViews = {
|
|||||||
label: 'All',
|
label: 'All',
|
||||||
component: OrdersContainer,
|
component: OrdersContainer,
|
||||||
},
|
},
|
||||||
|
stopOrders: {
|
||||||
|
label: 'Stop',
|
||||||
|
component: StopOrdersContainer,
|
||||||
|
},
|
||||||
collateral: { label: 'Collateral', component: AccountsContainer },
|
collateral: { label: 'Collateral', component: AccountsContainer },
|
||||||
fills: { label: 'Fills', component: FillsContainer },
|
fills: { label: 'Fills', component: FillsContainer },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const MarketsPage = () => {
|
|||||||
<div className="h-full pt-0.5 pb-3 px-1.5">
|
<div className="h-full pt-0.5 pb-3 px-1.5">
|
||||||
<div className="h-full my-1 border border-default rounded-sm">
|
<div className="h-full my-1 border border-default rounded-sm">
|
||||||
<Tabs storageKey="console-markets">
|
<Tabs storageKey="console-markets">
|
||||||
<Tab id="all-markets" name={t('All markets')}>
|
<Tab id="open-markets" name={t('Open markets')}>
|
||||||
<Markets />
|
<Markets />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="proposed-markets" name={t('Proposed markets')}>
|
<Tab id="proposed-markets" name={t('Proposed markets')}>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export const AccountHistoryContainer = () => {
|
|||||||
const { data: assets } = useAssetsDataProvider();
|
const { data: assets } = useAssetsDataProvider();
|
||||||
|
|
||||||
if (!pubKey) {
|
if (!pubKey) {
|
||||||
return <Splash>{t('Connect wallet')}</Splash>;
|
return <Splash>{t('Please connect Vega wallet')}</Splash>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
import { Button, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { DepositsTable } from '@vegaprotocol/deposits';
|
import { DepositsTable } from '@vegaprotocol/deposits';
|
||||||
import { depositsProvider } from '@vegaprotocol/deposits';
|
import { depositsProvider } from '@vegaprotocol/deposits';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { useRef } from 'react';
|
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
|
||||||
import { useSidebar, ViewType } from '../../components/sidebar';
|
import { useSidebar, ViewType } from '../../components/sidebar';
|
||||||
|
|
||||||
export const DepositsContainer = () => {
|
export const DepositsContainer = () => {
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
|
||||||
const { pubKey, isReadOnly } = useVegaWallet();
|
const { pubKey, isReadOnly } = useVegaWallet();
|
||||||
const { data, error } = useDataProvider({
|
const { data, error } = useDataProvider({
|
||||||
dataProvider: depositsProvider,
|
dataProvider: depositsProvider,
|
||||||
@@ -17,11 +14,13 @@ export const DepositsContainer = () => {
|
|||||||
skip: !pubKey,
|
skip: !pubKey,
|
||||||
});
|
});
|
||||||
const setView = useSidebar((store) => store.setView);
|
const setView = useSidebar((store) => store.setView);
|
||||||
|
if (!pubKey) {
|
||||||
|
return <Splash>{t('Please connect Vega wallet')}</Splash>;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="h-full">
|
<div className="h-full">
|
||||||
<DepositsTable
|
<DepositsTable
|
||||||
rowData={data}
|
rowData={data}
|
||||||
ref={gridRef}
|
|
||||||
overlayNoRowsTemplate={error ? error.message : t('No deposits')}
|
overlayNoRowsTemplate={error ? error.message : t('No deposits')}
|
||||||
/>
|
/>
|
||||||
{!isReadOnly && (
|
{!isReadOnly && (
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { FillsContainer } from '../../components/fills-container';
|
|||||||
import { PositionsContainer } from '../../components/positions-container';
|
import { PositionsContainer } from '../../components/positions-container';
|
||||||
import { WithdrawalsContainer } from './withdrawals-container';
|
import { WithdrawalsContainer } from './withdrawals-container';
|
||||||
import { OrdersContainer } from '../../components/orders-container';
|
import { OrdersContainer } from '../../components/orders-container';
|
||||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
|
||||||
import { LedgerContainer } from '../../components/ledger-container';
|
import { LedgerContainer } from '../../components/ledger-container';
|
||||||
import { AccountHistoryContainer } from './account-history-container';
|
import { AccountHistoryContainer } from './account-history-container';
|
||||||
import {
|
import {
|
||||||
@@ -62,29 +61,19 @@ export const Portfolio = () => {
|
|||||||
<PortfolioGridChild>
|
<PortfolioGridChild>
|
||||||
<Tabs storageKey="console-portfolio-top">
|
<Tabs storageKey="console-portfolio-top">
|
||||||
<Tab id="account-history" name={t('Account history')}>
|
<Tab id="account-history" name={t('Account history')}>
|
||||||
<VegaWalletContainer>
|
<AccountHistoryContainer />
|
||||||
<AccountHistoryContainer />
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="positions" name={t('Positions')}>
|
<Tab id="positions" name={t('Positions')}>
|
||||||
<VegaWalletContainer>
|
<PositionsContainer onMarketClick={onMarketClick} allKeys />
|
||||||
<PositionsContainer onMarketClick={onMarketClick} allKeys />
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="orders" name={t('Orders')}>
|
<Tab id="orders" name={t('Orders')}>
|
||||||
<VegaWalletContainer>
|
<OrdersContainer />
|
||||||
<OrdersContainer />
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="fills" name={t('Fills')}>
|
<Tab id="fills" name={t('Fills')}>
|
||||||
<VegaWalletContainer>
|
<FillsContainer onMarketClick={onMarketClick} />
|
||||||
<FillsContainer onMarketClick={onMarketClick} />
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="ledger-entries" name={t('Ledger entries')}>
|
<Tab id="ledger-entries" name={t('Ledger entries')}>
|
||||||
<VegaWalletContainer>
|
<LedgerContainer />
|
||||||
<LedgerContainer />
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</PortfolioGridChild>
|
</PortfolioGridChild>
|
||||||
@@ -97,14 +86,10 @@ export const Portfolio = () => {
|
|||||||
<PortfolioGridChild>
|
<PortfolioGridChild>
|
||||||
<Tabs storageKey="console-portfolio-bottom">
|
<Tabs storageKey="console-portfolio-bottom">
|
||||||
<Tab id="collateral" name={t('Collateral')}>
|
<Tab id="collateral" name={t('Collateral')}>
|
||||||
<VegaWalletContainer>
|
<AccountsContainer />
|
||||||
<AccountsContainer />
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="deposits" name={t('Deposits')}>
|
<Tab id="deposits" name={t('Deposits')}>
|
||||||
<VegaWalletContainer>
|
<DepositsContainer />
|
||||||
<DepositsContainer />
|
|
||||||
</VegaWalletContainer>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
id="withdrawals"
|
id="withdrawals"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
import { Button, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import {
|
import {
|
||||||
withdrawalProvider,
|
withdrawalProvider,
|
||||||
WithdrawalsTable,
|
WithdrawalsTable,
|
||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
|
||||||
import { ViewType, useSidebar } from '../../components/sidebar';
|
import { ViewType, useSidebar } from '../../components/sidebar';
|
||||||
|
|
||||||
export const WithdrawalsContainer = () => {
|
export const WithdrawalsContainer = () => {
|
||||||
@@ -19,9 +18,11 @@ export const WithdrawalsContainer = () => {
|
|||||||
});
|
});
|
||||||
const setView = useSidebar((store) => store.setView);
|
const setView = useSidebar((store) => store.setView);
|
||||||
const { ready, delayed } = useIncompleteWithdrawals();
|
const { ready, delayed } = useIncompleteWithdrawals();
|
||||||
|
if (!pubKey) {
|
||||||
|
return <Splash>{t('Please connect Vega wallet')}</Splash>;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<VegaWalletContainer>
|
<>
|
||||||
<div className="h-full relative">
|
<div className="h-full relative">
|
||||||
<WithdrawalsTable
|
<WithdrawalsTable
|
||||||
data-testid="withdrawals-history"
|
data-testid="withdrawals-history"
|
||||||
@@ -43,6 +44,6 @@ export const WithdrawalsContainer = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</VegaWalletContainer>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
|
||||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
||||||
import { AccountManager } from '@vegaprotocol/accounts';
|
import { AccountManager } from '@vegaprotocol/accounts';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
export const THROTTLE_UPDATE_TIME = 500;
|
export const THROTTLE_UPDATE_TIME = 500;
|
||||||
export const RISK_ACCEPTED_KEY = 'vega_risk_accepted';
|
export const ONBOARDING_VIEWED_KEY = 'vega_onboarding_viewed';
|
||||||
export const MAINNET_WELCOME_HEADER = t(
|
export const MAINNET_WELCOME_HEADER = t(
|
||||||
'Trade cash settled futures on the fully decentralised Vega network.'
|
'Trade cash settled futures on the fully decentralised Vega network.'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { FillsManager } from '@vegaprotocol/fills';
|
import { FillsManager } from '@vegaprotocol/fills';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
||||||
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,9 @@ import {
|
|||||||
NetworkParams,
|
NetworkParams,
|
||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
} from '@vegaprotocol/network-parameters';
|
} from '@vegaprotocol/network-parameters';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
|
||||||
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
||||||
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
|
|
||||||
@@ -26,8 +25,6 @@ export const LiquidityContainer = ({
|
|||||||
marketId: string | undefined;
|
marketId: string | undefined;
|
||||||
filter?: Filter;
|
filter?: Filter;
|
||||||
}) => {
|
}) => {
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
|
||||||
|
|
||||||
const gridStore = useLiquidityStore((store) => store.gridStore);
|
const gridStore = useLiquidityStore((store) => store.gridStore);
|
||||||
const updateGridStore = useLiquidityStore((store) => store.updateGridStore);
|
const updateGridStore = useLiquidityStore((store) => store.updateGridStore);
|
||||||
|
|
||||||
@@ -60,7 +57,6 @@ export const LiquidityContainer = ({
|
|||||||
return (
|
return (
|
||||||
<div className="h-full relative">
|
<div className="h-full relative">
|
||||||
<LiquidityTable
|
<LiquidityTable
|
||||||
ref={gridRef}
|
|
||||||
rowData={data}
|
rowData={data}
|
||||||
symbol={symbol}
|
symbol={symbol}
|
||||||
assetDecimalPlaces={assetDecimalPlaces}
|
assetDecimalPlaces={assetDecimalPlaces}
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ export const Navbar = ({
|
|||||||
'bg-vega-yellow text-vega-clight-50': theme === 'yellow',
|
'bg-vega-yellow text-vega-clight-50': theme === 'yellow',
|
||||||
'text-default': theme === 'system',
|
'text-default': theme === 'system',
|
||||||
})}
|
})}
|
||||||
|
style={{
|
||||||
|
background: theme === 'yellow' ? 'url(/testnet-logo-bg.png' : 'none',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<VLogo className="w-4" />
|
<VLogo className="w-4" />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
import { OrderbookManager } from '@vegaprotocol/market-depth';
|
import { OrderbookManager } from '@vegaprotocol/market-depth';
|
||||||
import { useCreateOrderStore } from '@vegaprotocol/orders';
|
|
||||||
import { ViewType, useSidebar } from '../sidebar';
|
import { ViewType, useSidebar } from '../sidebar';
|
||||||
|
import { useDealTicketFormValues } from '@vegaprotocol/deal-ticket';
|
||||||
|
|
||||||
export const OrderbookContainer = ({ marketId }: { marketId: string }) => {
|
export const OrderbookContainer = ({ marketId }: { marketId: string }) => {
|
||||||
const useOrderStoreRef = useCreateOrderStore();
|
const update = useDealTicketFormValues((state) => state.updateAll);
|
||||||
const updateOrder = useOrderStoreRef((store) => store.update);
|
|
||||||
const setView = useSidebar((store) => store.setView);
|
const setView = useSidebar((store) => store.setView);
|
||||||
return (
|
return (
|
||||||
<OrderbookManager
|
<OrderbookManager
|
||||||
marketId={marketId}
|
marketId={marketId}
|
||||||
onClick={({ price, size }) => {
|
onClick={(values) => {
|
||||||
if (price) {
|
update(marketId, values);
|
||||||
updateOrder(marketId, { price });
|
|
||||||
}
|
|
||||||
if (size) {
|
|
||||||
updateOrder(marketId, { size });
|
|
||||||
}
|
|
||||||
setView({ type: ViewType.Order });
|
setView({ type: ViewType.Order });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||||
|
import { Filter, OrderListManager } from '@vegaprotocol/orders';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Filter } from '@vegaprotocol/orders';
|
|
||||||
import { OrderListManager } from '@vegaprotocol/orders';
|
|
||||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
import { act, render, screen } from '@testing-library/react';
|
import { act, render, screen } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { Sidebar, SidebarContent, ViewType, useSidebar } from './sidebar';
|
import {
|
||||||
|
Sidebar,
|
||||||
|
SidebarButton,
|
||||||
|
SidebarContent,
|
||||||
|
ViewType,
|
||||||
|
useSidebar,
|
||||||
|
} from './sidebar';
|
||||||
import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
||||||
|
import { VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { VegaWalletProvider } from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
jest.mock('../node-health', () => ({
|
jest.mock('../node-health', () => ({
|
||||||
NodeHealthContainer: () => <span data-testid="node-health" />,
|
NodeHealthContainer: () => <span data-testid="node-health" />,
|
||||||
@@ -19,16 +27,23 @@ jest.mock('../settings', () => ({
|
|||||||
Settings: () => <div data-testid="settings" />,
|
Settings: () => <div data-testid="settings" />,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('../welcome-dialog', () => ({
|
||||||
|
GetStarted: () => <div data-testid="get-started" />,
|
||||||
|
}));
|
||||||
|
|
||||||
describe('Sidebar', () => {
|
describe('Sidebar', () => {
|
||||||
it.each(['/markets/all', '/portfolio'])(
|
it.each(['/markets/all', '/portfolio'])(
|
||||||
'does not render ticket and info',
|
'does not render ticket and info',
|
||||||
(path) => {
|
(path) => {
|
||||||
render(
|
render(
|
||||||
<MemoryRouter initialEntries={[path]}>
|
<VegaWalletProvider>
|
||||||
<Sidebar />
|
<MemoryRouter initialEntries={[path]}>
|
||||||
</MemoryRouter>
|
<Sidebar />
|
||||||
|
</MemoryRouter>
|
||||||
|
</VegaWalletProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
expect(screen.getByTestId(ViewType.ViewAs)).toBeInTheDocument();
|
||||||
expect(screen.getByTestId(ViewType.Settings)).toBeInTheDocument();
|
expect(screen.getByTestId(ViewType.Settings)).toBeInTheDocument();
|
||||||
expect(screen.getByTestId(ViewType.Transfer)).toBeInTheDocument();
|
expect(screen.getByTestId(ViewType.Transfer)).toBeInTheDocument();
|
||||||
expect(screen.getByTestId(ViewType.Deposit)).toBeInTheDocument();
|
expect(screen.getByTestId(ViewType.Deposit)).toBeInTheDocument();
|
||||||
@@ -43,11 +58,14 @@ describe('Sidebar', () => {
|
|||||||
|
|
||||||
it('renders ticket and info on market pages', () => {
|
it('renders ticket and info on market pages', () => {
|
||||||
render(
|
render(
|
||||||
<MemoryRouter initialEntries={['/markets/ABC']}>
|
<VegaWalletProvider>
|
||||||
<Sidebar />
|
<MemoryRouter initialEntries={['/markets/ABC']}>
|
||||||
</MemoryRouter>
|
<Sidebar />
|
||||||
|
</MemoryRouter>
|
||||||
|
</VegaWalletProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
expect(screen.getByTestId(ViewType.ViewAs)).toBeInTheDocument();
|
||||||
expect(screen.getByTestId(ViewType.Settings)).toBeInTheDocument();
|
expect(screen.getByTestId(ViewType.Settings)).toBeInTheDocument();
|
||||||
expect(screen.getByTestId(ViewType.Transfer)).toBeInTheDocument();
|
expect(screen.getByTestId(ViewType.Transfer)).toBeInTheDocument();
|
||||||
expect(screen.getByTestId(ViewType.Deposit)).toBeInTheDocument();
|
expect(screen.getByTestId(ViewType.Deposit)).toBeInTheDocument();
|
||||||
@@ -61,9 +79,11 @@ describe('Sidebar', () => {
|
|||||||
|
|
||||||
it('renders selected state', async () => {
|
it('renders selected state', async () => {
|
||||||
render(
|
render(
|
||||||
<MemoryRouter initialEntries={['/markets/ABC']}>
|
<VegaWalletProvider>
|
||||||
<Sidebar />
|
<MemoryRouter initialEntries={['/markets/ABC']}>
|
||||||
</MemoryRouter>
|
<Sidebar />
|
||||||
|
</MemoryRouter>
|
||||||
|
</VegaWalletProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
const settingsButton = screen.getByTestId(ViewType.Settings);
|
const settingsButton = screen.getByTestId(ViewType.Settings);
|
||||||
@@ -87,11 +107,13 @@ describe('Sidebar', () => {
|
|||||||
describe('SidebarContent', () => {
|
describe('SidebarContent', () => {
|
||||||
it('renders the correct content', () => {
|
it('renders the correct content', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<MemoryRouter initialEntries={['/markets/ABC']}>
|
<VegaWalletProvider>
|
||||||
<Routes>
|
<MemoryRouter initialEntries={['/markets/ABC']}>
|
||||||
<Route path="/markets/:marketId" element={<SidebarContent />} />
|
<Routes>
|
||||||
</Routes>
|
<Route path="/markets/:marketId" element={<SidebarContent />} />
|
||||||
</MemoryRouter>
|
</Routes>
|
||||||
|
</MemoryRouter>
|
||||||
|
</VegaWalletProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(container).toBeEmptyDOMElement();
|
expect(container).toBeEmptyDOMElement();
|
||||||
@@ -111,11 +133,13 @@ describe('SidebarContent', () => {
|
|||||||
|
|
||||||
it('closes sidebar if market id is required but not present', () => {
|
it('closes sidebar if market id is required but not present', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<MemoryRouter initialEntries={['/portfolio']}>
|
<VegaWalletProvider>
|
||||||
<Routes>
|
<MemoryRouter initialEntries={['/portfolio']}>
|
||||||
<Route path="/portfolio" element={<SidebarContent />} />
|
<Routes>
|
||||||
</Routes>
|
<Route path="/portfolio" element={<SidebarContent />} />
|
||||||
</MemoryRouter>
|
</Routes>
|
||||||
|
</MemoryRouter>
|
||||||
|
</VegaWalletProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -137,3 +161,25 @@ describe('SidebarContent', () => {
|
|||||||
expect(container).toBeEmptyDOMElement();
|
expect(container).toBeEmptyDOMElement();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('SidebarButton', () => {
|
||||||
|
it.each([ViewType.Info, ViewType.Deposit, ViewType.ViewAs])(
|
||||||
|
'runs given callback regardless of requested view (%s)',
|
||||||
|
async (view) => {
|
||||||
|
const onClick = jest.fn();
|
||||||
|
render(
|
||||||
|
<SidebarButton
|
||||||
|
icon={VegaIconNames.INFO}
|
||||||
|
tooltip="INFO"
|
||||||
|
onClick={onClick}
|
||||||
|
view={view}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const btn = screen.getByTestId(view);
|
||||||
|
await userEvent.click(btn);
|
||||||
|
|
||||||
|
expect(onClick).toBeCalled();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import { Tooltip } from '../../components/tooltip';
|
|||||||
import { WithdrawContainer } from '../withdraw-container';
|
import { WithdrawContainer } from '../withdraw-container';
|
||||||
import { Routes as AppRoutes } from '../../pages/client-router';
|
import { Routes as AppRoutes } from '../../pages/client-router';
|
||||||
import { persist } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
|
import { GetStarted } from '../welcome-dialog';
|
||||||
|
import { useVegaWallet, useViewAsDialog } from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
const STORAGE_KEY = 'vega_sidebar_store';
|
const STORAGE_KEY = 'vega_sidebar_store';
|
||||||
|
|
||||||
@@ -25,6 +27,7 @@ export enum ViewType {
|
|||||||
Withdraw = 'Withdraw',
|
Withdraw = 'Withdraw',
|
||||||
Transfer = 'Transfer',
|
Transfer = 'Transfer',
|
||||||
Settings = 'Settings',
|
Settings = 'Settings',
|
||||||
|
ViewAs = 'ViewAs',
|
||||||
}
|
}
|
||||||
|
|
||||||
type SidebarView =
|
type SidebarView =
|
||||||
@@ -52,6 +55,8 @@ type SidebarView =
|
|||||||
|
|
||||||
export const Sidebar = () => {
|
export const Sidebar = () => {
|
||||||
const navClasses = 'flex lg:flex-col items-center gap-2 lg:gap-4 p-1';
|
const navClasses = 'flex lg:flex-col items-center gap-2 lg:gap-4 p-1';
|
||||||
|
const setViewAsDialogOpen = useViewAsDialog((state) => state.setOpen);
|
||||||
|
const { pubKeys } = useVegaWallet();
|
||||||
return (
|
return (
|
||||||
<div className="flex lg:flex-col gap-2 h-full p-1" data-testid="sidebar">
|
<div className="flex lg:flex-col gap-2 h-full p-1" data-testid="sidebar">
|
||||||
<nav className={navClasses}>
|
<nav className={navClasses}>
|
||||||
@@ -104,6 +109,16 @@ export const Sidebar = () => {
|
|||||||
</Routes>
|
</Routes>
|
||||||
</nav>
|
</nav>
|
||||||
<nav className={classNames(navClasses, 'ml-auto lg:mt-auto lg:ml-0')}>
|
<nav className={classNames(navClasses, 'ml-auto lg:mt-auto lg:ml-0')}>
|
||||||
|
<SidebarButton
|
||||||
|
view={ViewType.ViewAs}
|
||||||
|
onClick={() => {
|
||||||
|
setViewAsDialogOpen(true);
|
||||||
|
}}
|
||||||
|
icon={VegaIconNames.EYE}
|
||||||
|
tooltip={t('View as party')}
|
||||||
|
disabled={Boolean(pubKeys)}
|
||||||
|
/>
|
||||||
|
|
||||||
<SidebarButton
|
<SidebarButton
|
||||||
view={ViewType.Settings}
|
view={ViewType.Settings}
|
||||||
icon={VegaIconNames.COG}
|
icon={VegaIconNames.COG}
|
||||||
@@ -115,25 +130,43 @@ export const Sidebar = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SidebarButton = ({
|
export const SidebarButton = ({
|
||||||
view,
|
view,
|
||||||
icon,
|
icon,
|
||||||
tooltip,
|
tooltip,
|
||||||
|
disabled = false,
|
||||||
|
onClick,
|
||||||
}: {
|
}: {
|
||||||
view: ViewType;
|
view?: ViewType;
|
||||||
icon: VegaIconNames;
|
icon: VegaIconNames;
|
||||||
tooltip: string;
|
tooltip: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
onClick?: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { currView, setView } = useSidebar((store) => ({
|
const { currView, setView } = useSidebar((store) => ({
|
||||||
currView: store.view,
|
currView: store.view,
|
||||||
setView: store.setView,
|
setView: store.setView,
|
||||||
}));
|
}));
|
||||||
const buttonClasses = classNames('flex items-center p-1 rounded', {
|
|
||||||
'text-vega-clight-200 dark:text-vega-cdark-200 hover:bg-vega-clight-500 dark:hover:bg-vega-cdark-500':
|
const onSelect = (view: SidebarView['type']) => {
|
||||||
view !== currView?.type,
|
if (view === currView?.type) {
|
||||||
'bg-vega-yellow hover:bg-vega-yellow-550 text-black':
|
setView(null);
|
||||||
view === currView?.type,
|
} else {
|
||||||
});
|
setView({ type: view });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttonClasses = classNames(
|
||||||
|
'flex items-center p-1 rounded',
|
||||||
|
'disabled:cursor-not-allowed disabled:text-vega-clight-500 dark:disabled:text-vega-cdark-500',
|
||||||
|
{
|
||||||
|
'text-vega-clight-200 dark:text-vega-cdark-200 enabled:hover:bg-vega-clight-500 dark:enabled:hover:bg-vega-cdark-500':
|
||||||
|
!view || view !== currView?.type,
|
||||||
|
'bg-vega-yellow enabled:hover:bg-vega-yellow-550 text-black':
|
||||||
|
view && view === currView?.type,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
description={tooltip}
|
description={tooltip}
|
||||||
@@ -145,13 +178,8 @@ const SidebarButton = ({
|
|||||||
<button
|
<button
|
||||||
className={buttonClasses}
|
className={buttonClasses}
|
||||||
data-testid={view}
|
data-testid={view}
|
||||||
onClick={() => {
|
onClick={onClick || (() => onSelect(view as SidebarView['type']))}
|
||||||
if (view === currView?.type) {
|
disabled={disabled}
|
||||||
setView(null);
|
|
||||||
} else {
|
|
||||||
setView({ type: view });
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<VegaIcon name={icon} size={20} />
|
<VegaIcon name={icon} size={20} />
|
||||||
</button>
|
</button>
|
||||||
@@ -184,6 +212,7 @@ export const SidebarContent = () => {
|
|||||||
setView({ type: ViewType.Deposit, assetId })
|
setView({ type: ViewType.Deposit, assetId })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<GetStarted />
|
||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -207,6 +236,7 @@ export const SidebarContent = () => {
|
|||||||
return (
|
return (
|
||||||
<ContentWrapper title={t('Deposit')}>
|
<ContentWrapper title={t('Deposit')}>
|
||||||
<DepositContainer assetId={view.assetId} />
|
<DepositContainer assetId={view.assetId} />
|
||||||
|
<GetStarted />
|
||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -215,6 +245,7 @@ export const SidebarContent = () => {
|
|||||||
return (
|
return (
|
||||||
<ContentWrapper title={t('Withdraw')}>
|
<ContentWrapper title={t('Withdraw')}>
|
||||||
<WithdrawContainer assetId={view.assetId} />
|
<WithdrawContainer assetId={view.assetId} />
|
||||||
|
<GetStarted />
|
||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -223,6 +254,7 @@ export const SidebarContent = () => {
|
|||||||
return (
|
return (
|
||||||
<ContentWrapper title={t('Transfer')}>
|
<ContentWrapper title={t('Transfer')}>
|
||||||
<TransferContainer assetId={view.assetId} />
|
<TransferContainer assetId={view.assetId} />
|
||||||
|
<GetStarted />
|
||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -277,7 +309,7 @@ export const useSidebar = create<{
|
|||||||
view: null,
|
view: null,
|
||||||
setView: (x) =>
|
setView: (x) =>
|
||||||
set(() => {
|
set(() => {
|
||||||
if (x === null) {
|
if (x == null) {
|
||||||
return { view: null, init: false };
|
return { view: null, init: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './stop-orders-container';
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { StopOrdersManager } from '@vegaprotocol/orders';
|
||||||
|
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
|
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||||
|
import { create } from 'zustand';
|
||||||
|
import { persist } from 'zustand/middleware';
|
||||||
|
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
||||||
|
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||||
|
|
||||||
|
export const StopOrdersContainer = () => {
|
||||||
|
const { pubKey, isReadOnly } = useVegaWallet();
|
||||||
|
const onMarketClick = useMarketClickHandler(true);
|
||||||
|
|
||||||
|
const gridStore = useStopOrdersStore((store) => store.gridStore);
|
||||||
|
const updateGridStore = useStopOrdersStore((store) => store.updateGridStore);
|
||||||
|
|
||||||
|
const gridStoreCallbacks = useDataGridEvents(gridStore, (colState) => {
|
||||||
|
updateGridStore(colState);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!pubKey) {
|
||||||
|
return <Splash>{t('Please connect Vega wallet')}</Splash>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StopOrdersManager
|
||||||
|
partyId={pubKey}
|
||||||
|
onMarketClick={onMarketClick}
|
||||||
|
isReadOnly={isReadOnly}
|
||||||
|
gridProps={gridStoreCallbacks}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStopOrdersStore = create<DataGridSlice>()(
|
||||||
|
persist(createDataGridSlice, {
|
||||||
|
name: 'vega_fills_store',
|
||||||
|
})
|
||||||
|
);
|
||||||
+10
@@ -27,6 +27,16 @@ describe('VegaWalletConnectButton', () => {
|
|||||||
it('should fire dialog when not connected', () => {
|
it('should fire dialog when not connected', () => {
|
||||||
render(generateJsx({ pubKey: null } as VegaWalletContextShape));
|
render(generateJsx({ pubKey: null } as VegaWalletContextShape));
|
||||||
|
|
||||||
|
const button = screen.getByTestId('connect-vega-wallet');
|
||||||
|
expect(button).toHaveTextContent('Get started');
|
||||||
|
fireEvent.click(button);
|
||||||
|
expect(mockUpdateDialogOpen).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render "Connect" when browser wallet is detected', () => {
|
||||||
|
window.vega = window.vega || ({} as Vega);
|
||||||
|
render(generateJsx({ pubKey: null } as VegaWalletContextShape));
|
||||||
|
|
||||||
const button = screen.getByTestId('connect-vega-wallet');
|
const button = screen.getByTestId('connect-vega-wallet');
|
||||||
expect(button).toHaveTextContent('Connect');
|
expect(button).toHaveTextContent('Connect');
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||||
|
import { isBrowserWalletInstalled } from '@vegaprotocol/wallet';
|
||||||
import { truncateByChars } from '@vegaprotocol/utils';
|
import { truncateByChars } from '@vegaprotocol/utils';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import {
|
import {
|
||||||
@@ -37,7 +38,7 @@ export const VegaWalletConnectButton = () => {
|
|||||||
fetchPubKeys,
|
fetchPubKeys,
|
||||||
} = useVegaWallet();
|
} = useVegaWallet();
|
||||||
const isConnected = pubKey !== null;
|
const isConnected = pubKey !== null;
|
||||||
|
const walletInstalled = isBrowserWalletInstalled();
|
||||||
const activeKey = useMemo(() => {
|
const activeKey = useMemo(() => {
|
||||||
return pubKeys?.find((pk) => pk.publicKey === pubKey);
|
return pubKeys?.find((pk) => pk.publicKey === pubKey);
|
||||||
}, [pubKey, pubKeys]);
|
}, [pubKey, pubKeys]);
|
||||||
@@ -118,7 +119,9 @@ export const VegaWalletConnectButton = () => {
|
|||||||
intent={Intent.None}
|
intent={Intent.None}
|
||||||
icon={<VegaIcon name={VegaIconNames.ARROW_RIGHT} size={14} />}
|
icon={<VegaIcon name={VegaIconNames.ARROW_RIGHT} size={14} />}
|
||||||
>
|
>
|
||||||
<span className="whitespace-nowrap uppercase">{t('Connect')}</span>
|
<span className="whitespace-nowrap uppercase">
|
||||||
|
{walletInstalled ? t('Connect') : t('Get started')}
|
||||||
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||||
|
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||||
|
import { GetStarted } from './get-started';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
|
||||||
|
describe('GetStarted', () => {
|
||||||
|
const renderComponent = (context: Partial<VegaWalletContextShape> = {}) => {
|
||||||
|
return render(
|
||||||
|
<VegaWalletContext.Provider value={context as VegaWalletContextShape}>
|
||||||
|
<GetStarted />
|
||||||
|
</VegaWalletContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders full get started content if not connected and no browser wallet detected', () => {
|
||||||
|
renderComponent();
|
||||||
|
expect(screen.getByTestId('get-started-banner')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders connect prompt if no pubKey but wallet installed', () => {
|
||||||
|
globalThis.window.vega = {} as Vega;
|
||||||
|
renderComponent();
|
||||||
|
expect(screen.getByTestId('order-connect-wallet')).toBeInTheDocument();
|
||||||
|
globalThis.window.vega = undefined as unknown as Vega;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders nothing if connected', () => {
|
||||||
|
const { container } = renderComponent({ pubKey: 'my-pubkey' });
|
||||||
|
expect(container).toBeEmptyDOMElement();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { ExternalLink, Intent, TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import {
|
||||||
|
useVegaWallet,
|
||||||
|
useVegaWalletDialogStore,
|
||||||
|
isBrowserWalletInstalled,
|
||||||
|
} from '@vegaprotocol/wallet';
|
||||||
|
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||||
|
import { useLocalStorage } from '@vegaprotocol/react-helpers';
|
||||||
|
import * as constants from '../constants';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
lead?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GetStarted = ({ lead }: Props) => {
|
||||||
|
const { pubKey } = useVegaWallet();
|
||||||
|
const { VEGA_ENV, VEGA_NETWORKS } = useEnvironment();
|
||||||
|
const CANONICAL_URL = VEGA_NETWORKS[VEGA_ENV] || 'https://console.vega.xyz';
|
||||||
|
|
||||||
|
const [, setOnboardingViewed] = useLocalStorage(
|
||||||
|
constants.ONBOARDING_VIEWED_KEY
|
||||||
|
);
|
||||||
|
|
||||||
|
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||||
|
(store) => store.openVegaWalletDialog
|
||||||
|
);
|
||||||
|
|
||||||
|
const onButtonClick = () => {
|
||||||
|
openVegaWalletDialog();
|
||||||
|
setOnboardingViewed('true');
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapperClasses = classNames(
|
||||||
|
'flex flex-col py-4 px-6 gap-4 rounded',
|
||||||
|
'bg-vega-blue-300 dark:bg-vega-blue-700',
|
||||||
|
'border border-vega-blue-350 dark:border-vega-blue-650',
|
||||||
|
{ 'mt-8': !lead }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!pubKey && !isBrowserWalletInstalled()) {
|
||||||
|
return (
|
||||||
|
<div className={wrapperClasses} data-testid="get-started-banner">
|
||||||
|
{lead && <h2>{lead}</h2>}
|
||||||
|
<h3 className="text-lg">{t('Get started')}</h3>
|
||||||
|
<div>
|
||||||
|
<ul className="list-decimal list-inside">
|
||||||
|
<li>{t('Get a Vega wallet')}</li>
|
||||||
|
<li>{t('Connect')}</li>
|
||||||
|
<li>{t('Deposit funds')}</li>
|
||||||
|
<li>{t('Open a position')}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<TradingButton
|
||||||
|
intent={Intent.Info}
|
||||||
|
onClick={onButtonClick}
|
||||||
|
data-testid="get-started-button"
|
||||||
|
>
|
||||||
|
{t('Get started')}
|
||||||
|
</TradingButton>
|
||||||
|
</div>
|
||||||
|
{VEGA_ENV === Networks.MAINNET && (
|
||||||
|
<p className="text-sm">
|
||||||
|
{t('Experiment for free with virtual assets on')}{' '}
|
||||||
|
<ExternalLink href={CANONICAL_URL}>
|
||||||
|
{t('Fairground Testnet')}
|
||||||
|
</ExternalLink>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{VEGA_ENV === Networks.TESTNET && (
|
||||||
|
<p className="text-sm">
|
||||||
|
{t('Ready to trade with real funds?')}{' '}
|
||||||
|
<ExternalLink href={CANONICAL_URL}>
|
||||||
|
{t('Switch to Mainnet')}
|
||||||
|
</ExternalLink>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pubKey) {
|
||||||
|
return (
|
||||||
|
<div className={wrapperClasses}>
|
||||||
|
<p className="text-sm mb-1">
|
||||||
|
You need a{' '}
|
||||||
|
<ExternalLink href="https://vega.xyz/wallet">
|
||||||
|
Vega wallet
|
||||||
|
</ExternalLink>{' '}
|
||||||
|
to start trading in this market.
|
||||||
|
</p>
|
||||||
|
<TradingButton
|
||||||
|
onClick={openVegaWalletDialog}
|
||||||
|
size="small"
|
||||||
|
data-testid="order-connect-wallet"
|
||||||
|
intent={Intent.Info}
|
||||||
|
>
|
||||||
|
{t('Connect wallet')}
|
||||||
|
</TradingButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './welcome-dialog';
|
export * from './welcome-dialog';
|
||||||
export * from './risk-message';
|
export * from './risk-message';
|
||||||
|
export * from './get-started';
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
import { render, screen, fireEvent } from '@testing-library/react';
|
|
||||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
|
||||||
import { RiskNoticeDialog } from './risk-notice-dialog';
|
|
||||||
|
|
||||||
jest.mock('@vegaprotocol/environment');
|
|
||||||
|
|
||||||
const mockEnvDefinitions = {
|
|
||||||
VEGA_CONFIG_URL: 'https://config.url',
|
|
||||||
VEGA_URL: 'https://test.url',
|
|
||||||
VEGA_NETWORKS: JSON.stringify({}),
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Risk notice dialog', () => {
|
|
||||||
const mockOnClose = jest.fn();
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each`
|
|
||||||
assertion | network
|
|
||||||
${'displays'} | ${Networks.CUSTOM}
|
|
||||||
${'displays'} | ${Networks.DEVNET}
|
|
||||||
${'displays'} | ${Networks.TESTNET}
|
|
||||||
`(
|
|
||||||
'$assertion a generic message on $network',
|
|
||||||
async ({ assertion, network }) => {
|
|
||||||
// @ts-ignore ignore mock implementation
|
|
||||||
useEnvironment.mockImplementation(() => ({
|
|
||||||
...mockEnvDefinitions,
|
|
||||||
VEGA_ENV: network,
|
|
||||||
}));
|
|
||||||
|
|
||||||
render(<RiskNoticeDialog onClose={mockOnClose} network={network} />);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
screen.getByText(
|
|
||||||
new RegExp(
|
|
||||||
`This application for trading on Vega is connected to ${network}`
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).toBeInTheDocument();
|
|
||||||
|
|
||||||
const button = screen.getByRole('button', {
|
|
||||||
name: 'Continue',
|
|
||||||
});
|
|
||||||
fireEvent.click(button);
|
|
||||||
expect(mockOnClose).toHaveBeenCalled();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user