Compare commits
403
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e87ee18b6 | ||
|
|
96d331e714 | ||
|
|
4cbf7c3a4a | ||
|
|
7800d2d566 | ||
|
|
089dc33323 | ||
|
|
b615e019b1 | ||
|
|
cfab9e61f3 | ||
|
|
53f3e39210 | ||
|
|
633c2ae526 | ||
|
|
3bc9d3386b | ||
|
|
17f93c2b7e | ||
|
|
fcd99722b9 | ||
|
|
ab6307497d | ||
|
|
4d20151abd | ||
|
|
630ef4a22d | ||
|
|
d0976bbd46 | ||
|
|
317dfc4bb1 | ||
|
|
e2d4a6d0eb | ||
|
|
786b85fde2 | ||
|
|
ee3b9a56c9 | ||
|
|
2d9fdbf98c | ||
|
|
d4cbd4042b | ||
|
|
26d277d775 | ||
|
|
da726ea439 | ||
|
|
6dded8c2d2 | ||
|
|
d15af74ba5 | ||
|
|
8877391284 | ||
|
|
6a57672257 | ||
|
|
bf34f1c060 | ||
|
|
513c7f2b1a | ||
|
|
884411e5b8 | ||
|
|
4516a09c43 | ||
|
|
cd99ae20a0 | ||
|
|
bc3a53c259 | ||
|
|
dddcd3d6f5 | ||
|
|
cc7897f723 | ||
|
|
bb82fe75da | ||
|
|
c6f8ff68b8 | ||
|
|
23b517b4a1 | ||
|
|
c3175d3e65 | ||
|
|
33be5bc069 | ||
|
|
bbb6cfe780 | ||
|
|
269d3820dc | ||
|
|
2fa640a467 | ||
|
|
e66b6586b5 | ||
|
|
5a5e06a8e9 | ||
|
|
ba9ad40ad2 | ||
|
|
bb8d2660a0 | ||
|
|
5f2c7179c9 | ||
|
|
31ea48b90a | ||
|
|
1964d42e5b | ||
|
|
70eeeeb1e2 | ||
|
|
044eb160af | ||
|
|
61cfac22a1 | ||
|
|
52b8f21a85 | ||
|
|
8f8ccc9f0c | ||
|
|
fbf21e9cb8 | ||
|
|
c15765de79 | ||
|
|
3c0dd55d7c | ||
|
|
082a58e6fc | ||
|
|
8d2fe118ec | ||
|
|
ce283aeee7 | ||
|
|
9465543b23 | ||
|
|
50611a4ba6 | ||
|
|
5d04efe52d | ||
|
|
349722d56d | ||
|
|
7c4ce6eb87 | ||
|
|
cc8f052a5b | ||
|
|
033ee14009 | ||
|
|
9a56fc9b6f | ||
|
|
ab760eee58 | ||
|
|
a6576132b1 | ||
|
|
21ae0f2592 | ||
|
|
fb464b956f | ||
|
|
835ffdbfb4 | ||
|
|
1a539efdd6 | ||
|
|
346901fc9c | ||
|
|
6a1b823838 | ||
|
|
d8544ddd00 | ||
|
|
3b41e9f2f8 | ||
|
|
1124a86527 | ||
|
|
941e439082 | ||
|
|
ee33721010 | ||
|
|
16d765fff3 | ||
|
|
50dfcfa058 | ||
|
|
e984ea8e2a | ||
|
|
1bc41c8a9a | ||
|
|
5e75e0ee21 | ||
|
|
9e7277e578 | ||
|
|
6958f551b8 | ||
|
|
8bbf12f754 | ||
|
|
c6540d9bb4 | ||
|
|
9dd9674e2f | ||
|
|
1b23ea1f70 | ||
|
|
d6c7f9bcc0 | ||
|
|
ed250c1ba2 | ||
|
|
0a52fca40f | ||
|
|
304503f515 | ||
|
|
904d7345d8 | ||
|
|
dbabea3aec | ||
|
|
da1eab5281 | ||
|
|
b1c15d5711 | ||
|
|
37a6217169 | ||
|
|
ecb19f226b | ||
|
|
8ecb4430cc | ||
|
|
144b4bd847 | ||
|
|
6d71109798 | ||
|
|
16d35df133 | ||
|
|
be9e1ee84b | ||
|
|
7aac1b6506 | ||
|
|
fe472acfe9 | ||
|
|
d674162e38 | ||
|
|
0182b32708 | ||
|
|
8246a942c2 | ||
|
|
6038fca01e | ||
|
|
56d9a70b97 | ||
|
|
1fce4c0ed6 | ||
|
|
969d66a6a1 | ||
|
|
dee0b016eb | ||
|
|
cb92a30015 | ||
|
|
29e6bc8375 | ||
|
|
152a55831a | ||
|
|
3f5a0bc452 | ||
|
|
f4fcb62395 | ||
|
|
79a53e18b8 | ||
|
|
38c58ba54e | ||
|
|
ad553f8a9e | ||
|
|
b45c97ed96 | ||
|
|
d071ffa777 | ||
|
|
06541a1527 | ||
|
|
7c5bfc4471 | ||
|
|
00381a2b3e | ||
|
|
50df63c858 | ||
|
|
5152e3f603 | ||
|
|
62203b5e73 | ||
|
|
f2aaf287eb | ||
|
|
5e423f4fd3 | ||
|
|
219e29b947 | ||
|
|
f2f0f33975 | ||
|
|
0129dbd611 | ||
|
|
7824c39bfe | ||
|
|
6ec6c6b8b7 | ||
|
|
a7d100bce8 | ||
|
|
0b8c9c836c | ||
|
|
0bb2e95091 | ||
|
|
64c85b2b4a | ||
|
|
503c831018 | ||
|
|
9dfe8789d1 | ||
|
|
224ec8653b | ||
|
|
178597dc01 | ||
|
|
e6c19cf9b1 | ||
|
|
79ddf307a9 | ||
|
|
2e841b009d | ||
|
|
e25f0085eb | ||
|
|
4d8abeb2a3 | ||
|
|
37ecb0d526 | ||
|
|
c3e70d6457 | ||
|
|
fb9505a8a8 | ||
|
|
2edd2d95ff | ||
|
|
4ac34a3c4b | ||
|
|
a62bc35a2a | ||
|
|
3be90c55bb | ||
|
|
ebf1f5ac7b | ||
|
|
185787dfe0 | ||
|
|
cafb5e3706 | ||
|
|
4adadcfe3c | ||
|
|
11dc6e39c7 | ||
|
|
1f9c53e210 | ||
|
|
1b8da24ea1 | ||
|
|
a83df68f7c | ||
|
|
a71f40956b | ||
|
|
eb3ca33eae | ||
|
|
ec47ee2930 | ||
|
|
057322c4d7 | ||
|
|
7d3c90f3ca | ||
|
|
7df7626418 | ||
|
|
48ce7978ee | ||
|
|
4ca22c4e98 | ||
|
|
ad9436c7cf | ||
|
|
329d073b34 | ||
|
|
38454a7e33 | ||
|
|
c03281ee0d | ||
|
|
2ef64a3e2f | ||
|
|
7a7766d79a | ||
|
|
e588418972 | ||
|
|
ae10cdfb2c | ||
|
|
ddeb514aaa | ||
|
|
656cda636f | ||
|
|
46d03826cc | ||
|
|
b2619eac7c | ||
|
|
0821cafdf0 | ||
|
|
2bf614afd2 | ||
|
|
50d0c45d51 | ||
|
|
1f8f54617b | ||
|
|
61721e61f6 | ||
|
|
d6583f5969 | ||
|
|
df04825ce5 | ||
|
|
e82c4b5b3a | ||
|
|
727d303932 | ||
|
|
27545ba697 | ||
|
|
7863384974 | ||
|
|
15e6c4ffef | ||
|
|
2031a57b48 | ||
|
|
3c53b7059b | ||
|
|
22ebbf746a | ||
|
|
d889b8e970 | ||
|
|
a40f494a6f | ||
|
|
faa1d51acb | ||
|
|
ae4960f700 | ||
|
|
406b69566f | ||
|
|
8156a3c1a9 | ||
|
|
eacf95ea10 | ||
|
|
4ed623c84c | ||
|
|
fe6c5520a9 | ||
|
|
40527e9bc8 | ||
|
|
6681c01b43 | ||
|
|
ae8ef6001c | ||
|
|
620bf1bab4 | ||
|
|
09476eea38 | ||
|
|
9486db134c | ||
|
|
edb31e0f46 | ||
|
|
f743828cb5 | ||
|
|
b10844147e | ||
|
|
361f8fa870 | ||
|
|
1d87eab47c | ||
|
|
96811b45e3 | ||
|
|
520f767d09 | ||
|
|
219c9e1b41 | ||
|
|
0a5a87f432 | ||
|
|
eb7b261ec4 | ||
|
|
d70059a0d4 | ||
|
|
b7c3b9cdb0 | ||
|
|
6473738758 | ||
|
|
1a2130abbd | ||
|
|
1ec7cc2ed5 | ||
|
|
dade1e502e | ||
|
|
335d1bef38 | ||
|
|
009a6cc2e1 | ||
|
|
2aa23ae202 | ||
|
|
1a7ad58199 | ||
|
|
682049d17c | ||
|
|
c221d0772c | ||
|
|
efcd128240 | ||
|
|
9a88c33458 | ||
|
|
d2a5adf6ce | ||
|
|
ab0065bd9a | ||
|
|
5600c56da1 | ||
|
|
3d7267f496 | ||
|
|
c87beb4050 | ||
|
|
907a4e256e | ||
|
|
835bf36393 | ||
|
|
57863a7167 | ||
|
|
4272fefb0b | ||
|
|
8fee3ca080 | ||
|
|
98abe2910d | ||
|
|
22f4edff82 | ||
|
|
28aa5cd060 | ||
|
|
7b0d41b4a6 | ||
|
|
83ea12b4cb | ||
|
|
a7768f154b | ||
|
|
65af6bc0a8 | ||
|
|
93c1835cd6 | ||
|
|
446af23d9c | ||
|
|
2cfe8608fb | ||
|
|
032805b5b9 | ||
|
|
7a7c4ad452 | ||
|
|
0c5b2f5c29 | ||
|
|
a8667eea31 | ||
|
|
8dd63d7cac | ||
|
|
8bffc05be2 | ||
|
|
26e3596c5a | ||
|
|
6ad68f87cc | ||
|
|
86fdd75d6c | ||
|
|
f688b28b29 | ||
|
|
6ddceaf6bd | ||
|
|
a9e8b6915e | ||
|
|
9318dab698 | ||
|
|
ae0424e21a | ||
|
|
5e484dfab0 | ||
|
|
e5b1390302 | ||
|
|
6a6779ee72 | ||
|
|
414b8ced13 | ||
|
|
e310f04034 | ||
|
|
adf6059701 | ||
|
|
5dda58334e | ||
|
|
3b03b16938 | ||
|
|
0d8c052ec6 | ||
|
|
9836f29e15 | ||
|
|
4d69dceaa7 | ||
|
|
6af189150b | ||
|
|
6f20c9125d | ||
|
|
7c6b14f73a | ||
|
|
0fa1f47ad5 | ||
|
|
c4468d507b | ||
|
|
191e73335e | ||
|
|
dae8949b46 | ||
|
|
3aca9207ed | ||
|
|
69db3fdecb | ||
|
|
d9a747102d | ||
|
|
3f6bd066f1 | ||
|
|
195e234f16 | ||
|
|
b505a0598d | ||
|
|
f87fd676f6 | ||
|
|
b885696659 | ||
|
|
5d553271a5 | ||
|
|
87f7efd960 | ||
|
|
d9e3b9de99 | ||
|
|
b5e2513d53 | ||
|
|
ba27f9e738 | ||
|
|
22787bd4c4 | ||
|
|
c5eeead356 | ||
|
|
612b906cb4 | ||
|
|
94a2de859f | ||
|
|
f287dced18 | ||
|
|
3beb43a719 | ||
|
|
da807c883d | ||
|
|
5a842c9be9 | ||
|
|
3bec65ac67 | ||
|
|
f124275ce5 | ||
|
|
d271f28b82 | ||
|
|
483cf05050 | ||
|
|
a452a6e831 | ||
|
|
ebf2bfc7a9 | ||
|
|
d60cf3e5e6 | ||
|
|
2650329a31 | ||
|
|
4ef8218267 | ||
|
|
e3254564ae | ||
|
|
7effa0791c | ||
|
|
93108c5b48 | ||
|
|
06a2fc4d12 | ||
|
|
c274a4694a | ||
|
|
756d4d00de | ||
|
|
ac16ca9ee5 | ||
|
|
c3cdcede9f | ||
|
|
186a624466 | ||
|
|
4d9c43cf19 | ||
|
|
8f20216b39 | ||
|
|
5c4af868a7 | ||
|
|
d95bfb60ea | ||
|
|
792459e589 | ||
|
|
4ca244a975 | ||
|
|
010d7e5e31 | ||
|
|
9b04310ab8 | ||
|
|
832327c918 | ||
|
|
c59aa19bd2 | ||
|
|
efc1d909b3 | ||
|
|
cc7a4f2ddd | ||
|
|
ddbaea5e3f | ||
|
|
1fd325a44f | ||
|
|
2ad248b6d7 | ||
|
|
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 |
+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
|
||||
@@ -0,0 +1,31 @@
|
||||
inputs:
|
||||
all:
|
||||
description: 'Install all binaries'
|
||||
default: false
|
||||
version:
|
||||
description: 'Vega version'
|
||||
gobin:
|
||||
description: 'GOBIN path'
|
||||
default: '/home/runner/go/bin'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Install Vega binaries
|
||||
if: ${{ inputs.all }}
|
||||
shell: bash
|
||||
run: |
|
||||
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/vega-linux-amd64.zip' -q
|
||||
unzip vega-linux-amd64.zip -d ${{ inputs.gobin }}
|
||||
|
||||
- name: Install date-node binaries
|
||||
if: ${{ inputs.all }}
|
||||
shell: bash
|
||||
run: |
|
||||
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/data-node-linux-amd64.zip' -q
|
||||
unzip data-node-linux-amd64.zip -d ${{ inputs.gobin }}
|
||||
|
||||
- name: Install Vega wallet binaries
|
||||
shell: bash
|
||||
run: |
|
||||
wget 'https://github.com/vegaprotocol/vega/releases/download/${{ env.VEGA_VERSION }}/vegawallet-linux-amd64.zip' -q
|
||||
unzip vegawallet-linux-amd64.zip -d ${{ inputs.gobin }}
|
||||
@@ -0,0 +1,30 @@
|
||||
inputs:
|
||||
github-token:
|
||||
description: 'github token'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Checkout capsule
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vegaprotocol/vegacapsule
|
||||
ref: main
|
||||
token: ${{ inputs.github-token }}
|
||||
path: './capsule'
|
||||
|
||||
- name: Build capsule
|
||||
run: go install
|
||||
shell: bash
|
||||
working-directory: capsule
|
||||
|
||||
- name: Login to docker
|
||||
shell: bash
|
||||
run: echo -n ${{ inputs.github-token }} | docker login https://ghcr.io -u vega-ci-bot --password-stdin
|
||||
|
||||
- name: Start nomad
|
||||
shell: bash
|
||||
run: vegacapsule nomad &
|
||||
|
||||
- name: Bootstrap network
|
||||
shell: bash
|
||||
run: vegacapsule network bootstrap --config-path=./frontend-monorepo/vegacapsule/config.hcl --force
|
||||
@@ -0,0 +1,45 @@
|
||||
inputs:
|
||||
recovery:
|
||||
description: 'Recovery phrase'
|
||||
passphrase:
|
||||
description: 'Wallet password'
|
||||
capsule:
|
||||
description: 'Is Capsule network used'
|
||||
default: false
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Create passphrase
|
||||
shell: bash
|
||||
run: echo "${{ inputs.passphrase }}" > ./passphrase
|
||||
|
||||
- name: Create recovery
|
||||
shell: bash
|
||||
run: echo "${{ inputs.recovery }}" > ./recovery
|
||||
|
||||
- name: Initialize wallet
|
||||
shell: bash
|
||||
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
|
||||
|
||||
- name: Import wallet
|
||||
shell: bash
|
||||
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
|
||||
- name: Create public key 2
|
||||
shell: bash
|
||||
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
|
||||
- name: Import fairground network
|
||||
shell: bash
|
||||
if: ${{ inputs.capsule==false }}
|
||||
run: vegawallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks-internal/master/stagnet3/stagnet3.toml" --force --home ~/.vegacapsule/testnet/wallet
|
||||
|
||||
- name: Start service using fairground network
|
||||
shell: bash
|
||||
if: ${{ inputs.capsule==false }}
|
||||
run: vegawallet service run --network stagnet3 --automatic-consent --no-version-check --home ~/.vegacapsule/testnet/wallet &
|
||||
|
||||
- name: Start service using capsule network
|
||||
shell: bash
|
||||
if: ${{ inputs.capsule==true }}
|
||||
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Capsule tests -- manual trigger
|
||||
name: Cypress tests -- manual trigger
|
||||
|
||||
# This workflow runs the frontend tests against chosen branch
|
||||
|
||||
@@ -15,20 +15,43 @@ on:
|
||||
- stats-e2e
|
||||
- token-e2e
|
||||
- trading-e2e
|
||||
includeFlows:
|
||||
description: 'Include long flows (if any)?'
|
||||
smokeOnly:
|
||||
description: 'Run only smoke tests?'
|
||||
required: true
|
||||
type: boolean
|
||||
default: true
|
||||
default: false
|
||||
skip-nx-cache:
|
||||
description: 'Add --skip-nx-cache to cypress test'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
manual:
|
||||
name: Run capsule tests -- manual trigger
|
||||
runs-on: ubuntu-latest
|
||||
name: Run Cypress tests -- manual trigger
|
||||
runs-on: self-hosted
|
||||
env:
|
||||
GO111MODULE: 'on'
|
||||
GOPROXY: ${{ secrets.GO_PROXY }}
|
||||
GOBIN: /home/runner/go/bin
|
||||
VEGA_VERSION: 'v0.58.0'
|
||||
steps:
|
||||
#######
|
||||
## Setup flags
|
||||
#######
|
||||
|
||||
- name: Set smoke tag
|
||||
if: ${{ github.event.inputs.smokeOnly == 'true' }}
|
||||
run: echo TAGS="--env.grepTags @smoke" >> $GITHUB_ENV
|
||||
|
||||
- name: Set --skip-nx-cache flag
|
||||
if: ${{ github.event.inputs.skip-nx-cache == 'true' }}
|
||||
run: echo SKIP_NX_CACHE="--skip-nx-cache" >> $GITHUB_ENV
|
||||
|
||||
# See if we capsule is needed for this project
|
||||
- name: Set capsule flag
|
||||
if: ${{ github.event.inputs.project == 'explorer-e2e' || github.event.inputs.project == 'token-e2e'}}
|
||||
run: echo RUN_CAPSULE=true >> $GITHUB_ENV
|
||||
|
||||
#######
|
||||
## Setup langs
|
||||
#######
|
||||
@@ -37,6 +60,7 @@ jobs:
|
||||
id: go
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Set up Node 16
|
||||
uses: actions/setup-node@v2
|
||||
id: npm
|
||||
@@ -44,112 +68,92 @@ jobs:
|
||||
node-version: 16
|
||||
|
||||
#######
|
||||
## Checkout capsule
|
||||
## Install Yarn
|
||||
#######
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
#######
|
||||
## Checkout repos
|
||||
#######
|
||||
|
||||
# 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
|
||||
# Restore node_modules from cache if possible
|
||||
- name: Restore node_modules from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
repository: vegaprotocol/vegacapsule
|
||||
ref: main
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './capsule'
|
||||
path: |
|
||||
frontend-monorepo/node_modules
|
||||
/home/runner/.cache/Cypress
|
||||
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
|
||||
|
||||
# Install frontend dependencies
|
||||
- name: Install root dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
#######
|
||||
## Build binaries
|
||||
## Build and run Vegacapsule network
|
||||
#######
|
||||
- name: Build capsule
|
||||
run: go install
|
||||
working-directory: capsule
|
||||
|
||||
- name: Set GOBIN
|
||||
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout Vega
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vegaprotocol/vega
|
||||
ref: v0.54.0
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './vega'
|
||||
|
||||
- name: Install Vega binaries
|
||||
run: go install -v ./cmd/vega
|
||||
working-directory: vega
|
||||
uses: ./frontend-monorepo/.github/actions/install-vega-binaries
|
||||
with:
|
||||
all: ${{ env.RUN_CAPSULE }}
|
||||
version: ${{ env.VEGA_VERSION }}
|
||||
gobin: ${{ env.GOBIN }}
|
||||
|
||||
- name: Install Vega wallet binaries
|
||||
run: go install ./cmd/vegawallet
|
||||
working-directory: vega
|
||||
|
||||
- name: Install date-node binaries
|
||||
run: go install ./cmd/data-node
|
||||
working-directory: vega
|
||||
|
||||
######
|
||||
## Start capsule
|
||||
######
|
||||
- name: Login to docker
|
||||
run: echo -n ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} | docker login https://ghcr.io -u vega-ci-bot --password-stdin
|
||||
|
||||
- name: Start nomad
|
||||
run: vegacapsule nomad &
|
||||
|
||||
- name: Bootstrap network
|
||||
run: vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
|
||||
working-directory: capsule
|
||||
- name: Build and run Vegacapsule network
|
||||
if: ${{ env.RUN_CAPSULE }}
|
||||
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
||||
with:
|
||||
github-token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
|
||||
######
|
||||
## Setup a Vega wallet for our user
|
||||
######
|
||||
- name: Create passphrase
|
||||
run: echo "${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}" > ./passphrase
|
||||
- name: Create recovery
|
||||
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
||||
|
||||
- name: Initialize wallet
|
||||
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Import wallet
|
||||
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Create public key 2
|
||||
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Start service
|
||||
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
|
||||
- name: Set up Vegawallet
|
||||
uses: ./frontend-monorepo/.github/actions/setup-vegawallet
|
||||
with:
|
||||
recovery: ${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}
|
||||
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
||||
capsule: ${{ env.RUN_CAPSULE }}
|
||||
|
||||
######
|
||||
## Run some tests
|
||||
######
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
# To make sure that all Cypress binaries are installed properly
|
||||
- name: Install cypress bins
|
||||
run: yarn cypress install
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: yarn nx run ${{ github.event.inputs.project }}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
run: yarn nx run ${{ github.event.inputs.project }}:e2e ${{ env.SKIP_NX_CACHE }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome ${{ env.TAGS }}
|
||||
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_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
|
||||
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: false
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
######
|
||||
|
||||
- name: Logs
|
||||
if: ${{ always() }}
|
||||
if: ${{ env.RUN_CAPSULE }}
|
||||
run: vegacapsule network logs > vega-capsule-logs.txt
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: ${{ env.RUN_CAPSULE }}
|
||||
with:
|
||||
name: logs
|
||||
path: ./vega-capsule-logs.txt
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
name: Capsule tests -- night run
|
||||
name: Cypress tests -- night run
|
||||
|
||||
# This workflow runs the frontend tests against latest develop of the core to preempt breaking changes
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 4 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
nightly:
|
||||
name: Run capsule tests -- nightly
|
||||
runs-on: ubuntu-latest
|
||||
name: Run Cypress tests -- nightly
|
||||
runs-on: self-hosted
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
GO111MODULE: 'on'
|
||||
GOBIN: /home/runner/go/bin
|
||||
VEGA_VERSION: 'v0.58.0'
|
||||
RUN_CAPSULE: true
|
||||
steps:
|
||||
#######
|
||||
## Setup langs
|
||||
@@ -28,110 +33,88 @@ jobs:
|
||||
node-version: 16
|
||||
|
||||
#######
|
||||
## Checkout capsule
|
||||
## Install Yarn
|
||||
#######
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
#######
|
||||
## Checkout repos
|
||||
#######
|
||||
|
||||
# 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
|
||||
# Restore node_modules from cache if possible
|
||||
- name: Restore node_modules from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
repository: vegaprotocol/vegacapsule
|
||||
ref: main
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './capsule'
|
||||
path: |
|
||||
frontend-monorepo/node_modules
|
||||
/home/runner/.cache/Cypress
|
||||
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
|
||||
|
||||
# Install frontend dependencies
|
||||
- name: Install root dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
#######
|
||||
## Build binaries
|
||||
## Build and run Vegacapsule network
|
||||
#######
|
||||
- name: Build capsule
|
||||
run: go install
|
||||
working-directory: capsule
|
||||
|
||||
- name: Set GOBIN
|
||||
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout Vega
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vegaprotocol/vega
|
||||
ref: v0.54.0
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './vega'
|
||||
|
||||
- name: Install Vega binaries
|
||||
run: go install -v ./cmd/vega
|
||||
working-directory: vega
|
||||
uses: ./frontend-monorepo/.github/actions/install-vega-binaries
|
||||
with:
|
||||
all: ${{ env.RUN_CAPSULE }}
|
||||
version: ${{ env.VEGA_VERSION }}
|
||||
gobin: ${{ env.GOBIN }}
|
||||
|
||||
- name: Install Vega wallet binaries
|
||||
run: go install ./cmd/vegawallet
|
||||
working-directory: vega
|
||||
|
||||
- name: Install date-node binaries
|
||||
run: go install ./cmd/data-node
|
||||
working-directory: vega
|
||||
|
||||
######
|
||||
## Start capsule
|
||||
######
|
||||
- name: Login to docker
|
||||
run: echo -n ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} | docker login https://ghcr.io -u vega-ci-bot --password-stdin
|
||||
|
||||
- name: Start nomad
|
||||
run: vegacapsule nomad &
|
||||
|
||||
- name: Bootstrap network
|
||||
run: vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
|
||||
working-directory: capsule
|
||||
- name: Build and run Vegacapsule network
|
||||
if: ${{ env.RUN_CAPSULE }}
|
||||
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
||||
with:
|
||||
github-token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
|
||||
######
|
||||
## Setup a Vega wallet for our user
|
||||
######
|
||||
- name: Create passphrase
|
||||
run: echo "${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}" > ./passphrase
|
||||
- name: Create recovery
|
||||
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
||||
|
||||
- name: Initialize wallet
|
||||
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Import wallet
|
||||
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Create public key 2
|
||||
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Start service
|
||||
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
|
||||
- name: Set up Vegawallet
|
||||
uses: ./frontend-monorepo/.github/actions/setup-vegawallet
|
||||
with:
|
||||
recovery: ${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}
|
||||
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
||||
capsule: ${{ env.RUN_CAPSULE }}
|
||||
|
||||
######
|
||||
## Run some tests
|
||||
######
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
# To make sure that all Cypress binaries are installed properly
|
||||
- name: Install cypress bins
|
||||
run: yarn cypress install
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: yarn nx run-many --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
run: yarn nx run-many --skip-nx-cache --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome --parallel=1
|
||||
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_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
|
||||
CYPRESS_NIGHTLY_RUN: true
|
||||
CYPRESS_INCLUDE_FLOWS: true
|
||||
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
######
|
||||
|
||||
- name: Logs
|
||||
if: ${{ always() }}
|
||||
run: vegacapsule network logs > vega-capsule-logs.txt
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
name: Capsule tests
|
||||
name: Cypress tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- main
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
@@ -14,11 +14,13 @@ on:
|
||||
|
||||
jobs:
|
||||
pr:
|
||||
name: Run capsule tests - PR
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == false }}
|
||||
name: Run Cypress tests - PR
|
||||
runs-on: self-hosted
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
GO111MODULE: 'on'
|
||||
GOBIN: /home/runner/go/bin
|
||||
VEGA_VERSION: 'v0.58.0'
|
||||
steps:
|
||||
#######
|
||||
## Setup langs
|
||||
@@ -28,6 +30,7 @@ jobs:
|
||||
id: go
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Set up Node 16
|
||||
uses: actions/setup-node@v2
|
||||
id: npm
|
||||
@@ -35,119 +38,109 @@ jobs:
|
||||
node-version: 16
|
||||
|
||||
#######
|
||||
## Checkout capsule
|
||||
## Install Yarn
|
||||
#######
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
#######
|
||||
## Checkout repos
|
||||
#######
|
||||
|
||||
# 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
|
||||
# Restore node_modules from cache if possible
|
||||
- name: Restore node_modules from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
repository: vegaprotocol/vegacapsule
|
||||
ref: main
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './capsule'
|
||||
path: |
|
||||
frontend-monorepo/node_modules
|
||||
/home/runner/.cache/Cypress
|
||||
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
|
||||
|
||||
# Install frontend dependencies
|
||||
- name: Install root dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
# Check SHAs
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v2
|
||||
with:
|
||||
working-directory: frontend-monorepo
|
||||
main-branch-name: ${{ github.base_ref || github.ref_name }}
|
||||
set-environment-variables-for-job: true
|
||||
|
||||
# See if we capsule is needed for this project
|
||||
- name: See affected apps
|
||||
run: echo AFFECTED=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects) >> $GITHUB_ENV
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
- name: See if capsule is necessary
|
||||
if: ${{ contains(env.AFFECTED, 'token') || contains(env.AFFECTED, 'token-e2e') || contains(env.AFFECTED, 'explorer') || contains(env.AFFECTED, 'explorer-e2e') }}
|
||||
run: echo RUN_CAPSULE=true >> $GITHUB_ENV
|
||||
|
||||
#######
|
||||
## Build binaries
|
||||
## Build and run Vegacapsule network
|
||||
#######
|
||||
- name: Build capsule
|
||||
run: go install
|
||||
working-directory: capsule
|
||||
|
||||
- name: Set GOBIN
|
||||
run: echo GOBIN=$(go env GOPATH)/bin >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout Vega
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: vegaprotocol/vega
|
||||
ref: v0.54.0
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
path: './vega'
|
||||
|
||||
- name: Install Vega binaries
|
||||
run: go install -v ./cmd/vega
|
||||
working-directory: vega
|
||||
uses: ./frontend-monorepo/.github/actions/install-vega-binaries
|
||||
with:
|
||||
all: ${{ env.RUN_CAPSULE }}
|
||||
version: ${{ env.VEGA_VERSION }}
|
||||
gobin: ${{ env.GOBIN }}
|
||||
|
||||
- name: Install Vega wallet binaries
|
||||
run: go install ./cmd/vegawallet
|
||||
working-directory: vega
|
||||
|
||||
- name: Install date-node binaries
|
||||
run: go install ./cmd/data-node
|
||||
working-directory: vega
|
||||
|
||||
######
|
||||
## Start capsule
|
||||
######
|
||||
- name: Login to docker
|
||||
run: echo -n ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} | docker login https://ghcr.io -u vega-ci-bot --password-stdin
|
||||
|
||||
- name: Start nomad
|
||||
run: vegacapsule nomad &
|
||||
|
||||
- name: Bootstrap network
|
||||
run: vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
|
||||
working-directory: capsule
|
||||
- name: Build and run Vegacapsule network
|
||||
if: ${{ env.RUN_CAPSULE }}
|
||||
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
||||
with:
|
||||
github-token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
|
||||
######
|
||||
## Setup a Vega wallet for our user
|
||||
######
|
||||
- name: Create passphrase
|
||||
run: echo "${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}" > ./passphrase
|
||||
- name: Create recovery
|
||||
run: echo "${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}" > ./recovery
|
||||
|
||||
- name: Initialize wallet
|
||||
run: vegawallet init -f --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Import wallet
|
||||
run: vegawallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Create public key 2
|
||||
run: vegawallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
|
||||
- name: Start service
|
||||
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
|
||||
- name: Set up Vegawallet
|
||||
uses: ./frontend-monorepo/.github/actions/setup-vegawallet
|
||||
with:
|
||||
recovery: ${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}
|
||||
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
|
||||
capsule: ${{ env.RUN_CAPSULE }}
|
||||
|
||||
######
|
||||
## Run some tests
|
||||
######
|
||||
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v2
|
||||
with:
|
||||
working-directory: frontend-monorepo
|
||||
main-branch-name: master
|
||||
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
# To make sure that all Cypress binaries are installed properly
|
||||
- name: Install cypress bins
|
||||
run: yarn cypress install
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: npx nx affected:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
run: npx nx affected:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --env.grepTags='@smoke' --browser chrome
|
||||
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_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
|
||||
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: false
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
######
|
||||
|
||||
- name: Logs
|
||||
if: ${{ always() }}
|
||||
if: ${{ env.RUN_CAPSULE }}
|
||||
run: vegacapsule network logs > vega-capsule-logs.txt
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: ${{ always() }}
|
||||
if: ${{ env.RUN_CAPSULE }}
|
||||
with:
|
||||
name: logs
|
||||
path: ./vega-capsule-logs.txt
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Generate queries
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
master:
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
name: Deploy affected projects to IPFS
|
||||
|
||||
'on':
|
||||
# Triggers the workflow on push to main branch
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch: null
|
||||
|
||||
jobs:
|
||||
master:
|
||||
name: Publish NX Affected
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
fetch-depth: 0
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.14.0
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
- name: Run deploy for affected sites
|
||||
env:
|
||||
FLEEK_API_KEY: ${{ secrets.FLEEK_API_KEY }}
|
||||
run: ./tools/ipfs-deploy.js
|
||||
+10
-37
@@ -3,50 +3,16 @@ name: Unit tests & build
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
master:
|
||||
name: Test and lint - main
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: 'read'
|
||||
actions: 'read'
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
fetch-depth: 0
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v2
|
||||
with:
|
||||
main-branch-name: master
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.14.0
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
- name: Check formatting
|
||||
run: yarn nx format:check
|
||||
- name: Lint affected
|
||||
run: yarn nx affected:lint --max-warnings=0
|
||||
- name: Test affected
|
||||
run: yarn nx affected:test
|
||||
- name: Build affected
|
||||
run: yarn nx affected:build
|
||||
pr:
|
||||
name: Test and lint - PR
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: 'read'
|
||||
actions: 'read'
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -55,14 +21,19 @@ 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: ${{ github.base_ref }}
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.14.0
|
||||
- name: Restore node_modules from cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: node_modules-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Check formatting
|
||||
run: yarn nx format:check
|
||||
- name: Lint affected
|
||||
@@ -71,3 +42,5 @@ jobs:
|
||||
run: yarn nx affected:test
|
||||
- name: Build affected
|
||||
run: yarn nx affected:build
|
||||
- name: Build affected spec
|
||||
run: yarn nx affected --target=build-spec
|
||||
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
@Library('vega-shared-library') _
|
||||
|
||||
def commitHash = 'UNKNOWN'
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
options {
|
||||
skipDefaultCheckout true
|
||||
parallelsAlwaysFailFast()
|
||||
}
|
||||
stages {
|
||||
stage('approbation') {
|
||||
steps {
|
||||
sh 'printenv'
|
||||
checkout scm
|
||||
runApprobation ignoreFailure: false, frontendBranch: env.BRANCH_NAME, type: 'frontend'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,10 @@ An application for the status of the Vega network. Showing block height and othe
|
||||
|
||||
Hosting for static content being shared across apps, for example fonts.
|
||||
|
||||
### [Multisig-signer](./apps/multisig-signer)
|
||||
|
||||
The utility dApp for validators wishing to add or remove themselves as a signer of the multisig contract.
|
||||
|
||||
# 🧱 Libraries in this repo
|
||||
|
||||
### [UI toolkit](./libs/ui-toolkit)
|
||||
|
||||
@@ -1,27 +1,8 @@
|
||||
# React Environment Variables
|
||||
|
||||
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#expanding-environment-variables-in-env
|
||||
|
||||
# Netlify Environment Variables
|
||||
|
||||
# https://www.netlify.com/docs/continuous-deployment/#environment-variables
|
||||
|
||||
NX_VERSION=$npm_package_version
|
||||
NX_REPOSITORY_URL=$REPOSITORY_URL
|
||||
NX_BRANCH=$BRANCH
|
||||
NX_PULL_REQUEST=$PULL_REQUEST
|
||||
NX_HEAD=$HEAD
|
||||
NX_COMMIT_REF=$COMMIT_REF
|
||||
NX_CONTEXT=$CONTEXT
|
||||
NX_REVIEW_ID=$REVIEW_ID
|
||||
NX_INCOMING_HOOK_TITLE=$INCOMING_HOOK_TITLE
|
||||
NX_INCOMING_HOOK_URL=$INCOMING_HOOK_URL
|
||||
NX_INCOMING_HOOK_BODY=$INCOMING_HOOK_BODY
|
||||
NX_URL=$URL
|
||||
NX_DEPLOY_URL=$DEPLOY_URL
|
||||
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
|
||||
# App configuration variables
|
||||
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_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
|
||||
@@ -3,14 +3,18 @@ module.exports = defineConfig({
|
||||
projectId: 'et4snf',
|
||||
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
require('cypress-grep/src/plugin')(config);
|
||||
return config;
|
||||
},
|
||||
baseUrl: 'http://localhost:4200',
|
||||
fileServerFolder: '.',
|
||||
fixturesFolder: false,
|
||||
specPattern: './src/integration/*.ts',
|
||||
excludeSpecPattern: '**/*.js',
|
||||
modifyObstructiveCode: false,
|
||||
supportFile: './src/support/index.ts',
|
||||
video: true,
|
||||
supportFile: './src/support/index.js',
|
||||
video: false,
|
||||
videoUploadOnPasses: false,
|
||||
videosFolder: '../../dist/cypress/apps/console-lite-e2e/videos',
|
||||
screenshotsFolder: '../../dist/cypress/apps/console-lite-e2e/screenshots',
|
||||
@@ -21,7 +25,7 @@ module.exports = defineConfig({
|
||||
env: {
|
||||
TRADING_TEST_VEGA_WALLET_NAME: 'UI_Trading_Test',
|
||||
ETHEREUM_PROVIDER_URL:
|
||||
'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
|
||||
'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
|
||||
VEGA_PUBLIC_KEY:
|
||||
'47836c253520d2661bf5bed6339c0de08fd02cf5d4db0efee3b4373f20c7d278',
|
||||
VEGA_PUBLIC_KEY2:
|
||||
@@ -29,11 +33,14 @@ module.exports = defineConfig({
|
||||
TRUNCATED_VEGA_PUBLIC_KEY: '47836c…c7d278',
|
||||
TRUNCATED_VEGA_PUBLIC_KEY2: '1a18cd…0cf2e4',
|
||||
ETHEREUM_WALLET_ADDRESS: '0x265Cc6d39a1B53d0d92068443009eE7410807158',
|
||||
ETHERSCAN_URL: 'https://ropsten.etherscan.io',
|
||||
ETHERSCAN_URL: 'https://sepolia.etherscan.io',
|
||||
tsConfig: 'tsconfig.json',
|
||||
TAGS: 'not @todo and not @ignore and not @manual',
|
||||
TRADING_TEST_VEGA_WALLET_PASSPHRASE: '123',
|
||||
ETH_WALLET_MNEMONIC:
|
||||
'ugly gallery notice network true range brave clarify flat logic someone chunk',
|
||||
grepTags: '@regression @smoke @slow',
|
||||
grepFilterSpecs: true,
|
||||
grepOmitFiltered: true,
|
||||
},
|
||||
});
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
declare module '*.scss';
|
||||
@@ -1,5 +1,17 @@
|
||||
describe('simple trading app', () => {
|
||||
beforeEach(() => cy.visit('/'));
|
||||
import { aliasQuery } from '@vegaprotocol/cypress';
|
||||
import {
|
||||
generateSimpleMarkets,
|
||||
generateMarketsCandles,
|
||||
} from '../support/mocks/generate-markets';
|
||||
|
||||
describe('simple trading app', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'Markets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
|
||||
});
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
it('render', () => {
|
||||
cy.get('#root').should('exist');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
describe('console lite header', () => {
|
||||
describe('console lite header', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
window.localStorage.setItem('theme', 'dark');
|
||||
cy.visit('/');
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import { aliasQuery } from '@vegaprotocol/cypress';
|
||||
import type { MarketsQuery } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
generateLongListMarkets,
|
||||
generateSimpleMarkets,
|
||||
generateMarketsCandles,
|
||||
} from '../support/mocks/generate-markets';
|
||||
|
||||
describe('market list', () => {
|
||||
describe('market list', { tags: '@smoke' }, () => {
|
||||
describe('simple url', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'Markets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
|
||||
});
|
||||
cy.visit('/markets');
|
||||
});
|
||||
@@ -62,7 +65,8 @@ describe('market list', () => {
|
||||
describe('url params should select filters', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'Markets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,10 +77,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: MarketsQuery | 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 +103,8 @@ 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, 'MarketsCandles', 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,26 +13,32 @@ 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, MarketsQuery } from '@vegaprotocol/market-list';
|
||||
|
||||
describe('market selector', () => {
|
||||
let markets;
|
||||
describe('market selector', { tags: '@smoke' }, () => {
|
||||
let markets: Market[];
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'DealTicketQuery', generateDealTicket());
|
||||
aliasQuery(req, 'Markets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
|
||||
aliasQuery(req, 'MarketsData', generateMarketsData());
|
||||
aliasQuery(req, 'DealTicket', generateDealTicket());
|
||||
aliasQuery(req, 'MarketTags', generateMarketTags());
|
||||
aliasQuery(req, 'MarketPositions', generateMarketPositions());
|
||||
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
|
||||
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
|
||||
aliasQuery(req, 'PartyBalance', generatePartyBalance());
|
||||
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: MarketsQuery | undefined = response?.response?.body?.data;
|
||||
if (data?.marketsConnection?.edges.length) {
|
||||
markets = data?.marketsConnection?.edges.map((edge) => edge.node);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -126,7 +136,7 @@ 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(
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { aliasQuery } from '@vegaprotocol/cypress';
|
||||
import { generateSimpleMarkets } from '../support/mocks/generate-markets';
|
||||
import {
|
||||
generateSimpleMarkets,
|
||||
generateMarketsCandles,
|
||||
generateMarketsData,
|
||||
generateMarket,
|
||||
} 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,25 +14,31 @@ 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 { MarketsQuery, Market } from '@vegaprotocol/market-list';
|
||||
|
||||
describe('Market trade', () => {
|
||||
let markets;
|
||||
describe('Market trade', { tags: '@smoke' }, () => {
|
||||
let markets: Market[];
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'Markets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
|
||||
aliasQuery(req, 'MarketsData', generateMarketsData());
|
||||
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
|
||||
aliasQuery(req, 'DealTicketQuery', generateDealTicket());
|
||||
aliasQuery(req, 'DealTicket', generateDealTicket());
|
||||
aliasQuery(req, 'MarketTags', generateMarketTags());
|
||||
aliasQuery(req, 'MarketPositions', generateMarketPositions());
|
||||
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
|
||||
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
|
||||
aliasQuery(req, 'PartyBalance', generatePartyBalance());
|
||||
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
|
||||
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
|
||||
aliasQuery(req, 'MarketDepth', generateMarketDepth());
|
||||
aliasQuery(req, 'Market', generateMarket());
|
||||
});
|
||||
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: MarketsQuery | undefined = response?.response?.body?.data;
|
||||
if (data?.marketsConnection?.edges.length) {
|
||||
markets = data?.marketsConnection?.edges.map((edge) => edge.node);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -287,11 +298,7 @@ describe('Market trade', () => {
|
||||
|
||||
cy.get('#step-3-panel').find('dd').eq(4).should('have.text', ' - ');
|
||||
|
||||
cy.getByTestId('place-order').click();
|
||||
cy.getByTestId('dialog-title').should(
|
||||
'have.text',
|
||||
'Confirm transaction in wallet'
|
||||
);
|
||||
cy.getByTestId('place-order').should('be.enabled').click();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -2,8 +2,23 @@ import {
|
||||
connectVegaWallet,
|
||||
disconnectVegaWallet,
|
||||
} from '../support/connect-wallet';
|
||||
import { aliasQuery } from '@vegaprotocol/cypress';
|
||||
import {
|
||||
generatePositions,
|
||||
emptyPositions,
|
||||
generateMargins,
|
||||
} from '../support/mocks/generate-positions';
|
||||
import { generateAccounts } from '../support/mocks/generate-accounts';
|
||||
import { generateAssets } from '../support/mocks/generate-assets';
|
||||
import { generateOrders } from '../support/mocks/generate-orders';
|
||||
import { generateFills } from '../support/mocks/generate-fills';
|
||||
import {
|
||||
generateFillsMarkets,
|
||||
generateMarketsData,
|
||||
generatePositionsMarkets,
|
||||
} from '../support/mocks/generate-markets';
|
||||
|
||||
describe('Portfolio page', () => {
|
||||
describe('Portfolio page', { tags: '@smoke' }, () => {
|
||||
afterEach(() => {
|
||||
disconnectVegaWallet();
|
||||
});
|
||||
@@ -19,19 +34,144 @@ describe('Portfolio page', () => {
|
||||
it('certain tabs should exist', () => {
|
||||
cy.visit('/portfolio');
|
||||
connectVegaWallet();
|
||||
cy.getByTestId('Assets').should('exist');
|
||||
cy.getByTestId('tab-assets').should('exist');
|
||||
|
||||
cy.getByTestId('Positions').click();
|
||||
cy.getByTestId('tab-positions').should('exist');
|
||||
cy.getByTestId('assets').click();
|
||||
cy.location('pathname').should('eq', '/portfolio/assets');
|
||||
|
||||
cy.getByTestId('Orders').click();
|
||||
cy.getByTestId('tab-orders').should('exist');
|
||||
cy.getByTestId('positions').click();
|
||||
cy.location('pathname').should('eq', '/portfolio/positions');
|
||||
|
||||
cy.getByTestId('Fills').click();
|
||||
cy.getByTestId('tab-fills').should('exist');
|
||||
cy.getByTestId('orders').click();
|
||||
cy.location('pathname').should('eq', '/portfolio/orders');
|
||||
|
||||
cy.getByTestId('Deposits').click();
|
||||
cy.getByTestId('tab-deposits').should('exist');
|
||||
cy.getByTestId('fills').click();
|
||||
cy.location('pathname').should('eq', '/portfolio/fills');
|
||||
|
||||
cy.getByTestId('deposits').click();
|
||||
cy.location('pathname').should('eq', '/portfolio/deposits');
|
||||
});
|
||||
|
||||
describe('Assets view', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'Positions', generatePositions());
|
||||
aliasQuery(req, 'Margins', generateMargins());
|
||||
aliasQuery(req, 'Markets', generatePositionsMarkets());
|
||||
aliasQuery(req, 'MarketsData', generateMarketsData());
|
||||
aliasQuery(req, 'Accounts', generateAccounts());
|
||||
aliasQuery(req, 'Assets', generateAssets());
|
||||
});
|
||||
cy.visit('/portfolio/assets');
|
||||
connectVegaWallet();
|
||||
});
|
||||
|
||||
it('data should be properly rendered', () => {
|
||||
cy.get('.ag-center-cols-container .ag-row').should('have.length', 3);
|
||||
cy.get(
|
||||
'.ag-center-cols-container [row-id="ACCOUNT_TYPE_GENERAL-asset-id-null"]'
|
||||
)
|
||||
.find('button')
|
||||
.click();
|
||||
cy.getByTestId('dialog-title').should(
|
||||
'have.text',
|
||||
'Asset details - tEURO'
|
||||
);
|
||||
cy.getByTestId('dialog-close').click();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Positions view', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'Positions', generatePositions());
|
||||
aliasQuery(req, 'Accounts', generateAccounts());
|
||||
aliasQuery(req, 'Margins', generateMargins());
|
||||
aliasQuery(req, 'Markets', generatePositionsMarkets());
|
||||
aliasQuery(req, 'MarketsData', generateMarketsData());
|
||||
aliasQuery(req, 'Assets', generateAssets());
|
||||
});
|
||||
cy.visit('/portfolio/positions');
|
||||
connectVegaWallet();
|
||||
});
|
||||
|
||||
it('data should be properly rendered', () => {
|
||||
cy.getByTestId('positions-asset-tDAI').should('exist');
|
||||
cy.getByTestId('positions-asset-tEURO').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Orders view', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'Orders', generateOrders());
|
||||
aliasQuery(req, 'Markets', generateFillsMarkets());
|
||||
});
|
||||
cy.visit('/portfolio/orders');
|
||||
connectVegaWallet();
|
||||
});
|
||||
|
||||
it('data should be properly rendered', () => {
|
||||
cy.get('.ag-center-cols-container .ag-row').should('have.length', 5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Fills view', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'Fills', generateFills());
|
||||
aliasQuery(req, 'Markets', generateFillsMarkets());
|
||||
});
|
||||
cy.visit('/portfolio/fills');
|
||||
connectVegaWallet();
|
||||
});
|
||||
|
||||
it('data should be properly rendered', () => {
|
||||
cy.get('.ag-center-cols-container .ag-row').should('have.length', 4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Empty views', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'Positions', emptyPositions());
|
||||
aliasQuery(req, 'Accounts', { party: null });
|
||||
aliasQuery(req, 'Orders', { party: null });
|
||||
aliasQuery(req, 'Fills', { party: null });
|
||||
aliasQuery(req, 'Markets', {
|
||||
marketsConnection: { edges: [], __typename: 'MarketConnection' },
|
||||
});
|
||||
aliasQuery(req, 'Assets', {
|
||||
assetsConnection: { edges: null, __typename: 'AssetsConnection' },
|
||||
});
|
||||
});
|
||||
cy.visit('/portfolio');
|
||||
connectVegaWallet();
|
||||
});
|
||||
|
||||
it('"No data to display" should be always displayed', () => {
|
||||
cy.getByTestId('assets').click();
|
||||
cy.get('div.flex.items-center.justify-center').should(
|
||||
'contain.text',
|
||||
'No data to display'
|
||||
);
|
||||
|
||||
cy.getByTestId('positions').click();
|
||||
cy.get('div.flex.items-center.justify-center').should(
|
||||
'contain.text',
|
||||
'No data to display'
|
||||
);
|
||||
|
||||
cy.getByTestId('orders').click();
|
||||
cy.get('div.flex.items-center.justify-center').should(
|
||||
'contain.text',
|
||||
'No data to display'
|
||||
);
|
||||
|
||||
cy.getByTestId('fills').click();
|
||||
cy.get('div.flex.items-center.justify-center').should(
|
||||
'contain.text',
|
||||
'No data to display'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,9 @@ export const connectVegaWallet = () => {
|
||||
const walletPassphrase = Cypress.env('TRADING_TEST_VEGA_WALLET_PASSPHRASE');
|
||||
|
||||
cy.getByTestId('connect-vega-wallet').click();
|
||||
cy.getByTestId('connectors-list').find('button').click();
|
||||
cy.getByTestId('connectors-list')
|
||||
.find('[data-testid="connector-gui"]')
|
||||
.click();
|
||||
cy.getByTestId(form).find('#wallet').click().type(walletName);
|
||||
cy.getByTestId(form).find('#passphrase').click().type(walletPassphrase);
|
||||
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
import '@vegaprotocol/cypress';
|
||||
import 'cypress-real-events/support';
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
import registerCypressGrep from 'cypress-grep';
|
||||
import { aliasQuery } from '@vegaprotocol/cypress';
|
||||
registerCypressGrep();
|
||||
|
||||
before(() => {
|
||||
// Mock chainId fetch which happens on every page for wallet connection
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'ChainId', {
|
||||
statistics: {
|
||||
__typename: 'Statistics',
|
||||
chainId: 'vega-fairground-202210041151',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,8 @@
|
||||
const protoCandles = [
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
|
||||
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
|
||||
|
||||
export const protoCandles = [
|
||||
{ open: '9556163', close: '9587028', __typename: 'Candle' },
|
||||
{
|
||||
open: '9587028',
|
||||
@@ -73,11 +77,29 @@ const protoCandles = [
|
||||
},
|
||||
];
|
||||
|
||||
export const protoMarket = {
|
||||
id: 'first-btcusd-id',
|
||||
state: 'STATE_ACTIVE',
|
||||
export const protoMarket: Market = {
|
||||
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
|
||||
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: '',
|
||||
},
|
||||
},
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
id: '',
|
||||
code: 'AAVEDAI.MF21',
|
||||
name: 'AAVEDAI Monthly (30 Jun 2022)',
|
||||
metadata: {
|
||||
@@ -94,12 +116,32 @@ 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',
|
||||
};
|
||||
|
||||
export const singleMarket: SingleMarketFieldsFragment = {
|
||||
...protoMarket,
|
||||
tradableInstrument: {
|
||||
...protoMarket.tradableInstrument,
|
||||
instrument: {
|
||||
...protoMarket.tradableInstrument.instrument,
|
||||
product: {
|
||||
...protoMarket.tradableInstrument.instrument.product,
|
||||
settlementAsset: {
|
||||
...protoMarket.tradableInstrument.instrument.product.settlementAsset,
|
||||
id: 'dai-id',
|
||||
name: 'DAI Name',
|
||||
},
|
||||
oracleSpecForTradingTermination: {
|
||||
id: 'oid',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import merge from 'lodash/merge';
|
||||
import type { AccountsQuery } from '@vegaprotocol/accounts';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
export const generateAccounts = (
|
||||
override?: PartialDeep<AccountsQuery>
|
||||
): AccountsQuery => {
|
||||
const defaultAccounts: AccountsQuery = {
|
||||
party: {
|
||||
__typename: 'Party',
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
accounts: [
|
||||
{
|
||||
__typename: 'AccountBalance',
|
||||
type: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
balance: '100000000',
|
||||
market: null,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id',
|
||||
},
|
||||
},
|
||||
{
|
||||
__typename: 'AccountBalance',
|
||||
type: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
balance: '100000000',
|
||||
market: {
|
||||
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
|
||||
__typename: 'Market',
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id-2',
|
||||
},
|
||||
},
|
||||
{
|
||||
__typename: 'AccountBalance',
|
||||
type: AccountType.ACCOUNT_TYPE_MARGIN,
|
||||
balance: '1000',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id',
|
||||
},
|
||||
},
|
||||
{
|
||||
__typename: 'AccountBalance',
|
||||
type: AccountType.ACCOUNT_TYPE_MARGIN,
|
||||
balance: '1000',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id-2',
|
||||
},
|
||||
},
|
||||
{
|
||||
__typename: 'AccountBalance',
|
||||
type: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
balance: '100000000',
|
||||
market: null,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-0',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
return merge(defaultAccounts, override);
|
||||
};
|
||||
@@ -0,0 +1,120 @@
|
||||
import merge from 'lodash/merge';
|
||||
import type { AssetsQuery } from '@vegaprotocol/assets';
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
|
||||
const defaultAssets: AssetsQuery = {
|
||||
assetsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: 'asset-id',
|
||||
symbol: 'tEURO',
|
||||
decimals: 5,
|
||||
name: 'Euro',
|
||||
source: {
|
||||
__typename: 'ERC20',
|
||||
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
|
||||
lifetimeLimit: '1',
|
||||
withdrawThreshold: '2',
|
||||
},
|
||||
quantum: '',
|
||||
status: Types.AssetStatus.STATUS_ENABLED,
|
||||
infrastructureFeeAccount: {
|
||||
balance: '1',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
globalRewardPoolAccount: {
|
||||
balance: '2',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
takerFeeRewardAccount: {
|
||||
balance: '3',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
makerFeeRewardAccount: {
|
||||
balance: '4',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
lpFeeRewardAccount: {
|
||||
balance: '5',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
marketProposerRewardAccount: {
|
||||
balance: '6',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
__typename: 'Asset',
|
||||
},
|
||||
},
|
||||
{
|
||||
node: {
|
||||
id: 'asset-id-2',
|
||||
symbol: 'tDAI',
|
||||
decimals: 5,
|
||||
name: 'DAI',
|
||||
source: {
|
||||
__typename: 'ERC20',
|
||||
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
|
||||
lifetimeLimit: '1',
|
||||
withdrawThreshold: '2',
|
||||
},
|
||||
quantum: '',
|
||||
status: Types.AssetStatus.STATUS_ENABLED,
|
||||
infrastructureFeeAccount: {
|
||||
balance: '1',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
globalRewardPoolAccount: {
|
||||
balance: '2',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
takerFeeRewardAccount: {
|
||||
balance: '3',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
makerFeeRewardAccount: {
|
||||
balance: '4',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
lpFeeRewardAccount: {
|
||||
balance: '5',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
marketProposerRewardAccount: {
|
||||
balance: '6',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
__typename: 'Asset',
|
||||
},
|
||||
},
|
||||
{
|
||||
node: {
|
||||
id: 'asset-0',
|
||||
symbol: 'AST0',
|
||||
decimals: 5,
|
||||
name: 'Asto',
|
||||
source: {
|
||||
__typename: 'BuiltinAsset',
|
||||
maxFaucetAmountMint: '3',
|
||||
},
|
||||
quantum: '',
|
||||
status: Types.AssetStatus.STATUS_ENABLED,
|
||||
infrastructureFeeAccount: {
|
||||
balance: '0',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
globalRewardPoolAccount: null,
|
||||
takerFeeRewardAccount: null,
|
||||
makerFeeRewardAccount: null,
|
||||
lpFeeRewardAccount: null,
|
||||
marketProposerRewardAccount: null,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
return merge(defaultAssets, override);
|
||||
};
|
||||
@@ -1,13 +1,21 @@
|
||||
export const generateDealTicket = () => {
|
||||
return {
|
||||
import type { DealTicketQuery } from '@vegaprotocol/deal-ticket';
|
||||
import { MarketTradingMode, MarketState } from '@vegaprotocol/types';
|
||||
import merge from 'lodash/merge';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
export const generateDealTicket = (
|
||||
override?: PartialDeep<DealTicketQuery>
|
||||
): DealTicketQuery => {
|
||||
const defaultResult: DealTicketQuery = {
|
||||
market: {
|
||||
id: 'first-btcusd-id',
|
||||
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
state: 'STATE_ACTIVE',
|
||||
tradingMode: 'Continuous',
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
|
||||
name: 'AAVEDAI Monthly (30 Jun 2022)',
|
||||
product: {
|
||||
quoteName: 'DAI',
|
||||
@@ -15,6 +23,7 @@ export const generateDealTicket = () => {
|
||||
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
symbol: 'tDAI',
|
||||
name: 'tDAI TEST',
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
__typename: 'Future',
|
||||
@@ -27,7 +36,17 @@ export const generateDealTicket = () => {
|
||||
lastTrade: { price: '9893006', __typename: 'Trade' },
|
||||
__typename: 'MarketDepth',
|
||||
},
|
||||
fees: {
|
||||
factors: {
|
||||
makerFee: '0.0002',
|
||||
infrastructureFee: '0.0005',
|
||||
liquidityFee: '0.001',
|
||||
__typename: 'FeeFactors',
|
||||
},
|
||||
__typename: 'Fees',
|
||||
},
|
||||
__typename: 'Market',
|
||||
},
|
||||
};
|
||||
return merge(defaultResult, override);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import type { FillsQuery, FillFieldsFragment } from '@vegaprotocol/fills';
|
||||
import { Schema } from '@vegaprotocol/types';
|
||||
import merge from 'lodash/merge';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
export const generateFills = (
|
||||
override?: PartialDeep<FillsQuery>
|
||||
): FillsQuery => {
|
||||
const fills: FillFieldsFragment[] = [
|
||||
generateFill({
|
||||
buyer: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
}),
|
||||
generateFill({
|
||||
id: '1',
|
||||
seller: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
aggressor: Schema.Side.SIDE_SELL,
|
||||
buyerFee: {
|
||||
infrastructureFee: '5000',
|
||||
},
|
||||
market: {
|
||||
id: 'market-1',
|
||||
},
|
||||
}),
|
||||
generateFill({
|
||||
id: '2',
|
||||
seller: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
aggressor: Schema.Side.SIDE_BUY,
|
||||
}),
|
||||
generateFill({
|
||||
id: '3',
|
||||
aggressor: Schema.Side.SIDE_SELL,
|
||||
market: {
|
||||
id: 'market-2',
|
||||
},
|
||||
buyer: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const defaultResult: FillsQuery = {
|
||||
party: {
|
||||
id: 'buyer-id',
|
||||
tradesConnection: {
|
||||
__typename: 'TradeConnection',
|
||||
edges: fills.map((f) => {
|
||||
return {
|
||||
__typename: 'TradeEdge',
|
||||
node: f,
|
||||
cursor: '3',
|
||||
};
|
||||
}),
|
||||
pageInfo: {
|
||||
__typename: 'PageInfo',
|
||||
startCursor: '1',
|
||||
endCursor: '2',
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
},
|
||||
},
|
||||
__typename: 'Party',
|
||||
},
|
||||
};
|
||||
|
||||
return merge(defaultResult, override);
|
||||
};
|
||||
|
||||
export const generateFill = (override?: PartialDeep<FillFieldsFragment>) => {
|
||||
const defaultFill: FillFieldsFragment = {
|
||||
__typename: 'Trade',
|
||||
id: '0',
|
||||
createdAt: new Date().toISOString(),
|
||||
price: '10000000',
|
||||
size: '50000',
|
||||
buyOrder: 'buy-order',
|
||||
sellOrder: 'sell-order',
|
||||
aggressor: Schema.Side.SIDE_BUY,
|
||||
buyer: {
|
||||
__typename: 'Party',
|
||||
id: 'buyer-id',
|
||||
},
|
||||
seller: {
|
||||
__typename: 'Party',
|
||||
id: 'seller-id',
|
||||
},
|
||||
buyerFee: {
|
||||
__typename: 'TradeFee',
|
||||
makerFee: '100',
|
||||
infrastructureFee: '100',
|
||||
liquidityFee: '100',
|
||||
},
|
||||
sellerFee: {
|
||||
__typename: 'TradeFee',
|
||||
makerFee: '200',
|
||||
infrastructureFee: '200',
|
||||
liquidityFee: '200',
|
||||
},
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-0',
|
||||
},
|
||||
};
|
||||
|
||||
return merge(defaultFill, override);
|
||||
};
|
||||
@@ -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 { MarketDepthQuery } from '../../../../../libs/market-depth/src/lib/__generated___/MarketDepth';
|
||||
|
||||
export const generateMarketDepth = (
|
||||
override?: PartialDeep<MarketDepthQuery>
|
||||
): MarketDepthQuery => {
|
||||
const defaultResult: MarketDepthQuery = {
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ export const generateMarketPositions = () => {
|
||||
},
|
||||
balance: '265329',
|
||||
market: {
|
||||
id: 'first-btcusd-id',
|
||||
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
|
||||
__typename: 'Market',
|
||||
},
|
||||
},
|
||||
@@ -43,7 +43,7 @@ export const generateMarketPositions = () => {
|
||||
node: {
|
||||
openVolume: '12',
|
||||
market: {
|
||||
id: 'first-btcusd-id',
|
||||
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Position',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,143 @@
|
||||
import merge from 'lodash/merge';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type { OrdersQuery, OrderFieldsFragment } from '@vegaprotocol/orders';
|
||||
import { Schema } from '@vegaprotocol/types';
|
||||
|
||||
export const generateOrders = (
|
||||
override?: PartialDeep<OrdersQuery>
|
||||
): OrdersQuery => {
|
||||
const orders: OrderFieldsFragment[] = [
|
||||
{
|
||||
__typename: 'Order',
|
||||
id: '066468C06549101DAF7BC51099E1412A0067DC08C246B7D8013C9D0CBF1E8EE7',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-0',
|
||||
},
|
||||
size: '10',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
status: Schema.OrderStatus.STATUS_FILLED,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
remaining: '0',
|
||||
price: '20000000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
createdAt: new Date(2020, 1, 30).toISOString(),
|
||||
updatedAt: null,
|
||||
expiresAt: null,
|
||||
rejectionReason: null,
|
||||
liquidityProvision: null,
|
||||
peggedOrder: null,
|
||||
},
|
||||
{
|
||||
__typename: 'Order',
|
||||
id: '48DB6767E4E4E0F649C5A13ABFADE39F8451C27DA828DAF14B7A1E8E5EBDAD99',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-1',
|
||||
},
|
||||
size: '1',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
status: Schema.OrderStatus.STATUS_FILLED,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
remaining: '0',
|
||||
price: '100',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
createdAt: new Date(2020, 1, 29).toISOString(),
|
||||
updatedAt: null,
|
||||
expiresAt: null,
|
||||
rejectionReason: null,
|
||||
liquidityProvision: null,
|
||||
peggedOrder: null,
|
||||
},
|
||||
{
|
||||
__typename: 'Order',
|
||||
id: '4e93702990712c41f6995fcbbd94f60bb372ad12d64dfa7d96d205c49f790336',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-2',
|
||||
},
|
||||
size: '1',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
status: Schema.OrderStatus.STATUS_FILLED,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
remaining: '0',
|
||||
price: '20000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
createdAt: new Date(2020, 1, 28).toISOString(),
|
||||
updatedAt: null,
|
||||
expiresAt: null,
|
||||
rejectionReason: null,
|
||||
liquidityProvision: null,
|
||||
peggedOrder: null,
|
||||
},
|
||||
{
|
||||
__typename: 'Order',
|
||||
id: '94737d2bafafa4bc3b80a56ef084ae52a983b91aa067c31e243c61a0f962a836',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-3',
|
||||
},
|
||||
size: '1',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
remaining: '0',
|
||||
price: '100000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
createdAt: new Date(2020, 1, 27).toISOString(),
|
||||
updatedAt: null,
|
||||
expiresAt: null,
|
||||
rejectionReason: null,
|
||||
liquidityProvision: null,
|
||||
peggedOrder: null,
|
||||
},
|
||||
{
|
||||
__typename: 'Order',
|
||||
id: '94aead3ca92dc932efcb503631b03a410e2a5d4606cae6083e2406dc38e52f78',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-3',
|
||||
},
|
||||
size: '10',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
status: Schema.OrderStatus.STATUS_PARTIALLY_FILLED,
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
remaining: '3',
|
||||
price: '100000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
createdAt: new Date(2020, 1, 27).toISOString(),
|
||||
updatedAt: null,
|
||||
expiresAt: null,
|
||||
liquidityProvision: null,
|
||||
peggedOrder: null,
|
||||
rejectionReason: null,
|
||||
},
|
||||
];
|
||||
|
||||
const defaultResult: OrdersQuery = {
|
||||
party: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
ordersConnection: {
|
||||
__typename: 'OrderConnection',
|
||||
edges: orders.map((f) => {
|
||||
return {
|
||||
__typename: 'OrderEdge',
|
||||
node: f,
|
||||
cursor: f.id,
|
||||
};
|
||||
}),
|
||||
pageInfo: {
|
||||
__typename: 'PageInfo',
|
||||
startCursor:
|
||||
'066468C06549101DAF7BC51099E1412A0067DC08C246B7D8013C9D0CBF1E8EE7',
|
||||
endCursor:
|
||||
'94737d2bafafa4bc3b80a56ef084ae52a983b91aa067c31e243c61a0f962a836',
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
},
|
||||
},
|
||||
__typename: 'Party',
|
||||
},
|
||||
};
|
||||
return merge(defaultResult, override);
|
||||
};
|
||||
@@ -1,10 +1,17 @@
|
||||
export const generatePartyBalance = () => {
|
||||
return {
|
||||
import merge from 'lodash/merge';
|
||||
import type { PartyBalanceQuery } from '@vegaprotocol/deal-ticket';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
|
||||
export const generatePartyBalance = (
|
||||
override?: PartialDeep<PartyBalanceQuery>
|
||||
): PartyBalanceQuery => {
|
||||
const defaultResult: PartyBalanceQuery = {
|
||||
party: {
|
||||
accounts: [
|
||||
{
|
||||
balance: '88474051',
|
||||
type: 'ACCOUNT_TYPE_GENERAL',
|
||||
type: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
asset: {
|
||||
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
symbol: 'tDAI',
|
||||
@@ -12,11 +19,11 @@ export const generatePartyBalance = () => {
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
__typename: 'Account',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
{
|
||||
balance: '100000000',
|
||||
type: 'ACCOUNT_TYPE_GENERAL',
|
||||
type: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
asset: {
|
||||
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
|
||||
symbol: 'tEURO',
|
||||
@@ -24,11 +31,11 @@ export const generatePartyBalance = () => {
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
__typename: 'Account',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
{
|
||||
balance: '3412867',
|
||||
type: 'ACCOUNT_TYPE_GENERAL',
|
||||
type: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
asset: {
|
||||
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
symbol: 'tDAI',
|
||||
@@ -36,11 +43,11 @@ export const generatePartyBalance = () => {
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
__typename: 'Account',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
{
|
||||
balance: '70007',
|
||||
type: 'ACCOUNT_TYPE_GENERAL',
|
||||
type: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
asset: {
|
||||
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
symbol: 'tDAI',
|
||||
@@ -48,10 +55,12 @@ export const generatePartyBalance = () => {
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
__typename: 'Account',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
],
|
||||
__typename: 'Party',
|
||||
},
|
||||
};
|
||||
|
||||
return merge(defaultResult, override);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ export const generatePartyMarketData = () => {
|
||||
balance: '1200000',
|
||||
asset: { id: 'fBTC', decimals: 5, __typename: 'Asset' },
|
||||
market: null,
|
||||
__typename: 'Account',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
],
|
||||
marginsConnection: { edges: null, __typename: 'MarginConnection' },
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import merge from 'lodash/merge';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type {
|
||||
PositionsQuery,
|
||||
PositionFieldsFragment,
|
||||
MarginsQuery,
|
||||
} from '@vegaprotocol/positions';
|
||||
|
||||
export const generatePositions = (
|
||||
override?: PartialDeep<PositionsQuery>
|
||||
): PositionsQuery => {
|
||||
const nodes: PositionFieldsFragment[] = [
|
||||
{
|
||||
__typename: 'Position',
|
||||
realisedPNL: '0',
|
||||
openVolume: '6',
|
||||
unrealisedPNL: '895000',
|
||||
averageEntryPrice: '1129935',
|
||||
updatedAt: '2022-07-28T15:09:34.441143Z',
|
||||
market: {
|
||||
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
|
||||
__typename: 'Market',
|
||||
},
|
||||
},
|
||||
{
|
||||
__typename: 'Position',
|
||||
realisedPNL: '100',
|
||||
openVolume: '20',
|
||||
unrealisedPNL: '895000',
|
||||
averageEntryPrice: '8509338',
|
||||
updatedAt: '2022-07-28T15:09:34.441143Z',
|
||||
market: {
|
||||
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
|
||||
__typename: 'Market',
|
||||
},
|
||||
},
|
||||
{
|
||||
realisedPNL: '0',
|
||||
openVolume: '1',
|
||||
unrealisedPNL: '-22519',
|
||||
averageEntryPrice: '84400088',
|
||||
updatedAt: '2022-07-28T14:53:54.725477Z',
|
||||
market: {
|
||||
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Position',
|
||||
},
|
||||
];
|
||||
|
||||
const defaultResult: PositionsQuery = {
|
||||
party: {
|
||||
__typename: 'Party',
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
positionsConnection: {
|
||||
__typename: 'PositionConnection',
|
||||
edges: nodes.map((node) => {
|
||||
return {
|
||||
__typename: 'PositionEdge',
|
||||
node,
|
||||
};
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return merge(defaultResult, override);
|
||||
};
|
||||
|
||||
export const emptyPositions = (): PositionsQuery => {
|
||||
return {
|
||||
party: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
positionsConnection: { edges: null, __typename: 'PositionConnection' },
|
||||
__typename: 'Party',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const generateMargins = (): MarginsQuery => {
|
||||
return {
|
||||
party: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
marginsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
__typename: 'MarginLevels',
|
||||
maintenanceLevel: '0',
|
||||
searchLevel: '0',
|
||||
initialLevel: '0',
|
||||
collateralReleaseLevel: '0',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'tDAI-id',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
node: {
|
||||
__typename: 'MarginLevels',
|
||||
maintenanceLevel: '0',
|
||||
searchLevel: '0',
|
||||
initialLevel: '0',
|
||||
collateralReleaseLevel: '0',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'tDAI-id',
|
||||
},
|
||||
},
|
||||
__typename: 'MarginEdge',
|
||||
},
|
||||
{
|
||||
node: {
|
||||
__typename: 'MarginLevels',
|
||||
maintenanceLevel: '0',
|
||||
searchLevel: '0',
|
||||
initialLevel: '0',
|
||||
collateralReleaseLevel: '0',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'tEURO-id',
|
||||
},
|
||||
},
|
||||
__typename: 'MarginEdge',
|
||||
},
|
||||
],
|
||||
__typename: 'MarginConnection',
|
||||
},
|
||||
__typename: 'Party',
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"jsx": "react-jsx",
|
||||
"sourceMap": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"allowJs": true,
|
||||
"types": ["cypress", "node", "cypress-real-events"]
|
||||
"types": ["cypress", "node", "cypress-real-events", "cypress-grep"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.js"]
|
||||
"include": ["src/**/*.ts", "src/**/*.js", "./declaration.d.ts"]
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
|
||||
NX_VEGA_CONFIG_URL="https://static.vega.xyz/assets/testnet-network.json"
|
||||
NX_VEGA_ENV = 'TESTNET'
|
||||
NX_VEGA_URL="https://api.n11.testnet.vega.xyz/graphql"
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789/api/v1
|
||||
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_NETWORKS={"MAINNET":"https://alpha.console.vega.xyz"}
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
|
||||
@@ -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,8 +2,7 @@
|
||||
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
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json
|
||||
NX_VEGA_URL=https://api.sandbox.vega.xyz/graphql
|
||||
NX_VEGA_ENV=SANDBOX
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json
|
||||
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/docs/testnet
|
||||
@@ -0,0 +1,10 @@
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet1-network.json
|
||||
NX_VEGA_ENV=STAGNET1
|
||||
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
|
||||
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://stagnet1.console.vega.xyz\",\"STAGNET3\":\"https://stagnet3.console.vega.xyz\"}
|
||||
NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
|
||||
NX_VEGA_URL=https://api.n00.stagnet1.vega.xyz/graphql
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
@@ -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
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
|
||||
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
|
||||
NX_VEGA_URL=https://api.n12.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
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
|
||||
@@ -77,6 +77,13 @@
|
||||
"nx build console-lite"
|
||||
]
|
||||
}
|
||||
},
|
||||
"build-spec": {
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"outputs": [],
|
||||
"options": {
|
||||
"command": "yarn tsc --project ./apps/console-lite/tsconfig.spec.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import 'jest-canvas-mock';
|
||||
import { defaultFallbackInView } from 'react-intersection-observer';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
|
||||
@@ -38,3 +39,5 @@ Object.defineProperty(window, 'matchMedia', {
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
|
||||
jest.setTimeout(30000);
|
||||
|
||||
@@ -40,11 +40,7 @@ function App() {
|
||||
<div className="max-h-full min-h-full dark:bg-lite-black dark:text-neutral-200 bg-white text-neutral-800 grid grid-rows-[min-content,1fr]">
|
||||
<Header />
|
||||
<Main />
|
||||
<VegaConnectDialog
|
||||
connectors={Connectors}
|
||||
dialogOpen={vegaWalletDialog.connect}
|
||||
setDialogOpen={vegaWalletDialog.setConnect}
|
||||
/>
|
||||
<VegaConnectDialog connectors={Connectors} />
|
||||
<VegaManageDialog
|
||||
dialogOpen={vegaWalletDialog.manage}
|
||||
setDialogOpen={vegaWalletDialog.setManage}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useContext,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||
import { ThemeContext, useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
GridOptions,
|
||||
GetRowIdParams,
|
||||
TabToNextCellParams,
|
||||
CellKeyDownEvent,
|
||||
FullWidthCellKeyDownEvent,
|
||||
IGetRowsParams,
|
||||
IDatasource,
|
||||
} from 'ag-grid-community';
|
||||
import { NO_DATA_MESSAGE } from '../../constants';
|
||||
import * as constants from '../simple-market-list/constants';
|
||||
|
||||
export interface GetRowsParams<T>
|
||||
extends Omit<IGetRowsParams, 'successCallback'> {
|
||||
successCallback(rowsThisBlock: T[], lastRow?: number): void;
|
||||
}
|
||||
|
||||
export interface Datasource<T> extends IDatasource {
|
||||
getRows(params: GetRowsParams<T>): void;
|
||||
}
|
||||
interface Props<T> extends GridOptions {
|
||||
rowData?: T[];
|
||||
datasource?: Datasource<T>;
|
||||
handleRowClicked?: (event: { data: T }) => void;
|
||||
components?: Record<string, unknown>;
|
||||
classNamesParam?: string | string[];
|
||||
}
|
||||
|
||||
const ConsoleLiteGrid = <T extends { id?: string }>(
|
||||
{ handleRowClicked, getRowId, classNamesParam, ...props }: Props<T>,
|
||||
ref?: React.Ref<AgGridReact>
|
||||
) => {
|
||||
const { isMobile, screenSize } = useScreenDimensions();
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const theme = useContext(ThemeContext);
|
||||
const handleOnGridReady = useCallback(() => {
|
||||
(
|
||||
(ref as React.RefObject<AgGridReact>) || gridRef
|
||||
).current?.api?.sizeColumnsToFit();
|
||||
}, [gridRef, ref]);
|
||||
const onTabToNextCell = useCallback((params: TabToNextCellParams) => {
|
||||
const {
|
||||
api,
|
||||
previousCellPosition: { rowIndex },
|
||||
} = params;
|
||||
const rowCount = api.getDisplayedRowCount();
|
||||
if (rowCount <= rowIndex + 1) {
|
||||
return null;
|
||||
}
|
||||
return { ...params.previousCellPosition, rowIndex: rowIndex + 1 };
|
||||
}, []);
|
||||
const getRowIdLocal = useCallback(({ data }: GetRowIdParams) => data.id, []);
|
||||
const onCellKeyDown = useCallback(
|
||||
(
|
||||
params: (CellKeyDownEvent | FullWidthCellKeyDownEvent) & {
|
||||
event: KeyboardEvent;
|
||||
}
|
||||
) => {
|
||||
const { event: { key = '' } = {}, data } = params;
|
||||
if (key === 'Enter') {
|
||||
handleRowClicked?.({ data });
|
||||
}
|
||||
},
|
||||
[handleRowClicked]
|
||||
);
|
||||
const shouldSuppressHorizontalScroll = useMemo(() => {
|
||||
return !isMobile && constants.LARGE_SCREENS.includes(screenSize);
|
||||
}, [isMobile, screenSize]);
|
||||
|
||||
return (
|
||||
<AgGrid
|
||||
className={classNames(classNamesParam)}
|
||||
rowHeight={60}
|
||||
customThemeParams={
|
||||
theme === 'dark'
|
||||
? constants.agGridDarkVariables
|
||||
: constants.agGridLightVariables
|
||||
}
|
||||
onGridReady={handleOnGridReady}
|
||||
onRowClicked={handleRowClicked}
|
||||
rowClass={isMobile ? 'mobile' : ''}
|
||||
rowClassRules={constants.ROW_CLASS_RULES}
|
||||
ref={ref || gridRef}
|
||||
overlayNoRowsTemplate={NO_DATA_MESSAGE}
|
||||
suppressContextMenu
|
||||
getRowId={getRowId || getRowIdLocal}
|
||||
suppressMovableColumns
|
||||
suppressRowTransform
|
||||
onCellKeyDown={onCellKeyDown}
|
||||
tabToNextCell={onTabToNextCell}
|
||||
suppressHorizontalScroll={shouldSuppressHorizontalScroll}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const ConsoleLiteGridForwarder = forwardRef(ConsoleLiteGrid) as <T>(
|
||||
p: Props<T> & { ref?: React.Ref<AgGridReact> }
|
||||
) => React.ReactElement;
|
||||
|
||||
export default ConsoleLiteGridForwarder;
|
||||
@@ -0,0 +1 @@
|
||||
export { default as ConsoleLiteGrid } from './console-lite-grid';
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AccountType } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: PartyBalanceQuery
|
||||
// ====================================================
|
||||
|
||||
export interface PartyBalanceQuery_party_accounts_asset {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The ID of the asset
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The symbol of the asset (e.g: GBP)
|
||||
*/
|
||||
symbol: string;
|
||||
/**
|
||||
* The full name of the asset (e.g: Great British Pound)
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
export interface PartyBalanceQuery_party_accounts {
|
||||
__typename: "Account";
|
||||
/**
|
||||
* Account type (General, Margin, etc)
|
||||
*/
|
||||
type: AccountType;
|
||||
/**
|
||||
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||
*/
|
||||
balance: string;
|
||||
/**
|
||||
* Asset, the 'currency'
|
||||
*/
|
||||
asset: PartyBalanceQuery_party_accounts_asset;
|
||||
}
|
||||
|
||||
export interface PartyBalanceQuery_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Collateral accounts relating to a party
|
||||
*/
|
||||
accounts: PartyBalanceQuery_party_accounts[] | null;
|
||||
}
|
||||
|
||||
export interface PartyBalanceQuery {
|
||||
/**
|
||||
* An entity that is trading on the Vega network
|
||||
*/
|
||||
party: PartyBalanceQuery_party | null;
|
||||
}
|
||||
|
||||
export interface PartyBalanceQueryVariables {
|
||||
partyId: string;
|
||||
}
|
||||
@@ -8,7 +8,7 @@ export type PartyBalanceQueryQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
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 type PartyBalanceQueryQuery = { __typename?: 'Query', party?: { __typename?: 'Party', accounts?: Array<{ __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } }> | null } | null };
|
||||
|
||||
|
||||
export const PartyBalanceQueryDocument = gql`
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import type {
|
||||
PartyBalanceQuery_party_accounts,
|
||||
PartyBalanceQuery_party_accounts_asset,
|
||||
} from './__generated__/PartyBalanceQuery';
|
||||
AccountFragment,
|
||||
DealTicketMarketFragment,
|
||||
} from '@vegaprotocol/deal-ticket';
|
||||
import { DealTicketBalance } from './deal-ticket-balance';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
|
||||
const tDAI: PartyBalanceQuery_party_accounts_asset = {
|
||||
__typename: 'Asset',
|
||||
id: '1',
|
||||
symbol: 'tDAI',
|
||||
name: 'TDAI',
|
||||
decimals: 2,
|
||||
};
|
||||
|
||||
const accounts: PartyBalanceQuery_party_accounts[] = [
|
||||
const tDAI: DealTicketMarketFragment['tradableInstrument']['instrument']['product']['settlementAsset'] =
|
||||
{
|
||||
__typename: 'Account',
|
||||
__typename: 'Asset',
|
||||
id: '1',
|
||||
symbol: 'tDAI',
|
||||
name: 'TDAI',
|
||||
decimals: 2,
|
||||
};
|
||||
|
||||
const accounts: AccountFragment[] = [
|
||||
{
|
||||
__typename: 'AccountBalance',
|
||||
type: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
balance: '1000000',
|
||||
asset: tDAI,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset } from '@vegaprotocol/deal-ticket';
|
||||
import type { PartyBalanceQuery_party_accounts } from './__generated__/PartyBalanceQuery';
|
||||
import { useSettlementAccount } from '../../hooks/use-settlement-account';
|
||||
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import type {
|
||||
AccountFragment,
|
||||
DealTicketMarketFragment,
|
||||
} from '@vegaprotocol/deal-ticket';
|
||||
import { useSettlementAccount } from '@vegaprotocol/deal-ticket';
|
||||
|
||||
interface DealTicketBalanceProps {
|
||||
settlementAsset: DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset;
|
||||
accounts: PartyBalanceQuery_party_accounts[];
|
||||
settlementAsset: DealTicketMarketFragment['tradableInstrument']['instrument']['product']['settlementAsset'];
|
||||
accounts: AccountFragment[];
|
||||
isWalletConnected: boolean;
|
||||
className?: string;
|
||||
}
|
||||
@@ -26,7 +27,7 @@ export const DealTicketBalance = ({
|
||||
accounts,
|
||||
AccountType.ACCOUNT_TYPE_GENERAL
|
||||
);
|
||||
const formatedNumber =
|
||||
const formattedNumber =
|
||||
settlementAccount?.balance &&
|
||||
settlementAccount.asset.decimals &&
|
||||
addDecimalsFormatNumber(
|
||||
@@ -37,7 +38,7 @@ export const DealTicketBalance = ({
|
||||
const balance = (
|
||||
<p className="text-blue text-lg font-semibold">
|
||||
{settlementAccount
|
||||
? t(`${formatedNumber}`)
|
||||
? t(`${formattedNumber}`)
|
||||
: `No ${settlementAssetSymbol} left to trade`}
|
||||
</p>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import {
|
||||
DealTicketManager,
|
||||
DealTicketContainer as Container,
|
||||
usePartyBalanceQuery,
|
||||
} from '@vegaprotocol/deal-ticket';
|
||||
import { Loader } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
@@ -11,47 +10,30 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { DealTicketSteps } from './deal-ticket-steps';
|
||||
import { DealTicketBalance } from './deal-ticket-balance';
|
||||
import Baubles from './baubles-decor';
|
||||
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
|
||||
import ConnectWallet from '../wallet-connector';
|
||||
|
||||
const tempEmptyText = (
|
||||
<p>{t('Please select a market from the markets page')}</p>
|
||||
);
|
||||
|
||||
const PARTY_BALANCE_QUERY = gql`
|
||||
query PartyBalanceQuery($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
accounts {
|
||||
type
|
||||
balance
|
||||
asset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const DealTicketContainer = () => {
|
||||
const { marketId } = useParams<{ marketId: string }>();
|
||||
const { keypair } = useVegaWallet();
|
||||
const { pubKey } = useVegaWallet();
|
||||
|
||||
const { data: partyData, loading } = useQuery<PartyBalanceQuery>(
|
||||
PARTY_BALANCE_QUERY,
|
||||
{
|
||||
variables: { partyId: keypair?.pub },
|
||||
skip: !keypair?.pub,
|
||||
}
|
||||
);
|
||||
const { data: partyData, loading } = usePartyBalanceQuery({
|
||||
variables: { partyId: pubKey || '' },
|
||||
skip: !pubKey,
|
||||
});
|
||||
|
||||
const loader = <Loader />;
|
||||
|
||||
const container = marketId ? (
|
||||
<Container marketId={marketId}>
|
||||
{(data) => {
|
||||
if (!data.market) {
|
||||
return null as unknown as JSX.Element;
|
||||
}
|
||||
|
||||
const balance = (
|
||||
<DealTicketBalance
|
||||
className="mb-4"
|
||||
@@ -59,14 +41,14 @@ export const DealTicketContainer = () => {
|
||||
data.market.tradableInstrument.instrument.product?.settlementAsset
|
||||
}
|
||||
accounts={partyData?.party?.accounts || []}
|
||||
isWalletConnected={!!keypair?.pub}
|
||||
isWalletConnected={!!pubKey}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<DealTicketManager market={data.market}>
|
||||
{loading ? loader : balance}
|
||||
<DealTicketSteps market={data.market} partyData={partyData} />
|
||||
<DealTicketSteps market={data.market} />
|
||||
</DealTicketManager>
|
||||
);
|
||||
}}
|
||||
@@ -78,7 +60,7 @@ export const DealTicketContainer = () => {
|
||||
return (
|
||||
<section className="flex p-4 md:p-6">
|
||||
<section className="w-full md:w-1/2 md:min-w-[500px]">
|
||||
{keypair ? container : <ConnectWallet />}
|
||||
{pubKey ? container : <ConnectWallet />}
|
||||
</section>
|
||||
<Baubles />
|
||||
</section>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { DealTicketEstimates } from './deal-ticket-estimates';
|
||||
import { DealTicketEstimates } from '@vegaprotocol/deal-ticket';
|
||||
import { DealTicketSizeInput } from './deal-ticket-size-input';
|
||||
|
||||
interface DealTicketSizeProps {
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
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 {
|
||||
Dialog,
|
||||
Icon,
|
||||
Intent,
|
||||
Tooltip,
|
||||
TrafficLight,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { InputSetter } from '../../components/input-setter';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import { DataTitle, ValueTooltipRow } from './deal-ticket-estimates';
|
||||
import {
|
||||
DataTitle,
|
||||
EST_SLIPPAGE,
|
||||
ValueTooltipRow,
|
||||
} from '@vegaprotocol/deal-ticket';
|
||||
|
||||
interface DealTicketSlippageProps {
|
||||
step?: number;
|
||||
@@ -40,12 +48,12 @@ export const DealTicketSlippage = ({
|
||||
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}>
|
||||
<Tooltip align="center" description={EST_SLIPPAGE}>
|
||||
<div className="cursor-help" tabIndex={-1}>
|
||||
<Icon
|
||||
name={IconNames.ISSUE}
|
||||
className="block rotate-180"
|
||||
ariaLabel={constants.EST_SLIPPAGE}
|
||||
ariaLabel={EST_SLIPPAGE}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -83,7 +91,7 @@ export const DealTicketSlippage = ({
|
||||
<DataTitle>{t('Est. Price Impact / Slippage')}</DataTitle>
|
||||
<div className="flex">
|
||||
<div className="mr-1">
|
||||
<ValueTooltipRow description={constants.EST_SLIPPAGE}>
|
||||
<ValueTooltipRow description={EST_SLIPPAGE}>
|
||||
<TrafficLight value={value} q1={1} q2={5}>
|
||||
{value}%
|
||||
</TrafficLight>
|
||||
|
||||
@@ -1,50 +1,51 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { Stepper } from '../stepper';
|
||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||
import { InputError } from '@vegaprotocol/ui-toolkit';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import { MarketSelector } from '@vegaprotocol/deal-ticket';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import { useVegaWallet, VegaTxStatus } from '@vegaprotocol/wallet';
|
||||
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
|
||||
import {
|
||||
t,
|
||||
addDecimalsFormatNumber,
|
||||
toDecimal,
|
||||
removeDecimal,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
useOrderCloseOut,
|
||||
useOrderMargin,
|
||||
usePartyBalanceQuery,
|
||||
useMaximumPositionSize,
|
||||
useCalculateSlippage,
|
||||
} from '@vegaprotocol/deal-ticket';
|
||||
import {
|
||||
getDefaultOrder,
|
||||
useOrderValidation,
|
||||
validateSize,
|
||||
} from '@vegaprotocol/deal-ticket';
|
||||
import { InputError } from '@vegaprotocol/ui-toolkit';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import { MarketSelector } from '@vegaprotocol/deal-ticket';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { VegaTxStatus } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
t,
|
||||
toDecimal,
|
||||
removeDecimal,
|
||||
addDecimalsFormatNumber,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
useOrderSubmit,
|
||||
getOrderDialogTitle,
|
||||
getOrderDialogIntent,
|
||||
getOrderDialogIcon,
|
||||
OrderFeedback,
|
||||
validateSize,
|
||||
} from '@vegaprotocol/orders';
|
||||
import { DealTicketSize } from './deal-ticket-size';
|
||||
import MarketNameRenderer from '../simple-market-list/simple-market-renderer';
|
||||
import SideSelector, { SIDE_NAMES } from './side-selector';
|
||||
import ReviewTrade from './review-trade';
|
||||
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
|
||||
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 { Schema } from '@vegaprotocol/types';
|
||||
import { DealTicketSlippage } from './deal-ticket-slippage';
|
||||
|
||||
interface DealTicketMarketProps {
|
||||
market: DealTicketQuery_market;
|
||||
partyData?: PartyBalanceQuery;
|
||||
market: DealTicketMarketFragment;
|
||||
}
|
||||
|
||||
export const DealTicketSteps = ({
|
||||
market,
|
||||
partyData,
|
||||
}: DealTicketMarketProps) => {
|
||||
export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
|
||||
const navigate = useNavigate();
|
||||
const setMarket = useCallback(
|
||||
(marketId: string) => {
|
||||
@@ -59,35 +60,36 @@ export const DealTicketSteps = ({
|
||||
watch,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<Order>({
|
||||
} = useForm<OrderSubmissionBody['orderSubmission']>({
|
||||
mode: 'onChange',
|
||||
defaultValues: getDefaultOrder(market),
|
||||
});
|
||||
|
||||
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 { message: invalidText, isDisabled } = useOrderValidation({
|
||||
market,
|
||||
orderType,
|
||||
orderTimeInForce,
|
||||
orderType: order.type,
|
||||
orderTimeInForce: order.timeInForce,
|
||||
fieldErrors: errors,
|
||||
});
|
||||
const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit();
|
||||
const { keypair } = useVegaWallet();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const estMargin = useOrderMargin({
|
||||
order,
|
||||
market,
|
||||
partyId: keypair?.pub || '',
|
||||
partyId: pubKey || '',
|
||||
});
|
||||
|
||||
const { data: partyBalance } = usePartyBalanceQuery({
|
||||
variables: { partyId: pubKey || '' },
|
||||
skip: !pubKey,
|
||||
});
|
||||
|
||||
const maxTrade = useMaximumPositionSize({
|
||||
partyId: keypair?.pub || '',
|
||||
accounts: partyData?.party?.accounts || [],
|
||||
partyId: pubKey || '',
|
||||
accounts: partyBalance?.party?.accounts || [],
|
||||
marketId: market.id,
|
||||
settlementAssetId:
|
||||
market.tradableInstrument.instrument.product.settlementAsset.id,
|
||||
@@ -95,7 +97,11 @@ export const DealTicketSteps = ({
|
||||
order,
|
||||
});
|
||||
|
||||
const estCloseOut = useOrderCloseOut({ order, market, partyData });
|
||||
const estCloseOut = useOrderCloseOut({
|
||||
order,
|
||||
market,
|
||||
partyData: partyBalance,
|
||||
});
|
||||
const slippage = useCalculateSlippage({ marketId: market.id, order });
|
||||
const [slippageValue, setSlippageValue] = useState(
|
||||
slippage ? parseFloat(slippage) : 0
|
||||
@@ -112,7 +118,7 @@ export const DealTicketSteps = ({
|
||||
|
||||
const price = useMemo(() => {
|
||||
if (slippage && market?.depth?.lastTrade?.price) {
|
||||
const isLong = order.side === Side.SIDE_BUY;
|
||||
const isLong = order.side === Schema.Side.SIDE_BUY;
|
||||
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
|
||||
parseFloat(slippage) / 100
|
||||
);
|
||||
@@ -128,26 +134,26 @@ export const DealTicketSteps = ({
|
||||
|
||||
const notionalSize = useMemo(() => {
|
||||
if (price) {
|
||||
const size = new BigNumber(price).multipliedBy(orderSize).toNumber();
|
||||
const size = new BigNumber(price).multipliedBy(order.size).toNumber();
|
||||
|
||||
return addDecimalsFormatNumber(size, market.decimalPlaces);
|
||||
}
|
||||
return null;
|
||||
}, [market.decimalPlaces, orderSize, price]);
|
||||
}, [market.decimalPlaces, order.size, price]);
|
||||
|
||||
const fees = useMemo(() => {
|
||||
if (estMargin?.fees && notionalSize) {
|
||||
const percentage = new BigNumber(estMargin?.fees)
|
||||
if (estMargin?.totalFees && notionalSize) {
|
||||
const percentage = new BigNumber(estMargin?.totalFees)
|
||||
.dividedBy(notionalSize)
|
||||
.multipliedBy(100)
|
||||
.decimalPlaces(2)
|
||||
.toString();
|
||||
|
||||
return `${estMargin.fees} (${percentage}%)`;
|
||||
return `${estMargin.totalFees} (${percentage}%)`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [estMargin?.fees, notionalSize]);
|
||||
}, [estMargin?.totalFees, notionalSize]);
|
||||
|
||||
const max = useMemo(() => {
|
||||
return new BigNumber(maxTrade)
|
||||
@@ -155,6 +161,10 @@ export const DealTicketSteps = ({
|
||||
.toNumber();
|
||||
}, [market.positionDecimalPlaces, maxTrade]);
|
||||
|
||||
useEffect(() => {
|
||||
setSlippageValue(slippage ? parseFloat(slippage) : 0);
|
||||
}, [slippage]);
|
||||
|
||||
const onSizeChange = useCallback(
|
||||
(value: number) => {
|
||||
const newVal = new BigNumber(value)
|
||||
@@ -172,7 +182,7 @@ export const DealTicketSteps = ({
|
||||
(value: number) => {
|
||||
if (market?.depth?.lastTrade?.price) {
|
||||
if (value) {
|
||||
const isLong = order.side === Side.SIDE_BUY;
|
||||
const isLong = order.side === Schema.Side.SIDE_BUY;
|
||||
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
|
||||
value / 100
|
||||
);
|
||||
@@ -183,11 +193,11 @@ export const DealTicketSteps = ({
|
||||
|
||||
setValue('price', bestAskPrice);
|
||||
|
||||
if (orderType === OrderType.TYPE_MARKET) {
|
||||
setValue('type', OrderType.TYPE_LIMIT);
|
||||
if (order.type === Schema.OrderType.TYPE_MARKET) {
|
||||
setValue('type', Schema.OrderType.TYPE_LIMIT);
|
||||
}
|
||||
} else {
|
||||
setValue('type', OrderType.TYPE_MARKET);
|
||||
setValue('type', Schema.OrderType.TYPE_MARKET);
|
||||
setValue('price', market?.depth?.lastTrade?.price);
|
||||
}
|
||||
}
|
||||
@@ -197,13 +207,14 @@ export const DealTicketSteps = ({
|
||||
market.decimalPlaces,
|
||||
market?.depth?.lastTrade?.price,
|
||||
order.side,
|
||||
orderType,
|
||||
order.type,
|
||||
setSlippageValue,
|
||||
setValue,
|
||||
]
|
||||
);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
(order: Order) => {
|
||||
(order: OrderSubmissionBody['orderSubmission']) => {
|
||||
if (transactionStatus !== 'pending') {
|
||||
submit({
|
||||
...order,
|
||||
@@ -244,7 +255,7 @@ export const DealTicketSteps = ({
|
||||
)}
|
||||
/>
|
||||
),
|
||||
value: SIDE_NAMES[orderSide] || '',
|
||||
value: SIDE_NAMES[order.side] || '',
|
||||
},
|
||||
{
|
||||
label: t('Choose Position Size'),
|
||||
@@ -256,7 +267,7 @@ export const DealTicketSteps = ({
|
||||
min={step}
|
||||
max={max}
|
||||
onSizeChange={onSizeChange}
|
||||
size={new BigNumber(orderSize).toNumber()}
|
||||
size={new BigNumber(order.size).toNumber()}
|
||||
name="size"
|
||||
price={formattedPrice || emptyString}
|
||||
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||
@@ -265,7 +276,7 @@ export const DealTicketSteps = ({
|
||||
.symbol
|
||||
}
|
||||
notionalSize={notionalSize || emptyString}
|
||||
estCloseOut={estCloseOut}
|
||||
estCloseOut={estCloseOut || emptyString}
|
||||
fees={fees || emptyString}
|
||||
estMargin={estMargin?.margin || emptyString}
|
||||
/>
|
||||
@@ -275,9 +286,9 @@ export const DealTicketSteps = ({
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
'loading...'
|
||||
t('Loading...')
|
||||
),
|
||||
value: orderSize,
|
||||
value: order.size,
|
||||
},
|
||||
{
|
||||
label: t('Review Trade'),
|
||||
@@ -295,7 +306,7 @@ export const DealTicketSteps = ({
|
||||
isDisabled={isDisabled}
|
||||
transactionStatus={transactionStatus}
|
||||
order={order}
|
||||
estCloseOut={estCloseOut}
|
||||
estCloseOut={estCloseOut || emptyString}
|
||||
estMargin={estMargin?.margin || emptyString}
|
||||
price={formattedPrice || emptyString}
|
||||
quoteName={
|
||||
@@ -310,9 +321,15 @@ export const DealTicketSteps = ({
|
||||
title={getOrderDialogTitle(finalizedOrder?.status)}
|
||||
intent={getOrderDialogIntent(finalizedOrder?.status)}
|
||||
icon={getOrderDialogIcon(finalizedOrder?.status)}
|
||||
>
|
||||
<OrderFeedback transaction={transaction} order={finalizedOrder} />
|
||||
</Dialog>
|
||||
content={{
|
||||
Complete: (
|
||||
<OrderFeedback
|
||||
transaction={transaction}
|
||||
order={finalizedOrder}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
disabled: true,
|
||||
|
||||
@@ -4,19 +4,18 @@ import {
|
||||
KeyValueTable,
|
||||
KeyValueTableRow,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
|
||||
import { DealTicketEstimates } from '@vegaprotocol/deal-ticket';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { SIDE_NAMES } from './side-selector';
|
||||
import SimpleMarketExpires from '../simple-market-list/simple-market-expires';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import type {
|
||||
MarketTags,
|
||||
MarketTagsVariables,
|
||||
} from './__generated__/MarketTags';
|
||||
import { DealTicketEstimates } from './deal-ticket-estimates';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import { Schema } from '@vegaprotocol/types';
|
||||
import { MarketExpires } from '@vegaprotocol/market-info';
|
||||
|
||||
export const MARKET_TAGS_QUERY = gql`
|
||||
query MarketTags($marketId: ID!) {
|
||||
@@ -33,10 +32,10 @@ export const MARKET_TAGS_QUERY = gql`
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
market: DealTicketQuery_market;
|
||||
market: DealTicketMarketFragment;
|
||||
isDisabled: boolean;
|
||||
transactionStatus?: string;
|
||||
order: Order;
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
estCloseOut: string;
|
||||
estMargin: string;
|
||||
quoteName: string;
|
||||
@@ -73,9 +72,10 @@ export default ({
|
||||
<div
|
||||
className={classNames(
|
||||
{
|
||||
'buyButton dark:buyButtonDark': order.side === Side.SIDE_BUY,
|
||||
'buyButton dark:buyButtonDark':
|
||||
order.side === Schema.Side.SIDE_BUY,
|
||||
'sellButton dark:sellButtonDark':
|
||||
order.side === Side.SIDE_SELL,
|
||||
order.side === Schema.Side.SIDE_SELL,
|
||||
},
|
||||
'px-2 py-1 inline text-ui-small'
|
||||
)}
|
||||
@@ -86,7 +86,7 @@ export default ({
|
||||
<div>
|
||||
{tagsData?.market?.tradableInstrument.instrument.metadata
|
||||
.tags && (
|
||||
<SimpleMarketExpires
|
||||
<MarketExpires
|
||||
tags={
|
||||
tagsData?.market.tradableInstrument.instrument.metadata.tags
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@ import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { FormGroup } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import { Schema } from '@vegaprotocol/types';
|
||||
|
||||
interface SideSelectorProps {
|
||||
value: Side;
|
||||
onSelect: (side: Side) => void;
|
||||
value: Schema.Side;
|
||||
onSelect: (side: Schema.Side) => void;
|
||||
}
|
||||
|
||||
export const SIDE_NAMES: Record<Side, string> = {
|
||||
[Side.SIDE_BUY]: t('Long'),
|
||||
[Side.SIDE_SELL]: t('Short'),
|
||||
export const SIDE_NAMES: Record<Schema.Side, string> = {
|
||||
[Schema.Side.SIDE_BUY]: t('Long'),
|
||||
[Schema.Side.SIDE_SELL]: t('Short'),
|
||||
};
|
||||
|
||||
export default ({ value, onSelect }: SideSelectorProps) => {
|
||||
@@ -31,9 +31,9 @@ export default ({ value, onSelect }: SideSelectorProps) => {
|
||||
className={classNames(
|
||||
'px-8 py-2',
|
||||
'buyButton hover:buyButton dark:buyButtonDark dark:hover:buyButtonDark',
|
||||
{ selected: value === Side.SIDE_BUY }
|
||||
{ selected: value === Schema.Side.SIDE_BUY }
|
||||
)}
|
||||
onClick={() => onSelect(Side.SIDE_BUY)}
|
||||
onClick={() => onSelect(Schema.Side.SIDE_BUY)}
|
||||
>
|
||||
{t('Long')}
|
||||
</button>
|
||||
@@ -43,9 +43,9 @@ export default ({ value, onSelect }: SideSelectorProps) => {
|
||||
className={classNames(
|
||||
'px-8 py-2',
|
||||
'sellButton hover:sellButton dark:sellButtonDark dark:hover:sellButtonDark',
|
||||
{ selected: value === Side.SIDE_SELL }
|
||||
{ selected: value === Schema.Side.SIDE_SELL }
|
||||
)}
|
||||
onClick={() => onSelect(Side.SIDE_SELL)}
|
||||
onClick={() => onSelect(Schema.Side.SIDE_SELL)}
|
||||
>
|
||||
{t('Short')}
|
||||
</button>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
query Deposits {
|
||||
query DepositAssets {
|
||||
assetsConnection {
|
||||
edges {
|
||||
node {
|
||||
|
||||
+15
-12
@@ -6,14 +6,14 @@
|
||||
import { AssetStatus } from "@vegaprotocol/types";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: Deposits
|
||||
// GraphQL query operation: DepositAssets
|
||||
// ====================================================
|
||||
|
||||
export interface Deposits_assetsConnection_edges_node_source_BuiltinAsset {
|
||||
export interface DepositAssets_assetsConnection_edges_node_source_BuiltinAsset {
|
||||
__typename: "BuiltinAsset";
|
||||
}
|
||||
|
||||
export interface Deposits_assetsConnection_edges_node_source_ERC20 {
|
||||
export interface DepositAssets_assetsConnection_edges_node_source_ERC20 {
|
||||
__typename: "ERC20";
|
||||
/**
|
||||
* The address of the ERC20 contract
|
||||
@@ -21,9 +21,9 @@ export interface Deposits_assetsConnection_edges_node_source_ERC20 {
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
export type Deposits_assetsConnection_edges_node_source = Deposits_assetsConnection_edges_node_source_BuiltinAsset | Deposits_assetsConnection_edges_node_source_ERC20;
|
||||
export type DepositAssets_assetsConnection_edges_node_source = DepositAssets_assetsConnection_edges_node_source_BuiltinAsset | DepositAssets_assetsConnection_edges_node_source_ERC20;
|
||||
|
||||
export interface Deposits_assetsConnection_edges_node {
|
||||
export interface DepositAssets_assetsConnection_edges_node {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The ID of the asset
|
||||
@@ -48,25 +48,28 @@ export interface Deposits_assetsConnection_edges_node {
|
||||
/**
|
||||
* The origin source of the asset (e.g: an ERC20 asset)
|
||||
*/
|
||||
source: Deposits_assetsConnection_edges_node_source;
|
||||
source: DepositAssets_assetsConnection_edges_node_source;
|
||||
}
|
||||
|
||||
export interface Deposits_assetsConnection_edges {
|
||||
export interface DepositAssets_assetsConnection_edges {
|
||||
__typename: "AssetEdge";
|
||||
node: Deposits_assetsConnection_edges_node;
|
||||
/**
|
||||
* The asset information
|
||||
*/
|
||||
node: DepositAssets_assetsConnection_edges_node;
|
||||
}
|
||||
|
||||
export interface Deposits_assetsConnection {
|
||||
export interface DepositAssets_assetsConnection {
|
||||
__typename: "AssetsConnection";
|
||||
/**
|
||||
* The assets
|
||||
*/
|
||||
edges: (Deposits_assetsConnection_edges | null)[] | null;
|
||||
edges: (DepositAssets_assetsConnection_edges | null)[] | null;
|
||||
}
|
||||
|
||||
export interface Deposits {
|
||||
export interface DepositAssets {
|
||||
/**
|
||||
* The list of all assets in use in the Vega network or the specified asset if ID is provided
|
||||
*/
|
||||
assetsConnection: Deposits_assetsConnection | null;
|
||||
assetsConnection: DepositAssets_assetsConnection | null;
|
||||
}
|
||||
@@ -3,14 +3,14 @@ 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 DepositAssetsQueryVariables = 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 type DepositAssetsQuery = { __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 {
|
||||
export const DepositAssetsDocument = gql`
|
||||
query DepositAssets {
|
||||
assetsConnection {
|
||||
edges {
|
||||
node {
|
||||
@@ -30,28 +30,28 @@ export const DepositsDocument = gql`
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useDepositsQuery__
|
||||
* __useDepositAssetsQuery__
|
||||
*
|
||||
* 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
|
||||
* To run a query within a React component, call `useDepositAssetsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useDepositAssetsQuery` 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({
|
||||
* const { data, loading, error } = useDepositAssetsQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDepositsQuery(baseOptions?: Apollo.QueryHookOptions<DepositsQuery, DepositsQueryVariables>) {
|
||||
export function useDepositAssetsQuery(baseOptions?: Apollo.QueryHookOptions<DepositAssetsQuery, DepositAssetsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<DepositsQuery, DepositsQueryVariables>(DepositsDocument, options);
|
||||
return Apollo.useQuery<DepositAssetsQuery, DepositAssetsQueryVariables>(DepositAssetsDocument, options);
|
||||
}
|
||||
export function useDepositsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<DepositsQuery, DepositsQueryVariables>) {
|
||||
export function useDepositAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<DepositAssetsQuery, DepositAssetsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<DepositsQuery, DepositsQueryVariables>(DepositsDocument, options);
|
||||
return Apollo.useLazyQuery<DepositAssetsQuery, DepositAssetsQueryVariables>(DepositAssetsDocument, options);
|
||||
}
|
||||
export type DepositsQueryHookResult = ReturnType<typeof useDepositsQuery>;
|
||||
export type DepositsLazyQueryHookResult = ReturnType<typeof useDepositsLazyQuery>;
|
||||
export type DepositsQueryResult = Apollo.QueryResult<DepositsQuery, DepositsQueryVariables>;
|
||||
export type DepositAssetsQueryHookResult = ReturnType<typeof useDepositAssetsQuery>;
|
||||
export type DepositAssetsLazyQueryHookResult = ReturnType<typeof useDepositAssetsLazyQuery>;
|
||||
export type DepositAssetsQueryResult = Apollo.QueryResult<DepositAssetsQuery, DepositAssetsQueryVariables>;
|
||||
@@ -1,53 +1,32 @@
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import { useMemo } from 'react';
|
||||
import { DepositManager } from '@vegaprotocol/deposits';
|
||||
import { getEnabledAssets, t } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { enabledAssetsProvider } from '@vegaprotocol/assets';
|
||||
import { useDataProvider } 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 type { Deposits } from './__generated__/Deposits';
|
||||
|
||||
const DEPOSITS_QUERY = gql`
|
||||
query Deposits {
|
||||
assetsConnection {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
symbol
|
||||
decimals
|
||||
status
|
||||
source {
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Fetches data required for the Deposit page
|
||||
*/
|
||||
export const DepositContainer = () => {
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
const { keypair } = useVegaWallet();
|
||||
|
||||
const { data, loading, error } = useQuery<Deposits>(DEPOSITS_QUERY, {
|
||||
variables: { partyId: keypair?.pub },
|
||||
skip: !keypair?.pub,
|
||||
const { pubKey } = useVegaWallet();
|
||||
const variables = useMemo(() => ({ partyId: pubKey }), [pubKey]);
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: enabledAssetsProvider,
|
||||
variables,
|
||||
skip: !pubKey,
|
||||
});
|
||||
|
||||
const assets = getEnabledAssets(data);
|
||||
|
||||
return (
|
||||
<AsyncRenderer<Deposits> data={data} loading={loading} error={error}>
|
||||
{assets.length ? (
|
||||
<AsyncRenderer data={data} loading={loading} error={error}>
|
||||
{data && data.length ? (
|
||||
<Web3Container>
|
||||
<DepositManager
|
||||
assets={assets}
|
||||
assets={data}
|
||||
isFaucetable={VEGA_ENV !== Networks.MAINNET}
|
||||
/>
|
||||
</Web3Container>
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import Logo from './logo';
|
||||
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
|
||||
import LocalContext from '../../context/local-context';
|
||||
|
||||
const Header = () => {
|
||||
const { updateVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||
updateVegaWalletDialog: store.updateVegaWalletDialog,
|
||||
}));
|
||||
const {
|
||||
vegaWalletDialog: { setConnect, setManage },
|
||||
vegaWalletDialog: { setManage },
|
||||
theme,
|
||||
toggleTheme,
|
||||
} = useContext(LocalContext);
|
||||
return (
|
||||
<div
|
||||
className="flex items-stretch pr-6 py-6 bg-black text-neutral-400"
|
||||
className="dark flex items-stretch pr-6 py-6 bg-black text-neutral-400"
|
||||
data-testid="header"
|
||||
>
|
||||
<Logo />
|
||||
<div className="flex items-center gap-2 ml-auto relative z-10">
|
||||
<VegaWalletConnectButton
|
||||
setConnectDialog={setConnect}
|
||||
setConnectDialog={updateVegaWalletDialog}
|
||||
setManageDialog={setManage}
|
||||
/>
|
||||
<ThemeSwitcher
|
||||
theme={theme}
|
||||
onToggle={toggleTheme}
|
||||
className="-my-4"
|
||||
fixedBg="dark"
|
||||
/>
|
||||
<ThemeSwitcher theme={theme} onToggle={toggleTheme} className="-my-4" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import classNames from 'classnames';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export interface Item {
|
||||
name: string;
|
||||
id: string;
|
||||
url?: string;
|
||||
isActive?: boolean;
|
||||
color?: string;
|
||||
cssClass?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
active?: string;
|
||||
cssClass?: string[];
|
||||
items: Item[];
|
||||
'data-testid'?: string;
|
||||
'aria-label'?: string;
|
||||
}
|
||||
|
||||
const MenuItem = ({ id, name, url, isActive, cssClass }: Item): JSX.Element => {
|
||||
if (!url) {
|
||||
return <span data-testid={id}>{name}</span>;
|
||||
}
|
||||
return (
|
||||
<Link
|
||||
to={url}
|
||||
aria-label={name}
|
||||
className={classNames('pl-0 hover:opacity-75', cssClass, {
|
||||
active: isActive,
|
||||
})}
|
||||
data-testid={id}
|
||||
>
|
||||
{name}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const findActive = (active?: string, items?: Item[]) => {
|
||||
if (!active && items?.length) {
|
||||
return 0;
|
||||
}
|
||||
return items?.length
|
||||
? items.findIndex((item) => item.id === active) || 0
|
||||
: -1;
|
||||
};
|
||||
|
||||
export const HorizontalMenu = ({
|
||||
items,
|
||||
active,
|
||||
'data-testid': dataTestId,
|
||||
'aria-label': ariaLabel,
|
||||
}: Props) => {
|
||||
const [activeNumber, setActiveNumber] = useState<number>(
|
||||
findActive(active, items)
|
||||
);
|
||||
const slideContRef = useRef<HTMLUListElement | null>(null);
|
||||
const [sliderStyles, setSliderStyles] = useState<Record<string, string>>({});
|
||||
|
||||
useEffect(() => {
|
||||
setActiveNumber(findActive(active, items));
|
||||
}, [active, items]);
|
||||
|
||||
useEffect(() => {
|
||||
const contStyles = (
|
||||
slideContRef.current as HTMLUListElement
|
||||
).getBoundingClientRect();
|
||||
const selectedStyles = (slideContRef.current as HTMLUListElement).children[
|
||||
activeNumber
|
||||
]?.getBoundingClientRect();
|
||||
const styles: Record<string, string> = selectedStyles
|
||||
? {
|
||||
backgroundColor: items[activeNumber].color || '',
|
||||
width: `${selectedStyles.width}px`,
|
||||
left: `${selectedStyles.left - contStyles.left}px`,
|
||||
}
|
||||
: {};
|
||||
setSliderStyles(styles);
|
||||
}, [activeNumber, slideContRef, items]);
|
||||
|
||||
return items.length ? (
|
||||
<ul
|
||||
ref={slideContRef}
|
||||
className="grid grid-flow-col auto-cols-min gap-4 relative pb-2 mb-2"
|
||||
data-testid={dataTestId}
|
||||
aria-label={ariaLabel}
|
||||
>
|
||||
{items.map((item, i) => (
|
||||
<li key={item.id} className="md:mr-2 whitespace-nowrap">
|
||||
<MenuItem {...item} isActive={i === activeNumber} />
|
||||
</li>
|
||||
))}
|
||||
<li
|
||||
className="absolute bottom-0 h-[2px] transition-left duration-300 dark:bg-white bg-black"
|
||||
key="slider"
|
||||
style={sliderStyles}
|
||||
/>
|
||||
</ul>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default HorizontalMenu;
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as HorizontalMenu } from './horizontal-menu';
|
||||
export type { Item as HorizontalMenuItem } from './horizontal-menu';
|
||||
@@ -0,0 +1,79 @@
|
||||
import { useMemo, useRef, useCallback } from 'react';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { PriceCell, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import type { AccountFields } from '@vegaprotocol/accounts';
|
||||
import { aggregatedAccountsDataProvider, getId } from '@vegaprotocol/accounts';
|
||||
import type { IGetRowsParams } from 'ag-grid-community';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
AssetDetailsDialog,
|
||||
useAssetDetailsDialogStore,
|
||||
} from '@vegaprotocol/assets';
|
||||
import { NO_DATA_MESSAGE } from '../../../constants';
|
||||
import { ConsoleLiteGrid } from '../../console-lite-grid';
|
||||
import { useAccountColumnDefinitions } from '.';
|
||||
|
||||
const AccountsManager = () => {
|
||||
const { partyId = '' } = useOutletContext<{ partyId: string }>();
|
||||
const { isOpen, symbol, setOpen } = useAssetDetailsDialogStore();
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const dataRef = useRef<AccountFields[] | null>(null);
|
||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||
const update = useCallback(
|
||||
({ data }: { data: AccountFields[] | null }) => {
|
||||
dataRef.current = data;
|
||||
gridRef.current?.api?.refreshInfiniteCache();
|
||||
return true;
|
||||
},
|
||||
[gridRef]
|
||||
);
|
||||
const { data, error, loading } = useDataProvider<AccountFields[], never>({
|
||||
dataProvider: aggregatedAccountsDataProvider,
|
||||
update,
|
||||
variables,
|
||||
});
|
||||
if (!dataRef.current && data) {
|
||||
dataRef.current = data;
|
||||
}
|
||||
const getRows = async ({
|
||||
successCallback,
|
||||
startRow,
|
||||
endRow,
|
||||
}: IGetRowsParams) => {
|
||||
const rowsThisBlock = dataRef.current
|
||||
? dataRef.current.slice(startRow, endRow)
|
||||
: [];
|
||||
const lastRow = dataRef.current?.length ?? -1;
|
||||
successCallback(rowsThisBlock, lastRow);
|
||||
};
|
||||
const { columnDefs, defaultColDef } = useAccountColumnDefinitions();
|
||||
return (
|
||||
<>
|
||||
<AsyncRenderer
|
||||
loading={loading}
|
||||
error={error}
|
||||
data={data}
|
||||
noDataMessage={NO_DATA_MESSAGE}
|
||||
>
|
||||
<ConsoleLiteGrid<AccountFields>
|
||||
rowData={data?.length ? undefined : []}
|
||||
rowModelType={data?.length ? 'infinite' : 'clientSide'}
|
||||
ref={gridRef}
|
||||
datasource={{ getRows }}
|
||||
columnDefs={columnDefs}
|
||||
defaultColDef={defaultColDef}
|
||||
components={{ PriceCell }}
|
||||
getRowId={({ data }) => getId(data)}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
<AssetDetailsDialog
|
||||
assetSymbol={symbol}
|
||||
open={isOpen}
|
||||
onChange={(open) => setOpen(open)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountsManager;
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as AccountManager } from './accounts';
|
||||
export { default as useAccountColumnDefinitions } from './use-column-definitions';
|
||||
@@ -0,0 +1,80 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import type { AccountFields } from '@vegaprotocol/accounts';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import type { ColDef, GroupCellRendererParams } from 'ag-grid-community';
|
||||
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
const useAccountColumnDefinitions = () => {
|
||||
const { open } = useAssetDetailsDialogStore();
|
||||
const columnDefs: ColDef[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
colId: 'account-asset',
|
||||
headerName: t('Asset'),
|
||||
field: 'asset.symbol',
|
||||
headerClass: 'uppercase justify-start',
|
||||
cellClass: 'uppercase flex h-full items-center md:pl-4',
|
||||
cellRenderer: ({ value }: GroupCellRendererParams) =>
|
||||
value && value.length > 0 ? (
|
||||
<div className="md:pl-4 grid h-full items-center" title={value}>
|
||||
<div className="truncate min-w-0">
|
||||
<button
|
||||
className="hover:underline"
|
||||
onClick={() => {
|
||||
open(value);
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
),
|
||||
},
|
||||
{
|
||||
colId: 'deposited',
|
||||
headerName: t('Deposited'),
|
||||
field: 'deposited',
|
||||
cellRenderer: 'PriceCell',
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<AccountFields, 'deposited'>) => {
|
||||
if (value && data) {
|
||||
return addDecimalsFormatNumber(value, data.asset.decimals);
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'used',
|
||||
headerName: t('Used'),
|
||||
field: 'used',
|
||||
cellRenderer: 'PriceCell',
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<AccountFields, 'used'>) => {
|
||||
if (value && data) {
|
||||
return addDecimalsFormatNumber(value, data.asset.decimals);
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [open]);
|
||||
|
||||
const defaultColDef = useMemo(() => {
|
||||
return {
|
||||
sortable: true,
|
||||
unSortIcon: true,
|
||||
headerClass: 'uppercase',
|
||||
editable: false,
|
||||
};
|
||||
}, []);
|
||||
return { columnDefs, defaultColDef };
|
||||
};
|
||||
|
||||
export default useAccountColumnDefinitions;
|
||||
@@ -0,0 +1,35 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const PORTFOLIO_ASSETS = 'assets';
|
||||
export const PORTFOLIO_POSITIONS = 'positions';
|
||||
export const PORTFOLIO_ORDERS = 'orders';
|
||||
export const PORTFOLIO_FILLS = 'fills';
|
||||
export const PORTFOLIO_DEPOSITS = 'deposits';
|
||||
|
||||
export const PORTFOLIO_ITEMS = [
|
||||
{
|
||||
name: t('Assets'),
|
||||
id: PORTFOLIO_ASSETS,
|
||||
url: `/portfolio/${PORTFOLIO_ASSETS}`,
|
||||
},
|
||||
{
|
||||
name: t('Positions'),
|
||||
id: PORTFOLIO_POSITIONS,
|
||||
url: `/portfolio/${PORTFOLIO_POSITIONS}`,
|
||||
},
|
||||
{
|
||||
name: t('Orders'),
|
||||
id: PORTFOLIO_ORDERS,
|
||||
url: `/portfolio/${PORTFOLIO_ORDERS}`,
|
||||
},
|
||||
{
|
||||
name: t('Fills'),
|
||||
id: PORTFOLIO_FILLS,
|
||||
url: `/portfolio/${PORTFOLIO_FILLS}`,
|
||||
},
|
||||
{
|
||||
name: t('Deposits'),
|
||||
id: PORTFOLIO_DEPOSITS,
|
||||
url: `/portfolio/${PORTFOLIO_DEPOSITS}`,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,53 @@
|
||||
import { useRef } from 'react';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { Trade } from '@vegaprotocol/fills';
|
||||
import { useFillsList } from '@vegaprotocol/fills';
|
||||
import type { BodyScrollEndEvent, BodyScrollEvent } from 'ag-grid-community';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { ConsoleLiteGrid } from '../../console-lite-grid';
|
||||
import { NO_DATA_MESSAGE } from '../../../constants';
|
||||
import useColumnDefinitions from './use-column-definitions';
|
||||
|
||||
const FillsManager = () => {
|
||||
const { partyId } = useOutletContext<{ partyId: string }>();
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions({ partyId });
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const scrolledToTop = useRef(true);
|
||||
const { data, error, loading, addNewRows, getRows } = useFillsList({
|
||||
partyId,
|
||||
gridRef,
|
||||
scrolledToTop,
|
||||
});
|
||||
|
||||
const onBodyScrollEnd = (event: BodyScrollEndEvent) => {
|
||||
if (event.top === 0) {
|
||||
addNewRows();
|
||||
}
|
||||
};
|
||||
|
||||
const onBodyScroll = (event: BodyScrollEvent) => {
|
||||
scrolledToTop.current = event.top <= 0;
|
||||
};
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
loading={loading}
|
||||
error={error}
|
||||
data={data?.length ? data : null}
|
||||
noDataMessage={NO_DATA_MESSAGE}
|
||||
>
|
||||
<ConsoleLiteGrid<Trade>
|
||||
ref={gridRef}
|
||||
rowModelType="infinite"
|
||||
datasource={{ getRows }}
|
||||
onBodyScrollEnd={onBodyScrollEnd}
|
||||
onBodyScroll={onBodyScroll}
|
||||
columnDefs={columnDefs}
|
||||
defaultColDef={defaultColDef}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
);
|
||||
};
|
||||
|
||||
export default FillsManager;
|
||||
@@ -0,0 +1 @@
|
||||
export { default as FillsManager } from './fills';
|
||||
@@ -0,0 +1,190 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { ColDef, ValueFormatterParams } from 'ag-grid-community';
|
||||
import type { Trade } from '@vegaprotocol/fills';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
addDecimal,
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
getDateTimeFormat,
|
||||
negativeClassNames,
|
||||
positiveClassNames,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { Schema } from '@vegaprotocol/types';
|
||||
|
||||
interface Props {
|
||||
partyId: string;
|
||||
}
|
||||
|
||||
const useColumnDefinitions = ({ partyId }: Props) => {
|
||||
const columnDefs: ColDef[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
colId: 'market',
|
||||
headerName: t('Market'),
|
||||
field: 'market.tradableInstrument.instrument.name',
|
||||
cellClass: '!flex h-full items-center !md:pl-4',
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
colId: 'size',
|
||||
headerName: t('Size'),
|
||||
headerClass: 'uppercase',
|
||||
field: 'size',
|
||||
width: 100,
|
||||
cellClass: ({ data }: { data: Trade }) => {
|
||||
return classNames('!flex h-full items-center justify-center', {
|
||||
[positiveClassNames]: data?.buyer.id === partyId,
|
||||
[negativeClassNames]: data?.seller.id,
|
||||
});
|
||||
},
|
||||
valueFormatter: ({ value, data }: ValueFormatterParams) => {
|
||||
if (value && data?.market) {
|
||||
let prefix;
|
||||
if (data.buyer.id === partyId) {
|
||||
prefix = '+';
|
||||
} else if (data.seller.id) {
|
||||
prefix = '-';
|
||||
}
|
||||
|
||||
const size = addDecimalsFormatNumber(
|
||||
value,
|
||||
data.market.positionDecimalPlaces
|
||||
);
|
||||
return `${prefix}${size}`;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'value',
|
||||
headerName: t('Value'),
|
||||
headerClass: 'uppercase text-center',
|
||||
cellClass: '!flex h-full items-center',
|
||||
field: 'price',
|
||||
valueFormatter: ({ value, data }: ValueFormatterParams) => {
|
||||
if (value && data?.market) {
|
||||
const asset =
|
||||
data.market.tradableInstrument.instrument.product.settlementAsset
|
||||
.symbol;
|
||||
const valueFormatted = addDecimalsFormatNumber(
|
||||
value,
|
||||
data.market.decimalPlaces
|
||||
);
|
||||
return `${valueFormatted} ${asset}`;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
type: 'rightAligned',
|
||||
},
|
||||
{
|
||||
colId: 'filledvalue',
|
||||
headerName: t('Filled value'),
|
||||
headerClass: 'uppercase text-center',
|
||||
cellClass: '!flex h-full items-center',
|
||||
field: 'price',
|
||||
valueFormatter: ({ value, data }: ValueFormatterParams) => {
|
||||
if (value && data?.market) {
|
||||
const asset =
|
||||
data.market.tradableInstrument.instrument.product.settlementAsset
|
||||
.symbol;
|
||||
const size = new BigNumber(
|
||||
addDecimal(data.size, data.market.positionDecimalPlaces)
|
||||
);
|
||||
const price = new BigNumber(
|
||||
addDecimal(value, data.market.decimalPlaces)
|
||||
);
|
||||
|
||||
const total = size.times(price).toString();
|
||||
const valueFormatted = formatNumber(
|
||||
total,
|
||||
data?.market.decimalPlaces
|
||||
);
|
||||
return `${valueFormatted} ${asset}`;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
type: 'rightAligned',
|
||||
},
|
||||
{
|
||||
colId: 'role',
|
||||
headerName: t('Role'),
|
||||
field: 'aggressor',
|
||||
width: 100,
|
||||
valueFormatter: ({ value, data }: ValueFormatterParams) => {
|
||||
if (value && data) {
|
||||
const taker = t('Taker');
|
||||
const maker = t('Maker');
|
||||
if (data?.buyer.id === partyId) {
|
||||
if (value === Schema.Side.SIDE_BUY) {
|
||||
return taker;
|
||||
} else {
|
||||
return maker;
|
||||
}
|
||||
} else if (data?.seller.id === partyId) {
|
||||
if (value === Schema.Side.SIDE_SELL) {
|
||||
return taker;
|
||||
} else {
|
||||
return maker;
|
||||
}
|
||||
}
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'fee',
|
||||
headerName: t('Fee'),
|
||||
headerClass: 'uppercase text-center',
|
||||
cellClass: '!flex h-full items-center',
|
||||
field: 'market.tradableInstrument.instrument.product',
|
||||
valueFormatter: ({ value, data }: ValueFormatterParams) => {
|
||||
if (value && data) {
|
||||
const asset = value.settlementAsset;
|
||||
let feesObj;
|
||||
if (data.buyer.id === partyId) {
|
||||
feesObj = data.buyerFee;
|
||||
} else if (data?.seller.id === partyId) {
|
||||
feesObj = data?.sellerFee;
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
|
||||
const fee = new BigNumber(feesObj.makerFee)
|
||||
.plus(feesObj.infrastructureFee)
|
||||
.plus(feesObj.liquidityFee);
|
||||
const totalFees = addDecimalsFormatNumber(
|
||||
fee.toString(),
|
||||
asset.decimals
|
||||
);
|
||||
return `${totalFees} ${asset.symbol}`;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
type: 'rightAligned',
|
||||
},
|
||||
{
|
||||
colId: 'date',
|
||||
headerName: t('Date'),
|
||||
field: 'createdAt',
|
||||
valueFormatter: ({ value }: ValueFormatterParams) => {
|
||||
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [partyId]);
|
||||
|
||||
const defaultColDef = useMemo(() => {
|
||||
return {
|
||||
sortable: true,
|
||||
unSortIcon: true,
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center',
|
||||
};
|
||||
}, []);
|
||||
return { columnDefs, defaultColDef };
|
||||
};
|
||||
|
||||
export default useColumnDefinitions;
|
||||
@@ -1 +1,6 @@
|
||||
export * from './portfolio';
|
||||
export * from './accounts';
|
||||
export * from './fills';
|
||||
export * from './orders';
|
||||
export * from './positions';
|
||||
export * as constants from './constants';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { default as OrdersManager } from './orders';
|
||||
@@ -0,0 +1,107 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { BodyScrollEndEvent, BodyScrollEvent } from 'ag-grid-community';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import {
|
||||
useOrderCancel,
|
||||
useOrderListData,
|
||||
useOrderEdit,
|
||||
OrderFeedback,
|
||||
getCancelDialogTitle,
|
||||
getCancelDialogIntent,
|
||||
getEditDialogTitle,
|
||||
OrderEditDialog,
|
||||
} from '@vegaprotocol/orders';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { ConsoleLiteGrid } from '../../console-lite-grid';
|
||||
import { NO_DATA_MESSAGE } from '../../../constants';
|
||||
import useColumnDefinitions from './use-column-definitions';
|
||||
|
||||
const OrdersManager = () => {
|
||||
const { partyId } = useOutletContext<{ partyId: string }>();
|
||||
const [editOrder, setEditOrder] = useState<Order | null>(null);
|
||||
const orderCancel = useOrderCancel();
|
||||
const orderEdit = useOrderEdit(editOrder);
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions({
|
||||
setEditOrder,
|
||||
orderCancel,
|
||||
});
|
||||
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const scrolledToTop = useRef(true);
|
||||
|
||||
const { data, error, loading, addNewRows, getRows } = useOrderListData({
|
||||
partyId,
|
||||
gridRef,
|
||||
scrolledToTop,
|
||||
});
|
||||
|
||||
const onBodyScrollEnd = (event: BodyScrollEndEvent) => {
|
||||
if (event.top === 0) {
|
||||
addNewRows();
|
||||
}
|
||||
};
|
||||
|
||||
const onBodyScroll = (event: BodyScrollEvent) => {
|
||||
scrolledToTop.current = event.top <= 0;
|
||||
};
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
loading={loading}
|
||||
error={error}
|
||||
data={data?.length ? data : null}
|
||||
noDataMessage={NO_DATA_MESSAGE}
|
||||
>
|
||||
<ConsoleLiteGrid<Order>
|
||||
ref={gridRef}
|
||||
rowModelType={data?.length ? 'infinite' : 'clientSide'}
|
||||
rowData={data?.length ? undefined : []}
|
||||
datasource={{ getRows }}
|
||||
onBodyScrollEnd={onBodyScrollEnd}
|
||||
onBodyScroll={onBodyScroll}
|
||||
columnDefs={columnDefs}
|
||||
defaultColDef={defaultColDef}
|
||||
/>
|
||||
<orderCancel.Dialog
|
||||
title={getCancelDialogTitle(orderCancel.cancelledOrder?.status)}
|
||||
intent={getCancelDialogIntent(orderCancel.cancelledOrder?.status)}
|
||||
content={{
|
||||
Complete: (
|
||||
<OrderFeedback
|
||||
transaction={orderCancel.transaction}
|
||||
order={orderCancel.cancelledOrder}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<orderEdit.Dialog
|
||||
title={getEditDialogTitle(orderEdit.updatedOrder?.status)}
|
||||
content={{
|
||||
Complete: (
|
||||
<OrderFeedback
|
||||
transaction={orderEdit.transaction}
|
||||
order={orderEdit.updatedOrder}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
{editOrder && (
|
||||
<OrderEditDialog
|
||||
isOpen={Boolean(editOrder)}
|
||||
onChange={(isOpen) => {
|
||||
if (!isOpen) setEditOrder(null);
|
||||
}}
|
||||
order={editOrder}
|
||||
onSubmit={(fields) => {
|
||||
setEditOrder(null);
|
||||
orderEdit.edit({ price: fields.limitPrice });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</AsyncRenderer>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrdersManager;
|
||||
@@ -0,0 +1,278 @@
|
||||
import { useMemo } from 'react';
|
||||
import type {
|
||||
ColDef,
|
||||
ValueFormatterParams,
|
||||
ICellRendererParams,
|
||||
} from 'ag-grid-community';
|
||||
import {
|
||||
addDecimal,
|
||||
getDateTimeFormat,
|
||||
negativeClassNames,
|
||||
positiveClassNames,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
OrderFieldsFragment,
|
||||
Order,
|
||||
CancelOrderArgs,
|
||||
} from '@vegaprotocol/orders';
|
||||
import { isOrderActive } from '@vegaprotocol/orders';
|
||||
import {
|
||||
OrderRejectionReasonMapping,
|
||||
OrderStatusMapping,
|
||||
OrderTypeMapping,
|
||||
Schema,
|
||||
OrderTimeInForceMapping,
|
||||
} from '@vegaprotocol/types';
|
||||
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
type StatusKey = keyof typeof OrderStatusMapping;
|
||||
type RejectReasonKey = keyof typeof OrderRejectionReasonMapping;
|
||||
type OrderTimeKey = keyof typeof OrderTimeInForceMapping;
|
||||
interface Props {
|
||||
setEditOrder: (order: Order) => void;
|
||||
orderCancel: {
|
||||
cancel: (args: CancelOrderArgs) => void;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
|
||||
const columnDefs: ColDef[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
colId: 'market',
|
||||
headerName: t('Market'),
|
||||
field: 'market.tradableInstrument.instrument.code',
|
||||
headerClass: 'uppercase justify-start',
|
||||
cellClass: '!flex h-full items-center !md:pl-4',
|
||||
},
|
||||
{
|
||||
colId: 'size',
|
||||
headerName: t('Size'),
|
||||
field: 'size',
|
||||
headerClass: 'uppercase',
|
||||
cellClass: 'font-mono !flex h-full items-center',
|
||||
width: 80,
|
||||
cellClassRules: {
|
||||
[positiveClassNames]: ({ data }: { data: OrderFieldsFragment }) =>
|
||||
data?.side === Schema.Side.SIDE_BUY,
|
||||
[negativeClassNames]: ({ data }: { data: OrderFieldsFragment }) =>
|
||||
data?.side === Schema.Side.SIDE_SELL,
|
||||
},
|
||||
valueFormatter: ({ value, data }: ValueFormatterParams) => {
|
||||
if (value && data && data.market) {
|
||||
const prefix = data
|
||||
? data.side === Schema.Side.SIDE_BUY
|
||||
? '+'
|
||||
: '-'
|
||||
: '';
|
||||
return (
|
||||
prefix + addDecimal(value, data.market.positionDecimalPlaces)
|
||||
);
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'type',
|
||||
field: 'type',
|
||||
width: 80,
|
||||
valueFormatter: ({
|
||||
value,
|
||||
}: ValueFormatterParams & {
|
||||
value?: OrderFieldsFragment['type'];
|
||||
}) => OrderTypeMapping[value as Schema.OrderType],
|
||||
},
|
||||
{
|
||||
colId: 'status',
|
||||
field: 'status',
|
||||
cellClass: 'text-center font-mono !flex h-full items-center',
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
}: ValueFormatterParams & {
|
||||
value?: StatusKey;
|
||||
}) => {
|
||||
if (value && data && data.market) {
|
||||
if (value === Schema.OrderStatus.STATUS_REJECTED) {
|
||||
return `${OrderStatusMapping[value as StatusKey]}: ${
|
||||
data.rejectionReason &&
|
||||
OrderRejectionReasonMapping[
|
||||
data.rejectionReason as RejectReasonKey
|
||||
]
|
||||
}`;
|
||||
}
|
||||
return OrderStatusMapping[value as StatusKey] as string;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'filled',
|
||||
headerName: t('Filled'),
|
||||
headerClass: 'uppercase',
|
||||
field: 'remaining',
|
||||
cellClass: 'font-mono text-center !flex h-full items-center',
|
||||
width: 80,
|
||||
valueFormatter: ({
|
||||
data,
|
||||
value,
|
||||
}: ValueFormatterParams & {
|
||||
value?: OrderFieldsFragment['remaining'];
|
||||
}) => {
|
||||
if (value && data && data.market) {
|
||||
const dps = data.market.positionDecimalPlaces;
|
||||
const size = new BigNumber(data.size);
|
||||
const remaining = new BigNumber(value);
|
||||
const fills = size.minus(remaining);
|
||||
return `${addDecimal(fills.toString(), dps)}/${addDecimal(
|
||||
size.toString(),
|
||||
dps
|
||||
)}`;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'price',
|
||||
field: 'price',
|
||||
type: 'rightAligned',
|
||||
width: 125,
|
||||
headerClass: 'uppercase text-right',
|
||||
cellClass: 'font-mono text-right !flex h-full items-center',
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
}: ValueFormatterParams & {
|
||||
value?: OrderFieldsFragment['price'];
|
||||
}) => {
|
||||
if (
|
||||
value === undefined ||
|
||||
!data ||
|
||||
!data.market ||
|
||||
data.type === Schema.OrderType.TYPE_MARKET
|
||||
) {
|
||||
return '-';
|
||||
}
|
||||
return addDecimal(value, data.market.decimalPlaces);
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'timeInForce',
|
||||
field: 'timeInForce',
|
||||
minWidth: 120,
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
}: ValueFormatterParams & {
|
||||
value?: OrderTimeKey;
|
||||
}) => {
|
||||
if (value && data?.market) {
|
||||
if (
|
||||
value === Schema.OrderTimeInForce.TIME_IN_FORCE_GTT &&
|
||||
data.expiresAt
|
||||
) {
|
||||
const expiry = getDateTimeFormat().format(
|
||||
new Date(data.expiresAt)
|
||||
);
|
||||
return `${
|
||||
OrderTimeInForceMapping[value as OrderTimeKey]
|
||||
}: ${expiry}`;
|
||||
}
|
||||
|
||||
return OrderTimeInForceMapping[value as OrderTimeKey];
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'createdat',
|
||||
field: 'createdAt',
|
||||
valueFormatter: ({
|
||||
value,
|
||||
}: ValueFormatterParams & {
|
||||
value?: OrderFieldsFragment['createdAt'];
|
||||
}) => {
|
||||
return value ? getDateTimeFormat().format(new Date(value)) : value;
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'updated',
|
||||
field: 'updatedAt',
|
||||
cellClass: '!flex h-full items-center justify-center',
|
||||
valueFormatter: ({
|
||||
value,
|
||||
}: ValueFormatterParams & {
|
||||
value?: OrderFieldsFragment['updatedAt'];
|
||||
}) => {
|
||||
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'edit',
|
||||
field: 'edit',
|
||||
width: 75,
|
||||
cellRenderer: ({ data }: ICellRendererParams) => {
|
||||
if (!data) return null;
|
||||
if (isOrderActive(data.status)) {
|
||||
return (
|
||||
<Button
|
||||
data-testid="edit"
|
||||
onClick={() => {
|
||||
setEditOrder(data);
|
||||
}}
|
||||
size="xs"
|
||||
>
|
||||
{t('Edit')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'cancel',
|
||||
field: 'cancel',
|
||||
minWidth: 130,
|
||||
cellRenderer: ({ data }: ICellRendererParams) => {
|
||||
if (!data) return null;
|
||||
if (isOrderActive(data.status)) {
|
||||
return (
|
||||
<Button
|
||||
size="xs"
|
||||
data-testid="cancel"
|
||||
onClick={() => {
|
||||
if (data.market) {
|
||||
orderCancel.cancel({
|
||||
orderId: data.id,
|
||||
marketId: data.market.id,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [orderCancel, setEditOrder]);
|
||||
const defaultColDef = useMemo(() => {
|
||||
return {
|
||||
sortable: true,
|
||||
unSortIcon: true,
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center',
|
||||
};
|
||||
}, []);
|
||||
return { columnDefs, defaultColDef };
|
||||
};
|
||||
|
||||
export default useColumnDefinitions;
|
||||
@@ -1,40 +1,27 @@
|
||||
import * as React from 'react';
|
||||
import { AccountsContainer } from '@vegaprotocol/accounts';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import React from 'react';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { Tabs, Tab } from '@vegaprotocol/ui-toolkit';
|
||||
import { OrderListContainer } from '@vegaprotocol/orders';
|
||||
import { PositionsContainer } from '@vegaprotocol/positions';
|
||||
import { FillsContainer } from '@vegaprotocol/fills';
|
||||
import ConnectWallet from '../wallet-connector';
|
||||
import { DepositContainer } from '../deposits';
|
||||
import { useOutlet, useLocation } from 'react-router-dom';
|
||||
import { HorizontalMenu } from '../horizontal-menu';
|
||||
import * as constants from './constants';
|
||||
|
||||
export const Portfolio = () => {
|
||||
const { keypair } = useVegaWallet();
|
||||
if (!keypair) {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { pathname } = useLocation();
|
||||
const module = pathname.split('/portfolio/')?.[1] ?? '';
|
||||
const outlet = useOutlet({ partyId: pubKey || '' });
|
||||
if (!pubKey) {
|
||||
return (
|
||||
<section className="xl:w-1/2">
|
||||
<ConnectWallet />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tabs>
|
||||
<Tab id="assets" name={t('Assets')}>
|
||||
<AccountsContainer />
|
||||
</Tab>
|
||||
<Tab id="positions" name={t('Positions')}>
|
||||
<PositionsContainer />
|
||||
</Tab>
|
||||
<Tab id="orders" name={t('Orders')}>
|
||||
<OrderListContainer />
|
||||
</Tab>
|
||||
<Tab id="fills" name={t('Fills')}>
|
||||
<FillsContainer />
|
||||
</Tab>
|
||||
<Tab id="deposits" name={t('Deposits')}>
|
||||
<DepositContainer />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
<div className="h-full p-4 md:p-6 grid grid-rows-[min-content_1fr]">
|
||||
<HorizontalMenu active={module} items={constants.PORTFOLIO_ITEMS} />
|
||||
{outlet}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { default as PositionsManager } from './positions';
|
||||
@@ -0,0 +1,58 @@
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { useRef } from 'react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { Position } from '@vegaprotocol/positions';
|
||||
import { PriceFlashCell, t } from '@vegaprotocol/react-helpers';
|
||||
import { AssetBalance } from '@vegaprotocol/accounts';
|
||||
import { usePositionsData } from '@vegaprotocol/positions';
|
||||
import { ConsoleLiteGrid } from '../../console-lite-grid';
|
||||
import useColumnDefinitions from './use-column-definitions';
|
||||
|
||||
interface Props {
|
||||
partyId: string;
|
||||
assetSymbol: string;
|
||||
}
|
||||
|
||||
const getRowId = ({ data }: { data: Position }) => data.marketId;
|
||||
|
||||
const PositionsAsset = ({ partyId, assetSymbol }: Props) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const { data, error, loading, getRows } = usePositionsData(
|
||||
partyId,
|
||||
gridRef,
|
||||
assetSymbol
|
||||
);
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions();
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||
<div
|
||||
data-testid={`positions-asset-${assetSymbol}`}
|
||||
className="flex justify-between items-center px-4 pt-3 pb-1"
|
||||
>
|
||||
<h4>
|
||||
{assetSymbol} {t('markets')}
|
||||
</h4>
|
||||
<div className="text-sm text-neutral-500 dark:text-neutral-300">
|
||||
{assetSymbol} {t('balance')}:
|
||||
<span data-testid="balance" className="pl-1 font-mono">
|
||||
<AssetBalance partyId={partyId} assetSymbol={assetSymbol} />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<ConsoleLiteGrid<Position & { id: undefined }>
|
||||
ref={gridRef}
|
||||
domLayout="autoHeight"
|
||||
classNamesParam="h-auto"
|
||||
columnDefs={columnDefs}
|
||||
defaultColDef={defaultColDef}
|
||||
getRowId={getRowId}
|
||||
rowModelType={data?.length ? 'infinite' : 'clientSide'}
|
||||
rowData={data?.length ? undefined : []}
|
||||
datasource={{ getRows }}
|
||||
components={{ PriceFlashCell }}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
);
|
||||
};
|
||||
|
||||
export default PositionsAsset;
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { usePositionsAssets } from '@vegaprotocol/positions';
|
||||
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import PositionsAsset from './positions-asset';
|
||||
|
||||
const Positions = () => {
|
||||
const { partyId } = useOutletContext<{ partyId: string }>();
|
||||
const { data, error, loading, assetSymbols } = usePositionsAssets(partyId);
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||
{assetSymbols && assetSymbols.length > 0 && (
|
||||
<div className="w-full, h-max">
|
||||
{assetSymbols?.map((assetSymbol) => (
|
||||
<PositionsAsset
|
||||
key={assetSymbol}
|
||||
partyId={partyId}
|
||||
assetSymbol={assetSymbol}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{assetSymbols?.length === 0 && <Splash>{t('No data to display')}</Splash>}
|
||||
</AsyncRenderer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Positions;
|
||||
@@ -0,0 +1,278 @@
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
getDateTimeFormat,
|
||||
PriceFlashCell,
|
||||
signedNumberCssClassRules,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type { Position } from '@vegaprotocol/positions';
|
||||
import { AmountCell } from '@vegaprotocol/positions';
|
||||
import type {
|
||||
CellRendererSelectorResult,
|
||||
ICellRendererParams,
|
||||
ValueGetterParams,
|
||||
GroupCellRendererParams,
|
||||
ColDef,
|
||||
} from 'ag-grid-community';
|
||||
import { MarketTradingMode } from '@vegaprotocol/types';
|
||||
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
|
||||
import { Intent, ProgressBarCell } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
const EmptyCell = () => '';
|
||||
|
||||
const useColumnDefinitions = () => {
|
||||
const columnDefs: ColDef[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
colId: 'market',
|
||||
headerName: t('Market'),
|
||||
headerClass: 'uppercase justify-start',
|
||||
cellClass: '!flex h-full items-center !md:pl-4',
|
||||
field: 'marketName',
|
||||
cellRenderer: ({ value }: GroupCellRendererParams) => {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
const valueFormatted: [string, string?] = (() => {
|
||||
// split market name into two parts, 'Part1 (Part2)' or 'Part1 - Part2'
|
||||
const matches = value.match(/^(.*)(\((.*)\)| - (.*))\s*$/);
|
||||
if (matches && matches[1] && matches[3]) {
|
||||
return [matches[1].trim(), matches[3].trim()];
|
||||
}
|
||||
return [value];
|
||||
})();
|
||||
if (valueFormatted && valueFormatted[1]) {
|
||||
return (
|
||||
<div className="leading-tight">
|
||||
<div>{valueFormatted[0]}</div>
|
||||
<div>{valueFormatted[1]}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return valueFormatted ? valueFormatted[0] : null;
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'amount',
|
||||
headerName: t('Amount'),
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center',
|
||||
field: 'openVolume',
|
||||
valueGetter: ({ node, data }: ValueGetterParams) => {
|
||||
return node?.rowPinned ? data?.notional : data?.openVolume;
|
||||
},
|
||||
type: 'rightAligned',
|
||||
cellRendererSelector: (
|
||||
params: ICellRendererParams
|
||||
): CellRendererSelectorResult => {
|
||||
return {
|
||||
component: params.node.rowPinned ? PriceFlashCell : AmountCell,
|
||||
};
|
||||
},
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
node,
|
||||
}: VegaValueFormatterParams<Position, 'openVolume'>) => {
|
||||
let ret;
|
||||
if (value && data) {
|
||||
ret = node?.rowPinned
|
||||
? addDecimalsFormatNumber(value, data.decimals)
|
||||
: data;
|
||||
}
|
||||
// FIXME this column needs refactoring
|
||||
return ret as unknown as string;
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'markprice',
|
||||
headerName: t('Mark price'),
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center justify-center',
|
||||
field: 'markPrice',
|
||||
cellRendererSelector: (
|
||||
params: ICellRendererParams
|
||||
): CellRendererSelectorResult => {
|
||||
return {
|
||||
component: params.node.rowPinned ? EmptyCell : PriceFlashCell,
|
||||
};
|
||||
},
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
node,
|
||||
}: VegaValueFormatterParams<Position, 'markPrice'>) => {
|
||||
if (
|
||||
data &&
|
||||
value &&
|
||||
node?.rowPinned &&
|
||||
data.marketTradingMode ===
|
||||
MarketTradingMode.TRADING_MODE_OPENING_AUCTION
|
||||
) {
|
||||
return addDecimalsFormatNumber(
|
||||
value.toString(),
|
||||
data.marketDecimalPlaces
|
||||
);
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'entryprice',
|
||||
headerName: t('Entry price'),
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center',
|
||||
field: 'averageEntryPrice',
|
||||
headerComponentParams: {
|
||||
template:
|
||||
'<div class="ag-cell-label-container" role="presentation">' +
|
||||
` <span>${t('Liquidation price (est)')}</span>` +
|
||||
' <span ref="eText" class="ag-header-cell-text"></span>' +
|
||||
'</div>',
|
||||
},
|
||||
cellRenderer: ({ node, data }: GroupCellRendererParams) => {
|
||||
const valueFormatted =
|
||||
data && !node?.rowPinned
|
||||
? (() => {
|
||||
const min = BigInt(data.averageEntryPrice);
|
||||
const max = BigInt(data.liquidationPrice);
|
||||
const mid = BigInt(data.markPrice);
|
||||
const range = max - min;
|
||||
return {
|
||||
low: addDecimalsFormatNumber(
|
||||
min.toString(),
|
||||
data.marketDecimalPlaces
|
||||
),
|
||||
high: addDecimalsFormatNumber(
|
||||
max.toString(),
|
||||
data.marketDecimalPlaces
|
||||
),
|
||||
value: range
|
||||
? Number(((mid - min) * BigInt(100)) / range)
|
||||
: 0,
|
||||
intent: data.lowMarginLevel ? Intent.Warning : undefined,
|
||||
};
|
||||
})()
|
||||
: undefined;
|
||||
return node.rowPinned ? (
|
||||
''
|
||||
) : (
|
||||
<ProgressBarCell valueFormatted={valueFormatted} />
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'leverage',
|
||||
headerName: t('Leverage'),
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center justify-center',
|
||||
field: 'currentLeverage',
|
||||
type: 'rightAligned',
|
||||
cellRendererSelector: (
|
||||
params: ICellRendererParams
|
||||
): CellRendererSelectorResult => {
|
||||
return {
|
||||
component: params.node.rowPinned ? EmptyCell : PriceFlashCell,
|
||||
};
|
||||
},
|
||||
valueFormatter: ({
|
||||
value,
|
||||
node,
|
||||
}: VegaValueFormatterParams<Position, 'currentLeverage'>) =>
|
||||
value === undefined ? '' : formatNumber(value.toString(), 1),
|
||||
},
|
||||
{
|
||||
colId: 'marginallocated',
|
||||
headerName: t('Margin allocated'),
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full flex-col justify-center',
|
||||
field: 'capitalUtilisation',
|
||||
type: 'rightAligned',
|
||||
cellRenderer: ({ value, node, data }: GroupCellRendererParams) => {
|
||||
const valueFormatted =
|
||||
data && value
|
||||
? (() => {
|
||||
return {
|
||||
low: `${formatNumber(value, 2)}%`,
|
||||
high: addDecimalsFormatNumber(
|
||||
data.totalBalance,
|
||||
data.decimals
|
||||
),
|
||||
value: Number(value),
|
||||
};
|
||||
})()
|
||||
: undefined;
|
||||
return node.rowPinned ? (
|
||||
''
|
||||
) : (
|
||||
<ProgressBarCell valueFormatted={valueFormatted} />
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'realisedpnl',
|
||||
headerName: t('Realised PNL'),
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center',
|
||||
field: 'realisedPNL',
|
||||
type: 'rightAligned',
|
||||
cellClassRules: signedNumberCssClassRules,
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<Position, 'realisedPNL'>) =>
|
||||
value === undefined || data === undefined
|
||||
? ''
|
||||
: addDecimalsFormatNumber(value.toString(), data.decimals),
|
||||
cellRenderer: 'PriceFlashCell',
|
||||
headerTooltip: t('P&L excludes any fees paid.'),
|
||||
},
|
||||
{
|
||||
colId: 'unrealisedpnl',
|
||||
headerName: t('Unrealised PNL'),
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center',
|
||||
field: 'unrealisedPNL',
|
||||
type: 'rightAligned',
|
||||
cellClassRules: signedNumberCssClassRules,
|
||||
valueFormatter: ({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<Position, 'unrealisedPNL'>) =>
|
||||
value === undefined || data === undefined
|
||||
? ''
|
||||
: addDecimalsFormatNumber(value.toString(), data.decimals),
|
||||
cellRenderer: 'PriceFlashCell',
|
||||
},
|
||||
{
|
||||
colId: 'updated',
|
||||
headerName: t('Updated'),
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center',
|
||||
field: 'updatedAt',
|
||||
type: 'rightAligned',
|
||||
valueFormatter: ({
|
||||
value,
|
||||
}: VegaValueFormatterParams<Position, 'updatedAt'>) => {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
return getDateTimeFormat().format(new Date(value));
|
||||
},
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
const defaultColDef = useMemo(() => {
|
||||
return {
|
||||
sortable: true,
|
||||
unSortIcon: true,
|
||||
headerClass: 'uppercase',
|
||||
cellClass: '!flex h-full items-center',
|
||||
};
|
||||
}, []);
|
||||
return { columnDefs, defaultColDef };
|
||||
};
|
||||
|
||||
export default useColumnDefinitions;
|
||||
@@ -1,5 +0,0 @@
|
||||
subscription CandleLive($marketId: ID!) {
|
||||
candles(marketId: $marketId, interval: INTERVAL_I1H) {
|
||||
close
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
fragment SimpleMarketDataFields on ObservableMarketData {
|
||||
marketId
|
||||
marketState
|
||||
}
|
||||
|
||||
query SimpleMarkets($CandleSince: String!) {
|
||||
markets {
|
||||
id
|
||||
state
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
name
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
product {
|
||||
__typename
|
||||
... on Future {
|
||||
quoteName
|
||||
settlementAsset {
|
||||
symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
candles(interval: INTERVAL_I1H, since: $CandleSince) {
|
||||
open
|
||||
close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subscription SimpleMarketDataSub($marketIds: [ID!]!) {
|
||||
marketsData(marketIds: $marketIds) {
|
||||
...SimpleMarketDataFields
|
||||
}
|
||||
}
|
||||
Generated
-33
@@ -1,33 +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_marketsData {
|
||||
__typename: "ObservableMarketData";
|
||||
/**
|
||||
* current state of the market
|
||||
*/
|
||||
marketState: MarketState;
|
||||
/**
|
||||
* market ID of the associated mark price
|
||||
*/
|
||||
marketId: string;
|
||||
}
|
||||
|
||||
export interface SimpleMarketDataSub {
|
||||
/**
|
||||
* Subscribe to the mark price changes
|
||||
*/
|
||||
marketsData: SimpleMarketDataSub_marketsData[];
|
||||
}
|
||||
|
||||
export interface SimpleMarketDataSubVariables {
|
||||
marketIds: string[];
|
||||
}
|
||||
-109
@@ -1,109 +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_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;
|
||||
/**
|
||||
* Full and fairly descriptive name for the instrument
|
||||
*/
|
||||
name: 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;
|
||||
/**
|
||||
* Current state of the market
|
||||
*/
|
||||
state: MarketState;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
-115
@@ -1,115 +0,0 @@
|
||||
import { Schema as Types } from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type SimpleMarketDataFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, marketState: Types.MarketState };
|
||||
|
||||
export type SimpleMarketsQueryVariables = Types.Exact<{
|
||||
CandleSince: Types.Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type SimpleMarketsQuery = { __typename?: 'Query', markets?: Array<{ __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', symbol: string } } } }, candles?: Array<{ __typename?: 'Candle', open: string, close: string } | null> | null }> | null };
|
||||
|
||||
export type SimpleMarketDataSubSubscriptionVariables = Types.Exact<{
|
||||
marketIds: Array<Types.Scalars['ID']> | Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type SimpleMarketDataSubSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, marketState: Types.MarketState }> };
|
||||
|
||||
export const SimpleMarketDataFieldsFragmentDoc = gql`
|
||||
fragment SimpleMarketDataFields on ObservableMarketData {
|
||||
marketId
|
||||
marketState
|
||||
}
|
||||
`;
|
||||
export const SimpleMarketsDocument = gql`
|
||||
query SimpleMarkets($CandleSince: String!) {
|
||||
markets {
|
||||
id
|
||||
state
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
name
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
product {
|
||||
__typename
|
||||
... on Future {
|
||||
quoteName
|
||||
settlementAsset {
|
||||
symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
candles(interval: INTERVAL_I1H, since: $CandleSince) {
|
||||
open
|
||||
close
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useSimpleMarketsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useSimpleMarketsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useSimpleMarketsQuery` 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 } = useSimpleMarketsQuery({
|
||||
* variables: {
|
||||
* CandleSince: // value for 'CandleSince'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useSimpleMarketsQuery(baseOptions: Apollo.QueryHookOptions<SimpleMarketsQuery, SimpleMarketsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<SimpleMarketsQuery, SimpleMarketsQueryVariables>(SimpleMarketsDocument, options);
|
||||
}
|
||||
export function useSimpleMarketsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<SimpleMarketsQuery, SimpleMarketsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<SimpleMarketsQuery, SimpleMarketsQueryVariables>(SimpleMarketsDocument, options);
|
||||
}
|
||||
export type SimpleMarketsQueryHookResult = ReturnType<typeof useSimpleMarketsQuery>;
|
||||
export type SimpleMarketsLazyQueryHookResult = ReturnType<typeof useSimpleMarketsLazyQuery>;
|
||||
export type SimpleMarketsQueryResult = Apollo.QueryResult<SimpleMarketsQuery, SimpleMarketsQueryVariables>;
|
||||
export const SimpleMarketDataSubDocument = gql`
|
||||
subscription SimpleMarketDataSub($marketIds: [ID!]!) {
|
||||
marketsData(marketIds: $marketIds) {
|
||||
...SimpleMarketDataFields
|
||||
}
|
||||
}
|
||||
${SimpleMarketDataFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useSimpleMarketDataSubSubscription__
|
||||
*
|
||||
* To run a query within a React component, call `useSimpleMarketDataSubSubscription` and pass it any options that fit your needs.
|
||||
* When your component renders, `useSimpleMarketDataSubSubscription` 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 } = useSimpleMarketDataSubSubscription({
|
||||
* variables: {
|
||||
* marketIds: // value for 'marketIds'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useSimpleMarketDataSubSubscription(baseOptions: Apollo.SubscriptionHookOptions<SimpleMarketDataSubSubscription, SimpleMarketDataSubSubscriptionVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useSubscription<SimpleMarketDataSubSubscription, SimpleMarketDataSubSubscriptionVariables>(SimpleMarketDataSubDocument, options);
|
||||
}
|
||||
export type SimpleMarketDataSubSubscriptionHookResult = ReturnType<typeof useSimpleMarketDataSubSubscription>;
|
||||
export type SimpleMarketDataSubSubscriptionResult = Apollo.SubscriptionResult<SimpleMarketDataSubSubscription>;
|
||||
@@ -1,9 +1,9 @@
|
||||
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';
|
||||
import { IS_MARKET_TRADABLE } from '../../constants';
|
||||
|
||||
export const STATES_FILTER = [
|
||||
{ value: 'all', text: t('All') },
|
||||
@@ -192,8 +192,17 @@ 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 ALL_PRODUCTS_ITEM = {
|
||||
name: t('All Markets'),
|
||||
id: 'allmarkets',
|
||||
cssClass: 'text-pink',
|
||||
color: theme.colors.pink,
|
||||
};
|
||||
|
||||
export const AG_GRID_CONTAINER_STYLES = { width: '100%', height: '100%' };
|
||||
|
||||
@@ -1,92 +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';
|
||||
|
||||
export const MARKETS_QUERY = gql`
|
||||
query SimpleMarkets($CandleSince: String!) {
|
||||
markets {
|
||||
id
|
||||
state
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
code
|
||||
name
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
product {
|
||||
__typename
|
||||
... on Future {
|
||||
quoteName
|
||||
settlementAsset {
|
||||
symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
candles(interval: INTERVAL_I1H, since: $CandleSince) {
|
||||
open
|
||||
close
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const MARKET_DATA_SUB = gql`
|
||||
subscription SimpleMarketDataSub($marketIds: [ID!]!) {
|
||||
marketsData(marketIds: $marketIds) {
|
||||
marketState
|
||||
marketId
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
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].state = delta.market.state;
|
||||
}
|
||||
// @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;
|
||||
@@ -1,34 +0,0 @@
|
||||
import React from 'react';
|
||||
import { format, isValid, parseISO } from 'date-fns';
|
||||
import { EXPIRE_DATE_FORMAT } from '../../constants';
|
||||
|
||||
const SimpleMarketExpires = ({
|
||||
tags,
|
||||
}: {
|
||||
tags: ReadonlyArray<string> | null;
|
||||
}) => {
|
||||
if (tags) {
|
||||
const dateFound = tags.reduce<Date | null>((agg, tag) => {
|
||||
const parsed = parseISO(
|
||||
(tag.match(/^settlement.*:/) &&
|
||||
tag
|
||||
.split(':')
|
||||
.filter((item, i) => i)
|
||||
.join(':')) as string
|
||||
);
|
||||
if (isValid(parsed)) {
|
||||
agg = parsed;
|
||||
}
|
||||
return agg;
|
||||
}, null);
|
||||
return dateFound ? (
|
||||
<div className="p-2 text-ui-small border border-pink text-pink inline-block">{`${format(
|
||||
dateFound as Date,
|
||||
EXPIRE_DATE_FORMAT
|
||||
)}`}</div>
|
||||
) : null;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default SimpleMarketExpires;
|
||||
+33
-107
@@ -4,21 +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 { MarketState } from '@vegaprotocol/types';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import SimpleMarketList from './simple-market-list';
|
||||
import { MARKETS_QUERY } from './data-provider';
|
||||
import type {
|
||||
SimpleMarkets_markets,
|
||||
SimpleMarkets,
|
||||
} from './__generated__/SimpleMarkets';
|
||||
import type { SimpleMarketDataSub_marketData } from './__generated__/SimpleMarketDataSub';
|
||||
|
||||
const mockedNavigate = jest.fn();
|
||||
|
||||
@@ -28,20 +21,11 @@ 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 updateMock: ({
|
||||
delta,
|
||||
}: {
|
||||
delta: SimpleMarketDataSub_marketData;
|
||||
}) => boolean;
|
||||
|
||||
let mockData = [
|
||||
let marketsMock = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Market 1',
|
||||
id: 'MARKET_A',
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
@@ -57,8 +41,7 @@ let mockData = [
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Market 2',
|
||||
id: 'MARKET_B',
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
@@ -73,20 +56,22 @@ let mockData = [
|
||||
},
|
||||
},
|
||||
},
|
||||
] as unknown as SimpleMarkets_markets[];
|
||||
] as unknown as Market[];
|
||||
|
||||
const mockUseDataProvider = ({ update }: { update: () => boolean }) => {
|
||||
updateMock = update;
|
||||
return { data: mockData, loading: false, error: false };
|
||||
const LIB = '@vegaprotocol/react-helpers';
|
||||
const useDataProvider = () => {
|
||||
return {
|
||||
data: marketsMock,
|
||||
loading: false,
|
||||
error: false,
|
||||
};
|
||||
};
|
||||
|
||||
jest.mock('@vegaprotocol/react-helpers', () => ({
|
||||
...jest.requireActual('@vegaprotocol/react-helpers'),
|
||||
useDataProvider: jest.fn((args) => mockUseDataProvider(args)),
|
||||
jest.mock(LIB, () => ({
|
||||
...jest.requireActual(LIB),
|
||||
useDataProvider: jest.fn(() => useDataProvider()),
|
||||
}));
|
||||
|
||||
const mockIsTradable = jest.fn((_arg) => true);
|
||||
|
||||
jest.mock('../../constants', () => ({
|
||||
...jest.requireActual('../../constants'),
|
||||
IS_MARKET_TRADABLE: jest.fn((arg) => mockIsTradable(arg)),
|
||||
@@ -95,25 +80,12 @@ jest.mock('../../constants', () => ({
|
||||
describe('SimpleMarketList', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
const mocks: MockedResponse<SimpleMarkets> = {
|
||||
request: {
|
||||
query: MARKETS_QUERY,
|
||||
variables: {
|
||||
CandleSince: '2022-06-02T11:11:21.721Z',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: { markets: mockData },
|
||||
},
|
||||
};
|
||||
|
||||
it('should be properly rendered with some data', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[mocks]}>
|
||||
<MockedProvider mocks={[]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
@@ -124,95 +96,49 @@ 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('update should return proper boolean value', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[mocks]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
document.querySelector('.ag-center-cols-container')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
await expect(
|
||||
updateMock({
|
||||
delta: {
|
||||
__typename: 'MarketData',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: '2',
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
},
|
||||
},
|
||||
})
|
||||
).toEqual(true);
|
||||
|
||||
await expect(
|
||||
updateMock({
|
||||
delta: {
|
||||
__typename: 'MarketData',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: '2',
|
||||
state: MarketState.STATE_SUSPENDED,
|
||||
},
|
||||
},
|
||||
})
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
it('click on row should be properly handled', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[mocks]}>
|
||||
<MockedProvider mocks={[]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
document.querySelector('.ag-center-cols-container')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
mockIsTradable.mockClear();
|
||||
const container = document.querySelector('.ag-center-cols-container');
|
||||
const firstRow = getAllByRole(container as HTMLDivElement, 'row')[0];
|
||||
expect(firstRow).toHaveAttribute('row-id', '1');
|
||||
fireEvent.click(firstRow);
|
||||
expect(firstRow).toHaveAttribute('row-id', marketsMock[0].id);
|
||||
await act(async () => {
|
||||
fireEvent.click(firstRow);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(mockIsTradable).toHaveBeenCalledWith({
|
||||
...mockData[0],
|
||||
percentChange: '-',
|
||||
});
|
||||
expect(mockedNavigate).toHaveBeenCalledWith(`/trading/${mockData[0].id}`);
|
||||
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 () => {
|
||||
mockData = [];
|
||||
marketsMock = [];
|
||||
await act(async () => {
|
||||
render(
|
||||
<MockedProvider mocks={[mocks]}>
|
||||
<MockedProvider mocks={[]}>
|
||||
<SimpleMarketList />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('No data to display')).toBeInTheDocument();
|
||||
|
||||
@@ -1,40 +1,23 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { useCallback, useEffect, useRef, useMemo } 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,
|
||||
useDataProvider,
|
||||
useYesterday,
|
||||
} 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 * as constants from './constants';
|
||||
import useMarketsFilterData from './use-markets-filter-data';
|
||||
import useColumnDefinitions from './use-column-definitions';
|
||||
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,
|
||||
FullWidthCellKeyDownEvent,
|
||||
} from 'ag-grid-community/dist/lib/events';
|
||||
import type {
|
||||
GetRowIdParams,
|
||||
TabToNextCellParams,
|
||||
} from 'ag-grid-community/dist/lib/entities/iCallbackParams';
|
||||
import { ConsoleLiteGrid } from '../console-lite-grid';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import { Interval } from '@vegaprotocol/types';
|
||||
import { marketsWithCandlesProvider } from '@vegaprotocol/market-list';
|
||||
|
||||
export type SimpleMarketsType = SimpleMarkets_markets & {
|
||||
export type MarketWithPercentChange = Market & {
|
||||
percentChange?: number | '-';
|
||||
};
|
||||
|
||||
@@ -45,33 +28,25 @@ export type RouterParams = Partial<{
|
||||
}>;
|
||||
|
||||
const SimpleMarketList = () => {
|
||||
const { isMobile, screenSize } = useScreenDimensions();
|
||||
const { isMobile } = 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 yesterday = useYesterday();
|
||||
const variables = useMemo(() => {
|
||||
return {
|
||||
since: new Date(yesterday).toISOString(),
|
||||
interval: Interval.INTERVAL_I1H,
|
||||
};
|
||||
}, [yesterday]);
|
||||
const { data, error, loading } = useDataProvider({
|
||||
dataProvider,
|
||||
update,
|
||||
dataProvider: marketsWithCandlesProvider,
|
||||
variables,
|
||||
noUpdate: true,
|
||||
});
|
||||
const localData: Array<SimpleMarketsType> = useMarketsFilterData(
|
||||
data || [],
|
||||
params
|
||||
);
|
||||
const localData = useMarketsFilterData(data, params);
|
||||
|
||||
const handleOnGridReady = useCallback(() => {
|
||||
gridRef.current?.api?.sizeColumnsToFit();
|
||||
@@ -92,10 +67,8 @@ const SimpleMarketList = () => {
|
||||
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions({ isMobile });
|
||||
|
||||
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}`);
|
||||
}
|
||||
@@ -103,64 +76,17 @@ const SimpleMarketList = () => {
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const onTabToNextCell = useCallback((params: TabToNextCellParams) => {
|
||||
const {
|
||||
api,
|
||||
previousCellPosition: { rowIndex },
|
||||
} = params;
|
||||
const rowCount = api.getDisplayedRowCount();
|
||||
if (rowCount <= rowIndex + 1) {
|
||||
return null;
|
||||
}
|
||||
return { ...params.previousCellPosition, rowIndex: rowIndex + 1 };
|
||||
}, []);
|
||||
|
||||
const onCellKeyDown = useCallback(
|
||||
(
|
||||
params: (CellKeyDownEvent | FullWidthCellKeyDownEvent) & {
|
||||
event: KeyboardEvent;
|
||||
}
|
||||
) => {
|
||||
const { event: { key = '' } = {}, data } = params;
|
||||
if (key === 'Enter') {
|
||||
handleRowClicked({ data });
|
||||
}
|
||||
},
|
||||
[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 || []} />
|
||||
<AsyncRenderer loading={loading} error={error} data={localData}>
|
||||
<AgGrid
|
||||
className="mb-32 min-h-[300px]"
|
||||
defaultColDef={defaultColDef}
|
||||
<ConsoleLiteGrid<MarketWithPercentChange>
|
||||
classNamesParam="mb-32 min-h-[300px]"
|
||||
columnDefs={columnDefs}
|
||||
rowData={localData}
|
||||
rowHeight={60}
|
||||
customThemeParams={
|
||||
theme === 'dark'
|
||||
? constants.agGridDarkVariables
|
||||
: constants.agGridLightVariables
|
||||
}
|
||||
onGridReady={handleOnGridReady}
|
||||
onRowClicked={handleRowClicked}
|
||||
rowClass={isMobile ? 'mobile' : ''}
|
||||
rowClassRules={constants.ROW_CLASS_RULES}
|
||||
ref={gridRef}
|
||||
overlayNoRowsTemplate={t('No data to display')}
|
||||
suppressContextMenu
|
||||
getRowId={getRowId}
|
||||
suppressMovableColumns
|
||||
suppressRowTransform
|
||||
onCellKeyDown={onCellKeyDown}
|
||||
tabToNextCell={onTabToNextCell}
|
||||
suppressHorizontalScroll={shouldSuppressHorizontalScroll}
|
||||
defaultColDef={defaultColDef}
|
||||
handleRowClicked={handleRowClicked}
|
||||
getRowId={({ data }) => data.id}
|
||||
/>
|
||||
</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
|
||||
|
||||
+20
-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, useYesterday } 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,19 @@ 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 yesterday = useYesterday();
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketCandlesProvider,
|
||||
variables: {
|
||||
marketId,
|
||||
interval: Interval.INTERVAL_I1D,
|
||||
since: new Date(yesterday).toISOString(),
|
||||
},
|
||||
});
|
||||
|
||||
const close = data?.map((m) => m.close);
|
||||
|
||||
const change = getChange(candles, close?.[0]);
|
||||
const colorClasses = getClassColor(change);
|
||||
useEffect(() => {
|
||||
const value = parseFloat(change);
|
||||
|
||||
+10
-10
@@ -1,36 +1,36 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import type { MarketNames_markets } from '@vegaprotocol/deal-ticket';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import MarketNameRenderer from './simple-market-renderer';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
|
||||
describe('SimpleMarketRenderer', () => {
|
||||
const market = {
|
||||
id: 'marketId',
|
||||
id: 'MARKET_A',
|
||||
state: MarketState.STATE_ACTIVE,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'Market code',
|
||||
name: 'Market Name',
|
||||
code: 'MARKET_A_CODE',
|
||||
name: 'MARKET_A_NAME',
|
||||
product: {
|
||||
quoteName: 'Quote name',
|
||||
quoteName: 'MARKET_A_QUOTE_NAME',
|
||||
},
|
||||
metadata: {
|
||||
tags: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as MarketNames_markets;
|
||||
} as Market;
|
||||
|
||||
it('should properly render not mobile', () => {
|
||||
render(<MarketNameRenderer market={market} isMobile={false} />);
|
||||
expect(screen.getByText('Market Name')).toBeInTheDocument();
|
||||
expect(screen.getByText('Quote name')).toBeInTheDocument();
|
||||
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 code')).toBeInTheDocument();
|
||||
expect(screen.getByText('Quote name')).toBeInTheDocument();
|
||||
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';
|
||||
import { MarketExpires } from '@vegaprotocol/market-info';
|
||||
|
||||
interface Props {
|
||||
market: MarketNames_markets;
|
||||
market: Market;
|
||||
isMobile?: boolean;
|
||||
}
|
||||
|
||||
@@ -20,7 +19,7 @@ const MarketNameRenderer = ({ market, isMobile }: Props) => {
|
||||
{isMobile
|
||||
? market.tradableInstrument.instrument.code
|
||||
: market.tradableInstrument.instrument.name}{' '}
|
||||
<SimpleMarketExpires
|
||||
<MarketExpires
|
||||
tags={market.tradableInstrument.instrument.metadata.tags}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+9
-23
@@ -15,8 +15,8 @@ import {
|
||||
} from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/react-testing';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
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();
|
||||
@@ -35,35 +35,23 @@ describe('SimpleMarketToolbar', () => {
|
||||
const routes = useRoutes([
|
||||
{
|
||||
path: '/',
|
||||
element: (
|
||||
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
|
||||
),
|
||||
element: <SimpleMarketToolbar data={filterData as Market[]} />,
|
||||
},
|
||||
{
|
||||
path: 'markets',
|
||||
children: [
|
||||
{
|
||||
path: `:state`,
|
||||
element: (
|
||||
<SimpleMarketToolbar
|
||||
data={filterData as SimpleMarkets_markets[]}
|
||||
/>
|
||||
),
|
||||
element: <SimpleMarketToolbar data={filterData as Market[]} />,
|
||||
children: [
|
||||
{
|
||||
path: `:product`,
|
||||
element: (
|
||||
<SimpleMarketToolbar
|
||||
data={filterData as SimpleMarkets_markets[]}
|
||||
/>
|
||||
),
|
||||
element: <SimpleMarketToolbar data={filterData as Market[]} />,
|
||||
children: [
|
||||
{
|
||||
path: `:asset`,
|
||||
element: (
|
||||
<SimpleMarketToolbar
|
||||
data={filterData as SimpleMarkets_markets[]}
|
||||
/>
|
||||
<SimpleMarketToolbar data={filterData as Market[]} />
|
||||
),
|
||||
},
|
||||
],
|
||||
@@ -71,9 +59,7 @@ describe('SimpleMarketToolbar', () => {
|
||||
],
|
||||
},
|
||||
],
|
||||
element: (
|
||||
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
|
||||
),
|
||||
element: <SimpleMarketToolbar data={filterData as Market[]} />,
|
||||
},
|
||||
]);
|
||||
const location = useLocation();
|
||||
@@ -166,7 +152,7 @@ describe('SimpleMarketToolbar', () => {
|
||||
}));
|
||||
render(
|
||||
<MockedProvider mocks={[]} addTypename={false}>
|
||||
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
|
||||
<SimpleMarketToolbar data={filterData as Market[]} />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
@@ -187,7 +173,7 @@ describe('SimpleMarketToolbar', () => {
|
||||
(useParams as jest.Mock).mockImplementation(() => ({}));
|
||||
render(
|
||||
<MockedProvider mocks={[]} addTypename={false}>
|
||||
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
|
||||
<SimpleMarketToolbar data={filterData as Market[]} />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
@@ -211,7 +197,7 @@ describe('SimpleMarketToolbar', () => {
|
||||
}));
|
||||
render(
|
||||
<MockedProvider mocks={[]} addTypename={false}>
|
||||
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
|
||||
<SimpleMarketToolbar data={filterData as Market[]} />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user