Compare commits
116
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
024be309b5 | ||
|
|
e62f5f8ea2 | ||
|
|
10e1315afa | ||
|
|
4ddacb5269 | ||
|
|
597a1fa878 | ||
|
|
3bf5d823ee | ||
|
|
df3b79478e | ||
|
|
f383dedb24 | ||
|
|
592ec14b26 | ||
|
|
76126ae386 | ||
|
|
c211c179b6 | ||
|
|
4818b57fb2 | ||
|
|
70df56f745 | ||
|
|
2b76e7d5c8 | ||
|
|
947180a6a6 | ||
|
|
d25755474f | ||
|
|
888cbbec68 | ||
|
|
46884e3fec | ||
|
|
589c15de9d | ||
|
|
0271e62439 | ||
|
|
84a5cbd44b | ||
|
|
a386ea5cad | ||
|
|
599ee1a360 | ||
|
|
d176285021 | ||
|
|
40337ee698 | ||
|
|
d47d754ac9 | ||
|
|
666fe9aebb | ||
|
|
b8d5680011 | ||
|
|
4aa9bbaa23 | ||
|
|
9385e0f4c3 | ||
|
|
03df9e9c5d | ||
|
|
e8d110d207 | ||
|
|
6c41c0b14d | ||
|
|
e4f175b691 | ||
|
|
4b6c7f062d | ||
|
|
2fa80f65d0 | ||
|
|
7fb3a23a5a | ||
|
|
9169165a03 | ||
|
|
608ecf36af | ||
|
|
df29c9ee72 | ||
|
|
e3809f5bc3 | ||
|
|
ff317f1c3a | ||
|
|
e6b7f73be2 | ||
|
|
d65bdb1482 | ||
|
|
ff7c501621 | ||
|
|
60f286c8af | ||
|
|
a2c8c5a9c4 | ||
|
|
2eea3e2e34 | ||
|
|
040cf0b83b | ||
|
|
9d2f2fe3aa | ||
|
|
a08f63c7d8 | ||
|
|
3ff5bbb5a7 | ||
|
|
535bdb5183 | ||
|
|
4505e86363 | ||
|
|
7b2e86f32e | ||
|
|
f34edf1862 | ||
|
|
d8512afb2b | ||
|
|
549e0e004d | ||
|
|
8b08e48840 | ||
|
|
846f9114d8 | ||
|
|
a9216c12a3 | ||
|
|
d85c5d7c1f | ||
|
|
7675fe0ab0 | ||
|
|
bd51564207 | ||
|
|
fac08bc831 | ||
|
|
a34ea77488 | ||
|
|
e50afc64ff | ||
|
|
9f4bf97465 | ||
|
|
dc59f56a6f | ||
|
|
8a9372c88a | ||
|
|
8563625079 | ||
|
|
946ee9423b | ||
|
|
e3aa1e40c8 | ||
|
|
179d34ff40 | ||
|
|
7613a9fa9f | ||
|
|
1beaad5759 | ||
|
|
8958db0612 | ||
|
|
4db77a8e8a | ||
|
|
097cf5da94 | ||
|
|
3f1ea6b83d | ||
|
|
93f41d429f | ||
|
|
37aa5be725 | ||
|
|
65528a8007 | ||
|
|
87ae478b9c | ||
|
|
dc59859964 | ||
|
|
621feada26 | ||
|
|
bb81c1786c | ||
|
|
760be23c27 | ||
|
|
19e12145cb | ||
|
|
c83b5bf93c | ||
|
|
9f6376c1b2 | ||
|
|
b5271d07e4 | ||
|
|
6ddf706cf2 | ||
|
|
d2791f2e59 | ||
|
|
9de3683bf3 | ||
|
|
293e2ffbc3 | ||
|
|
beeb1db1e1 | ||
|
|
cae6162a7f | ||
|
|
fa6ddcfdf1 | ||
|
|
e06b5e741c | ||
|
|
925c1721aa | ||
|
|
002b11eb4a | ||
|
|
bc1324aafe | ||
|
|
510b6ad0d5 | ||
|
|
e97f82edfe | ||
|
|
bacd2a509e | ||
|
|
f401870848 | ||
|
|
a5f21ed1f8 | ||
|
|
a57d484496 | ||
|
|
b531094fda | ||
|
|
7fe282a9fb | ||
|
|
5eb06254de | ||
|
|
578d6ecf6f | ||
|
|
744c084ca2 | ||
|
|
adec04918e | ||
|
|
9cb84df35c |
+3
-3
@@ -51,8 +51,7 @@
|
||||
"ul": ["list"],
|
||||
"ol": ["list"]
|
||||
}
|
||||
],
|
||||
"curly": "warn"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -75,7 +74,8 @@
|
||||
"prefer": "type-imports",
|
||||
"disallowTypeAnnotations": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"curly": ["error", "multi-line"]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
name: "\U0001F41B Bug"
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: "\U0001F41B bug"
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
## Expected behavior
|
||||
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
## Screenshots
|
||||
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
## Device details
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
## Additional context
|
||||
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: Chore
|
||||
about:
|
||||
A template to capture non feature / enhancement work we need to do like work
|
||||
to support other functions or housekeeping etc.
|
||||
title: ''
|
||||
labels: chore
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## The Chore
|
||||
|
||||
What we need to achieve and who for
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] What do we need to do first
|
||||
- [ ] and then what?
|
||||
- [ ] Etc.
|
||||
|
||||
## Additional details / background info
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: User Story
|
||||
about:
|
||||
A template to describe a features or enhancements we want to make from a users
|
||||
perspective to ensure we understand what is needed and the value it would add
|
||||
title: ''
|
||||
labels: feature
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## Story
|
||||
|
||||
As a
|
||||
I want
|
||||
So that
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] I can
|
||||
- [ ] I can
|
||||
- [ ] I can
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Explore and sketch
|
||||
- [ ] Team and stakeholder review
|
||||
- [ ] Visual Design
|
||||
- [ ] Team review
|
||||
- [ ] Etc.
|
||||
|
||||
## Sketch
|
||||
|
||||
## Additional details / background info
|
||||
@@ -47,6 +47,14 @@ jobs:
|
||||
## Checkout capsule
|
||||
#######
|
||||
|
||||
# Checkout front ends
|
||||
- name: Checkout frontend mono repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
fetch-depth: 0
|
||||
path: './frontend-monorepo'
|
||||
|
||||
# Checkout capsule to build local network
|
||||
- name: Checkout capsule
|
||||
uses: actions/checkout@v2
|
||||
@@ -70,7 +78,7 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vegaprotocol/vega
|
||||
ref: develop
|
||||
ref: v0.55.0
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './vega'
|
||||
|
||||
@@ -120,23 +128,19 @@ jobs:
|
||||
## Run some tests
|
||||
######
|
||||
|
||||
# Checkout front ends
|
||||
- name: Checkout frontend mono repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: yarn nx run ${{ github.event.inputs.project }}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
|
||||
run: yarn nx run ${{ github.event.inputs.project }}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
working-directory: frontend-monorepo
|
||||
env:
|
||||
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
|
||||
CYPRESS_INCLUDE_FLOWS: ${{ github.event.inputs.includeFlows }}
|
||||
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
|
||||
@@ -31,6 +31,14 @@ jobs:
|
||||
## Checkout capsule
|
||||
#######
|
||||
|
||||
# Checkout front ends
|
||||
- name: Checkout frontend mono repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
fetch-depth: 0
|
||||
path: './frontend-monorepo'
|
||||
|
||||
# Checkout capsule to build local network
|
||||
- name: Checkout capsule
|
||||
uses: actions/checkout@v2
|
||||
@@ -54,7 +62,7 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vegaprotocol/vega
|
||||
ref: develop
|
||||
ref: v0.55.0
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './vega'
|
||||
|
||||
@@ -104,24 +112,20 @@ jobs:
|
||||
## Run some tests
|
||||
######
|
||||
|
||||
# Checkout front ends
|
||||
- name: Checkout frontend mono repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: master
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: yarn nx run-many --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
|
||||
run: yarn nx run-many --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
working-directory: frontend-monorepo
|
||||
env:
|
||||
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
|
||||
CYPRESS_NIGHTLY_RUN: true
|
||||
CYPRESS_INCLUDE_FLOWS: true
|
||||
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vegaprotocol/vega
|
||||
ref: develop
|
||||
ref: v0.54.0
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './vega'
|
||||
|
||||
@@ -130,13 +130,14 @@ jobs:
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: npx nx affected:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
|
||||
run: npx nx affected:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
working-directory: frontend-monorepo
|
||||
env:
|
||||
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPESS_ETH_WALLET_MNEMONIC }}
|
||||
CYPRESS_INCLUDE_FLOWS: false
|
||||
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v2
|
||||
with:
|
||||
main-branch-name: master
|
||||
main-branch-name: develop
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v3
|
||||
|
||||
@@ -6,7 +6,3 @@ yarn commitlint --edit "${1}"
|
||||
|
||||
# Lint all staged files
|
||||
yarn lint-staged
|
||||
|
||||
# Build & test affected apps
|
||||
yarn nx affected:build --uncommitted
|
||||
yarn nx affected:test --uncommitted
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/dist
|
||||
/coverage
|
||||
__generated__
|
||||
__generated___
|
||||
|
||||
apps/static/src/assets/devnet-tranches.json
|
||||
apps/static/src/assets/mainnet-tranches.json
|
||||
|
||||
@@ -69,10 +69,10 @@ Run `nx serve my-app` for a dev server. Navigate to the port specified in `app/<
|
||||
|
||||
### Using Apollo GraphQL and Generate Types
|
||||
|
||||
In order to generate the schemas for your GraphQL queries, you can run `NX_VEGA_URL=[YOUR URL HERE] nx run types:generate`.
|
||||
In order to generate the schemas for your GraphQL queries, you can run `GRAPHQL_SCHEMA_PATH=[YOUR SCHEMA FILE / API URL HERE] nx run types:generate`.
|
||||
|
||||
```bash
|
||||
export NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
|
||||
export GRAPHQL_SCHEMA_PATH=https://api.n11.testnet.vega.xyz/graphql
|
||||
yarn nx run types:generate
|
||||
```
|
||||
|
||||
|
||||
@@ -23,5 +23,4 @@ NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
|
||||
|
||||
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_REST=https://api.n11.testnet.vega.xyz
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789/api/v1
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import { aliasQuery } from '@vegaprotocol/cypress';
|
||||
import type { Markets } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
generateLongListMarkets,
|
||||
generateSimpleMarkets,
|
||||
generateMarketsData,
|
||||
generateMarketsCandles,
|
||||
} from '../support/mocks/generate-markets';
|
||||
|
||||
describe('market list', () => {
|
||||
describe('simple url', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'Markets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
|
||||
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
|
||||
});
|
||||
cy.visit('/markets');
|
||||
});
|
||||
@@ -62,7 +67,9 @@ describe('market list', () => {
|
||||
describe('url params should select filters', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'Markets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
|
||||
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,10 +80,11 @@ describe('market list', () => {
|
||||
|
||||
it('last asset (if exists)', () => {
|
||||
cy.visit('/markets');
|
||||
cy.wait('@SimpleMarkets').then((filters) => {
|
||||
if (filters?.response?.body?.data?.markets?.length) {
|
||||
cy.wait('@Markets').then((filters) => {
|
||||
const data: Markets | undefined = filters?.response?.body?.data;
|
||||
if (data.marketsConnection.edges.length) {
|
||||
const asset =
|
||||
filters.response.body.data.markets[0].tradableInstrument.instrument
|
||||
data.marketsConnection.edges[0].node.tradableInstrument.instrument
|
||||
.product.settlementAsset.symbol;
|
||||
cy.visit(`/markets/Suspended/Future/${asset}`);
|
||||
cy.getByTestId('market-assets-menu')
|
||||
@@ -98,7 +106,9 @@ describe('market list', () => {
|
||||
it('handles 1000 markets', () => {
|
||||
cy.viewport(1440, 900);
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'SimpleMarkets', generateLongListMarkets(1000));
|
||||
aliasQuery(req, 'Markets', generateLongListMarkets(1000));
|
||||
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
|
||||
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
|
||||
});
|
||||
performance.mark('start-1k');
|
||||
cy.visit('/markets');
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { connectVegaWallet } from '../support/connect-wallet';
|
||||
import { aliasQuery } from '@vegaprotocol/cypress';
|
||||
import { generateSimpleMarkets } from '../support/mocks/generate-markets';
|
||||
import {
|
||||
generateMarketsCandles,
|
||||
generateMarketsData,
|
||||
generateSimpleMarkets,
|
||||
} from '../support/mocks/generate-markets';
|
||||
import { generateDealTicket } from '../support/mocks/generate-deal-ticket';
|
||||
import { generateMarketTags } from '../support/mocks/generate-market-tags';
|
||||
import { generateMarketPositions } from '../support/mocks/generate-market-positions';
|
||||
@@ -9,12 +13,16 @@ import { generatePartyBalance } from '../support/mocks/generate-party-balance';
|
||||
import { generatePartyMarketData } from '../support/mocks/generate-party-market-data';
|
||||
import { generateMarketMarkPrice } from '../support/mocks/generate-market-mark-price';
|
||||
import { generateMarketNames } from '../support/mocks/generate-market-names';
|
||||
import { generateMarketDepth } from '../support/mocks/generate-market-depth';
|
||||
import type { Market, Markets } from '@vegaprotocol/market-list';
|
||||
|
||||
describe('market selector', () => {
|
||||
let markets;
|
||||
let markets: Market[];
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'Markets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
|
||||
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
|
||||
aliasQuery(req, 'DealTicketQuery', generateDealTicket());
|
||||
aliasQuery(req, 'MarketTags', generateMarketTags());
|
||||
aliasQuery(req, 'MarketPositions', generateMarketPositions());
|
||||
@@ -23,12 +31,14 @@ describe('market selector', () => {
|
||||
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
|
||||
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
|
||||
aliasQuery(req, 'MarketNames', generateMarketNames());
|
||||
aliasQuery(req, 'MarketDepth', generateMarketDepth());
|
||||
});
|
||||
|
||||
cy.visit('/markets');
|
||||
cy.wait('@SimpleMarkets').then((response) => {
|
||||
if (response.response.body.data?.markets?.length) {
|
||||
markets = response.response.body.data.markets;
|
||||
cy.wait('@Markets').then((response) => {
|
||||
const data: Markets | undefined = response?.response?.body?.data;
|
||||
if (data.marketsConnection.edges.length) {
|
||||
markets = data.marketsConnection.edges.map((edge) => edge.node);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -39,7 +49,7 @@ describe('market selector', () => {
|
||||
connectVegaWallet();
|
||||
cy.get('input[placeholder="Search"]').should(
|
||||
'have.value',
|
||||
markets[0].name
|
||||
markets[0].tradableInstrument.instrument.name
|
||||
);
|
||||
cy.getByTestId('arrow-button').click();
|
||||
cy.getByTestId('market-pane').should('be.visible');
|
||||
@@ -47,7 +57,7 @@ describe('market selector', () => {
|
||||
.children()
|
||||
.find('[role="button"]')
|
||||
.first()
|
||||
.should('contain.text', markets[0].name);
|
||||
.should('contain.text', markets[0].tradableInstrument.instrument.name);
|
||||
cy.getByTestId('market-pane')
|
||||
.children()
|
||||
.find('[role="button"]')
|
||||
@@ -70,8 +80,8 @@ describe('market selector', () => {
|
||||
cy.get('input[placeholder="Search"]').type('aa');
|
||||
const filtered = markets.filter(
|
||||
(market) =>
|
||||
market.data.market.state === 'STATE_ACTIVE' &&
|
||||
market.name.match(/aa/i)
|
||||
market.state === 'STATE_ACTIVE' &&
|
||||
market.tradableInstrument.instrument.name.match(/aa/i)
|
||||
);
|
||||
cy.getByTestId('market-pane')
|
||||
.children()
|
||||
@@ -88,7 +98,7 @@ describe('market selector', () => {
|
||||
);
|
||||
cy.get('input[placeholder="Search"]').should(
|
||||
'have.value',
|
||||
filtered[filtered.length - 1].name
|
||||
filtered[filtered.length - 1].tradableInstrument.instrument.name
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -126,12 +136,12 @@ describe('market selector', () => {
|
||||
cy.getByTestId('market-pane')
|
||||
.children()
|
||||
.find('[role="button"]')
|
||||
.should('have.length', 3);
|
||||
.should('have.length', 9);
|
||||
cy.get('div[role="dialog"]').should('have.class', 'w-screen');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
cy.get('input[placeholder="Search"]').should(
|
||||
'have.value',
|
||||
markets[0].name
|
||||
markets[0].tradableInstrument.instrument.name
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { aliasQuery } from '@vegaprotocol/cypress';
|
||||
import { generateSimpleMarkets } from '../support/mocks/generate-markets';
|
||||
import {
|
||||
generateSimpleMarkets,
|
||||
generateMarketsCandles,
|
||||
generateMarketsData,
|
||||
} from '../support/mocks/generate-markets';
|
||||
import { generateDealTicket } from '../support/mocks/generate-deal-ticket';
|
||||
import { generateMarketTags } from '../support/mocks/generate-market-tags';
|
||||
import { generateMarketPositions } from '../support/mocks/generate-market-positions';
|
||||
@@ -9,11 +13,15 @@ import { generatePartyMarketData } from '../support/mocks/generate-party-market-
|
||||
import { generateMarketMarkPrice } from '../support/mocks/generate-market-mark-price';
|
||||
import { generateMarketDepth } from '../support/mocks/generate-market-depth';
|
||||
import { connectVegaWallet } from '../support/connect-wallet';
|
||||
import type { Markets, Market } from '@vegaprotocol/market-list';
|
||||
|
||||
describe('Market trade', () => {
|
||||
let markets;
|
||||
let markets: Market[];
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'Markets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles());
|
||||
aliasQuery(req, 'MarketsDataQuery', generateMarketsData());
|
||||
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'DealTicketQuery', generateDealTicket());
|
||||
aliasQuery(req, 'MarketTags', generateMarketTags());
|
||||
@@ -25,9 +33,10 @@ describe('Market trade', () => {
|
||||
aliasQuery(req, 'MarketDepth', generateMarketDepth());
|
||||
});
|
||||
cy.visit('/markets');
|
||||
cy.wait('@SimpleMarkets').then((response) => {
|
||||
if (response.response.body.data?.markets?.length) {
|
||||
markets = response.response.body.data.markets;
|
||||
cy.wait('@Markets').then((response) => {
|
||||
const data: Markets | undefined = response?.response?.body?.data;
|
||||
if (data.marketsConnection.edges.length) {
|
||||
markets = data.marketsConnection.edges.map((edge) => edge.node);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -170,7 +179,50 @@ describe('Market trade', () => {
|
||||
.find('button')
|
||||
.should('have.text', '2');
|
||||
cy.get('button').contains('Max').click();
|
||||
cy.getByTestId('price-slippage-value').should('have.text', '0.02%');
|
||||
}
|
||||
});
|
||||
|
||||
it('slippage value should be displayed', () => {
|
||||
if (markets?.length) {
|
||||
cy.visit(`/trading/${markets[1].id}`);
|
||||
connectVegaWallet();
|
||||
cy.get('#step-1-control [aria-label^="Selected value"]').click();
|
||||
cy.get('button[aria-label="Open short position"]').click();
|
||||
cy.get('#step-2-control').click();
|
||||
cy.get('button').contains('Max').click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dl')
|
||||
.eq(2)
|
||||
.find('dd')
|
||||
.should('have.text', '0.02%');
|
||||
}
|
||||
});
|
||||
|
||||
it('allow slippage value to be adjusted', () => {
|
||||
if (markets?.length) {
|
||||
cy.visit(`/trading/${markets[1].id}`);
|
||||
connectVegaWallet();
|
||||
cy.get('#step-1-control [aria-label^="Selected value"]').click();
|
||||
cy.get('button[aria-label="Open short position"]').click();
|
||||
cy.get('#step-2-control').click();
|
||||
cy.get('button').contains('Max').click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dl')
|
||||
.eq(2)
|
||||
.find('dd')
|
||||
.should('have.text', '0.02%');
|
||||
cy.get('#step-2-panel').find('dl').eq(2).find('button').click();
|
||||
cy.get('#input-order-slippage')
|
||||
.focus()
|
||||
.type('{backspace}{backspace}{backspace}1');
|
||||
|
||||
cy.getByTestId('slippage-dialog').find('button').click();
|
||||
|
||||
cy.get('#step-2-panel')
|
||||
.find('dl')
|
||||
.eq(2)
|
||||
.find('dd')
|
||||
.should('have.text', '1%');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -195,9 +247,9 @@ describe('Market trade', () => {
|
||||
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dt')
|
||||
.eq(3)
|
||||
.eq(2)
|
||||
.should('have.text', 'Est. Position Size (tDAI)');
|
||||
cy.get('#step-2-panel').find('dd').eq(3).should('have.text', '197.86012');
|
||||
cy.get('#step-2-panel').find('dd').eq(2).should('have.text', '197.86012');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -210,11 +262,11 @@ describe('Market trade', () => {
|
||||
cy.get('#step-2-control').click();
|
||||
cy.get('#step-2-panel')
|
||||
.find('dt')
|
||||
.eq(4)
|
||||
.eq(3)
|
||||
.should('have.text', 'Est. Fees (tDAI)');
|
||||
cy.get('#step-2-panel')
|
||||
.find('dd')
|
||||
.eq(4)
|
||||
.eq(3)
|
||||
.should('have.text', '3.00000 (3.03%)');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
const protoCandles = [
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
|
||||
|
||||
export const protoCandles = [
|
||||
{ open: '9556163', close: '9587028', __typename: 'Candle' },
|
||||
{
|
||||
open: '9587028',
|
||||
@@ -73,20 +76,31 @@ const protoCandles = [
|
||||
},
|
||||
];
|
||||
|
||||
export const protoMarket = {
|
||||
export const protoMarket: Market = {
|
||||
id: 'first-btcusd-id',
|
||||
name: 'AAVEDAI Monthly (30 Jun 2022)',
|
||||
data: {
|
||||
market: {
|
||||
id: 'first-btcusd-id',
|
||||
state: 'STATE_ACTIVE',
|
||||
__typename: 'Market',
|
||||
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
marketTimestamps: {
|
||||
__typename: 'MarketTimestamps',
|
||||
close: '',
|
||||
open: '',
|
||||
},
|
||||
fees: {
|
||||
__typename: 'Fees',
|
||||
factors: {
|
||||
__typename: 'FeeFactors',
|
||||
makerFee: '',
|
||||
infrastructureFee: '',
|
||||
liquidityFee: '',
|
||||
},
|
||||
__typename: 'MarketData',
|
||||
},
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
id: '',
|
||||
code: 'AAVEDAI.MF21',
|
||||
name: 'AAVEDAI Monthly (30 Jun 2022)',
|
||||
metadata: {
|
||||
tags: [
|
||||
'formerly:2839D9B2329C9E70',
|
||||
@@ -101,12 +115,11 @@ export const protoMarket = {
|
||||
product: {
|
||||
__typename: 'Future',
|
||||
quoteName: 'DAI',
|
||||
settlementAsset: { symbol: 'tDAI', __typename: 'Asset' },
|
||||
settlementAsset: { symbol: 'tDAI', __typename: 'Asset', decimals: 5 },
|
||||
},
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
__typename: 'TradableInstrument',
|
||||
},
|
||||
candles: protoCandles,
|
||||
__typename: 'Market',
|
||||
};
|
||||
|
||||
@@ -2,13 +2,13 @@ export const generateDealTicket = () => {
|
||||
return {
|
||||
market: {
|
||||
id: 'first-btcusd-id',
|
||||
name: 'AAVEDAI Monthly (30 Jun 2022)',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
state: 'STATE_ACTIVE',
|
||||
tradingMode: 'Continuous',
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
name: 'AAVEDAI Monthly (30 Jun 2022)',
|
||||
product: {
|
||||
quoteName: 'DAI',
|
||||
settlementAsset: {
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
export const generateMarketDepth = () => {
|
||||
return {
|
||||
import merge from 'lodash/merge';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
|
||||
import type { MarketDepth } from '../../../../../libs/market-depth/src/lib/__generated__/MarketDepth';
|
||||
|
||||
export const generateMarketDepth = (
|
||||
override?: PartialDeep<MarketDepth>
|
||||
): MarketDepth => {
|
||||
const defaultResult: MarketDepth = {
|
||||
market: {
|
||||
id: 'a46bd7e5277087723b7ab835844dec3cef8b4445738101269624bf5537d5d423',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
data: {
|
||||
staticMidPrice: '9893006',
|
||||
marketTradingMode: 'TRADING_MODE_CONTINUOUS',
|
||||
indicativeVolume: '0',
|
||||
indicativePrice: '0',
|
||||
bestStaticBidPrice: '9893006',
|
||||
bestStaticOfferPrice: '9893006',
|
||||
market: {
|
||||
id: 'a46bd7e5277087723b7ab835844dec3cef8b4445738101269624bf5537d5d423',
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'MarketData',
|
||||
},
|
||||
depth: {
|
||||
lastTrade: { price: '9893006', __typename: 'Trade' },
|
||||
sell: [
|
||||
{
|
||||
price: '9893007',
|
||||
@@ -215,4 +206,5 @@ export const generateMarketDepth = () => {
|
||||
__typename: 'Market',
|
||||
},
|
||||
};
|
||||
return merge(defaultResult, override);
|
||||
};
|
||||
|
||||
@@ -6,11 +6,11 @@ export const generateMarketNames = () => {
|
||||
{ ...protoMarket },
|
||||
{
|
||||
id: '1d7ddf67dac4924db03f5bf58571a7bcb1908d70c66580467717aabc5345b68a',
|
||||
name: 'Apple Monthly (30 Jun 2022)',
|
||||
state: 'STATE_SUSPENDED',
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'AAPL.MF21',
|
||||
name: 'Apple Monthly (30 Jun 2022)',
|
||||
metadata: {
|
||||
tags: [
|
||||
'formerly:4899E01009F1A721',
|
||||
@@ -32,11 +32,11 @@ export const generateMarketNames = () => {
|
||||
},
|
||||
{
|
||||
id: '87ae87cd3244fc1fab4b0e2dad2437879864192bb969f3109b69293421644c8b',
|
||||
name: 'Tesla Quarterly (30 Jun 2022)',
|
||||
state: 'STATE_SUSPENDED',
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'TSLA.QM21',
|
||||
name: 'Tesla Quarterly (30 Jun 2022)',
|
||||
metadata: {
|
||||
tags: [
|
||||
'formerly:5A86B190C384997F',
|
||||
@@ -58,11 +58,11 @@ export const generateMarketNames = () => {
|
||||
},
|
||||
{
|
||||
id: '69205712a854f1bbfb69fa3d11b60e01a1e249bafb5ece88115e7451e8ef07b3',
|
||||
name: 'BTCUSD Monthly (30 Jun 2022)',
|
||||
state: 'STATE_SUSPENDED',
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'BTCUSD.MF21',
|
||||
name: 'BTCUSD Monthly (30 Jun 2022)',
|
||||
metadata: {
|
||||
tags: [
|
||||
'formerly:076BB86A5AA41E3E',
|
||||
@@ -83,11 +83,11 @@ export const generateMarketNames = () => {
|
||||
},
|
||||
{
|
||||
id: 'ethbtc-quaterly',
|
||||
name: 'ETHBTC Quarterly (30 Jun 2022)',
|
||||
state: 'STATE_ACTIVE',
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'ETHBTC.QM21',
|
||||
name: 'ETHBTC Quarterly (30 Jun 2022)',
|
||||
metadata: {
|
||||
tags: [
|
||||
'formerly:1F0BB6EB5703B099',
|
||||
@@ -108,11 +108,11 @@ export const generateMarketNames = () => {
|
||||
},
|
||||
{
|
||||
id: '3c62b2714c4332d1a689a5352bff090e6aabccfd6bd87ce018936b38372530c9',
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
state: 'STATE_ACTIVE',
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'UNIDAI.MF21',
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
metadata: {
|
||||
tags: [
|
||||
'formerly:3C58ED2A4A6C5D7E',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_URL=http://localhost:3028/query
|
||||
NX_VEGA_ENV=LOCAL
|
||||
NX_VEGA_REST=http://localhost:3029
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/devnet-network.json
|
||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||
NX_VEGA_ENV=DEVNET
|
||||
NX_VEGA_REST=https://api.n04.d.vega.xyz
|
||||
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"}
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/mainnet-network.json
|
||||
NX_VEGA_URL=https://api.token.vega.xyz/query
|
||||
NX_VEGA_URL=https://api.vega.xyz/query
|
||||
NX_VEGA_ENV=MAINNET
|
||||
NX_VEGA_REST=https://api.token.vega.xyz
|
||||
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
|
||||
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://etherscan.io
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
|
||||
NX_VEGA_URL=https://api.n01.stagnet3.vega.xyz/graphql
|
||||
NX_VEGA_ENV=STAGNET3
|
||||
NX_VEGA_REST=https://api.n01.stagnet3.vega.xyz
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://staging2.explorer.vega.xyz
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
|
||||
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_REST=https://api.n11.testnet.vega.xyz
|
||||
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*", "__generated__"],
|
||||
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
|
||||
@@ -1,7 +1,30 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import 'jest-canvas-mock';
|
||||
import { defaultFallbackInView } from 'react-intersection-observer';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
|
||||
defaultFallbackInView(true);
|
||||
global.ResizeObserver = ResizeObserver;
|
||||
|
||||
global.DOMRect = class DOMRect {
|
||||
bottom = 0;
|
||||
left = 0;
|
||||
right = 0;
|
||||
top = 0;
|
||||
|
||||
constructor(
|
||||
public x = 0,
|
||||
public y = 0,
|
||||
public width = 0,
|
||||
public height = 0
|
||||
) {}
|
||||
static fromRect(other?: DOMRectInit): DOMRect {
|
||||
return new DOMRect(other?.x, other?.y, other?.width, other?.height);
|
||||
}
|
||||
toJSON() {
|
||||
return JSON.stringify(this);
|
||||
}
|
||||
};
|
||||
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
@@ -16,3 +39,5 @@ Object.defineProperty(window, 'matchMedia', {
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
|
||||
jest.setTimeout(30000);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
query MarketTags($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
query PartyBalanceQuery($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarketTagsQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketTagsQuery = { __typename?: 'Query', market?: { __typename?: 'Market', tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null } } } } | null };
|
||||
|
||||
|
||||
export const MarketTagsDocument = gql`
|
||||
query MarketTags($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useMarketTagsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useMarketTagsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useMarketTagsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useMarketTagsQuery({
|
||||
* variables: {
|
||||
* marketId: // value for 'marketId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useMarketTagsQuery(baseOptions: Apollo.QueryHookOptions<MarketTagsQuery, MarketTagsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<MarketTagsQuery, MarketTagsQueryVariables>(MarketTagsDocument, options);
|
||||
}
|
||||
export function useMarketTagsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MarketTagsQuery, MarketTagsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<MarketTagsQuery, MarketTagsQueryVariables>(MarketTagsDocument, options);
|
||||
}
|
||||
export type MarketTagsQueryHookResult = ReturnType<typeof useMarketTagsQuery>;
|
||||
export type MarketTagsLazyQueryHookResult = ReturnType<typeof useMarketTagsLazyQuery>;
|
||||
export type MarketTagsQueryResult = Apollo.QueryResult<MarketTagsQuery, MarketTagsQueryVariables>;
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type PartyBalanceQueryQueryVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type PartyBalanceQueryQuery = { __typename?: 'Query', party?: { __typename?: 'Party', accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } }> | null } | null };
|
||||
|
||||
|
||||
export const PartyBalanceQueryDocument = gql`
|
||||
query PartyBalanceQuery($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __usePartyBalanceQueryQuery__
|
||||
*
|
||||
* To run a query within a React component, call `usePartyBalanceQueryQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `usePartyBalanceQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = usePartyBalanceQueryQuery({
|
||||
* variables: {
|
||||
* partyId: // value for 'partyId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function usePartyBalanceQueryQuery(baseOptions: Apollo.QueryHookOptions<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>(PartyBalanceQueryDocument, options);
|
||||
}
|
||||
export function usePartyBalanceQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>(PartyBalanceQueryDocument, options);
|
||||
}
|
||||
export type PartyBalanceQueryQueryHookResult = ReturnType<typeof usePartyBalanceQueryQuery>;
|
||||
export type PartyBalanceQueryLazyQueryHookResult = ReturnType<typeof usePartyBalanceQueryLazyQuery>;
|
||||
export type PartyBalanceQueryQueryResult = Apollo.QueryResult<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>;
|
||||
@@ -4,6 +4,7 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import * as constants from './constants';
|
||||
import { TrafficLight } from '../traffic-light';
|
||||
|
||||
interface DealTicketEstimatesProps {
|
||||
quoteName?: string;
|
||||
@@ -13,6 +14,7 @@ interface DealTicketEstimatesProps {
|
||||
fees?: string;
|
||||
notionalSize?: string;
|
||||
size?: string;
|
||||
slippage?: string;
|
||||
}
|
||||
|
||||
interface DataTitleProps {
|
||||
@@ -20,7 +22,7 @@ interface DataTitleProps {
|
||||
quoteName?: string;
|
||||
}
|
||||
|
||||
const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
|
||||
export const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
|
||||
<dt>
|
||||
{children}
|
||||
{quoteName && <small> ({quoteName})</small>}
|
||||
@@ -28,14 +30,20 @@ const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
|
||||
);
|
||||
|
||||
interface ValueTooltipProps {
|
||||
value: string;
|
||||
value?: string;
|
||||
children?: ReactNode;
|
||||
description: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const ValueTooltipRow = ({ value, description, id }: ValueTooltipProps) => (
|
||||
export const ValueTooltipRow = ({
|
||||
value,
|
||||
children,
|
||||
description,
|
||||
id,
|
||||
}: ValueTooltipProps) => (
|
||||
<dd className="flex gap-x-2 items-center">
|
||||
{value}
|
||||
{value || children}
|
||||
<Tooltip align="center" description={description}>
|
||||
<div className="cursor-help" id={id || ''} tabIndex={-1}>
|
||||
<Icon
|
||||
@@ -56,6 +64,7 @@ export const DealTicketEstimates = ({
|
||||
fees,
|
||||
notionalSize,
|
||||
size,
|
||||
slippage,
|
||||
}: DealTicketEstimatesProps) => (
|
||||
<dl className="text-black dark:text-white">
|
||||
{size && (
|
||||
@@ -93,7 +102,7 @@ export const DealTicketEstimates = ({
|
||||
</div>
|
||||
)}
|
||||
{estMargin && (
|
||||
<div className="flex justify-between mb-8">
|
||||
<div className="flex justify-between mb-2">
|
||||
<DataTitle quoteName={quoteName}>{t('Est. Margin')}</DataTitle>
|
||||
<ValueTooltipRow
|
||||
value={estMargin}
|
||||
@@ -102,17 +111,23 @@ export const DealTicketEstimates = ({
|
||||
</div>
|
||||
)}
|
||||
{estCloseOut && (
|
||||
<div className="flex justify-between">
|
||||
<dt>
|
||||
<span>{t('Est. Close out')}</span>
|
||||
|
||||
<small>({quoteName})</small>
|
||||
</dt>
|
||||
<div className="flex justify-between mb-2">
|
||||
<DataTitle quoteName={quoteName}>{t('Est. Close out')}</DataTitle>
|
||||
<ValueTooltipRow
|
||||
value={estCloseOut}
|
||||
description={constants.EST_CLOSEOUT_TOOLTIP_TEXT}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{slippage && (
|
||||
<div className="flex justify-between mb-2">
|
||||
<DataTitle>{t('Est. Price Impact / Slippage')}</DataTitle>
|
||||
<ValueTooltipRow description={constants.EST_SLIPPAGE}>
|
||||
<TrafficLight value={parseFloat(slippage)} q1={1} q2={5}>
|
||||
{slippage}%
|
||||
</TrafficLight>
|
||||
</ValueTooltipRow>
|
||||
</div>
|
||||
)}
|
||||
</dl>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
SliderRoot,
|
||||
SliderThumb,
|
||||
SliderTrack,
|
||||
SliderRange,
|
||||
FormGroup,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { InputSetter } from '../input-setter';
|
||||
|
||||
interface DealTicketSizeInputProps {
|
||||
step: number;
|
||||
min: number;
|
||||
max: number;
|
||||
value: number;
|
||||
onValueChange: (value: number) => void;
|
||||
positionDecimalPlaces: number;
|
||||
}
|
||||
|
||||
const getSizeLabel = (value: number): string => {
|
||||
const MIN_LABEL = 'Min';
|
||||
const MAX_LABEL = 'Max';
|
||||
if (value === 0) {
|
||||
return MIN_LABEL;
|
||||
} else if (value === 100) {
|
||||
return MAX_LABEL;
|
||||
}
|
||||
|
||||
return `${value}%`;
|
||||
};
|
||||
|
||||
export const DealTicketSizeInput = ({
|
||||
value,
|
||||
step,
|
||||
min,
|
||||
max,
|
||||
onValueChange,
|
||||
positionDecimalPlaces,
|
||||
}: DealTicketSizeInputProps) => {
|
||||
const sizeRatios = [0, 25, 50, 75, 100];
|
||||
const [inputValue, setInputValue] = useState(value);
|
||||
|
||||
const onInputValueChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let value = parseFloat(event.target.value);
|
||||
const isLessThanMin = value < min;
|
||||
const isMoreThanMax = value > max;
|
||||
if (isLessThanMin) {
|
||||
value = min;
|
||||
} else if (isMoreThanMax) {
|
||||
value = max;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
onValueChange(value);
|
||||
}
|
||||
|
||||
setInputValue(value);
|
||||
},
|
||||
[min, max, onValueChange, setInputValue]
|
||||
);
|
||||
|
||||
const onButtonValueChange = (size: number) => {
|
||||
const newVal = new BigNumber(size)
|
||||
.decimalPlaces(positionDecimalPlaces)
|
||||
.toNumber();
|
||||
onValueChange(newVal);
|
||||
setInputValue(newVal);
|
||||
};
|
||||
|
||||
const onSliderValueChange = useCallback(
|
||||
(value: number[]) => {
|
||||
const val = value[0];
|
||||
setInputValue(val);
|
||||
onValueChange(val);
|
||||
},
|
||||
[onValueChange]
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex justify-between text-black dark:text-white mb-2">
|
||||
<span data-testid="min-label">{min}</span>
|
||||
<span data-testid="max-label">{max}</span>
|
||||
</div>
|
||||
<SliderRoot
|
||||
className="mb-2"
|
||||
value={[value]}
|
||||
onValueChange={onSliderValueChange}
|
||||
step={step}
|
||||
min={min}
|
||||
max={max}
|
||||
>
|
||||
<SliderTrack className="bg-lightGrey dark:bg-offBlack">
|
||||
<SliderRange className="!bg-black dark:!bg-white" />
|
||||
</SliderTrack>
|
||||
<SliderThumb />
|
||||
</SliderRoot>
|
||||
|
||||
<div
|
||||
data-testid="percentage-selector"
|
||||
className="flex w-full justify-between text-black dark:text-white mb-6"
|
||||
>
|
||||
{sizeRatios.map((size, index) => {
|
||||
const proportionalSize = size ? (size / 100) * max : min;
|
||||
return (
|
||||
<button
|
||||
className="no-underline hover:underline text-blue"
|
||||
onClick={() => onButtonValueChange(proportionalSize)}
|
||||
type="button"
|
||||
key={index}
|
||||
>
|
||||
{getSizeLabel(size)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<dl className="text-black dark:text-white">
|
||||
<div className="flex items-center justify-between">
|
||||
<dt>{t('Contracts')}</dt>
|
||||
<dd className="flex justify-end w-full">
|
||||
<FormGroup
|
||||
hideLabel={true}
|
||||
label="Enter Size"
|
||||
labelFor="trade-size-input"
|
||||
className="mb-1"
|
||||
>
|
||||
<InputSetter
|
||||
id="input-order-size-market"
|
||||
type="number"
|
||||
step={step}
|
||||
min={min}
|
||||
max={max}
|
||||
className="w-full"
|
||||
value={inputValue}
|
||||
onChange={onInputValueChange}
|
||||
>
|
||||
{inputValue}
|
||||
</InputSetter>
|
||||
</FormGroup>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,27 +1,13 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
SliderRoot,
|
||||
SliderThumb,
|
||||
SliderTrack,
|
||||
SliderRange,
|
||||
FormGroup,
|
||||
Icon,
|
||||
Tooltip,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import React from 'react';
|
||||
import { DealTicketEstimates } from './deal-ticket-estimates';
|
||||
import { InputSetter } from '../input-setter';
|
||||
import * as constants from './constants';
|
||||
import { DealTicketSizeInput } from './deal-ticket-size-input';
|
||||
|
||||
interface DealTicketSizeProps {
|
||||
step: number;
|
||||
min: number;
|
||||
max: number;
|
||||
value: number;
|
||||
onValueChange: (value: number[]) => void;
|
||||
size: number;
|
||||
onSizeChange: (value: number) => void;
|
||||
name: string;
|
||||
quoteName: string;
|
||||
price: string;
|
||||
@@ -30,173 +16,33 @@ interface DealTicketSizeProps {
|
||||
fees: string;
|
||||
positionDecimalPlaces: number;
|
||||
notionalSize: string;
|
||||
slippage: string | null;
|
||||
}
|
||||
|
||||
const getSizeLabel = (value: number): string => {
|
||||
const MIN_LABEL = 'Min';
|
||||
const MAX_LABEL = 'Max';
|
||||
if (value === 0) {
|
||||
return MIN_LABEL;
|
||||
} else if (value === 100) {
|
||||
return MAX_LABEL;
|
||||
}
|
||||
|
||||
return `${value}%`;
|
||||
};
|
||||
|
||||
export const DealTicketSize = ({
|
||||
value,
|
||||
step,
|
||||
min,
|
||||
max,
|
||||
price,
|
||||
quoteName,
|
||||
onValueChange,
|
||||
size,
|
||||
onSizeChange,
|
||||
estCloseOut,
|
||||
positionDecimalPlaces,
|
||||
fees,
|
||||
notionalSize,
|
||||
slippage,
|
||||
}: DealTicketSizeProps) => {
|
||||
const sizeRatios = [0, 25, 50, 75, 100];
|
||||
const [inputValue, setInputValue] = useState(value);
|
||||
|
||||
const onInputValueChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = parseFloat(event.target.value);
|
||||
const isLessThanMin = value < min;
|
||||
const isMoreThanMax = value > max;
|
||||
if (value) {
|
||||
if (isLessThanMin) {
|
||||
onValueChange([min]);
|
||||
} else if (isMoreThanMax) {
|
||||
onValueChange([max]);
|
||||
} else {
|
||||
onValueChange([value]);
|
||||
}
|
||||
}
|
||||
setInputValue(value);
|
||||
},
|
||||
[min, max, onValueChange, setInputValue]
|
||||
);
|
||||
|
||||
const onButtonValueChange = useCallback(
|
||||
(size: number) => {
|
||||
const newVal = new BigNumber(size)
|
||||
.decimalPlaces(positionDecimalPlaces)
|
||||
.toNumber();
|
||||
onValueChange([newVal]);
|
||||
setInputValue(newVal);
|
||||
},
|
||||
[onValueChange, positionDecimalPlaces]
|
||||
);
|
||||
|
||||
const onSliderValueChange = useCallback(
|
||||
(value: number[]) => {
|
||||
setInputValue(value[0]);
|
||||
onValueChange(value);
|
||||
},
|
||||
[onValueChange]
|
||||
);
|
||||
|
||||
return max === 0 ? (
|
||||
<p>Not enough balance to trade</p>
|
||||
) : (
|
||||
<div>
|
||||
<div className="flex justify-between text-black dark:text-white mb-2">
|
||||
<span data-testid="min-label">{min}</span>
|
||||
<span data-testid="max-label">{max}</span>
|
||||
</div>
|
||||
<SliderRoot
|
||||
className="mb-2"
|
||||
value={[value]}
|
||||
onValueChange={onSliderValueChange}
|
||||
<DealTicketSizeInput
|
||||
step={step}
|
||||
min={min}
|
||||
max={max}
|
||||
>
|
||||
<SliderTrack className="bg-lightGrey dark:bg-offBlack">
|
||||
<SliderRange className="!bg-black dark:!bg-white" />
|
||||
</SliderTrack>
|
||||
<SliderThumb />
|
||||
</SliderRoot>
|
||||
|
||||
<div
|
||||
data-testid="percentage-selector"
|
||||
className="flex w-full justify-between text-black dark:text-white mb-6"
|
||||
>
|
||||
{sizeRatios.map((size, index) => {
|
||||
const proportionalSize = size ? (size / 100) * max : min;
|
||||
return (
|
||||
<button
|
||||
className="no-underline hover:underline text-blue"
|
||||
onClick={() => onButtonValueChange(proportionalSize)}
|
||||
type="button"
|
||||
key={index}
|
||||
>
|
||||
{getSizeLabel(size)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<dl className="text-black dark:text-white">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<dt>{t('Contracts')}</dt>
|
||||
<dd className="flex justify-end w-full">
|
||||
<FormGroup
|
||||
hideLabel={true}
|
||||
label="Enter Size"
|
||||
labelFor="trade-size-input"
|
||||
>
|
||||
<InputSetter
|
||||
id="input-order-size-market"
|
||||
type="number"
|
||||
step={step}
|
||||
min={min}
|
||||
max={max}
|
||||
className="w-full"
|
||||
value={inputValue}
|
||||
onChange={onInputValueChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
{slippage && (
|
||||
<dl className="text-black dark:text-white">
|
||||
<div className="flex items-center justify-between mb-8">
|
||||
<dt>{t('Est. Price Impact / Slippage')}</dt>
|
||||
<dd
|
||||
className="flex justify-end gap-x-5"
|
||||
data-testid="price-slippage-value"
|
||||
aria-label={t('Est. Price Impact / Slippage')}
|
||||
>
|
||||
<span
|
||||
className={classNames({
|
||||
'text-darkerGreen dark:text-lightGreen':
|
||||
parseFloat(slippage) < 1,
|
||||
'text-amber':
|
||||
parseFloat(slippage) >= 1 && parseFloat(slippage) < 5,
|
||||
'text-vega-red': parseFloat(slippage) >= 5,
|
||||
})}
|
||||
>
|
||||
{slippage}%
|
||||
</span>
|
||||
<Tooltip align="center" description={constants.EST_SLIPPAGE}>
|
||||
<div className="cursor-help" tabIndex={-1}>
|
||||
<Icon
|
||||
name={IconNames.ISSUE}
|
||||
className="block rotate-180"
|
||||
ariaLabel={constants.EST_SLIPPAGE}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
)}
|
||||
value={size}
|
||||
onValueChange={onSizeChange}
|
||||
positionDecimalPlaces={positionDecimalPlaces}
|
||||
/>
|
||||
<DealTicketEstimates
|
||||
quoteName={quoteName}
|
||||
fees={fees}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import * as constants from './constants';
|
||||
import { TrafficLight } from '../traffic-light';
|
||||
import { Dialog, Icon, Intent, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { InputSetter } from '../../components/input-setter';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import { DataTitle, ValueTooltipRow } from './deal-ticket-estimates';
|
||||
|
||||
interface DealTicketSlippageProps {
|
||||
step?: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
value: number;
|
||||
onValueChange(value: number): void;
|
||||
}
|
||||
|
||||
export const DealTicketSlippage = ({
|
||||
value,
|
||||
step = 0.01,
|
||||
min = 0,
|
||||
max = 50,
|
||||
onValueChange,
|
||||
}: DealTicketSlippageProps) => {
|
||||
const [isDialogVisible, setIsDialogVisible] = useState(false);
|
||||
|
||||
const onChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
const numericValue = parseFloat(value);
|
||||
onValueChange(numericValue);
|
||||
},
|
||||
[onValueChange]
|
||||
);
|
||||
|
||||
const toggleDialog = useCallback(() => {
|
||||
setIsDialogVisible(!isDialogVisible);
|
||||
}, [isDialogVisible]);
|
||||
|
||||
const formLabel = (
|
||||
<label className="flex items-center mb-1">
|
||||
<span className="mr-1">{t('Adjust slippage tolerance')}</span>
|
||||
<Tooltip align="center" description={constants.EST_SLIPPAGE}>
|
||||
<div className="cursor-help" tabIndex={-1}>
|
||||
<Icon
|
||||
name={IconNames.ISSUE}
|
||||
className="block rotate-180"
|
||||
ariaLabel={constants.EST_SLIPPAGE}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</label>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
open={isDialogVisible}
|
||||
onChange={toggleDialog}
|
||||
intent={Intent.None}
|
||||
title={t('Transaction Settings')}
|
||||
>
|
||||
<div data-testid="slippage-dialog">
|
||||
{formLabel}
|
||||
<InputSetter
|
||||
id="input-order-slippage"
|
||||
isInputVisible
|
||||
hasError={!value}
|
||||
type="number"
|
||||
step={step}
|
||||
min={min}
|
||||
max={max}
|
||||
className="w-full"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
>
|
||||
{value}%
|
||||
</InputSetter>
|
||||
</div>
|
||||
</Dialog>
|
||||
<dl className="text-black dark:text-white">
|
||||
<div className="flex justify-between mb-2">
|
||||
<DataTitle>{t('Est. Price Impact / Slippage')}</DataTitle>
|
||||
<div className="flex">
|
||||
<div className="mr-1">
|
||||
<ValueTooltipRow description={constants.EST_SLIPPAGE}>
|
||||
<TrafficLight value={value} q1={1} q2={5}>
|
||||
{value}%
|
||||
</TrafficLight>
|
||||
</ValueTooltipRow>
|
||||
</div>
|
||||
<button type="button" onClick={toggleDialog}>
|
||||
<Icon
|
||||
name={IconNames.COG}
|
||||
className="block rotate-180"
|
||||
ariaLabel={t('Override slippage value')}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</dl>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { Stepper } from '../stepper';
|
||||
@@ -10,7 +10,7 @@ import type { Order } from '@vegaprotocol/orders';
|
||||
import { useVegaWallet, VegaTxStatus } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
t,
|
||||
addDecimal,
|
||||
addDecimalsFormatNumber,
|
||||
toDecimal,
|
||||
removeDecimal,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
@@ -33,6 +33,8 @@ import useOrderCloseOut from '../../hooks/use-order-closeout';
|
||||
import useOrderMargin from '../../hooks/use-order-margin';
|
||||
import useMaximumPositionSize from '../../hooks/use-maximum-position-size';
|
||||
import useCalculateSlippage from '../../hooks/use-calculate-slippage';
|
||||
import { Side, OrderType } from '@vegaprotocol/types';
|
||||
import { DealTicketSlippage } from './deal-ticket-slippage';
|
||||
|
||||
interface DealTicketMarketProps {
|
||||
market: DealTicketQuery_market;
|
||||
@@ -62,28 +64,26 @@ export const DealTicketSteps = ({
|
||||
defaultValues: getDefaultOrder(market),
|
||||
});
|
||||
|
||||
const [max, setMax] = useState<number | null>(null);
|
||||
const emptyString = ' - ';
|
||||
const step = toDecimal(market.positionDecimalPlaces);
|
||||
const orderType = watch('type');
|
||||
const orderTimeInForce = watch('timeInForce');
|
||||
const orderSide = watch('side');
|
||||
const orderSize = watch('size');
|
||||
const order = watch();
|
||||
const estCloseOut = useOrderCloseOut({ order, market, partyData });
|
||||
const { message: invalidText, isDisabled } = useOrderValidation({
|
||||
market,
|
||||
orderType,
|
||||
orderTimeInForce,
|
||||
fieldErrors: errors,
|
||||
});
|
||||
const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit();
|
||||
const { keypair } = useVegaWallet();
|
||||
const estMargin = useOrderMargin({
|
||||
order,
|
||||
market,
|
||||
partyId: keypair?.pub || '',
|
||||
});
|
||||
const value = new BigNumber(orderSize).toNumber();
|
||||
const price =
|
||||
market.depth.lastTrade &&
|
||||
addDecimal(market.depth.lastTrade.price, market.decimalPlaces);
|
||||
const emptyString = ' - ';
|
||||
|
||||
const [notionalSize, setNotionalSize] = useState<string | null>(null);
|
||||
const [fees, setFees] = useState<string | null>(null);
|
||||
|
||||
const maxTrade = useMaximumPositionSize({
|
||||
partyId: keypair?.pub || '',
|
||||
@@ -94,46 +94,48 @@ export const DealTicketSteps = ({
|
||||
price: market?.depth?.lastTrade?.price,
|
||||
order,
|
||||
});
|
||||
|
||||
const estCloseOut = useOrderCloseOut({ order, market, partyData });
|
||||
const slippage = useCalculateSlippage({ marketId: market.id, order });
|
||||
useEffect(() => {
|
||||
setMax(
|
||||
new BigNumber(maxTrade)
|
||||
.decimalPlaces(market.positionDecimalPlaces)
|
||||
.toNumber()
|
||||
);
|
||||
}, [maxTrade, market.positionDecimalPlaces]);
|
||||
|
||||
const { message: invalidText, isDisabled } = useOrderValidation({
|
||||
market,
|
||||
orderType,
|
||||
orderTimeInForce,
|
||||
fieldErrors: errors,
|
||||
});
|
||||
|
||||
const { submit, transaction, finalizedOrder, TransactionDialog } =
|
||||
useOrderSubmit();
|
||||
|
||||
const onSizeChange = (value: number[]) => {
|
||||
const newVal = new BigNumber(value[0])
|
||||
.decimalPlaces(market.positionDecimalPlaces)
|
||||
.toString();
|
||||
const isValid = validateSize(step)(newVal);
|
||||
if (isValid !== 'step') {
|
||||
setValue('size', newVal);
|
||||
}
|
||||
};
|
||||
const [slippageValue, setSlippageValue] = useState(
|
||||
slippage ? parseFloat(slippage) : 0
|
||||
);
|
||||
const transactionStatus =
|
||||
transaction.status === VegaTxStatus.Requested ||
|
||||
transaction.status === VegaTxStatus.Pending
|
||||
? 'pending'
|
||||
: 'default';
|
||||
|
||||
useEffect(() => {
|
||||
if (market?.depth?.lastTrade?.price) {
|
||||
const size = new BigNumber(market.depth.lastTrade.price)
|
||||
.multipliedBy(value)
|
||||
setSlippageValue(slippage ? parseFloat(slippage) : 0);
|
||||
}, [slippage]);
|
||||
|
||||
const price = useMemo(() => {
|
||||
if (slippage && market?.depth?.lastTrade?.price) {
|
||||
const isLong = order.side === Side.SIDE_BUY;
|
||||
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
|
||||
parseFloat(slippage) / 100
|
||||
);
|
||||
return new BigNumber(market?.depth?.lastTrade?.price)
|
||||
.multipliedBy(multiplier)
|
||||
.toNumber();
|
||||
|
||||
setNotionalSize(addDecimal(size, market.decimalPlaces));
|
||||
}
|
||||
}, [market, value]);
|
||||
return null;
|
||||
}, [market?.depth?.lastTrade?.price, order.side, slippage]);
|
||||
|
||||
useEffect(() => {
|
||||
const formattedPrice =
|
||||
price && addDecimalsFormatNumber(price, market.decimalPlaces);
|
||||
|
||||
const notionalSize = useMemo(() => {
|
||||
if (price) {
|
||||
const size = new BigNumber(price).multipliedBy(orderSize).toNumber();
|
||||
|
||||
return addDecimalsFormatNumber(size, market.decimalPlaces);
|
||||
}
|
||||
return null;
|
||||
}, [market.decimalPlaces, orderSize, price]);
|
||||
|
||||
const fees = useMemo(() => {
|
||||
if (estMargin?.fees && notionalSize) {
|
||||
const percentage = new BigNumber(estMargin?.fees)
|
||||
.dividedBy(notionalSize)
|
||||
@@ -141,17 +143,66 @@ export const DealTicketSteps = ({
|
||||
.decimalPlaces(2)
|
||||
.toString();
|
||||
|
||||
setFees(`${estMargin.fees} (${percentage}%)`);
|
||||
return `${estMargin.fees} (${percentage}%)`;
|
||||
}
|
||||
}, [estMargin, notionalSize]);
|
||||
|
||||
const transactionStatus =
|
||||
transaction.status === VegaTxStatus.Requested ||
|
||||
transaction.status === VegaTxStatus.Pending
|
||||
? 'pending'
|
||||
: 'default';
|
||||
return null;
|
||||
}, [estMargin?.fees, notionalSize]);
|
||||
|
||||
const onSubmit = React.useCallback(
|
||||
const max = useMemo(() => {
|
||||
return new BigNumber(maxTrade)
|
||||
.decimalPlaces(market.positionDecimalPlaces)
|
||||
.toNumber();
|
||||
}, [market.positionDecimalPlaces, maxTrade]);
|
||||
|
||||
const onSizeChange = useCallback(
|
||||
(value: number) => {
|
||||
const newVal = new BigNumber(value)
|
||||
.decimalPlaces(market.positionDecimalPlaces)
|
||||
.toString();
|
||||
const isValid = validateSize(step)(newVal);
|
||||
if (isValid !== 'step') {
|
||||
setValue('size', newVal);
|
||||
}
|
||||
},
|
||||
[market.positionDecimalPlaces, setValue, step]
|
||||
);
|
||||
|
||||
const onSlippageChange = useCallback(
|
||||
(value: number) => {
|
||||
if (market?.depth?.lastTrade?.price) {
|
||||
if (value) {
|
||||
const isLong = order.side === Side.SIDE_BUY;
|
||||
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
|
||||
value / 100
|
||||
);
|
||||
const bestAskPrice = new BigNumber(market?.depth?.lastTrade?.price)
|
||||
.multipliedBy(multiplier)
|
||||
.decimalPlaces(market.decimalPlaces)
|
||||
.toString();
|
||||
|
||||
setValue('price', bestAskPrice);
|
||||
|
||||
if (orderType === OrderType.TYPE_MARKET) {
|
||||
setValue('type', OrderType.TYPE_LIMIT);
|
||||
}
|
||||
} else {
|
||||
setValue('type', OrderType.TYPE_MARKET);
|
||||
setValue('price', market?.depth?.lastTrade?.price);
|
||||
}
|
||||
}
|
||||
setSlippageValue(value);
|
||||
},
|
||||
[
|
||||
market.decimalPlaces,
|
||||
market?.depth?.lastTrade?.price,
|
||||
order.side,
|
||||
orderType,
|
||||
setValue,
|
||||
]
|
||||
);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
(order: Order) => {
|
||||
if (transactionStatus !== 'pending') {
|
||||
submit({
|
||||
@@ -180,7 +231,7 @@ export const DealTicketSteps = ({
|
||||
ItemRenderer={MarketNameRenderer}
|
||||
/>
|
||||
),
|
||||
value: market.name,
|
||||
value: market.tradableInstrument.instrument.name,
|
||||
},
|
||||
{
|
||||
label: t('Select Direction'),
|
||||
@@ -199,25 +250,30 @@ export const DealTicketSteps = ({
|
||||
label: t('Choose Position Size'),
|
||||
component:
|
||||
max !== null ? (
|
||||
<DealTicketSize
|
||||
step={step}
|
||||
min={step}
|
||||
max={max}
|
||||
onValueChange={onSizeChange}
|
||||
value={new BigNumber(orderSize).toNumber()}
|
||||
name="size"
|
||||
price={price || emptyString}
|
||||
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||
quoteName={
|
||||
market.tradableInstrument.instrument.product.settlementAsset
|
||||
.symbol
|
||||
}
|
||||
notionalSize={notionalSize || emptyString}
|
||||
estCloseOut={estCloseOut}
|
||||
fees={fees || emptyString}
|
||||
estMargin={estMargin?.margin || emptyString}
|
||||
slippage={slippage}
|
||||
/>
|
||||
<>
|
||||
<DealTicketSize
|
||||
step={step}
|
||||
min={step}
|
||||
max={max}
|
||||
onSizeChange={onSizeChange}
|
||||
size={new BigNumber(orderSize).toNumber()}
|
||||
name="size"
|
||||
price={formattedPrice || emptyString}
|
||||
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||
quoteName={
|
||||
market.tradableInstrument.instrument.product.settlementAsset
|
||||
.symbol
|
||||
}
|
||||
notionalSize={notionalSize || emptyString}
|
||||
estCloseOut={estCloseOut}
|
||||
fees={fees || emptyString}
|
||||
estMargin={estMargin?.margin || emptyString}
|
||||
/>
|
||||
<DealTicketSlippage
|
||||
value={slippageValue}
|
||||
onValueChange={onSlippageChange}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
'loading...'
|
||||
),
|
||||
@@ -241,21 +297,22 @@ export const DealTicketSteps = ({
|
||||
order={order}
|
||||
estCloseOut={estCloseOut}
|
||||
estMargin={estMargin?.margin || emptyString}
|
||||
price={price || emptyString}
|
||||
price={formattedPrice || emptyString}
|
||||
quoteName={
|
||||
market.tradableInstrument.instrument.product.settlementAsset
|
||||
.symbol
|
||||
}
|
||||
notionalSize={notionalSize || emptyString}
|
||||
fees={fees || emptyString}
|
||||
slippage={slippageValue}
|
||||
/>
|
||||
<TransactionDialog
|
||||
<Dialog
|
||||
title={getOrderDialogTitle(finalizedOrder?.status)}
|
||||
intent={getOrderDialogIntent(finalizedOrder?.status)}
|
||||
icon={getOrderDialogIcon(finalizedOrder?.status)}
|
||||
>
|
||||
<OrderFeedback transaction={transaction} order={finalizedOrder} />
|
||||
</TransactionDialog>
|
||||
</Dialog>
|
||||
</div>
|
||||
),
|
||||
disabled: true,
|
||||
|
||||
@@ -43,6 +43,7 @@ interface Props {
|
||||
price: string;
|
||||
fees: string;
|
||||
notionalSize: string;
|
||||
slippage: number;
|
||||
}
|
||||
|
||||
export default ({
|
||||
@@ -55,6 +56,7 @@ export default ({
|
||||
fees,
|
||||
price,
|
||||
notionalSize,
|
||||
slippage,
|
||||
}: Props) => {
|
||||
const { data: tagsData } = useQuery<MarketTags, MarketTagsVariables>(
|
||||
MARKET_TAGS_QUERY,
|
||||
@@ -105,6 +107,7 @@ export default ({
|
||||
fees={fees}
|
||||
estCloseOut={estCloseOut}
|
||||
notionalSize={notionalSize}
|
||||
slippage={slippage.toString()}
|
||||
/>
|
||||
|
||||
<div className="mt-12 max-w-sm">
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
query Deposits {
|
||||
assetsConnection {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
symbol
|
||||
decimals
|
||||
source {
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AssetStatus } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: Deposits
|
||||
// ====================================================
|
||||
@@ -39,6 +41,10 @@ export interface Deposits_assetsConnection_edges_node {
|
||||
* The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18
|
||||
*/
|
||||
decimals: number;
|
||||
/**
|
||||
* The status of the asset in the Vega network
|
||||
*/
|
||||
status: AssetStatus;
|
||||
/**
|
||||
* The origin source of the asset (e.g: an ERC20 asset)
|
||||
*/
|
||||
@@ -62,5 +68,5 @@ export interface Deposits {
|
||||
/**
|
||||
* The list of all assets in use in the Vega network or the specified asset if ID is provided
|
||||
*/
|
||||
assetsConnection: Deposits_assetsConnection;
|
||||
assetsConnection: Deposits_assetsConnection | null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type DepositsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type DepositsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } } } | null> | null } | null };
|
||||
|
||||
|
||||
export const DepositsDocument = gql`
|
||||
query Deposits {
|
||||
assetsConnection {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
symbol
|
||||
decimals
|
||||
source {
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useDepositsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useDepositsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useDepositsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useDepositsQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDepositsQuery(baseOptions?: Apollo.QueryHookOptions<DepositsQuery, DepositsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<DepositsQuery, DepositsQueryVariables>(DepositsDocument, options);
|
||||
}
|
||||
export function useDepositsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<DepositsQuery, DepositsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<DepositsQuery, DepositsQueryVariables>(DepositsDocument, options);
|
||||
}
|
||||
export type DepositsQueryHookResult = ReturnType<typeof useDepositsQuery>;
|
||||
export type DepositsLazyQueryHookResult = ReturnType<typeof useDepositsLazyQuery>;
|
||||
export type DepositsQueryResult = Apollo.QueryResult<DepositsQuery, DepositsQueryVariables>;
|
||||
@@ -1,11 +1,10 @@
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import { DepositManager } from '@vegaprotocol/deposits';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { getEnabledAssets, t } from '@vegaprotocol/react-helpers';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { Web3Container } from '@vegaprotocol/web3';
|
||||
import { assetsConnectionToAssets } from '@vegaprotocol/react-helpers';
|
||||
import type { Deposits } from './__generated__/Deposits';
|
||||
|
||||
const DEPOSITS_QUERY = gql`
|
||||
@@ -17,6 +16,7 @@ const DEPOSITS_QUERY = gql`
|
||||
name
|
||||
symbol
|
||||
decimals
|
||||
status
|
||||
source {
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
@@ -40,7 +40,7 @@ export const DepositContainer = () => {
|
||||
skip: !keypair?.pub,
|
||||
});
|
||||
|
||||
const assets = assetsConnectionToAssets(data?.assetsConnection);
|
||||
const assets = getEnabledAssets(data);
|
||||
|
||||
return (
|
||||
<AsyncRenderer<Deposits> data={data} loading={loading} error={error}>
|
||||
|
||||
@@ -22,9 +22,8 @@ export const NavigationDrawer = ({
|
||||
const width = 'w-full md:w-auto md:min-w-[15%] shrink-0';
|
||||
const position = 'absolute inset-0 h-full z-10 md:static';
|
||||
const background = 'bg-black/50 dark:bg-white/50';
|
||||
const border = 'border-r border-neutral-300 dark:border-neutral-700';
|
||||
const flex = 'flex justify-end overflow-hidden';
|
||||
const joinedClasses = [flex, width, position, background, border].join(' ');
|
||||
const joinedClasses = [flex, width, position, background].join(' ');
|
||||
|
||||
const outerStyles = classNames(joinedClasses, {
|
||||
visible: isMenuOpen,
|
||||
|
||||
@@ -12,7 +12,7 @@ const Header = () => {
|
||||
} = useContext(LocalContext);
|
||||
return (
|
||||
<div
|
||||
className="flex items-stretch pr-6 py-6 bg-black text-neutral-400 border-b border-neutral-300 dark:border-neutral-700"
|
||||
className="flex items-stretch pr-6 py-6 bg-black text-neutral-400"
|
||||
data-testid="header"
|
||||
>
|
||||
<Logo />
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { Input } from '@vegaprotocol/ui-toolkit';
|
||||
import type { InputProps } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
interface InputSetterProps {
|
||||
buttonLabel?: string;
|
||||
value: string | number;
|
||||
isInputVisible?: boolean;
|
||||
onValueChange?: () => string;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export const InputSetter = ({
|
||||
buttonLabel = t('set'),
|
||||
value = '',
|
||||
isInputVisible = false,
|
||||
onValueChange,
|
||||
children,
|
||||
...props
|
||||
}: InputSetterProps & InputProps) => {
|
||||
const [isInputToggled, setIsInputToggled] = useState(isInputVisible);
|
||||
@@ -35,7 +34,7 @@ export const InputSetter = ({
|
||||
|
||||
return isInputToggled ? (
|
||||
<div className="flex items-center">
|
||||
<Input {...props} value={value} onKeyDown={onInputEnter} />
|
||||
<Input {...props} onKeyDown={onInputEnter} />
|
||||
<button
|
||||
type="button"
|
||||
className="no-underline hover:underline text-blue ml-2"
|
||||
@@ -47,10 +46,10 @@ export const InputSetter = ({
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="no-underline hover:underline text-blue"
|
||||
className="no-underline hover:underline text-blue py-1.5"
|
||||
onClick={toggleInput}
|
||||
>
|
||||
{value}
|
||||
{children || props.value}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ interface TabBarProps {
|
||||
export const TabBar = ({ className }: TabBarProps) => (
|
||||
<div role="group" aria-label="Tab Bar Navigation Menu" className={className}>
|
||||
<div role="presentation" className="py-[42px]" />
|
||||
<div className="md:hidden fixed bottom-0 left-0 right-0 bg-black py-4 border-t border-neutral-300 dark:border-neutral-700">
|
||||
<div className="md:hidden fixed bottom-0 left-0 right-0 bg-black py-4 border-t border-neutral-300 dark:border-neutral-600">
|
||||
<Nav tabs className="flex justify-evenly items-center" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Generated
-30
@@ -1,30 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { MarketState } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: SimpleMarketDataFields
|
||||
// ====================================================
|
||||
|
||||
export interface SimpleMarketDataFields_market {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Current state of the market
|
||||
*/
|
||||
state: MarketState;
|
||||
}
|
||||
|
||||
export interface SimpleMarketDataFields {
|
||||
__typename: "MarketData";
|
||||
/**
|
||||
* market ID of the associated mark price
|
||||
*/
|
||||
market: SimpleMarketDataFields_market;
|
||||
}
|
||||
Generated
-37
@@ -1,37 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { MarketState } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL subscription operation: SimpleMarketDataSub
|
||||
// ====================================================
|
||||
|
||||
export interface SimpleMarketDataSub_marketData_market {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Current state of the market
|
||||
*/
|
||||
state: MarketState;
|
||||
}
|
||||
|
||||
export interface SimpleMarketDataSub_marketData {
|
||||
__typename: "MarketData";
|
||||
/**
|
||||
* market ID of the associated mark price
|
||||
*/
|
||||
market: SimpleMarketDataSub_marketData_market;
|
||||
}
|
||||
|
||||
export interface SimpleMarketDataSub {
|
||||
/**
|
||||
* Subscribe to the mark price changes
|
||||
*/
|
||||
marketData: SimpleMarketDataSub_marketData;
|
||||
}
|
||||
-133
@@ -1,133 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { MarketState } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: SimpleMarkets
|
||||
// ====================================================
|
||||
|
||||
export interface SimpleMarkets_markets_data_market {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Current state of the market
|
||||
*/
|
||||
state: MarketState;
|
||||
}
|
||||
|
||||
export interface SimpleMarkets_markets_data {
|
||||
__typename: "MarketData";
|
||||
/**
|
||||
* market ID of the associated mark price
|
||||
*/
|
||||
market: SimpleMarkets_markets_data_market;
|
||||
}
|
||||
|
||||
export interface SimpleMarkets_markets_tradableInstrument_instrument_metadata {
|
||||
__typename: "InstrumentMetadata";
|
||||
/**
|
||||
* An arbitrary list of tags to associated to associate to the Instrument (string list)
|
||||
*/
|
||||
tags: string[] | null;
|
||||
}
|
||||
|
||||
export interface SimpleMarkets_markets_tradableInstrument_instrument_product_settlementAsset {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The symbol of the asset (e.g: GBP)
|
||||
*/
|
||||
symbol: string;
|
||||
}
|
||||
|
||||
export interface SimpleMarkets_markets_tradableInstrument_instrument_product {
|
||||
__typename: "Future";
|
||||
/**
|
||||
* String representing the quote (e.g. BTCUSD -> USD is quote)
|
||||
*/
|
||||
quoteName: string;
|
||||
/**
|
||||
* The name of the asset (string)
|
||||
*/
|
||||
settlementAsset: SimpleMarkets_markets_tradableInstrument_instrument_product_settlementAsset;
|
||||
}
|
||||
|
||||
export interface SimpleMarkets_markets_tradableInstrument_instrument {
|
||||
__typename: "Instrument";
|
||||
/**
|
||||
* A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string)
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* Metadata for this instrument
|
||||
*/
|
||||
metadata: SimpleMarkets_markets_tradableInstrument_instrument_metadata;
|
||||
/**
|
||||
* A reference to or instance of a fully specified product, including all required product parameters for that product (Product union)
|
||||
*/
|
||||
product: SimpleMarkets_markets_tradableInstrument_instrument_product;
|
||||
}
|
||||
|
||||
export interface SimpleMarkets_markets_tradableInstrument {
|
||||
__typename: "TradableInstrument";
|
||||
/**
|
||||
* An instance of, or reference to, a fully specified instrument.
|
||||
*/
|
||||
instrument: SimpleMarkets_markets_tradableInstrument_instrument;
|
||||
}
|
||||
|
||||
export interface SimpleMarkets_markets_candles {
|
||||
__typename: "Candle";
|
||||
/**
|
||||
* Open price (uint64)
|
||||
*/
|
||||
open: string;
|
||||
/**
|
||||
* Close price (uint64)
|
||||
*/
|
||||
close: string;
|
||||
}
|
||||
|
||||
export interface SimpleMarkets_markets {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Market full name
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Current state of the market
|
||||
*/
|
||||
state: MarketState;
|
||||
/**
|
||||
* marketData for the given market
|
||||
*/
|
||||
data: SimpleMarkets_markets_data | null;
|
||||
/**
|
||||
* An instance of, or reference to, a tradable instrument.
|
||||
*/
|
||||
tradableInstrument: SimpleMarkets_markets_tradableInstrument;
|
||||
/**
|
||||
* Candles on a market, for the 'last' n candles, at 'interval' seconds as specified by parameters
|
||||
*/
|
||||
candles: (SimpleMarkets_markets_candles | null)[] | null;
|
||||
}
|
||||
|
||||
export interface SimpleMarkets {
|
||||
/**
|
||||
* One or more instruments that are trading on the VEGA network
|
||||
*/
|
||||
markets: SimpleMarkets_markets[] | null;
|
||||
}
|
||||
|
||||
export interface SimpleMarketsVariables {
|
||||
CandleSince: string;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type CandleLiveSubscriptionVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type CandleLiveSubscription = { __typename?: 'Subscription', candles: { __typename?: 'Candle', close: string } };
|
||||
|
||||
|
||||
export const CandleLiveDocument = gql`
|
||||
subscription CandleLive($marketId: ID!) {
|
||||
candles(marketId: $marketId, interval: INTERVAL_I1H) {
|
||||
close
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useCandleLiveSubscription__
|
||||
*
|
||||
* To run a query within a React component, call `useCandleLiveSubscription` and pass it any options that fit your needs.
|
||||
* When your component renders, `useCandleLiveSubscription` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useCandleLiveSubscription({
|
||||
* variables: {
|
||||
* marketId: // value for 'marketId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useCandleLiveSubscription(baseOptions: Apollo.SubscriptionHookOptions<CandleLiveSubscription, CandleLiveSubscriptionVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useSubscription<CandleLiveSubscription, CandleLiveSubscriptionVariables>(CandleLiveDocument, options);
|
||||
}
|
||||
export type CandleLiveSubscriptionHookResult = ReturnType<typeof useCandleLiveSubscription>;
|
||||
export type CandleLiveSubscriptionResult = Apollo.SubscriptionResult<CandleLiveSubscription>;
|
||||
@@ -2,8 +2,8 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
import { themelite as theme } from '@vegaprotocol/tailwindcss-config';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import { IS_MARKET_TRADABLE } from '../../constants';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
import colors from 'tailwindcss/colors';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
|
||||
export const STATES_FILTER = [
|
||||
{ value: 'all', text: t('All') },
|
||||
@@ -192,6 +192,10 @@ export const agGridDarkVariables = `
|
||||
`;
|
||||
|
||||
export const ROW_CLASS_RULES = {
|
||||
'cursor-pointer': ({ data }: { data: SimpleMarkets_markets }) =>
|
||||
'cursor-pointer': ({ data }: { data: Market }) =>
|
||||
IS_MARKET_TRADABLE(data || {}),
|
||||
};
|
||||
|
||||
export const LARGE_SCREENS = ['xl', 'xxl'];
|
||||
|
||||
export const AG_GRID_CONTAINER_STYLES = { width: '100%', height: '100%' };
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
import produce from 'immer';
|
||||
import { gql } from '@apollo/client';
|
||||
import { makeDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
SimpleMarkets,
|
||||
SimpleMarkets_markets,
|
||||
} from './__generated__/SimpleMarkets';
|
||||
import type {
|
||||
SimpleMarketDataSub,
|
||||
SimpleMarketDataSub_marketData,
|
||||
} from './__generated__/SimpleMarketDataSub';
|
||||
|
||||
const MARKET_DATA_FRAGMENT = gql`
|
||||
fragment SimpleMarketDataFields on MarketData {
|
||||
market {
|
||||
id
|
||||
state
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const MARKETS_QUERY = gql`
|
||||
${MARKET_DATA_FRAGMENT}
|
||||
query SimpleMarkets($CandleSince: String!) {
|
||||
markets {
|
||||
id
|
||||
name
|
||||
state
|
||||
data {
|
||||
...SimpleMarketDataFields
|
||||
}
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
product {
|
||||
__typename
|
||||
... on Future {
|
||||
quoteName
|
||||
settlementAsset {
|
||||
symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
candles(interval: INTERVAL_I1H, since: $CandleSince) {
|
||||
open
|
||||
close
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const MARKET_DATA_SUB = gql`
|
||||
${MARKET_DATA_FRAGMENT}
|
||||
subscription SimpleMarketDataSub {
|
||||
marketData {
|
||||
...SimpleMarketDataFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const CANDLE_SUB = gql`
|
||||
subscription CandleLive($marketId: ID!) {
|
||||
candles(marketId: $marketId, interval: INTERVAL_I1H) {
|
||||
close
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const update = (
|
||||
data: SimpleMarkets_markets[],
|
||||
delta: SimpleMarketDataSub_marketData
|
||||
) => {
|
||||
return produce(data, (draft) => {
|
||||
const index = draft.findIndex((m) => m.id === delta.market.id);
|
||||
if (index !== -1) {
|
||||
draft[index].data = delta;
|
||||
}
|
||||
// @TODO - else push new market to draft
|
||||
});
|
||||
};
|
||||
|
||||
const getData = (responseData: SimpleMarkets) => responseData.markets;
|
||||
const getDelta = (
|
||||
subscriptionData: SimpleMarketDataSub
|
||||
): SimpleMarketDataSub_marketData => subscriptionData.marketData;
|
||||
|
||||
export const dataProvider = makeDataProvider<
|
||||
SimpleMarkets,
|
||||
SimpleMarkets_markets[],
|
||||
SimpleMarketDataSub,
|
||||
SimpleMarketDataSub_marketData
|
||||
>({
|
||||
query: MARKETS_QUERY,
|
||||
subscriptionQuery: MARKET_DATA_SUB,
|
||||
update,
|
||||
getData,
|
||||
getDelta,
|
||||
});
|
||||
|
||||
export default dataProvider;
|
||||
+106
-94
@@ -4,19 +4,14 @@ import {
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
cleanup,
|
||||
getAllByRole,
|
||||
fireEvent,
|
||||
} from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import SimpleMarketList from './simple-market-list';
|
||||
import { MARKETS_QUERY } from './data-provider';
|
||||
import type {
|
||||
SimpleMarkets_markets,
|
||||
SimpleMarkets,
|
||||
} from './__generated__/SimpleMarkets';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import SimpleMarketList from './simple-market-list';
|
||||
|
||||
const mockedNavigate = jest.fn();
|
||||
|
||||
@@ -26,100 +21,75 @@ jest.mock('react-router-dom', () => ({
|
||||
useParams: () => ({}),
|
||||
}));
|
||||
|
||||
jest.mock('date-fns', () => ({
|
||||
subDays: () => new Date('2022-06-02T11:11:21.721Z'),
|
||||
jest.mock('./simple-market-percent-change', () => jest.fn());
|
||||
|
||||
let marketsMock = [
|
||||
{
|
||||
id: 'MARKET_A',
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
product: {
|
||||
settlementAsset: {
|
||||
symbol: 'tUSD',
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
tags: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'MARKET_B',
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
product: {
|
||||
settlementAsset: {
|
||||
symbol: 'ETH',
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
tags: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
] as unknown as Market[];
|
||||
|
||||
const LIB = '@vegaprotocol/market-list';
|
||||
const useMarketList = () => {
|
||||
return {
|
||||
data: {
|
||||
markets: marketsMock,
|
||||
marketsData: [],
|
||||
marketsCandles: [],
|
||||
},
|
||||
loading: false,
|
||||
error: false,
|
||||
};
|
||||
};
|
||||
jest.mock(LIB, () => ({
|
||||
...jest.requireActual(LIB),
|
||||
useMarketList: jest.fn(() => useMarketList()),
|
||||
}));
|
||||
|
||||
const mockIsTradable = jest.fn((_arg) => true);
|
||||
jest.mock('../../constants', () => ({
|
||||
...jest.requireActual('../../constants'),
|
||||
IS_MARKET_TRADABLE: jest.fn((arg) => mockIsTradable(arg)),
|
||||
}));
|
||||
|
||||
describe('SimpleMarketList', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should be properly renderer as empty', async () => {
|
||||
const mocks: MockedResponse<SimpleMarkets> = {
|
||||
request: {
|
||||
query: MARKETS_QUERY,
|
||||
variables: {
|
||||
CandleSince: '2022-06-02T11:11:21.721Z',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: { markets: [] },
|
||||
},
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[mocks]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('No data to display')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be properly rendered with some data', async () => {
|
||||
const data = [
|
||||
{
|
||||
id: '1',
|
||||
data: {
|
||||
market: {
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
},
|
||||
},
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
product: {
|
||||
settlementAsset: {
|
||||
symbol: 'tUSD',
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
tags: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: {
|
||||
market: {
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
},
|
||||
},
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
product: {
|
||||
settlementAsset: {
|
||||
symbol: 'ETH',
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
tags: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
] as unknown as SimpleMarkets_markets[];
|
||||
|
||||
const mocks: MockedResponse<SimpleMarkets> = {
|
||||
request: {
|
||||
query: MARKETS_QUERY,
|
||||
variables: {
|
||||
CandleSince: '2022-06-02T11:11:21.721Z',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: { markets: data },
|
||||
},
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[mocks]}>
|
||||
<MockedProvider mocks={[]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
@@ -130,10 +100,52 @@ describe('SimpleMarketList', () => {
|
||||
expect(
|
||||
document.querySelector('.ag-center-cols-container')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
await waitFor(() => {
|
||||
const container = document.querySelector('.ag-center-cols-container');
|
||||
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('click on row should be properly handled', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
});
|
||||
mockIsTradable.mockClear();
|
||||
const container = document.querySelector('.ag-center-cols-container');
|
||||
const firstRow = getAllByRole(container as HTMLDivElement, 'row')[0];
|
||||
expect(firstRow).toHaveAttribute('row-id', marketsMock[0].id);
|
||||
await act(async () => {
|
||||
fireEvent.click(firstRow);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(mockIsTradable).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
id: marketsMock[0].id,
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
})
|
||||
);
|
||||
expect(mockedNavigate).toHaveBeenCalledWith(
|
||||
`/trading/${marketsMock[0].id}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be properly renderer as empty', async () => {
|
||||
marketsMock = [];
|
||||
await act(async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('No data to display')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,29 +1,16 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { useCallback, useContext, useEffect, useMemo, useRef } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { subDays } from 'date-fns';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
useDataProvider,
|
||||
useScreenDimensions,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { ThemeContext } from '@vegaprotocol/react-helpers';
|
||||
import type { MarketState } from '@vegaprotocol/types';
|
||||
import useMarketsFilterData from '../../hooks/use-markets-filter-data';
|
||||
import useColumnDefinitions from '../../hooks/use-column-definitions';
|
||||
import dataProvider from './data-provider';
|
||||
import useMarketsFilterData from './use-markets-filter-data';
|
||||
import useColumnDefinitions from './use-column-definitions';
|
||||
import * as constants from './constants';
|
||||
import SimpleMarketToolbar from './simple-market-toolbar';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
import type { SimpleMarketDataSub_marketData } from './__generated__/SimpleMarketDataSub';
|
||||
import { IS_MARKET_TRADABLE } from '../../constants';
|
||||
import type {
|
||||
CellKeyDownEvent,
|
||||
@@ -33,8 +20,10 @@ import type {
|
||||
GetRowIdParams,
|
||||
TabToNextCellParams,
|
||||
} from 'ag-grid-community/dist/lib/entities/iCallbackParams';
|
||||
import type { Market, MarketsListData } from '@vegaprotocol/market-list';
|
||||
import { useMarketList } from '@vegaprotocol/market-list';
|
||||
|
||||
export type SimpleMarketsType = SimpleMarkets_markets & {
|
||||
export type MarketWithPercentChange = Market & {
|
||||
percentChange?: number | '-';
|
||||
};
|
||||
|
||||
@@ -45,33 +34,15 @@ export type RouterParams = Partial<{
|
||||
}>;
|
||||
|
||||
const SimpleMarketList = () => {
|
||||
const { isMobile } = useScreenDimensions();
|
||||
const { isMobile, screenSize } = useScreenDimensions();
|
||||
const navigate = useNavigate();
|
||||
const params = useParams<RouterParams>();
|
||||
const theme = useContext(ThemeContext);
|
||||
const statusesRef = useRef<Record<string, MarketState | ''>>({});
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
CandleSince: subDays(Date.now(), 1).toJSON(),
|
||||
}),
|
||||
[]
|
||||
);
|
||||
const update = useCallback(
|
||||
({ delta }: { delta: SimpleMarketDataSub_marketData }) =>
|
||||
statusesRef.current[delta.market.id] === delta.market.state,
|
||||
[statusesRef]
|
||||
);
|
||||
|
||||
const { data, error, loading } = useDataProvider({
|
||||
dataProvider,
|
||||
update,
|
||||
variables,
|
||||
});
|
||||
const localData: Array<SimpleMarketsType> = useMarketsFilterData(
|
||||
data || [],
|
||||
params
|
||||
);
|
||||
const { data, error, loading } = useMarketList();
|
||||
const localData = useMarketsFilterData(data as MarketsListData, params);
|
||||
|
||||
const handleOnGridReady = useCallback(() => {
|
||||
gridRef.current?.api?.sizeColumnsToFit();
|
||||
@@ -79,8 +50,8 @@ const SimpleMarketList = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const statuses: Record<string, MarketState | ''> = {};
|
||||
data?.forEach((market) => {
|
||||
statuses[market.id] = market.data?.market.state || '';
|
||||
data?.markets?.forEach((market) => {
|
||||
statuses[market.id] = market.state || '';
|
||||
});
|
||||
statusesRef.current = statuses;
|
||||
}, [data, statusesRef]);
|
||||
@@ -95,7 +66,7 @@ const SimpleMarketList = () => {
|
||||
const getRowId = useCallback(({ data }: GetRowIdParams) => data.id, []);
|
||||
|
||||
const handleRowClicked = useCallback(
|
||||
({ data }: { data: SimpleMarketsType }) => {
|
||||
({ data }: { data: Market }) => {
|
||||
if (IS_MARKET_TRADABLE(data)) {
|
||||
navigate(`/trading/${data.id}`);
|
||||
}
|
||||
@@ -129,12 +100,17 @@ const SimpleMarketList = () => {
|
||||
[handleRowClicked]
|
||||
);
|
||||
|
||||
const shouldSuppressHorizontalScroll = useMemo(() => {
|
||||
return !isMobile && constants.LARGE_SCREENS.includes(screenSize);
|
||||
}, [isMobile, screenSize]);
|
||||
|
||||
return (
|
||||
<div className="h-full p-4 md:p-6 grid grid-rows-[min-content,1fr]">
|
||||
<SimpleMarketToolbar data={data || []} />
|
||||
<SimpleMarketToolbar data={data?.markets || []} />
|
||||
<AsyncRenderer loading={loading} error={error} data={localData}>
|
||||
<AgGrid
|
||||
className="mb-32 min-h-[300px]"
|
||||
className="mb-32 min-h-[300px] w-full"
|
||||
style={constants.AG_GRID_CONTAINER_STYLES}
|
||||
defaultColDef={defaultColDef}
|
||||
columnDefs={columnDefs}
|
||||
rowData={localData}
|
||||
@@ -156,6 +132,7 @@ const SimpleMarketList = () => {
|
||||
suppressRowTransform
|
||||
onCellKeyDown={onCellKeyDown}
|
||||
tabToNextCell={onTabToNextCell}
|
||||
suppressHorizontalScroll={shouldSuppressHorizontalScroll}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
</div>
|
||||
|
||||
+4
-12
@@ -2,10 +2,10 @@ import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/react-testing';
|
||||
import SimpleMarketPercentChange from './simple-market-percent-change';
|
||||
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
||||
import type { Candle } from '@vegaprotocol/market-list';
|
||||
|
||||
describe('SimpleMarketPercentChange should parse proper change', () => {
|
||||
let candles: (SimpleMarkets_markets_candles | null)[] | null;
|
||||
let candles: (Candle | null)[] | null;
|
||||
const setValue = () => undefined;
|
||||
it('empty array', () => {
|
||||
candles = [];
|
||||
@@ -34,11 +34,7 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
||||
expect(screen.getByText('-')).toBeInTheDocument();
|
||||
});
|
||||
it('an appreciated one', () => {
|
||||
candles = [
|
||||
{ open: '50' } as SimpleMarkets_markets_candles,
|
||||
{ close: '100' } as SimpleMarkets_markets_candles,
|
||||
null,
|
||||
];
|
||||
candles = [{ open: '50' } as Candle, { close: '100' } as Candle, null];
|
||||
render(
|
||||
<MockedProvider>
|
||||
<SimpleMarketPercentChange
|
||||
@@ -54,11 +50,7 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
||||
);
|
||||
});
|
||||
it('a depreciated one', () => {
|
||||
candles = [
|
||||
{ open: '100' } as SimpleMarkets_markets_candles,
|
||||
{ close: '50' } as SimpleMarkets_markets_candles,
|
||||
null,
|
||||
];
|
||||
candles = [{ open: '100' } as Candle, { close: '50' } as Candle, null];
|
||||
render(
|
||||
<MockedProvider>
|
||||
<SimpleMarketPercentChange
|
||||
|
||||
+15
-18
@@ -1,26 +1,20 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { InView } from 'react-intersection-observer';
|
||||
import { useSubscription } from '@apollo/client';
|
||||
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
||||
import type {
|
||||
CandleLive,
|
||||
CandleLiveVariables,
|
||||
} from './__generated__/CandleLive';
|
||||
import { CANDLE_SUB } from './data-provider';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import type { Candle } from '@vegaprotocol/market-list';
|
||||
import { marketCandlesProvider } from '@vegaprotocol/market-list';
|
||||
import { Interval } from '@vegaprotocol/types';
|
||||
|
||||
interface Props {
|
||||
candles: (SimpleMarkets_markets_candles | null)[] | null;
|
||||
candles: (Candle | null)[] | null;
|
||||
marketId: string;
|
||||
setValue: (arg: unknown) => void;
|
||||
}
|
||||
|
||||
const EMPTY_VALUE = ' - ';
|
||||
|
||||
const getChange = (
|
||||
candles: (SimpleMarkets_markets_candles | null)[] | null,
|
||||
lastClose?: string
|
||||
) => {
|
||||
const getChange = (candles: (Candle | null)[] | null, lastClose?: string) => {
|
||||
if (candles) {
|
||||
const first = parseInt(candles.find((item) => item?.open)?.open || '-1');
|
||||
const last =
|
||||
@@ -74,11 +68,14 @@ const SimpleMarketPercentChangeWrapper = (props: Props) => {
|
||||
};
|
||||
|
||||
const SimpleMarketPercentChange = ({ candles, marketId, setValue }: Props) => {
|
||||
const { data: { candles: { close = undefined } = {} } = {} } =
|
||||
useSubscription<CandleLive, CandleLiveVariables>(CANDLE_SUB, {
|
||||
variables: { marketId },
|
||||
});
|
||||
const change = getChange(candles, close);
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketCandlesProvider,
|
||||
variables: { marketId, interval: Interval.INTERVAL_I1D },
|
||||
});
|
||||
|
||||
const close = data?.map((m) => m.close);
|
||||
|
||||
const change = getChange(candles, close?.[0]);
|
||||
const colorClasses = getClassColor(change);
|
||||
useEffect(() => {
|
||||
const value = parseFloat(change);
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import MarketNameRenderer from './simple-market-renderer';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
|
||||
describe('SimpleMarketRenderer', () => {
|
||||
const market = {
|
||||
id: 'MARKET_A',
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'MARKET_A_CODE',
|
||||
name: 'MARKET_A_NAME',
|
||||
product: {
|
||||
quoteName: 'MARKET_A_QUOTE_NAME',
|
||||
},
|
||||
metadata: {
|
||||
tags: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as Market;
|
||||
|
||||
it('should properly render not mobile', () => {
|
||||
render(<MarketNameRenderer market={market} isMobile={false} />);
|
||||
expect(screen.getByText('MARKET_A_NAME')).toBeInTheDocument();
|
||||
expect(screen.getByText('MARKET_A_QUOTE_NAME')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should properly render mobile', () => {
|
||||
render(<MarketNameRenderer market={market} isMobile={true} />);
|
||||
expect(screen.getByText('MARKET_A_CODE')).toBeInTheDocument();
|
||||
expect(screen.getByText('MARKET_A_QUOTE_NAME')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,10 +1,9 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { MarketNames_markets } from '@vegaprotocol/deal-ticket';
|
||||
import SimpleMarketExpires from './simple-market-expires';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
|
||||
interface Props {
|
||||
market: MarketNames_markets;
|
||||
market: Market;
|
||||
isMobile?: boolean;
|
||||
}
|
||||
|
||||
@@ -17,7 +16,9 @@ const MarketNameRenderer = ({ market, isMobile }: Props) => {
|
||||
)}
|
||||
/>
|
||||
<div className="col-span-2 uppercase justify-start text-black dark:text-white text-ui-small md:text-market self-end">
|
||||
{isMobile ? market.tradableInstrument.instrument.code : market.name}{' '}
|
||||
{isMobile
|
||||
? market.tradableInstrument.instrument.code
|
||||
: market.tradableInstrument.instrument.name}{' '}
|
||||
<SimpleMarketExpires
|
||||
tags={market.tradableInstrument.instrument.metadata.tags}
|
||||
/>
|
||||
|
||||
+108
-11
@@ -1,11 +1,35 @@
|
||||
import React from 'react';
|
||||
import { useLocation, useRoutes, BrowserRouter } from 'react-router-dom';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import {
|
||||
useLocation,
|
||||
useRoutes,
|
||||
BrowserRouter,
|
||||
useParams,
|
||||
} from 'react-router-dom';
|
||||
import {
|
||||
render,
|
||||
screen,
|
||||
fireEvent,
|
||||
waitFor,
|
||||
act,
|
||||
getAllByText,
|
||||
} from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/react-testing';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import SimpleMarketToolbar from './simple-market-toolbar';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
import { markets as filterData } from './mocks/market-filters.json';
|
||||
|
||||
const mockedNavigate = jest.fn();
|
||||
|
||||
jest.mock('react-router-dom', () => {
|
||||
const actualRouter = jest.requireActual('react-router-dom');
|
||||
return {
|
||||
...actualRouter,
|
||||
useNavigate: () => mockedNavigate,
|
||||
useParams: jest.fn(() => actualRouter.useParams()),
|
||||
};
|
||||
});
|
||||
|
||||
describe('SimpleMarketToolbar', () => {
|
||||
const WrappedCompForTest = () => {
|
||||
const routes = useRoutes([
|
||||
@@ -60,9 +84,8 @@ describe('SimpleMarketToolbar', () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should be properly rendered', async () => {
|
||||
@@ -83,7 +106,7 @@ describe('SimpleMarketToolbar', () => {
|
||||
expect(screen.getByTestId('market-assets-menu').children).toHaveLength(6);
|
||||
});
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
expect(screen.getByRole('menu').children).toHaveLength(10);
|
||||
});
|
||||
@@ -104,7 +127,7 @@ describe('SimpleMarketToolbar', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/STATE_ACTIVE/Future'
|
||||
`/markets/${MarketState.STATE_ACTIVE}/Future`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -115,17 +138,91 @@ describe('SimpleMarketToolbar', () => {
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/STATE_ACTIVE/Future/tEURO'
|
||||
`/markets/${MarketState.STATE_ACTIVE}/Future/tEURO`
|
||||
);
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText('Pending'));
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Pending/Future/tEURO'
|
||||
});
|
||||
const menu = screen.getByRole('menu');
|
||||
const pending = getAllByText(menu, 'Pending')[0];
|
||||
await act(() => {
|
||||
fireEvent.click(pending);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(mockedNavigate).toHaveBeenCalledWith(
|
||||
`/markets/${MarketState.STATE_PENDING}/Future/tEURO`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('stateChange callback should work well', async () => {
|
||||
(useParams as jest.Mock).mockImplementation(() => ({
|
||||
asset: 'asset1',
|
||||
product: 'product1',
|
||||
state: 'state1',
|
||||
}));
|
||||
render(
|
||||
<MockedProvider mocks={[]} addTypename={false}>
|
||||
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
});
|
||||
const menu = screen.getByRole('menu');
|
||||
const suspended = getAllByText(menu, 'Suspended')[0];
|
||||
fireEvent.click(suspended);
|
||||
|
||||
expect(mockedNavigate).toHaveBeenCalledWith(
|
||||
`/markets/${MarketState.STATE_SUSPENDED}/product1/asset1`
|
||||
);
|
||||
});
|
||||
|
||||
it('stateChange callback should call navigate with url with state only', async () => {
|
||||
(useParams as jest.Mock).mockImplementation(() => ({}));
|
||||
render(
|
||||
<MockedProvider mocks={[]} addTypename={false}>
|
||||
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
});
|
||||
const menu = screen.getByRole('menu');
|
||||
const closed = getAllByText(menu, 'Closed')[0];
|
||||
fireEvent.click(closed);
|
||||
|
||||
expect(mockedNavigate).toHaveBeenCalledWith(
|
||||
`/markets/${MarketState.STATE_CLOSED}`
|
||||
);
|
||||
});
|
||||
|
||||
it('stateChange callback should call navigate with no asset', async () => {
|
||||
(useParams as jest.Mock).mockImplementation(() => ({
|
||||
asset: 'all',
|
||||
state: 'state1',
|
||||
}));
|
||||
render(
|
||||
<MockedProvider mocks={[]} addTypename={false}>
|
||||
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const menu = screen.getByRole('menu');
|
||||
const active = getAllByText(menu, 'Active')[0];
|
||||
fireEvent.click(active);
|
||||
expect(mockedNavigate).toHaveBeenCalledWith('/markets');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useNavigate, useParams, Link } from 'react-router-dom';
|
||||
import {
|
||||
@@ -17,10 +17,10 @@ import {
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import useMarketFiltersData from '../../hooks/use-markets-filter';
|
||||
import { STATES_FILTER } from './constants';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
import type { Markets_marketsConnection_edges_node } from '@vegaprotocol/market-list';
|
||||
|
||||
interface Props {
|
||||
data: SimpleMarkets_markets[];
|
||||
data: Markets_marketsConnection_edges_node[];
|
||||
}
|
||||
|
||||
const SimpleMarketToolbar = ({ data }: Props) => {
|
||||
@@ -75,7 +75,7 @@ const SimpleMarketToolbar = ({ data }: Props) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-full mb-4 font-alpha">
|
||||
<div className="w-full max-w-full mb-2 md:mb-8 font-alpha">
|
||||
<ul
|
||||
ref={slideContRef}
|
||||
className="grid grid-flow-col auto-cols-min gap-4 relative pb-2 mb-2"
|
||||
@@ -98,7 +98,7 @@ const SimpleMarketToolbar = ({ data }: Props) => {
|
||||
</Link>
|
||||
</li>
|
||||
{products.map((product, i) => (
|
||||
<li key={product} className="mx-2 whitespace-nowrap">
|
||||
<li key={`${product}-${i}`} className="mx-2 whitespace-nowrap">
|
||||
<Link
|
||||
to={`/markets/${
|
||||
params.state || MarketState.STATE_ACTIVE
|
||||
@@ -121,12 +121,13 @@ const SimpleMarketToolbar = ({ data }: Props) => {
|
||||
style={sliderStyles}
|
||||
/>
|
||||
</ul>
|
||||
<div className="grid gap-8 pb-4 mt-6 md:grid-cols-[min-content,min-content,1fr]">
|
||||
<div className="pb-8">
|
||||
<DropdownMenu onOpenChange={(open) => setOpen(open)}>
|
||||
<div className="grid gap-4 pb-2 mt-2 md:mt-6 md:grid-cols-[min-content,min-content,1fr]">
|
||||
<div className="pb-2">
|
||||
<DropdownMenu open={isOpen} onOpenChange={(open) => setOpen(open)}>
|
||||
<DropdownMenuTrigger
|
||||
className="mr-2 w-auto text-capMenu text-black dark:text-white"
|
||||
data-testid="state-trigger"
|
||||
onClick={() => setOpen(!isOpen)}
|
||||
>
|
||||
<div className="w-full justify-between uppercase inline-flex items-center justify-center box-border">
|
||||
{STATES_FILTER.find(
|
||||
@@ -148,7 +149,7 @@ const SimpleMarketToolbar = ({ data }: Props) => {
|
||||
<DropdownMenuContent>
|
||||
{STATES_FILTER.map(({ value, text }) => (
|
||||
<DropdownMenuCheckboxItem
|
||||
className="uppercase text-ui dark:text-white"
|
||||
className="uppercase text-ui"
|
||||
key={value}
|
||||
checked={
|
||||
value === params.state ||
|
||||
@@ -170,7 +171,7 @@ const SimpleMarketToolbar = ({ data }: Props) => {
|
||||
</div>
|
||||
{activeNumber > 0 && (
|
||||
<ul
|
||||
className="md:gap-6 gap-4 pb-4 md:ml-2 flex flex-wrap"
|
||||
className="md:gap-x-6 gap-x-4 gap-y-1 pb-2 md:ml-2 flex flex-wrap"
|
||||
data-testid="market-assets-menu"
|
||||
aria-label={t('Asset on the market')}
|
||||
>
|
||||
|
||||
+14
-15
@@ -1,14 +1,13 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import type { SimpleMarkets_markets } from '../components/simple-market-list/__generated__/SimpleMarkets';
|
||||
import MarketNameRenderer from '../components/simple-market-list/simple-market-renderer';
|
||||
import SimpleMarketPercentChange from '../components/simple-market-list/simple-market-percent-change';
|
||||
import MarketNameRenderer from './simple-market-renderer';
|
||||
import SimpleMarketPercentChange from './simple-market-percent-change';
|
||||
import { Icon } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ValueSetterParams } from 'ag-grid-community';
|
||||
import type { SimpleMarketsType } from '../components/simple-market-list/simple-market-list';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import { IS_MARKET_TRADABLE, MARKET_STATES_MAP } from '../constants';
|
||||
import { IS_MARKET_TRADABLE, MARKET_STATES_MAP } from '../../constants';
|
||||
import type { Candle, Market } from '@vegaprotocol/market-list';
|
||||
|
||||
interface Props {
|
||||
isMobile: boolean;
|
||||
@@ -22,9 +21,9 @@ const useColumnDefinitions = ({ isMobile }: Props) => {
|
||||
headerName: t('Markets'),
|
||||
headerClass: 'uppercase',
|
||||
minWidth: isMobile ? 160 : 350,
|
||||
field: 'name',
|
||||
field: 'tradableInstrument.instrument.name',
|
||||
cellClass: 'overflow-visible',
|
||||
cellRenderer: ({ data }: { data: SimpleMarketsType }) => (
|
||||
cellRenderer: ({ data }: { data: Market }) => (
|
||||
<MarketNameRenderer market={data} isMobile={isMobile} />
|
||||
),
|
||||
},
|
||||
@@ -35,7 +34,7 @@ const useColumnDefinitions = ({ isMobile }: Props) => {
|
||||
minWidth: isMobile ? 50 : 80,
|
||||
cellClass: 'uppercase flex h-full items-center',
|
||||
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||
cellRenderer: ({ data }: { data: SimpleMarketsType }) => (
|
||||
cellRenderer: ({ data }: { data: Market }) => (
|
||||
<div
|
||||
className="grid h-full items-center text-center"
|
||||
title={
|
||||
@@ -70,7 +69,7 @@ const useColumnDefinitions = ({ isMobile }: Props) => {
|
||||
data,
|
||||
setValue,
|
||||
}: {
|
||||
data: SimpleMarketsType;
|
||||
data: { id: string; candles: Candle[] };
|
||||
setValue: (arg: unknown) => void;
|
||||
}) => (
|
||||
<SimpleMarketPercentChange
|
||||
@@ -93,13 +92,13 @@ const useColumnDefinitions = ({ isMobile }: Props) => {
|
||||
{
|
||||
colId: 'status',
|
||||
headerName: t('Status'),
|
||||
field: 'data.market.state',
|
||||
field: 'state',
|
||||
headerClass: 'uppercase',
|
||||
minWidth: 100,
|
||||
cellRenderer: ({ data }: { data: SimpleMarkets_markets }) => (
|
||||
cellRenderer: ({ data }: { data: Market }) => (
|
||||
<div className="uppercase flex h-full items-center justify-center">
|
||||
<div className="border text-center px-2 md:px-8 leading-4 md:leading-6">
|
||||
{MARKET_STATES_MAP[data.data?.market.state || '']}
|
||||
<div className="border text-center px-2 md:px-6 leading-4 md:leading-6">
|
||||
{MARKET_STATES_MAP[data.state || '']}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
@@ -110,7 +109,7 @@ const useColumnDefinitions = ({ isMobile }: Props) => {
|
||||
headerClass: 'uppercase',
|
||||
sortable: false,
|
||||
width: isMobile ? 35 : 100,
|
||||
cellRenderer: ({ data }: { data: SimpleMarkets_markets }) => (
|
||||
cellRenderer: ({ data }: { data: Market }) => (
|
||||
<div className="h-full flex h-full items-center justify-end">
|
||||
<div className="uppercase text-center pr-2">
|
||||
{!isMobile && t('Trade')}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { useMemo } from 'react';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import type { MarketsListData } from '@vegaprotocol/market-list';
|
||||
import type { RouterParams } from './simple-market-list';
|
||||
|
||||
const useMarketsFilterData = (data: MarketsListData, params: RouterParams) => {
|
||||
return useMemo(() => {
|
||||
const markets =
|
||||
data?.markets?.filter((item) => {
|
||||
if (
|
||||
params.product &&
|
||||
params.product !==
|
||||
item.tradableInstrument.instrument.product.__typename
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
params.asset &&
|
||||
params.asset !== 'all' &&
|
||||
params.asset !==
|
||||
item.tradableInstrument.instrument.product.settlementAsset.symbol
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const state =
|
||||
params.state === 'all'
|
||||
? ''
|
||||
: params.state
|
||||
? params.state
|
||||
: MarketState.STATE_ACTIVE;
|
||||
if (state && state !== item.state) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}) || [];
|
||||
|
||||
return markets.map((market) => ({
|
||||
...market,
|
||||
candles: (data?.marketsCandles || [])
|
||||
.filter((c) => c.marketId === market.id)
|
||||
.map((c) => c.candles),
|
||||
}));
|
||||
}, [
|
||||
data?.marketsCandles,
|
||||
data?.markets,
|
||||
params.product,
|
||||
params.asset,
|
||||
params.state,
|
||||
]);
|
||||
};
|
||||
|
||||
export default useMarketsFilterData;
|
||||
@@ -88,7 +88,7 @@ export const Stepper = ({ steps }: StepperProps) => {
|
||||
'md:mt-0 font-alpha uppercase text-black dark:text-white',
|
||||
{
|
||||
'mt-2 text-md md:text-2xl': isActive,
|
||||
'mt-4 text-sm md:text-lg md:ml-8': !isActive,
|
||||
'mt-4 text-sm md:text-lg md:ml-2': !isActive,
|
||||
}
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './traffic-light';
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface TrafficLightProps {
|
||||
value: number;
|
||||
q1: number;
|
||||
q2: number;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const TrafficLight = ({
|
||||
value,
|
||||
q1,
|
||||
q2,
|
||||
children,
|
||||
}: TrafficLightProps) => {
|
||||
const slippageClassName = classNames({
|
||||
'text-darkerGreen dark:text-lightGreen': value < q1,
|
||||
'text-amber': value >= q1 && value < q2,
|
||||
'text-vega-red': value >= q2,
|
||||
});
|
||||
|
||||
return <div className={slippageClassName}>{children || value}</div>;
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { SimpleMarkets_markets } from '../components/simple-market-list/__generated__/SimpleMarkets';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
|
||||
export const DATE_FORMAT = 'dd MMMM yyyy HH:mm';
|
||||
export const EXPIRE_DATE_FORMAT = 'MMM dd';
|
||||
@@ -9,8 +9,8 @@ export const TRADABLE_STATES = {
|
||||
[MarketState.STATE_ACTIVE]: true,
|
||||
};
|
||||
|
||||
export const IS_MARKET_TRADABLE = (market: SimpleMarkets_markets) =>
|
||||
Boolean((market.data?.market.state ?? '') in TRADABLE_STATES && market?.id);
|
||||
export const IS_MARKET_TRADABLE = (market: Market) =>
|
||||
Boolean((market.state ?? '') in TRADABLE_STATES && market?.id);
|
||||
|
||||
export const MARKET_STATES_MAP: Record<MarketState | '', string> = {
|
||||
[MarketState.STATE_ACTIVE]: t('Active'),
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
query EstimateOrder(
|
||||
$marketId: ID!
|
||||
$partyId: ID!
|
||||
$price: String
|
||||
$size: String!
|
||||
$side: Side!
|
||||
$timeInForce: OrderTimeInForce!
|
||||
$expiration: String
|
||||
$type: OrderType!
|
||||
) {
|
||||
estimateOrder(
|
||||
marketId: $marketId
|
||||
partyId: $partyId
|
||||
price: $price
|
||||
size: $size
|
||||
side: $side
|
||||
timeInForce: $timeInForce
|
||||
expiration: $expiration
|
||||
type: $type
|
||||
) {
|
||||
fee {
|
||||
makerFee
|
||||
infrastructureFee
|
||||
liquidityFee
|
||||
}
|
||||
marginLevels {
|
||||
initialLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
query MarketMarkPrice($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
decimalPlaces
|
||||
data {
|
||||
markPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
query MarketPositions($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
decimals
|
||||
}
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
positionsConnection {
|
||||
edges {
|
||||
node {
|
||||
openVolume
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
query PartyMarketData($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
id
|
||||
decimals
|
||||
}
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
marginsConnection {
|
||||
edges {
|
||||
node {
|
||||
market {
|
||||
id
|
||||
}
|
||||
initialLevel
|
||||
maintenanceLevel
|
||||
searchLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ export interface PartyMarketData_party {
|
||||
/**
|
||||
* Margin levels for a market
|
||||
*/
|
||||
marginsConnection: PartyMarketData_party_marginsConnection;
|
||||
marginsConnection: PartyMarketData_party_marginsConnection | null;
|
||||
}
|
||||
|
||||
export interface PartyMarketData {
|
||||
|
||||
@@ -91,7 +91,7 @@ export interface MarketPositions_party {
|
||||
/**
|
||||
* Trading positions relating to a party
|
||||
*/
|
||||
positionsConnection: MarketPositions_party_positionsConnection;
|
||||
positionsConnection: MarketPositions_party_positionsConnection | null;
|
||||
}
|
||||
|
||||
export interface MarketPositions {
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type EstimateOrderQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
partyId: Types.Scalars['ID'];
|
||||
price?: Types.InputMaybe<Types.Scalars['String']>;
|
||||
size: Types.Scalars['String'];
|
||||
side: Types.Side;
|
||||
timeInForce: Types.OrderTimeInForce;
|
||||
expiration?: Types.InputMaybe<Types.Scalars['String']>;
|
||||
type: Types.OrderType;
|
||||
}>;
|
||||
|
||||
|
||||
export type EstimateOrderQuery = { __typename?: 'Query', estimateOrder: { __typename?: 'OrderEstimate', fee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, marginLevels: { __typename?: 'MarginLevels', initialLevel: string } } };
|
||||
|
||||
|
||||
export const EstimateOrderDocument = gql`
|
||||
query EstimateOrder($marketId: ID!, $partyId: ID!, $price: String, $size: String!, $side: Side!, $timeInForce: OrderTimeInForce!, $expiration: String, $type: OrderType!) {
|
||||
estimateOrder(
|
||||
marketId: $marketId
|
||||
partyId: $partyId
|
||||
price: $price
|
||||
size: $size
|
||||
side: $side
|
||||
timeInForce: $timeInForce
|
||||
expiration: $expiration
|
||||
type: $type
|
||||
) {
|
||||
fee {
|
||||
makerFee
|
||||
infrastructureFee
|
||||
liquidityFee
|
||||
}
|
||||
marginLevels {
|
||||
initialLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useEstimateOrderQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useEstimateOrderQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useEstimateOrderQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useEstimateOrderQuery({
|
||||
* variables: {
|
||||
* marketId: // value for 'marketId'
|
||||
* partyId: // value for 'partyId'
|
||||
* price: // value for 'price'
|
||||
* size: // value for 'size'
|
||||
* side: // value for 'side'
|
||||
* timeInForce: // value for 'timeInForce'
|
||||
* expiration: // value for 'expiration'
|
||||
* type: // value for 'type'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useEstimateOrderQuery(baseOptions: Apollo.QueryHookOptions<EstimateOrderQuery, EstimateOrderQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<EstimateOrderQuery, EstimateOrderQueryVariables>(EstimateOrderDocument, options);
|
||||
}
|
||||
export function useEstimateOrderLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<EstimateOrderQuery, EstimateOrderQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<EstimateOrderQuery, EstimateOrderQueryVariables>(EstimateOrderDocument, options);
|
||||
}
|
||||
export type EstimateOrderQueryHookResult = ReturnType<typeof useEstimateOrderQuery>;
|
||||
export type EstimateOrderLazyQueryHookResult = ReturnType<typeof useEstimateOrderLazyQuery>;
|
||||
export type EstimateOrderQueryResult = Apollo.QueryResult<EstimateOrderQuery, EstimateOrderQueryVariables>;
|
||||
@@ -0,0 +1,51 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarketMarkPriceQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketMarkPriceQuery = { __typename?: 'Query', market?: { __typename?: 'Market', decimalPlaces: number, data?: { __typename?: 'MarketData', markPrice: string } | null } | null };
|
||||
|
||||
|
||||
export const MarketMarkPriceDocument = gql`
|
||||
query MarketMarkPrice($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
decimalPlaces
|
||||
data {
|
||||
markPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useMarketMarkPriceQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useMarketMarkPriceQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useMarketMarkPriceQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useMarketMarkPriceQuery({
|
||||
* variables: {
|
||||
* marketId: // value for 'marketId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useMarketMarkPriceQuery(baseOptions: Apollo.QueryHookOptions<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>(MarketMarkPriceDocument, options);
|
||||
}
|
||||
export function useMarketMarkPriceLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>(MarketMarkPriceDocument, options);
|
||||
}
|
||||
export type MarketMarkPriceQueryHookResult = ReturnType<typeof useMarketMarkPriceQuery>;
|
||||
export type MarketMarkPriceLazyQueryHookResult = ReturnType<typeof useMarketMarkPriceLazyQuery>;
|
||||
export type MarketMarkPriceQueryResult = Apollo.QueryResult<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>;
|
||||
@@ -0,0 +1,68 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarketPositionsQueryVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketPositionsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', decimals: number }, market?: { __typename?: 'Market', id: string } | null }> | null, positionsConnection?: { __typename?: 'PositionConnection', edges?: Array<{ __typename?: 'PositionEdge', node: { __typename?: 'Position', openVolume: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
|
||||
|
||||
|
||||
export const MarketPositionsDocument = gql`
|
||||
query MarketPositions($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
decimals
|
||||
}
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
positionsConnection {
|
||||
edges {
|
||||
node {
|
||||
openVolume
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useMarketPositionsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useMarketPositionsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useMarketPositionsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useMarketPositionsQuery({
|
||||
* variables: {
|
||||
* partyId: // value for 'partyId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useMarketPositionsQuery(baseOptions: Apollo.QueryHookOptions<MarketPositionsQuery, MarketPositionsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<MarketPositionsQuery, MarketPositionsQueryVariables>(MarketPositionsDocument, options);
|
||||
}
|
||||
export function useMarketPositionsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MarketPositionsQuery, MarketPositionsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<MarketPositionsQuery, MarketPositionsQueryVariables>(MarketPositionsDocument, options);
|
||||
}
|
||||
export type MarketPositionsQueryHookResult = ReturnType<typeof useMarketPositionsQuery>;
|
||||
export type MarketPositionsLazyQueryHookResult = ReturnType<typeof useMarketPositionsLazyQuery>;
|
||||
export type MarketPositionsQueryResult = Apollo.QueryResult<MarketPositionsQuery, MarketPositionsQueryVariables>;
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type PartyMarketDataQueryVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type PartyMarketDataQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, decimals: number }, market?: { __typename?: 'Market', id: string } | null }> | null, marginsConnection?: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', initialLevel: string, maintenanceLevel: string, searchLevel: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
|
||||
|
||||
|
||||
export const PartyMarketDataDocument = gql`
|
||||
query PartyMarketData($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
id
|
||||
decimals
|
||||
}
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
marginsConnection {
|
||||
edges {
|
||||
node {
|
||||
market {
|
||||
id
|
||||
}
|
||||
initialLevel
|
||||
maintenanceLevel
|
||||
searchLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __usePartyMarketDataQuery__
|
||||
*
|
||||
* To run a query within a React component, call `usePartyMarketDataQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `usePartyMarketDataQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = usePartyMarketDataQuery({
|
||||
* variables: {
|
||||
* partyId: // value for 'partyId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function usePartyMarketDataQuery(baseOptions: Apollo.QueryHookOptions<PartyMarketDataQuery, PartyMarketDataQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<PartyMarketDataQuery, PartyMarketDataQueryVariables>(PartyMarketDataDocument, options);
|
||||
}
|
||||
export function usePartyMarketDataLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PartyMarketDataQuery, PartyMarketDataQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<PartyMarketDataQuery, PartyMarketDataQueryVariables>(PartyMarketDataDocument, options);
|
||||
}
|
||||
export type PartyMarketDataQueryHookResult = ReturnType<typeof usePartyMarketDataQuery>;
|
||||
export type PartyMarketDataLazyQueryHookResult = ReturnType<typeof usePartyMarketDataLazyQuery>;
|
||||
export type PartyMarketDataQueryResult = Apollo.QueryResult<PartyMarketDataQuery, PartyMarketDataQueryVariables>;
|
||||
@@ -64,6 +64,15 @@ jest.mock('@vegaprotocol/market-depth', () => ({
|
||||
useOrderBookData: jest.fn(() => mockOrderBookData),
|
||||
}));
|
||||
|
||||
jest.mock('@vegaprotocol/react-helpers', () => ({
|
||||
...jest.requireActual('@vegaprotocol/react-helpers'),
|
||||
useDataProvider: jest.fn(() => ({
|
||||
data: {
|
||||
marketsConnection: [],
|
||||
},
|
||||
})),
|
||||
}));
|
||||
|
||||
describe('useCalculateSlippage Hook', () => {
|
||||
describe('calculate proper result', () => {
|
||||
afterEach(() => {
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import { useOrderBookData } from '@vegaprotocol/market-depth';
|
||||
import { marketProvider } from '@vegaprotocol/market-list';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import { formatNumber, toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
formatNumber,
|
||||
toBigNum,
|
||||
useDataProvider,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
|
||||
interface Props {
|
||||
marketId: string;
|
||||
@@ -16,11 +22,16 @@ const useCalculateSlippage = ({ marketId, order }: Props) => {
|
||||
variables,
|
||||
throttleMilliseconds: 5000,
|
||||
});
|
||||
const { data: market } = useDataProvider<Market, never>({
|
||||
dataProvider: marketProvider,
|
||||
noUpdate: true,
|
||||
variables,
|
||||
});
|
||||
const volPriceArr =
|
||||
data?.depth[order.side === Side.SIDE_BUY ? 'sell' : 'buy'] || [];
|
||||
if (volPriceArr.length) {
|
||||
const decimals = data?.decimalPlaces ?? 0;
|
||||
const positionDecimals = data?.positionDecimalPlaces ?? 0;
|
||||
if (volPriceArr.length && market) {
|
||||
const decimals = market.decimalPlaces ?? 0;
|
||||
const positionDecimals = market.positionDecimalPlaces ?? 0;
|
||||
const bestPrice = toBigNum(volPriceArr[0].price, decimals);
|
||||
const { size } = order;
|
||||
let descSize = new BigNumber(size);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import type { SimpleMarkets_markets } from '../components/simple-market-list/__generated__/SimpleMarkets';
|
||||
import type { RouterParams } from '../components/simple-market-list/simple-market-list';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
|
||||
const useMarketsFilterData = (
|
||||
data: SimpleMarkets_markets[] = [],
|
||||
params: RouterParams
|
||||
) => {
|
||||
return data.filter((item) => {
|
||||
if (
|
||||
params.product &&
|
||||
params.product !== item.tradableInstrument.instrument.product.__typename
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
params.asset &&
|
||||
params.asset !== 'all' &&
|
||||
params.asset !==
|
||||
item.tradableInstrument.instrument.product.settlementAsset.symbol
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const state =
|
||||
params.state === 'all'
|
||||
? ''
|
||||
: params.state
|
||||
? params.state
|
||||
: MarketState.STATE_ACTIVE;
|
||||
if (state && state !== item.data?.market.state) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
export default useMarketsFilterData;
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { SimpleMarkets_markets } from '../components/simple-market-list/__generated__/SimpleMarkets';
|
||||
|
||||
const useMarketFilters = (data: SimpleMarkets_markets[]) => {
|
||||
const useMarketFilters = (data: Market[]) => {
|
||||
const [products, setProducts] = useState<string[]>([]);
|
||||
const [assetsPerProduct, setAssetsPerProduct] = useState<
|
||||
Record<string, string[]>
|
||||
|
||||
@@ -74,7 +74,7 @@ const useOrderCloseOut = ({ order, market, partyData }: Props): string => {
|
||||
|
||||
const marginMaintenanceLevel = new BigNumber(
|
||||
addDecimal(
|
||||
data?.party?.marginsConnection.edges?.find(
|
||||
data?.party?.marginsConnection?.edges?.find(
|
||||
(nodes) => nodes.node.market.id === market.id
|
||||
)?.node.maintenanceLevel || 0,
|
||||
market.decimalPlaces
|
||||
|
||||
@@ -38,6 +38,9 @@ export function createClient(base?: string) {
|
||||
Node: {
|
||||
keyFields: false,
|
||||
},
|
||||
Instrument: {
|
||||
keyFields: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
NX_VEGA_URL=http://localhost:3028/query
|
||||
NX_VEGA_ENV=CUSTOM
|
||||
NX_VEGA_REST=http://localhost:3029
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/capsule-network.json
|
||||
|
||||
CYPRESS_VEGA_TENDERMINT_URL=http://localhost:26617
|
||||
|
||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_URL=https://n04.d.vega.xyz/tm
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||
NX_VEGA_ENV=DEVNET
|
||||
NX_VEGA_REST=https://api.n04.d.vega.xyz
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
@@ -12,7 +11,7 @@ NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_TXS_LIST=0
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
NX_EXPLORER_VALIDATORS=1
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||
NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
|
||||
NX_VEGA_URL=https://api.token.vega.xyz/query
|
||||
NX_VEGA_URL=https://api.vega.xyz/query
|
||||
NX_VEGA_ENV=MAINNET
|
||||
NX_VEGA_REST=https://api.token.vega.xyz/
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_URL=https://n01.stagnet3.vega.xyz/tm
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://n01.stagnet3.vega.xyz/tm/websocket
|
||||
NX_VEGA_URL=https://api.n01.stagnet3.vega.xyz/graphql
|
||||
NX_VEGA_ENV=STAGNET3
|
||||
NX_VEGA_REST=https://api.n01.stagnet3.vega.xyz
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
@@ -12,7 +11,7 @@ NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_TXS_LIST=0
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
NX_EXPLORER_VALIDATORS=1
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
# App configuration variables
|
||||
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||
NX_TENDERMINT_URL=https://tm.n06.testnet.vega.xyz/tm
|
||||
NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
|
||||
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_REST=https://api.n11.testnet.vega.xyz
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
@@ -12,7 +11,7 @@ NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_TXS_LIST=0
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
NX_EXPLORER_VALIDATORS=1
|
||||
|
||||
+1
-8
@@ -1,14 +1,7 @@
|
||||
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
NX_VEGA_URL=http://localhost:3028/query
|
||||
NX_VEGA_ENV=CUSTOM
|
||||
|
||||
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||
NX_TENDERMINT_URL=https://n01.stagnet3.vega.xyz/tm
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://n01.stagnet3.vega.xyz/tm/websocket
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
|
||||
NX_VEGA_URL=https://api.n01.stagnet3.vega.xyz/graphql
|
||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_VEGA_ENV=STAGNET3
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
@@ -22,4 +15,4 @@ NX_EXPLORER_PARTIES=1
|
||||
NX_EXPLORER_VALIDATORS=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_TXS_LIST=0
|
||||
|
||||
@@ -13,7 +13,7 @@ NX_EXPLORER_GENESIS=1
|
||||
NX_EXPLORER_GOVERNANCE=1
|
||||
NX_EXPLORER_MARKETS=1
|
||||
NX_EXPLORER_ORACLES=1
|
||||
NX_EXPLORER_TXS_LIST=1
|
||||
NX_EXPLORER_TXS_LIST=0
|
||||
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
NX_EXPLORER_VALIDATORS=1
|
||||
|
||||
@@ -3,7 +3,7 @@ NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-exp
|
||||
NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/mainnet-network.json
|
||||
NX_VEGA_URL=https://api.token.vega.xyz/query
|
||||
NX_VEGA_URL=https://api.vega.xyz/query
|
||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_VEGA_ENV=MAINNET
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
# App configuration variables
|
||||
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||
NX_TENDERMINT_URL=https://tm.n06.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n06.testnet.vega.xyz/websocket
|
||||
NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n07.testnet.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
|
||||
NX_VEGA_URL=https://api.n09.testnet.vega.xyz/graphql
|
||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*", "__generated__"],
|
||||
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
|
||||
@@ -2,6 +2,12 @@ import { render, screen } from '@testing-library/react';
|
||||
import { Header } from './header';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
jest.mock('@vegaprotocol/environment', () => ({
|
||||
NetworkSwitcher: () => (
|
||||
<div data-testid="network-switcher">NetworkSwitcher</div>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('../search', () => ({
|
||||
Search: () => <div data-testid="search">OrderList</div>,
|
||||
}));
|
||||
@@ -25,4 +31,10 @@ describe('Header', () => {
|
||||
|
||||
expect(screen.getByTestId('search')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render network switcher', () => {
|
||||
render(renderComponent());
|
||||
|
||||
expect(screen.getByTestId('network-switcher')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
import { Search } from '../search';
|
||||
import { Routes } from '../../routes/route-names';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
||||
|
||||
interface ThemeToggleProps {
|
||||
theme: 'light' | 'dark';
|
||||
@@ -27,14 +28,17 @@ export const Header = ({
|
||||
);
|
||||
return (
|
||||
<header className={headerClasses}>
|
||||
<Link to={Routes.HOME}>
|
||||
<h1
|
||||
className="text-3xl font-alpha uppercase calt mb-0"
|
||||
data-testid="explorer-header"
|
||||
>
|
||||
{t('Vega Explorer')}
|
||||
</h1>
|
||||
</Link>
|
||||
<div className="flex h-full items-center sm:items-stretch gap-4">
|
||||
<Link to={Routes.HOME}>
|
||||
<h1
|
||||
className="text-3xl font-alpha uppercase calt mb-0"
|
||||
data-testid="explorer-header"
|
||||
>
|
||||
{t('Vega Explorer')}
|
||||
</h1>
|
||||
</Link>
|
||||
<NetworkSwitcher />
|
||||
</div>
|
||||
<button
|
||||
data-testid="open-menu"
|
||||
className="md:hidden"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
query AssetsQuery {
|
||||
assetsConnection {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
symbol
|
||||
decimals
|
||||
source {
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
... on BuiltinAsset {
|
||||
maxFaucetAmountMint
|
||||
}
|
||||
}
|
||||
infrastructureFeeAccount {
|
||||
type
|
||||
balance
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,5 +96,5 @@ export interface AssetsQuery {
|
||||
/**
|
||||
* The list of all assets in use in the Vega network or the specified asset if ID is provided
|
||||
*/
|
||||
assetsConnection: AssetsQuery_assetsConnection;
|
||||
assetsConnection: AssetsQuery_assetsConnection | null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type AssetsQueryQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type AssetsQueryQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string }, infrastructureFeeAccount: { __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string } | null } } } | null> | null } | null };
|
||||
|
||||
|
||||
export const AssetsQueryDocument = gql`
|
||||
query AssetsQuery {
|
||||
assetsConnection {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
symbol
|
||||
decimals
|
||||
source {
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
... on BuiltinAsset {
|
||||
maxFaucetAmountMint
|
||||
}
|
||||
}
|
||||
infrastructureFeeAccount {
|
||||
type
|
||||
balance
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useAssetsQueryQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useAssetsQueryQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useAssetsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useAssetsQueryQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useAssetsQueryQuery(baseOptions?: Apollo.QueryHookOptions<AssetsQueryQuery, AssetsQueryQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<AssetsQueryQuery, AssetsQueryQueryVariables>(AssetsQueryDocument, options);
|
||||
}
|
||||
export function useAssetsQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AssetsQueryQuery, AssetsQueryQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<AssetsQueryQuery, AssetsQueryQueryVariables>(AssetsQueryDocument, options);
|
||||
}
|
||||
export type AssetsQueryQueryHookResult = ReturnType<typeof useAssetsQueryQuery>;
|
||||
export type AssetsQueryLazyQueryHookResult = ReturnType<typeof useAssetsQueryLazyQuery>;
|
||||
export type AssetsQueryQueryResult = Apollo.QueryResult<AssetsQueryQuery, AssetsQueryQueryVariables>;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import { assetsConnectionToAssets, t } from '@vegaprotocol/react-helpers';
|
||||
import { getAssets, t } from '@vegaprotocol/react-helpers';
|
||||
import React from 'react';
|
||||
import { RouteTitle } from '../../components/route-title';
|
||||
import { SubHeading } from '../../components/sub-heading';
|
||||
@@ -39,7 +39,7 @@ export const ASSETS_QUERY = gql`
|
||||
const Assets = () => {
|
||||
const { data } = useQuery<AssetsQuery>(ASSETS_QUERY);
|
||||
|
||||
const assets = assetsConnectionToAssets(data?.assetsConnection);
|
||||
const assets = getAssets(data);
|
||||
|
||||
return (
|
||||
<section>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
query ProposalsQuery {
|
||||
proposals {
|
||||
id
|
||||
reference
|
||||
state
|
||||
datetime
|
||||
rejectionReason
|
||||
party {
|
||||
id
|
||||
}
|
||||
terms {
|
||||
closingDatetime
|
||||
enactmentDatetime
|
||||
change {
|
||||
... on NewMarket {
|
||||
instrument {
|
||||
name
|
||||
}
|
||||
}
|
||||
... on UpdateMarket {
|
||||
marketId
|
||||
}
|
||||
... on NewAsset {
|
||||
__typename
|
||||
symbol
|
||||
source {
|
||||
... on BuiltinAsset {
|
||||
maxFaucetAmountMint
|
||||
}
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
... on UpdateNetworkParameter {
|
||||
networkParameter {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
votes {
|
||||
yes {
|
||||
totalTokens
|
||||
totalNumber
|
||||
votes {
|
||||
value
|
||||
party {
|
||||
id
|
||||
stake {
|
||||
currentStakeAvailable
|
||||
}
|
||||
}
|
||||
datetime
|
||||
}
|
||||
}
|
||||
no {
|
||||
totalTokens
|
||||
totalNumber
|
||||
votes {
|
||||
value
|
||||
party {
|
||||
id
|
||||
stake {
|
||||
currentStakeAvailable
|
||||
}
|
||||
}
|
||||
datetime
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,23 @@ import { ProposalState, ProposalRejectionReason, VoteValue } from "@vegaprotocol
|
||||
// GraphQL query operation: ProposalsQuery
|
||||
// ====================================================
|
||||
|
||||
export interface ProposalsQuery_proposals_party {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_rationale {
|
||||
__typename: "ProposalRationale";
|
||||
/**
|
||||
* Title to be used to give a short description of the proposal in lists.
|
||||
* This is to be between 0 and 100 unicode characters.
|
||||
* This is mandatory for all proposals.
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* Description to show a short title / something in case the link goes offline.
|
||||
* This is to be between 0 and 20k unicode characters.
|
||||
* This is mandatory for all proposals.
|
||||
*/
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Party identifier
|
||||
@@ -17,11 +33,11 @@ export interface ProposalsQuery_proposals_party {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_UpdateAsset {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateAsset {
|
||||
__typename: "UpdateAsset" | "NewFreeform";
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewMarket_instrument {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewMarket_instrument {
|
||||
__typename: "InstrumentConfiguration";
|
||||
/**
|
||||
* Full and fairly descriptive name for the instrument
|
||||
@@ -29,20 +45,20 @@ export interface ProposalsQuery_proposals_terms_change_NewMarket_instrument {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewMarket {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewMarket {
|
||||
__typename: "NewMarket";
|
||||
/**
|
||||
* New market instrument configuration
|
||||
*/
|
||||
instrument: ProposalsQuery_proposals_terms_change_NewMarket_instrument;
|
||||
instrument: ProposalsQuery_proposalsConnection_edges_node_terms_change_NewMarket_instrument;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_UpdateMarket {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateMarket {
|
||||
__typename: "UpdateMarket";
|
||||
marketId: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewAsset_source_BuiltinAsset {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source_BuiltinAsset {
|
||||
__typename: "BuiltinAsset";
|
||||
/**
|
||||
* Maximum amount that can be requested by a party through the built-in asset faucet at a time
|
||||
@@ -50,7 +66,7 @@ export interface ProposalsQuery_proposals_terms_change_NewAsset_source_BuiltinAs
|
||||
maxFaucetAmountMint: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewAsset_source_ERC20 {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source_ERC20 {
|
||||
__typename: "ERC20";
|
||||
/**
|
||||
* The address of the ERC20 contract
|
||||
@@ -58,9 +74,9 @@ export interface ProposalsQuery_proposals_terms_change_NewAsset_source_ERC20 {
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
export type ProposalsQuery_proposals_terms_change_NewAsset_source = ProposalsQuery_proposals_terms_change_NewAsset_source_BuiltinAsset | ProposalsQuery_proposals_terms_change_NewAsset_source_ERC20;
|
||||
export type ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source = ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source_BuiltinAsset | ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source_ERC20;
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewAsset {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset {
|
||||
__typename: "NewAsset";
|
||||
/**
|
||||
* The symbol of the asset (e.g: GBP)
|
||||
@@ -69,10 +85,10 @@ export interface ProposalsQuery_proposals_terms_change_NewAsset {
|
||||
/**
|
||||
* The source of the new asset
|
||||
*/
|
||||
source: ProposalsQuery_proposals_terms_change_NewAsset_source;
|
||||
source: ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_UpdateNetworkParameter_networkParameter {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateNetworkParameter_networkParameter {
|
||||
__typename: "NetworkParameter";
|
||||
/**
|
||||
* The name of the network parameter
|
||||
@@ -84,14 +100,14 @@ export interface ProposalsQuery_proposals_terms_change_UpdateNetworkParameter_ne
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_UpdateNetworkParameter {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateNetworkParameter {
|
||||
__typename: "UpdateNetworkParameter";
|
||||
networkParameter: ProposalsQuery_proposals_terms_change_UpdateNetworkParameter_networkParameter;
|
||||
networkParameter: ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateNetworkParameter_networkParameter;
|
||||
}
|
||||
|
||||
export type ProposalsQuery_proposals_terms_change = ProposalsQuery_proposals_terms_change_UpdateAsset | ProposalsQuery_proposals_terms_change_NewMarket | ProposalsQuery_proposals_terms_change_UpdateMarket | ProposalsQuery_proposals_terms_change_NewAsset | ProposalsQuery_proposals_terms_change_UpdateNetworkParameter;
|
||||
export type ProposalsQuery_proposalsConnection_edges_node_terms_change = ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateAsset | ProposalsQuery_proposalsConnection_edges_node_terms_change_NewMarket | ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateMarket | ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset | ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateNetworkParameter;
|
||||
|
||||
export interface ProposalsQuery_proposals_terms {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_terms {
|
||||
__typename: "ProposalTerms";
|
||||
/**
|
||||
* RFC3339Nano time and date when voting closes for this proposal.
|
||||
@@ -107,18 +123,18 @@ export interface ProposalsQuery_proposals_terms {
|
||||
/**
|
||||
* Actual change being introduced by the proposal - action the proposal triggers if passed and enacted.
|
||||
*/
|
||||
change: ProposalsQuery_proposals_terms_change;
|
||||
change: ProposalsQuery_proposalsConnection_edges_node_terms_change;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_yes_votes_party_stake {
|
||||
__typename: "PartyStake";
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes_party_stakingSummary {
|
||||
__typename: "StakingSummary";
|
||||
/**
|
||||
* The stake currently available for the party
|
||||
*/
|
||||
currentStakeAvailable: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_yes_votes_party {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Party identifier
|
||||
@@ -127,10 +143,10 @@ export interface ProposalsQuery_proposals_votes_yes_votes_party {
|
||||
/**
|
||||
* The staking information for this Party
|
||||
*/
|
||||
stake: ProposalsQuery_proposals_votes_yes_votes_party_stake;
|
||||
stakingSummary: ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes_party_stakingSummary;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_yes_votes {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes {
|
||||
__typename: "Vote";
|
||||
/**
|
||||
* The vote value cast
|
||||
@@ -139,14 +155,14 @@ export interface ProposalsQuery_proposals_votes_yes_votes {
|
||||
/**
|
||||
* The party casting the vote
|
||||
*/
|
||||
party: ProposalsQuery_proposals_votes_yes_votes_party;
|
||||
party: ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes_party;
|
||||
/**
|
||||
* RFC3339Nano time and date when the vote reached Vega network
|
||||
*/
|
||||
datetime: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_yes {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_votes_yes {
|
||||
__typename: "ProposalVoteSide";
|
||||
/**
|
||||
* Total number of governance tokens from the votes cast for this side
|
||||
@@ -159,18 +175,18 @@ export interface ProposalsQuery_proposals_votes_yes {
|
||||
/**
|
||||
* All votes cast for this side
|
||||
*/
|
||||
votes: ProposalsQuery_proposals_votes_yes_votes[] | null;
|
||||
votes: ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes[] | null;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_no_votes_party_stake {
|
||||
__typename: "PartyStake";
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_votes_no_votes_party_stakingSummary {
|
||||
__typename: "StakingSummary";
|
||||
/**
|
||||
* The stake currently available for the party
|
||||
*/
|
||||
currentStakeAvailable: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_no_votes_party {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_votes_no_votes_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Party identifier
|
||||
@@ -179,10 +195,10 @@ export interface ProposalsQuery_proposals_votes_no_votes_party {
|
||||
/**
|
||||
* The staking information for this Party
|
||||
*/
|
||||
stake: ProposalsQuery_proposals_votes_no_votes_party_stake;
|
||||
stakingSummary: ProposalsQuery_proposalsConnection_edges_node_votes_no_votes_party_stakingSummary;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_no_votes {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_votes_no_votes {
|
||||
__typename: "Vote";
|
||||
/**
|
||||
* The vote value cast
|
||||
@@ -191,14 +207,14 @@ export interface ProposalsQuery_proposals_votes_no_votes {
|
||||
/**
|
||||
* The party casting the vote
|
||||
*/
|
||||
party: ProposalsQuery_proposals_votes_no_votes_party;
|
||||
party: ProposalsQuery_proposalsConnection_edges_node_votes_no_votes_party;
|
||||
/**
|
||||
* RFC3339Nano time and date when the vote reached Vega network
|
||||
*/
|
||||
datetime: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_no {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_votes_no {
|
||||
__typename: "ProposalVoteSide";
|
||||
/**
|
||||
* Total number of governance tokens from the votes cast for this side
|
||||
@@ -211,27 +227,31 @@ export interface ProposalsQuery_proposals_votes_no {
|
||||
/**
|
||||
* All votes cast for this side
|
||||
*/
|
||||
votes: ProposalsQuery_proposals_votes_no_votes[] | null;
|
||||
votes: ProposalsQuery_proposalsConnection_edges_node_votes_no_votes[] | null;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node_votes {
|
||||
__typename: "ProposalVotes";
|
||||
/**
|
||||
* Yes votes cast for this proposal
|
||||
*/
|
||||
yes: ProposalsQuery_proposals_votes_yes;
|
||||
yes: ProposalsQuery_proposalsConnection_edges_node_votes_yes;
|
||||
/**
|
||||
* No votes cast for this proposal
|
||||
*/
|
||||
no: ProposalsQuery_proposals_votes_no;
|
||||
no: ProposalsQuery_proposalsConnection_edges_node_votes_no;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals {
|
||||
export interface ProposalsQuery_proposalsConnection_edges_node {
|
||||
__typename: "Proposal";
|
||||
/**
|
||||
* Proposal ID that is filled by Vega once proposal reaches the network
|
||||
*/
|
||||
id: string | null;
|
||||
/**
|
||||
* Rationale behind the proposal
|
||||
*/
|
||||
rationale: ProposalsQuery_proposalsConnection_edges_node_rationale;
|
||||
/**
|
||||
* A UUID reference to aid tracking proposals on Vega
|
||||
*/
|
||||
@@ -251,20 +271,36 @@ export interface ProposalsQuery_proposals {
|
||||
/**
|
||||
* Party that prepared the proposal
|
||||
*/
|
||||
party: ProposalsQuery_proposals_party;
|
||||
party: ProposalsQuery_proposalsConnection_edges_node_party;
|
||||
/**
|
||||
* Terms of the proposal
|
||||
*/
|
||||
terms: ProposalsQuery_proposals_terms;
|
||||
terms: ProposalsQuery_proposalsConnection_edges_node_terms;
|
||||
/**
|
||||
* Votes cast for this proposal
|
||||
*/
|
||||
votes: ProposalsQuery_proposals_votes;
|
||||
votes: ProposalsQuery_proposalsConnection_edges_node_votes;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposalsConnection_edges {
|
||||
__typename: "ProposalEdge";
|
||||
/**
|
||||
* The proposal data
|
||||
*/
|
||||
node: ProposalsQuery_proposalsConnection_edges_node;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposalsConnection {
|
||||
__typename: "ProposalsConnection";
|
||||
/**
|
||||
* List of proposals available for the connection
|
||||
*/
|
||||
edges: (ProposalsQuery_proposalsConnection_edges | null)[] | null;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery {
|
||||
/**
|
||||
* All governance proposals in the Vega network
|
||||
*/
|
||||
proposals: ProposalsQuery_proposals[] | null;
|
||||
proposalsConnection: ProposalsQuery_proposalsConnection | null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type ProposalsQueryQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type ProposalsQueryQuery = { __typename?: 'Query', proposals?: Array<{ __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, rejectionReason?: Types.ProposalRejectionReason | null, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename: 'NewAsset', symbol: string, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', instrument: { __typename?: 'InstrumentConfiguration', name: string } } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null } } }> | null };
|
||||
|
||||
|
||||
export const ProposalsQueryDocument = gql`
|
||||
query ProposalsQuery {
|
||||
proposals {
|
||||
id
|
||||
reference
|
||||
state
|
||||
datetime
|
||||
rejectionReason
|
||||
party {
|
||||
id
|
||||
}
|
||||
terms {
|
||||
closingDatetime
|
||||
enactmentDatetime
|
||||
change {
|
||||
... on NewMarket {
|
||||
instrument {
|
||||
name
|
||||
}
|
||||
}
|
||||
... on UpdateMarket {
|
||||
marketId
|
||||
}
|
||||
... on NewAsset {
|
||||
__typename
|
||||
symbol
|
||||
source {
|
||||
... on BuiltinAsset {
|
||||
maxFaucetAmountMint
|
||||
}
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
... on UpdateNetworkParameter {
|
||||
networkParameter {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
votes {
|
||||
yes {
|
||||
totalTokens
|
||||
totalNumber
|
||||
votes {
|
||||
value
|
||||
party {
|
||||
id
|
||||
stake {
|
||||
currentStakeAvailable
|
||||
}
|
||||
}
|
||||
datetime
|
||||
}
|
||||
}
|
||||
no {
|
||||
totalTokens
|
||||
totalNumber
|
||||
votes {
|
||||
value
|
||||
party {
|
||||
id
|
||||
stake {
|
||||
currentStakeAvailable
|
||||
}
|
||||
}
|
||||
datetime
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useProposalsQueryQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useProposalsQueryQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useProposalsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useProposalsQueryQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useProposalsQueryQuery(baseOptions?: Apollo.QueryHookOptions<ProposalsQueryQuery, ProposalsQueryQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<ProposalsQueryQuery, ProposalsQueryQueryVariables>(ProposalsQueryDocument, options);
|
||||
}
|
||||
export function useProposalsQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ProposalsQueryQuery, ProposalsQueryQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<ProposalsQueryQuery, ProposalsQueryQueryVariables>(ProposalsQueryDocument, options);
|
||||
}
|
||||
export type ProposalsQueryQueryHookResult = ReturnType<typeof useProposalsQueryQuery>;
|
||||
export type ProposalsQueryLazyQueryHookResult = ReturnType<typeof useProposalsQueryLazyQuery>;
|
||||
export type ProposalsQueryQueryResult = Apollo.QueryResult<ProposalsQueryQuery, ProposalsQueryQueryVariables>;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user