Compare commits
239
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35a52f00da | ||
|
|
567345e7aa | ||
|
|
5ba4d57f1f | ||
|
|
7563c92df2 | ||
|
|
2002731c52 | ||
|
|
a49139f127 | ||
|
|
e216b23472 | ||
|
|
e52ae97233 | ||
|
|
1780f6fa7f | ||
|
|
8b91592b93 | ||
|
|
508274268d | ||
|
|
2a40d9ec4d | ||
|
|
efb746f373 | ||
|
|
6d2f367987 | ||
|
|
6b7bbc9c94 | ||
|
|
9153677a33 | ||
|
|
cff1818940 | ||
|
|
d05dd6e4cb | ||
|
|
4ef789e00a | ||
|
|
0bd13a5f7b | ||
|
|
67d38ff03e | ||
|
|
6aea10c27b | ||
|
|
27a9d5f247 | ||
|
|
261f32aa5b | ||
|
|
053775bef6 | ||
|
|
0660eda334 | ||
|
|
f22a3bc2d2 | ||
|
|
fde77ebccb | ||
|
|
e309669736 | ||
|
|
b1621d1191 | ||
|
|
39907f07db | ||
|
|
3dab5f3d9b | ||
|
|
3cf9ae7582 | ||
|
|
557894e2ef | ||
|
|
baf9875c69 | ||
|
|
51199b02ce | ||
|
|
bb826c88f0 | ||
|
|
0da20b750f | ||
|
|
e16c447564 | ||
|
|
a2170d27d6 | ||
|
|
00d840b7b3 | ||
|
|
2a4a05630f | ||
|
|
97f1f40f2c | ||
|
|
a8e6963521 | ||
|
|
a2bffa1dfd | ||
|
|
9253e8067a | ||
|
|
58972f0a11 | ||
|
|
a3c55fd7c3 | ||
|
|
c63cba1071 | ||
|
|
bc9d87fe30 | ||
|
|
6a21862378 | ||
|
|
0fb4348e9c | ||
|
|
b751bcf17d | ||
|
|
d32f27fcb1 | ||
|
|
d05cd6a2ed | ||
|
|
c003e5fa30 | ||
|
|
f62d3289ab | ||
|
|
a3d3d18c5c | ||
|
|
77ca101781 | ||
|
|
d238c37d0c | ||
|
|
79feb485f6 | ||
|
|
6aa5c3b6e3 | ||
|
|
82abc13fda | ||
|
|
933f07cddf | ||
|
|
c8067669c2 | ||
|
|
78f5a9c520 | ||
|
|
462066959d | ||
|
|
f12f5ab961 | ||
|
|
98b2460d8b | ||
|
|
67c182f3de | ||
|
|
68e0009ab0 | ||
|
|
ad74b12908 | ||
|
|
7fff33e493 | ||
|
|
e7cb2c8276 | ||
|
|
4adaeea40a | ||
|
|
d47d894147 | ||
|
|
515932d401 | ||
|
|
723ff2805d | ||
|
|
424cced4be | ||
|
|
b2c7ee82c5 | ||
|
|
4cc63be4f9 | ||
|
|
9fbb7a13e6 | ||
|
|
1874095222 | ||
|
|
e459e92127 | ||
|
|
4dd65b4923 | ||
|
|
5d792d2458 | ||
|
|
59b2f75b13 | ||
|
|
95775679ca | ||
|
|
4cffee29f8 | ||
|
|
bd70b0c233 | ||
|
|
145792f216 | ||
|
|
10add7c236 | ||
|
|
362a2031c7 | ||
|
|
5aaeb87059 | ||
|
|
d240dddab5 | ||
|
|
0af1d0ba82 | ||
|
|
665ab6693a | ||
|
|
902ee2696c | ||
|
|
3beeb0140c | ||
|
|
4b208e90bf | ||
|
|
ec837854cf | ||
|
|
8b94a75ba4 | ||
|
|
08c57b6759 | ||
|
|
bb2184498f | ||
|
|
8b07ce3024 | ||
|
|
8a110584dd | ||
|
|
b82615a3d8 | ||
|
|
f178b85846 | ||
|
|
0796f2b31f | ||
|
|
67be224138 | ||
|
|
51c426ef4b | ||
|
|
fa28d31ef3 | ||
|
|
201a586b05 | ||
|
|
7d96d9bcd1 | ||
|
|
345be81142 | ||
|
|
2221e9faca | ||
|
|
7c0139e107 | ||
|
|
a157ff1e05 | ||
|
|
2e9fa0c52e | ||
|
|
c0790c1e93 | ||
|
|
13c1044f8e | ||
|
|
cf9f313e4c | ||
|
|
f56d34fe6e | ||
|
|
1379366caa | ||
|
|
8958c12fe3 | ||
|
|
fef13874db | ||
|
|
40f02ecf89 | ||
|
|
41cd6b1455 | ||
|
|
3cd393dac0 | ||
|
|
a52e60d6a2 | ||
|
|
bc13f1b359 | ||
|
|
eb81f4ae44 | ||
|
|
51ab02a2e2 | ||
|
|
ffada1b93d | ||
|
|
9dda3f712b | ||
|
|
df20dbeee0 | ||
|
|
cdfd8a2d00 | ||
|
|
1e5c523bc4 | ||
|
|
37cd69ba6e | ||
|
|
2c11045dd9 | ||
|
|
9aef41a119 | ||
|
|
80ab8821d0 | ||
|
|
8a3657a9b9 | ||
|
|
7100b0e9fc | ||
|
|
614a83b7d6 | ||
|
|
3dc77b0eff | ||
|
|
a59f7dfd29 | ||
|
|
61471228aa | ||
|
|
127e784ceb | ||
|
|
70d748fb15 | ||
|
|
e06f4818fc | ||
|
|
8182da3b31 | ||
|
|
c8c56307bb | ||
|
|
a8cd7f157f | ||
|
|
4f18caa486 | ||
|
|
5c7c626bbc | ||
|
|
e4c4c20631 | ||
|
|
0697302d07 | ||
|
|
2d926c0ce0 | ||
|
|
f57d6a7c7b | ||
|
|
15f905046f | ||
|
|
4f7918f64e | ||
|
|
52ab0562b0 | ||
|
|
4e2b0d1b1d | ||
|
|
0b0bcad9b3 | ||
|
|
bcf17bb34e | ||
|
|
a2b9b0da05 | ||
|
|
7588d0cd11 | ||
|
|
5ee1748495 | ||
|
|
73a118978f | ||
|
|
eac26c1966 | ||
|
|
d615587564 | ||
|
|
ba4ce1ce88 | ||
|
|
3bbacc1aa0 | ||
|
|
de5371435d | ||
|
|
12cb5e10b6 | ||
|
|
ee2909cc84 | ||
|
|
068d6abf1b | ||
|
|
e5d4d2b0b8 | ||
|
|
d4e801cfc6 | ||
|
|
964deb2f23 | ||
|
|
6669125dd3 | ||
|
|
129b6c4e89 | ||
|
|
ca418cabfe | ||
|
|
192af844c4 | ||
|
|
6a841f226a | ||
|
|
76426baa2a | ||
|
|
6fdac2419c | ||
|
|
87807d2088 | ||
|
|
a5f2533a66 | ||
|
|
1e9251c9c0 | ||
|
|
2a27e124d7 | ||
|
|
4ee85720ab | ||
|
|
a19da4c408 | ||
|
|
65ad4fffda | ||
|
|
11317cdb2e | ||
|
|
c98870f27d | ||
|
|
c0c56e4c48 | ||
|
|
a9ca215276 | ||
|
|
61a9eb2f5c | ||
|
|
bb47747501 | ||
|
|
5827b87f89 | ||
|
|
19b95832c4 | ||
|
|
48e4ab53a1 | ||
|
|
cefcff040f | ||
|
|
c3ef639daf | ||
|
|
b6052bc3e5 | ||
|
|
6e8894936e | ||
|
|
66f55855ae | ||
|
|
5725b824ad | ||
|
|
9344a2abc0 | ||
|
|
fae66ca4ce | ||
|
|
31524ac7a7 | ||
|
|
ea3e5a7651 | ||
|
|
b062339682 | ||
|
|
824bcf89bd | ||
|
|
f315917094 | ||
|
|
8e898cfd78 | ||
|
|
f377e07996 | ||
|
|
090d340364 | ||
|
|
6d32fa7362 | ||
|
|
1a7682c3c9 | ||
|
|
3294c0cabe | ||
|
|
c10084d441 | ||
|
|
96658134ee | ||
|
|
a070504d2e | ||
|
|
f891caf08b | ||
|
|
69bdc637e5 | ||
|
|
78add88014 | ||
|
|
02c425f304 | ||
|
|
06769f25cf | ||
|
|
b3014bb98a | ||
|
|
132f2e4b2b | ||
|
|
374890dc08 | ||
|
|
7f95ba577e | ||
|
|
2f7e53e282 | ||
|
|
568dcd5305 | ||
|
|
9605b0e7fa | ||
|
|
0776332ba7 |
+3
-1
@@ -73,9 +73,11 @@
|
|||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"prefer": "type-imports",
|
"prefer": "type-imports",
|
||||||
"disallowTypeAnnotations": true
|
"disallowTypeAnnotations": true,
|
||||||
|
"fixStyle": "inline-type-imports"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"@typescript-eslint/no-useless-constructor": 0,
|
||||||
"curly": ["error", "multi-line"]
|
"curly": ["error", "multi-line"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
* text eol=lf
|
* text eol=lf
|
||||||
*.png binary
|
*.png binary
|
||||||
*.ico binary
|
*.ico binary
|
||||||
|
*.woff2 binary
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
${{ runner.os }}-cache-node-modules-
|
${{ runner.os }}-cache-node-modules-
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
@@ -57,7 +57,7 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
@@ -96,7 +96,7 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -128,7 +128,7 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -182,7 +182,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
if [[ "${{ github.base_ref }}" == "develop" ]]; then
|
if [[ "${{ github.base_ref }}" == "develop" ]]; then
|
||||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ github.base_ref }}" == "main" ]]; then
|
elif [[ "${{ github.base_ref }}" == "main" ]]; then
|
||||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
||||||
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/"* ]]; then
|
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/"* ]]; then
|
||||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
||||||
@@ -205,7 +205,7 @@ jobs:
|
|||||||
|
|
||||||
console-e2e:
|
console-e2e:
|
||||||
needs: [build-sources, check-e2e-needed]
|
needs: [build-sources, check-e2e-needed]
|
||||||
name: '(CI) console python'
|
name: '(CI) trading e2e python'
|
||||||
uses: ./.github/workflows/console-test-run.yml
|
uses: ./.github/workflows/console-test-run.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
if: needs.check-e2e-needed.outputs.run-tests == 'true' && contains(needs.build-sources.outputs.projects, 'trading')
|
if: needs.check-e2e-needed.outputs.run-tests == 'true' && contains(needs.build-sources.outputs.projects, 'trading')
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ on:
|
|||||||
inputs:
|
inputs:
|
||||||
console-test-branch:
|
console-test-branch:
|
||||||
type: choice
|
type: choice
|
||||||
description: 'main: v0.72.14, develop: v0.73.0-preview7'
|
description: 'main: v0.73.5, develop: v0.73.5'
|
||||||
options:
|
options:
|
||||||
- main
|
- main
|
||||||
- develop
|
- develop
|
||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
create-docker-image:
|
create-docker-image:
|
||||||
name: Create docker image for console-test
|
name: Create docker image for console-test
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
timeout-minutes: 20
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# check-out frontend-monorepo
|
# check-out frontend-monorepo
|
||||||
@@ -32,9 +32,9 @@ jobs:
|
|||||||
# cache node modules
|
# cache node modules
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: setup node
|
- name: setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '16'
|
node-version-file: '.nvmrc'
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: Cache node modules
|
||||||
@@ -138,7 +138,7 @@ jobs:
|
|||||||
name: run-tests
|
name: run-tests
|
||||||
runs-on: 8-cores
|
runs-on: 8-cores
|
||||||
needs: [create-docker-image, console-test-branch]
|
needs: [create-docker-image, console-test-branch]
|
||||||
timeout-minutes: 20
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# load docker image
|
# load docker image
|
||||||
@@ -153,25 +153,19 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
docker load --input /tmp/console-image.tar
|
docker load --input /tmp/console-image.tar
|
||||||
docker image ls -a
|
docker image ls -a
|
||||||
|
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# check-out tests repo
|
# check-out frontend-monorepo
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Checkout console test repo
|
- name: Checkout frontend-monorepo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: vegaprotocol/console-test
|
ref: ${{ inputs.github-sha || github.sha }}
|
||||||
ref: ${{ needs.console-test-branch.outputs.console-branch }}
|
#----------------------------------------------
|
||||||
|
# get vega version
|
||||||
- name: Load console test envs
|
#----------------------------------------------
|
||||||
id: console-test-env
|
- name: Set VEGA_VERSION from .env
|
||||||
uses: falti/dotenv-action@v1.0.4
|
id: set_vega_version
|
||||||
with:
|
run: echo "VEGA_VERSION=$(grep VEGA_VERSION apps/trading/e2e/.env | cut -d '=' -f2)" >> $GITHUB_ENV
|
||||||
path: '.env.${{ needs.console-test-branch.outputs.console-branch }}'
|
|
||||||
export-variables: true
|
|
||||||
keys-case: upper
|
|
||||||
log-variables: true
|
|
||||||
|
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# ----- Setup python -----
|
# ----- Setup python -----
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
@@ -194,22 +188,25 @@ jobs:
|
|||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: poetry install --no-interaction --no-root
|
run: poetry install --no-interaction --no-root
|
||||||
|
working-directory: apps/trading/e2e
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install vega binaries
|
# install vega binaries
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Install vega binaries
|
- name: Install vega binaries
|
||||||
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
|
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
|
||||||
|
working-directory: apps/trading/e2e
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install playwright
|
# install playwrightworking-directory: apps/trading/e2e
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: install playwright
|
- name: install playwright
|
||||||
run: poetry run playwright install --with-deps chromium
|
run: poetry run playwright install --with-deps chromium
|
||||||
|
working-directory: apps/trading/e2e
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# run tests
|
# run tests
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
|
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v --numprocesses 1 --dist loadfile --durations=45
|
||||||
|
working-directory: apps/trading/e2e
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# upload traces
|
# upload traces
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
@@ -218,7 +215,7 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: playwright-trace
|
name: playwright-trace
|
||||||
path: ./traces/
|
path: apps/trading/e2e/traces/
|
||||||
retention-days: 15
|
retention-days: 15
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# ----- upload logs -----
|
# ----- upload logs -----
|
||||||
@@ -230,3 +227,46 @@ jobs:
|
|||||||
name: worker-logs
|
name: worker-logs
|
||||||
path: ./logs/
|
path: ./logs/
|
||||||
retention-days: 15
|
retention-days: 15
|
||||||
|
#----------------------------------------------
|
||||||
|
# ----- upload market-sim logs -----
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Prepare and Zip market-sim-logs
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
parent_dir="/tmp/market-sim-logs"
|
||||||
|
echo "Creating parent directory at $parent_dir"
|
||||||
|
mkdir -p "$parent_dir"
|
||||||
|
|
||||||
|
echo "Waiting for vega-sim-* folders to be created..."
|
||||||
|
sleep 10 # Waits 10 seconds to ensure all folders are created
|
||||||
|
|
||||||
|
echo "Before searching for vega-sim-* folders in /tmp..."
|
||||||
|
folders=$(find /tmp -mindepth 1 -type d -name 'vega-sim-*' -print) || echo "Find command failed with exit code $?"
|
||||||
|
|
||||||
|
echo "After searching for vega-sim-* folders in /tmp..."
|
||||||
|
|
||||||
|
if [ -z "$folders" ]; then
|
||||||
|
echo "No vega-sim-* folders found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Moving vega-sim-* folders to $parent_dir"
|
||||||
|
echo "$folders" | xargs -I {} mv {} "$parent_dir/"
|
||||||
|
|
||||||
|
echo "Checking if $parent_dir is not empty..."
|
||||||
|
if [ "$(ls -A $parent_dir)" ]; then
|
||||||
|
echo "Zipping the parent directory..."
|
||||||
|
zip -r market-sim-logs.zip "$parent_dir" && echo "Zip file created successfully."
|
||||||
|
else
|
||||||
|
echo "$parent_dir is empty. No zip file created."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
shell: /usr/bin/bash -e {0}
|
||||||
|
|
||||||
|
- name: Upload market-sim-logs
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: market-sim-logs
|
||||||
|
path: market-sim-logs.zip
|
||||||
|
retention-days: 15
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Use Node.js 16
|
- name: Use Node.js 20
|
||||||
id: Node
|
id: Node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 16.15.1
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- name: Run Cypress tests
|
- name: Run Cypress tests
|
||||||
uses: cypress-io/github-action@v4
|
uses: cypress-io/github-action@v4
|
||||||
|
|||||||
@@ -57,6 +57,14 @@ jobs:
|
|||||||
path: './frontend-monorepo'
|
path: './frontend-monorepo'
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: './frontend-monorepo/.nvmrc'
|
||||||
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
cache: yarn
|
||||||
|
cache-dependency-path: './frontend-monorepo/yarn.lock'
|
||||||
|
|
||||||
# Restore node_modules from cache if possible
|
# Restore node_modules from cache if possible
|
||||||
- name: Restore node_modules from cache
|
- name: Restore node_modules from cache
|
||||||
id: cache-node-modules
|
id: cache-node-modules
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
rm package.json
|
rm package.json
|
||||||
npm install --no-save @commitlint/cli @commitlint/config-conventional @commitlint/config-nx-scopes nx
|
npm install --no-save @commitlint/cli @commitlint/config-conventional @commitlint/config-nx-scopes nx
|
||||||
|
|
||||||
- name: Check PR title
|
- name: Check PR title
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
|||||||
+9
-1
@@ -48,7 +48,15 @@ cypress.env.json
|
|||||||
# Next.js
|
# Next.js
|
||||||
.next
|
.next
|
||||||
|
|
||||||
#cypress
|
# cypress
|
||||||
/apps/**/cypress/reports/
|
/apps/**/cypress/reports/
|
||||||
/apps/**/cypress/downloads/
|
/apps/**/cypress/downloads/
|
||||||
/apps/**/fixtures/wallet/node**
|
/apps/**/fixtures/wallet/node**
|
||||||
|
|
||||||
|
# apps/trading/e2e
|
||||||
|
__pycache__/
|
||||||
|
apps/trading/e2e/logs/
|
||||||
|
apps/trading/e2e/.pytest_cache/
|
||||||
|
apps/trading/e2e/traces/
|
||||||
|
|
||||||
|
.nx/
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
# Auto-format all files
|
||||||
|
yarn nx format:write
|
||||||
|
|
||||||
# Lint all staged files
|
# Lint all staged files
|
||||||
yarn lint-staged
|
yarn lint-staged
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
# Lint all staged files
|
# Lint all staged files - this brings more value as pre-commit
|
||||||
yarn nx format:check
|
# yarn nx format:check
|
||||||
|
|
||||||
# Test all projects with changes
|
# Test all projects with changes
|
||||||
yarn nx affected -t test --exclude trading
|
# yarn nx affected -t test --exclude trading
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Add files here to ignore them from prettier formatting
|
# Add files here to ignore them from prettier formatting
|
||||||
|
|
||||||
/dist
|
/dist
|
||||||
|
/dist-result
|
||||||
/coverage
|
/coverage
|
||||||
__generated__
|
__generated__
|
||||||
__generated___
|
__generated___
|
||||||
@@ -8,3 +9,15 @@ __generated___
|
|||||||
apps/static/src/assets/devnet-tranches.json
|
apps/static/src/assets/devnet-tranches.json
|
||||||
apps/static/src/assets/mainnet-tranches.json
|
apps/static/src/assets/mainnet-tranches.json
|
||||||
apps/static/src/assets/testnet-tranches.json
|
apps/static/src/assets/testnet-tranches.json
|
||||||
|
|
||||||
|
/apps/**/cypress/reports/
|
||||||
|
/apps/**/cypress/downloads/
|
||||||
|
|
||||||
|
/.nx/cache
|
||||||
|
|
||||||
|
# apps/trading/e2e
|
||||||
|
__pycache__/
|
||||||
|
apps/trading/e2e/logs/
|
||||||
|
apps/trading/e2e/.pytest_cache/
|
||||||
|
apps/trading/e2e/traces/
|
||||||
|
.pytest_cache/
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
* @vegaprotocol/frontend
|
* @vegaprotocol/frontend
|
||||||
|
apps/ @vegaprotocol/frontend-qa
|
||||||
|
libs/ @vegaprotocol/frontend-qa
|
||||||
*.graphql @vegaprotocol/core
|
*.graphql @vegaprotocol/core
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ The [`docker`](./docker) subfolder has some docker configurations for easily set
|
|||||||
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build). The multistage builds ensures consistent CPU architecture and build toolchains are used so that the result will be identical.
|
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build). The multistage builds ensures consistent CPU architecture and build toolchains are used so that the result will be identical.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=16.5.1 --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
|
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=20.9.1 --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Computing ipfs-hash of the build
|
### Computing ipfs-hash of the build
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
"rules": {}
|
"rules": {
|
||||||
|
"cypress/unsafe-to-chain-command": 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nx/linter:eslint",
|
"executor": "@nx/eslint:lint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
|||||||
cy.getByTestId('icon-cross').click();
|
cy.getByTestId('icon-cross').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('Proposal page displayed on mobile', function () {
|
it('Proposal page displayed on mobile', function () {
|
||||||
const proposalTitle = 'Add Lorem Ipsum market';
|
const proposalTitle = 'Add Lorem Ipsum market';
|
||||||
|
|
||||||
cy.common_switch_to_mobile_and_click_toggle();
|
cy.common_switch_to_mobile_and_click_toggle();
|
||||||
@@ -55,7 +55,7 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to view new asset proposal', function () {
|
it.skip('Able to view new asset proposal', function () {
|
||||||
const proposalTitle = 'Test new asset proposal';
|
const proposalTitle = 'Test new asset proposal';
|
||||||
const newAssetProposalBody = getNewAssetTxBody();
|
const newAssetProposalBody = getNewAssetTxBody();
|
||||||
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
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.rocks
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.rocks
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
|
||||||
NX_VEGA_ENV=STAGNET1
|
NX_VEGA_ENV=STAGNET1
|
||||||
@@ -9,7 +8,6 @@ NX_VEGA_WALLET_URL=http://localhost:1789
|
|||||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||||
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.rocks/rest
|
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.rocks/rest
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks
|
NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
NX_VEGA_ENV=DEVNET
|
NX_VEGA_ENV=DEVNET
|
||||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://dev.governance.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://dev.governance.vega.xyz
|
||||||
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/maste
|
|||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
NX_VEGA_ENV=MAINNET
|
NX_VEGA_ENV=MAINNET
|
||||||
NX_BLOCK_EXPLORER=https://be.vega.community/rest
|
NX_BLOCK_EXPLORER=https://be.vega.community/rest
|
||||||
NX_ETHERSCAN_URL=https://etherscan.io
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-inter
|
|||||||
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
||||||
NX_VEGA_ENV=MAINNET_MIRROR
|
NX_VEGA_ENV=MAINNET_MIRROR
|
||||||
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
|
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-inter
|
|||||||
NX_VEGA_ENV=TESTNET
|
NX_VEGA_ENV=TESTNET
|
||||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/maste
|
|||||||
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
||||||
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
|
|
||||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ NX_TENDERMINT_URL=http://localhost:26607/
|
|||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
|
||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_BLOCK_EXPLORER=
|
NX_BLOCK_EXPLORER=
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
[[redirects]]
|
|
||||||
from = "/*"
|
|
||||||
to = "/index.html"
|
|
||||||
status = 200
|
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nx/linter:eslint",
|
"executor": "@nx/eslint:lint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
||||||
@@ -63,14 +63,7 @@
|
|||||||
"executor": "@nx/jest:jest",
|
"executor": "@nx/jest:jest",
|
||||||
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
||||||
"options": {
|
"options": {
|
||||||
"jestConfig": "apps/explorer/jest.config.ts",
|
"jestConfig": "apps/explorer/jest.config.ts"
|
||||||
"passWithNoTests": true
|
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"ci": {
|
|
||||||
"ci": true,
|
|
||||||
"codeCoverage": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generate-types": {
|
"generate-types": {
|
||||||
@@ -81,15 +74,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build-netlify": {
|
|
||||||
"executor": "nx:run-commands",
|
|
||||||
"options": {
|
|
||||||
"commands": [
|
|
||||||
"cp apps/explorer/netlify.toml netlify.toml",
|
|
||||||
"nx build explorer"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"build-spec": {
|
"build-spec": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import '../i18n';
|
||||||
import {
|
import {
|
||||||
NetworkLoader,
|
NetworkLoader,
|
||||||
NodeFailure,
|
NodeFailure,
|
||||||
@@ -11,7 +12,8 @@ import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-web
|
|||||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { router } from './routes/router-config';
|
import { useRouterConfig } from './routes/router-config';
|
||||||
|
import { createBrowserRouter } from 'react-router-dom';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
@@ -28,20 +30,27 @@ function App() {
|
|||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<TendermintWebsocketProvider>
|
<TendermintWebsocketProvider>
|
||||||
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
<Suspense fallback={splashLoading}>
|
||||||
<NodeGuard
|
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
||||||
skeleton={<div>{t('Loading')}</div>}
|
<NodeGuard
|
||||||
failure={<NodeFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />}
|
skeleton={<div>{t('Loading')}</div>}
|
||||||
>
|
failure={
|
||||||
<Suspense fallback={splashLoading}>
|
<NodeFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />
|
||||||
<RouterProvider router={router} fallbackElement={splashLoading} />
|
}
|
||||||
</Suspense>
|
>
|
||||||
</NodeGuard>
|
<Suspense fallback={splashLoading}>
|
||||||
<NodeSwitcherDialog
|
<RouterProvider
|
||||||
open={nodeSwitcherOpen}
|
router={createBrowserRouter(useRouterConfig())}
|
||||||
setOpen={setNodeSwitcherOpen}
|
fallbackElement={splashLoading}
|
||||||
/>
|
/>
|
||||||
</NetworkLoader>
|
</Suspense>
|
||||||
|
</NodeGuard>
|
||||||
|
<NodeSwitcherDialog
|
||||||
|
open={nodeSwitcherOpen}
|
||||||
|
setOpen={setNodeSwitcherOpen}
|
||||||
|
/>
|
||||||
|
</NetworkLoader>
|
||||||
|
</Suspense>
|
||||||
</TendermintWebsocketProvider>
|
</TendermintWebsocketProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useAssetDataProvider } from '@vegaprotocol/assets';
|
import { useAssetDataProvider } from '@vegaprotocol/assets';
|
||||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
|
||||||
import { AssetLink } from '../links';
|
import { AssetLink } from '../links';
|
||||||
|
|
||||||
export type AssetBalanceProps = {
|
export type AssetBalanceProps = {
|
||||||
@@ -23,12 +23,12 @@ const AssetBalance = ({
|
|||||||
|
|
||||||
const label =
|
const label =
|
||||||
!loading && asset && asset.decimals
|
!loading && asset && asset.decimals
|
||||||
? addDecimalsFormatNumber(price, asset.decimals)
|
? addDecimalsFixedFormatNumber(price, asset.decimals)
|
||||||
: price;
|
: price;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inline-block">
|
<div className="inline-block">
|
||||||
<span>{label}</span>{' '}
|
<span className="font-mono">{label}</span>{' '}
|
||||||
{showAssetLink && asset?.id ? (
|
{showAssetLink && asset?.id ? (
|
||||||
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
|
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
import {
|
||||||
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
useAssetTypeMapping,
|
||||||
|
useAssetStatusMapping,
|
||||||
|
type AssetFieldsFragment,
|
||||||
|
} from '@vegaprotocol/assets';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import { type AgGridReact } from 'ag-grid-react';
|
||||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
import { type VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
||||||
import { useRef, useLayoutEffect } from 'react';
|
import { useRef, useLayoutEffect } from 'react';
|
||||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
import { type ColDef } from 'ag-grid-community';
|
||||||
|
import type { RowClickedEvent } from 'ag-grid-community';
|
||||||
|
|
||||||
type AssetsTableProps = {
|
type AssetsTableProps = {
|
||||||
data: AssetFieldsFragment[] | null;
|
data: AssetFieldsFragment[] | null;
|
||||||
};
|
};
|
||||||
export const AssetsTable = ({ data }: AssetsTableProps) => {
|
export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||||
|
const assetTypeMapping = useAssetTypeMapping();
|
||||||
|
const assetStatusMapping = useAssetStatusMapping();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const ref = useRef<AgGridReact>(null);
|
const ref = useRef<AgGridReact>(null);
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
ref.current?.columnApi.setColumnsVisible(
|
ref.current?.api.setColumnsVisible(
|
||||||
['id', 'type', 'status'],
|
['id', 'type', 'status'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
@@ -47,14 +53,14 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
field: 'source.__typename',
|
field: 'source.__typename',
|
||||||
hide: window.innerWidth < BREAKPOINT_MD,
|
hide: window.innerWidth < BREAKPOINT_MD,
|
||||||
valueFormatter: ({ value }: { value?: string }) =>
|
valueFormatter: ({ value }: { value?: string }) =>
|
||||||
value ? AssetTypeMapping[value].value : '',
|
value ? assetTypeMapping[value].value : '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: t('Status'),
|
headerName: t('Status'),
|
||||||
field: 'status',
|
field: 'status',
|
||||||
hide: window.innerWidth < BREAKPOINT_MD,
|
hide: window.innerWidth < BREAKPOINT_MD,
|
||||||
valueFormatter: ({ value }: { value?: string }) =>
|
valueFormatter: ({ value }: { value?: string }) =>
|
||||||
value ? AssetStatusMapping[value].value : '',
|
value ? assetStatusMapping[value].value : '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colId: 'actions',
|
colId: 'actions',
|
||||||
@@ -69,7 +75,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
||||||
value ? (
|
value ? (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
onClick={(e) => {
|
onClick={() => {
|
||||||
navigate(value);
|
navigate(value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -80,7 +86,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[navigate]
|
[navigate, assetStatusMapping, assetTypeMapping]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { Routes } from '../../routes/route-names';
|
|||||||
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
||||||
import type { Navigable } from '../../routes/router-config';
|
import type { Navigable } from '../../routes/router-config';
|
||||||
import { isNavigable } from '../../routes/router-config';
|
import { isNavigable } from '../../routes/router-config';
|
||||||
import { routerConfig } from '../../routes/router-config';
|
import { useRouterConfig } from '../../routes/router-config';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import { Search } from '../search';
|
import { Search } from '../search';
|
||||||
@@ -26,6 +26,7 @@ const routeToNavigationItem = (r: Navigable) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
|
const routerConfig = useRouterConfig();
|
||||||
const isHome = Boolean(useMatch(Routes.HOME));
|
const isHome = Boolean(useMatch(Routes.HOME));
|
||||||
const pages = routerConfig[0].children || [];
|
const pages = routerConfig[0].children || [];
|
||||||
const mainItems = compact(
|
const mainItems = compact(
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { DATA_SOURCES } from '../../../config';
|
|
||||||
import Hash from '../hash';
|
|
||||||
|
|
||||||
export enum EthExplorerLinkTypes {
|
|
||||||
block = 'block',
|
|
||||||
address = 'address',
|
|
||||||
tx = 'tx',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EthExplorerLinkProps = Partial<typeof HTMLAnchorElement> & {
|
|
||||||
id: string;
|
|
||||||
type: EthExplorerLinkTypes;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const EthExplorerLink = ({
|
|
||||||
id,
|
|
||||||
type,
|
|
||||||
...props
|
|
||||||
}: EthExplorerLinkProps) => {
|
|
||||||
const link = `${DATA_SOURCES.ethExplorerUrl}/${type}/${id}`;
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
className="underline external font-mono"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
{...props}
|
|
||||||
href={link}
|
|
||||||
>
|
|
||||||
<Hash text={id} />
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import type { ChainIdMapping } from './external-chain';
|
||||||
|
import { SUPPORTED_CHAIN_IDS, SUPPORTED_CHAIN_LABELS } from './external-chain';
|
||||||
|
|
||||||
|
export const SUPPORTED_CHAIN_ICON_URLS: ChainIdMapping = {
|
||||||
|
'1': '/assets/chain-eth-logo.svg',
|
||||||
|
'100': '/assets/chain-gno-logo.svg',
|
||||||
|
'42161': '/assets/chain-arb-logo.svg',
|
||||||
|
'11155111': '/assets/chain-eth-logo.svg',
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExternalChainIconProps = {
|
||||||
|
chainId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ExternalChainIcon = ({
|
||||||
|
// If chainID is not provided, default to a non-existent chain
|
||||||
|
chainId = '-1',
|
||||||
|
}: ExternalChainIconProps) => {
|
||||||
|
if (SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
||||||
|
const url = SUPPORTED_CHAIN_ICON_URLS[chainId];
|
||||||
|
const alt = SUPPORTED_CHAIN_LABELS[chainId];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
src={url}
|
||||||
|
className="inline-block w-4 h-4 mr-1 dark:invert"
|
||||||
|
alt={alt}
|
||||||
|
title={alt}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
export type ChainIdMapping = {
|
||||||
|
[K in typeof SUPPORTED_CHAIN_IDS[number]]: string;
|
||||||
|
};
|
||||||
|
export const SUPPORTED_CHAIN_IDS: string[] = ['1', '100', '42161', '11155111'];
|
||||||
|
|
||||||
|
export const SUPPORTED_CHAIN_LABELS: ChainIdMapping = {
|
||||||
|
'1': 'Ethereum',
|
||||||
|
'100': 'Gnosis',
|
||||||
|
'42161': 'Arbitrum',
|
||||||
|
'11155111': 'Sepolia',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getExternalExplorerLink(chainId: string, type: string) {
|
||||||
|
if (SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
||||||
|
switch (chainId) {
|
||||||
|
case '1':
|
||||||
|
return 'https://etherscan.io';
|
||||||
|
case '100':
|
||||||
|
return 'https://gnosisscan.io';
|
||||||
|
case '42161':
|
||||||
|
return 'https://arbiscan.io';
|
||||||
|
case '11155111':
|
||||||
|
return 'https://sepolia.etherscan.io';
|
||||||
|
default:
|
||||||
|
return '#';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return '#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getExternalChainLabel(chainId?: string) {
|
||||||
|
if (chainId && SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
||||||
|
return SUPPORTED_CHAIN_LABELS[chainId];
|
||||||
|
} else {
|
||||||
|
return 'Custom Chain';
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
import Hash from '../hash';
|
||||||
|
import { getExternalExplorerLink } from './external-chain';
|
||||||
|
import { ExternalChainIcon } from './external-chain-icon';
|
||||||
|
|
||||||
|
export enum EthExplorerLinkTypes {
|
||||||
|
block = 'block',
|
||||||
|
address = 'address',
|
||||||
|
tx = 'tx',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ExternalExplorerLinkProps = Partial<typeof HTMLAnchorElement> & {
|
||||||
|
id: string;
|
||||||
|
type: EthExplorerLinkTypes;
|
||||||
|
// Defaults to Ethereum Mainnet, as chain support was added late
|
||||||
|
chain?: string;
|
||||||
|
code?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ExternalExplorerLink = ({
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
chain = '1',
|
||||||
|
code = false,
|
||||||
|
...props
|
||||||
|
}: ExternalExplorerLinkProps) => {
|
||||||
|
const link = `${getExternalExplorerLink(chain, type)}/${type}/${id}${
|
||||||
|
code ? '#code' : ''
|
||||||
|
}`;
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
className="underline external font-mono"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
{...props}
|
||||||
|
href={link}
|
||||||
|
>
|
||||||
|
<ExternalChainIcon chainId={chain} />
|
||||||
|
<Hash text={id} />
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export type HashProps = {
|
export type HashProps = React.HTMLProps<HTMLSpanElement> & {
|
||||||
text: string;
|
text: string;
|
||||||
truncate?: boolean;
|
truncate?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ export { default as BlockLink } from './block-link/block-link';
|
|||||||
export { default as PartyLink } from './party-link/party-link';
|
export { default as PartyLink } from './party-link/party-link';
|
||||||
export { default as NodeLink } from './node-link/node-link';
|
export { default as NodeLink } from './node-link/node-link';
|
||||||
export { default as MarketLink } from './market-link/market-link';
|
export { default as MarketLink } from './market-link/market-link';
|
||||||
|
export { default as NetworkParameterLink } from './network-parameter-link/network-parameter-link';
|
||||||
export * from './asset-link/asset-link';
|
export * from './asset-link/asset-link';
|
||||||
|
|||||||
@@ -91,6 +91,6 @@ describe('Market link component', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const res = render(renderComponent('123', [mock]));
|
const res = render(renderComponent('123', [mock]));
|
||||||
expect(await res.findByText('123')).toBeInTheDocument();
|
expect(await res.findByTitle('123')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Routes } from '../../../routes/route-names';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import type { ComponentProps } from 'react';
|
||||||
|
import Hash from '../hash';
|
||||||
|
|
||||||
|
export type NetworkParameterLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||||
|
parameter: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Links a given network parameter to the relevant page and anchor on the page
|
||||||
|
*/
|
||||||
|
const NetworkParameterLink = ({
|
||||||
|
parameter,
|
||||||
|
...props
|
||||||
|
}: NetworkParameterLinkProps) => {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
className="underline"
|
||||||
|
{...props}
|
||||||
|
to={`/${Routes.NETWORK_PARAMETERS}#${parameter}`}
|
||||||
|
>
|
||||||
|
<Hash text={parameter} />
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NetworkParameterLink;
|
||||||
@@ -60,7 +60,7 @@ const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="whitespace-nowrap">
|
<span>
|
||||||
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
||||||
<Link
|
<Link
|
||||||
className="underline font-mono"
|
className="underline font-mono"
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
query ExplorerProposal($id: ID!) {
|
query ExplorerProposal($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
id
|
... on Proposal {
|
||||||
rationale {
|
id
|
||||||
title
|
rationale {
|
||||||
description
|
title
|
||||||
|
description
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -8,16 +8,18 @@ export type ExplorerProposalQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerProposalQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null };
|
export type ExplorerProposalQuery = { __typename?: 'Query', proposal?: { __typename?: 'BatchProposal' } | { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null };
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerProposalDocument = gql`
|
export const ExplorerProposalDocument = gql`
|
||||||
query ExplorerProposal($id: ID!) {
|
query ExplorerProposal($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
id
|
... on Proposal {
|
||||||
rationale {
|
id
|
||||||
title
|
rationale {
|
||||||
description
|
title
|
||||||
|
description
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ import { MockedProvider } from '@apollo/client/testing';
|
|||||||
import type { MockedResponse } from '@apollo/client/testing';
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import ProposalLink from './proposal-link';
|
import ProposalLink from './proposal-link';
|
||||||
import { ExplorerProposalDocument } from './__generated__/Proposal';
|
import {
|
||||||
|
ExplorerProposalDocument,
|
||||||
|
type ExplorerProposalQuery,
|
||||||
|
type ExplorerProposalQueryVariables,
|
||||||
|
} from './__generated__/Proposal';
|
||||||
import { GraphQLError } from 'graphql';
|
import { GraphQLError } from 'graphql';
|
||||||
|
|
||||||
function renderComponent(id: string, mocks: MockedResponse[]) {
|
function renderComponent(id: string, mocks: MockedResponse[]) {
|
||||||
@@ -23,7 +27,10 @@ describe('Proposal link component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Renders the ID on error', async () => {
|
it('Renders the ID on error', async () => {
|
||||||
const mock = {
|
const mock: MockedResponse<
|
||||||
|
ExplorerProposalQuery,
|
||||||
|
ExplorerProposalQueryVariables
|
||||||
|
> = {
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerProposalDocument,
|
query: ExplorerProposalDocument,
|
||||||
variables: {
|
variables: {
|
||||||
@@ -40,17 +47,22 @@ describe('Proposal link component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Renders the proposal title when the query returns a result', async () => {
|
it('Renders the proposal title when the query returns a result', async () => {
|
||||||
const mock = {
|
const proposalId = '123';
|
||||||
|
const mock: MockedResponse<
|
||||||
|
ExplorerProposalQuery,
|
||||||
|
ExplorerProposalQueryVariables
|
||||||
|
> = {
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerProposalDocument,
|
query: ExplorerProposalDocument,
|
||||||
variables: {
|
variables: {
|
||||||
id: '123',
|
id: proposalId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
data: {
|
data: {
|
||||||
proposal: {
|
proposal: {
|
||||||
id: '123',
|
__typename: 'Proposal',
|
||||||
|
id: proposalId,
|
||||||
rationale: {
|
rationale: {
|
||||||
title: 'test-title',
|
title: 'test-title',
|
||||||
description: 'test description',
|
description: 'test description',
|
||||||
@@ -60,13 +72,16 @@ describe('Proposal link component', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = render(renderComponent('123', [mock]));
|
const res = render(renderComponent(proposalId, [mock]));
|
||||||
expect(res.getByText('123')).toBeInTheDocument();
|
expect(res.getByText(proposalId)).toBeInTheDocument();
|
||||||
expect(await res.findByText('test-title')).toBeInTheDocument();
|
expect(await res.findByText('test-title')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Leaves the proposal id when the market is not found', async () => {
|
it('Leaves the proposal id when the market is not found', async () => {
|
||||||
const mock = {
|
const mock: MockedResponse<
|
||||||
|
ExplorerProposalQuery,
|
||||||
|
ExplorerProposalQueryVariables
|
||||||
|
> = {
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerProposalDocument,
|
query: ExplorerProposalDocument,
|
||||||
variables: {
|
variables: {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { useExplorerProposalQuery } from './__generated__/Proposal';
|
import {
|
||||||
|
useExplorerProposalQuery,
|
||||||
|
type ExplorerProposalQuery,
|
||||||
|
} from './__generated__/Proposal';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { ENV } from '../../../config/env';
|
import { ENV } from '../../../config/env';
|
||||||
import Hash from '../hash';
|
import Hash from '../hash';
|
||||||
|
|
||||||
export type ProposalLinkProps = {
|
export type ProposalLinkProps = {
|
||||||
id: string;
|
id: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
@@ -16,8 +20,13 @@ const ProposalLink = ({ id, text }: ProposalLinkProps) => {
|
|||||||
variables: { id },
|
variables: { id },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const proposal = data?.proposal as Extract<
|
||||||
|
ExplorerProposalQuery['proposal'],
|
||||||
|
{ __typename?: 'Proposal' }
|
||||||
|
>;
|
||||||
|
|
||||||
const base = ENV.dataSources.governanceUrl;
|
const base = ENV.dataSources.governanceUrl;
|
||||||
const label = data?.proposal?.rationale.title || id;
|
const label = proposal?.rationale?.title || id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ExternalLink href={`${base}/proposals/${id}`}>
|
<ExternalLink href={`${base}/proposals/${id}`}>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
|
LiquidationStrategyInfoPanel,
|
||||||
LiquidityPriceRangeInfoPanel,
|
LiquidityPriceRangeInfoPanel,
|
||||||
LiquiditySLAParametersInfoPanel,
|
LiquiditySLAParametersInfoPanel,
|
||||||
MarginScalingFactorsPanel,
|
MarginScalingFactorsPanel,
|
||||||
@@ -94,6 +95,8 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
<h2 className={headerClassName}>{t('Liquidation strategy')}</h2>
|
||||||
|
<LiquidationStrategyInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
||||||
<LiquidityMonitoringParametersInfoPanel market={market} />
|
<LiquidityMonitoringParametersInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
||||||
|
|||||||
@@ -2,18 +2,18 @@ import { useMemo } from 'react';
|
|||||||
import { getAsset, type MarketFieldsFragment } from '@vegaprotocol/markets';
|
import { getAsset, type MarketFieldsFragment } from '@vegaprotocol/markets';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import { type AgGridReact } from 'ag-grid-react';
|
||||||
import type { ColDef } from 'ag-grid-community';
|
import { type ColDef } from 'ag-grid-community';
|
||||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type {
|
import {
|
||||||
VegaICellRendererParams,
|
type VegaICellRendererParams,
|
||||||
VegaValueGetterParams,
|
type VegaValueGetterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { useRef, useLayoutEffect } from 'react';
|
import { useRef, useLayoutEffect } from 'react';
|
||||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||||
import { MarketStateMapping } from '@vegaprotocol/types';
|
import { MarketStateMapping } from '@vegaprotocol/types';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import type { RowClickedEvent } from 'ag-grid-community';
|
import { type RowClickedEvent } from 'ag-grid-community';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
type MarketsTableProps = {
|
type MarketsTableProps = {
|
||||||
@@ -29,7 +29,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
const gridRef = useRef<AgGridReact>(null);
|
const gridRef = useRef<AgGridReact>(null);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
gridRef.current?.columnApi.setColumnsVisible(
|
gridRef.current?.api.setColumnsVisible(
|
||||||
['id', 'state', 'asset'],
|
['id', 'state', 'asset'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { render, waitFor } from '@testing-library/react';
|
import { render, waitFor } from '@testing-library/react';
|
||||||
import {
|
import { NestedDataList, sortNestedDataByChildren } from './nested-data-list';
|
||||||
BORDER_COLOURS,
|
|
||||||
NestedDataList,
|
|
||||||
sortNestedDataByChildren,
|
|
||||||
} from './nested-data-list';
|
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
const mockData = {
|
const mockData = {
|
||||||
@@ -61,38 +57,6 @@ describe('NestedDataList', () => {
|
|||||||
expect(parent[0].querySelector('li')).toHaveClass('pl-4 border-l-4 pt-2');
|
expect(parent[0].querySelector('li')).toHaveClass('pl-4 border-l-4 pt-2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should repeat the border colours in the correct order', () => {
|
|
||||||
const colourMockData = {
|
|
||||||
t0: {
|
|
||||||
t1: {
|
|
||||||
t2: {
|
|
||||||
t3: {
|
|
||||||
t4: {
|
|
||||||
t5: {
|
|
||||||
t6: {
|
|
||||||
t7: {
|
|
||||||
t8: {
|
|
||||||
hello: 'world',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const tree = render(<NestedDataList data={colourMockData} />);
|
|
||||||
const { getByTestId } = tree;
|
|
||||||
|
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
const item = getByTestId(`T${i}`);
|
|
||||||
const expected = BORDER_COLOURS.light[i % 5];
|
|
||||||
expect(item.style.borderColor.toUpperCase()).toBe(expected);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should sort the data by values with children', () => {
|
it('should sort the data by values with children', () => {
|
||||||
const mockData = {
|
const mockData = {
|
||||||
nonce: '5980890939790185837',
|
nonce: '5980890939790185837',
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function renderAmendOrderDetails(
|
|||||||
mocks: MockedResponse[]
|
mocks: MockedResponse[]
|
||||||
) {
|
) {
|
||||||
return render(
|
return render(
|
||||||
<MockedProvider mocks={mocks} addTypename={false}>
|
<MockedProvider mocks={mocks}>
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<AmendOrderDetails version={version} id={id} amend={amend} />
|
<AmendOrderDetails version={version} id={id} amend={amend} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
@@ -44,18 +44,18 @@ function renderExistingAmend(
|
|||||||
orderByID: {
|
orderByID: {
|
||||||
__typename: 'Order',
|
__typename: 'Order',
|
||||||
id: '123',
|
id: '123',
|
||||||
type: 'GTT',
|
type: Schema.OrderType.TYPE_LIMIT,
|
||||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||||
version: version,
|
version: version ? version.toString() : '',
|
||||||
createdAt: '123',
|
createdAt: '123',
|
||||||
updatedAt: '456',
|
updatedAt: '456',
|
||||||
expiresAt: '789',
|
expiresAt: '789',
|
||||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||||
price: '200',
|
price: '200',
|
||||||
side: 'BUY',
|
side: Schema.Side.SIDE_BUY,
|
||||||
peggedOrder: null,
|
peggedOrder: null,
|
||||||
remaining: '99',
|
remaining: '99',
|
||||||
rejectionReason: 'rejection',
|
rejectionReason: Schema.OrderRejectionReason.ORDER_ERROR_NOT_FOUND,
|
||||||
reference: '123',
|
reference: '123',
|
||||||
size: '100',
|
size: '100',
|
||||||
party: {
|
party: {
|
||||||
@@ -65,18 +65,15 @@ function renderExistingAmend(
|
|||||||
market: {
|
market: {
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
id: '789',
|
id: '789',
|
||||||
state: 'STATUS_ACTIVE',
|
state: Schema.MarketState.STATE_ACTIVE,
|
||||||
positionDecimalPlaces: 2,
|
positionDecimalPlaces: 2,
|
||||||
decimalPlaces: '5',
|
decimalPlaces: 0,
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
product: {
|
product: {
|
||||||
__typename: 'Future',
|
__typename: 'Future',
|
||||||
quoteName: '123',
|
quoteName: '123',
|
||||||
settlementAsset: {
|
|
||||||
decimals: 8,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -97,18 +94,18 @@ function renderExistingAmend(
|
|||||||
orderByID: {
|
orderByID: {
|
||||||
__typename: 'Order',
|
__typename: 'Order',
|
||||||
id: '123',
|
id: '123',
|
||||||
type: 'GTT',
|
type: Schema.OrderType.TYPE_LIMIT,
|
||||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||||
version: 100,
|
version: '100',
|
||||||
createdAt: '123',
|
createdAt: '123',
|
||||||
updatedAt: '456',
|
updatedAt: '456',
|
||||||
expiresAt: '789',
|
expiresAt: '789',
|
||||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||||
peggedOrder: null,
|
peggedOrder: null,
|
||||||
price: '200',
|
price: '200',
|
||||||
side: 'BUY',
|
side: Schema.Side.SIDE_BUY,
|
||||||
remaining: '99',
|
remaining: '99',
|
||||||
rejectionReason: 'rejection',
|
rejectionReason: Schema.OrderRejectionReason.ORDER_ERROR_NOT_FOUND,
|
||||||
reference: '123',
|
reference: '123',
|
||||||
size: '200',
|
size: '200',
|
||||||
party: {
|
party: {
|
||||||
@@ -117,19 +114,16 @@ function renderExistingAmend(
|
|||||||
},
|
},
|
||||||
market: {
|
market: {
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
id: 'amend-to-order-latest-version',
|
id: '8888',
|
||||||
state: 'STATUS_ACTIVE',
|
state: Schema.MarketState.STATE_ACTIVE,
|
||||||
positionDecimalPlaces: 2,
|
positionDecimalPlaces: 2,
|
||||||
decimalPlaces: '5',
|
decimalPlaces: 0,
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
name: 'amend-to-order-latest-version-test',
|
name: 'amend-to-order-latest-version-test',
|
||||||
product: {
|
product: {
|
||||||
__typename: 'Future',
|
__typename: 'Future',
|
||||||
quoteName: '123',
|
quoteName: '123',
|
||||||
settlementAsset: {
|
|
||||||
decimals: 8,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -142,13 +136,13 @@ function renderExistingAmend(
|
|||||||
request: {
|
request: {
|
||||||
query: ExplorerMarketDocument,
|
query: ExplorerMarketDocument,
|
||||||
variables: {
|
variables: {
|
||||||
id: '789',
|
id: '8888',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
data: {
|
data: {
|
||||||
market: {
|
market: {
|
||||||
id: '789',
|
id: '8888',
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
positionDecimalPlaces: 2,
|
positionDecimalPlaces: 2,
|
||||||
state: 'irrelevant-test-data',
|
state: 'irrelevant-test-data',
|
||||||
@@ -225,12 +219,10 @@ describe('Amend order details', () => {
|
|||||||
|
|
||||||
it('Fetches latest version when version is not specified', async () => {
|
it('Fetches latest version when version is not specified', async () => {
|
||||||
const amend: Amend = {
|
const amend: Amend = {
|
||||||
price: '-7879',
|
price: '123',
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = renderExistingAmend('123', undefined, amend);
|
const res = renderExistingAmend('123', undefined, amend);
|
||||||
expect(
|
expect(await res.findByText('test-label')).toBeInTheDocument();
|
||||||
await res.findByText('amend-to-order-latest-version')
|
|
||||||
).toBeInTheDocument();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-12 lg:mb-0">
|
<div className="mb-12 lg:mb-0">
|
||||||
<div className="relative block rounded-lg px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block rounded-lg px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="text-3xl font-bold mb-4 display-5">
|
<h2 className="display-5 mb-4 text-3xl font-bold">
|
||||||
{t('Order not found')}
|
{t('Order not found')}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-500 mb-12">
|
<p className="mb-12 text-gray-500">
|
||||||
{t('No order created from this transaction')}
|
{t('No order created from this transaction')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,24 +68,24 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-12 lg:mb-0">
|
<div className="mb-12 lg:mb-0">
|
||||||
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="text-3xl font-bold mb-4 display-5">
|
<h2 className="display-5 mb-4 text-3xl font-bold">
|
||||||
{t('Edits to ')}
|
{t('Edits to ')}
|
||||||
{sideText[o.side]}
|
{sideText[o.side]}
|
||||||
{t(' order')}
|
{t(' order')}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-500 mb-4">
|
<div className="mb-4 text-gray-500">
|
||||||
In <MarketLink id={o.market.id} />, updated at{' '}
|
In <MarketLink id={o.market.id} />, updated at{' '}
|
||||||
<Time date={o.updatedAt} />.
|
<Time date={o.updatedAt} />.
|
||||||
</p>
|
</div>
|
||||||
|
|
||||||
<div className="grid md:grid-cols-4 gap-x-6">
|
<div className="grid gap-x-6 md:grid-cols-4">
|
||||||
{amend.sizeDelta && amend.sizeDelta !== '0' ? (
|
{amend.sizeDelta && amend.sizeDelta !== '0' ? (
|
||||||
<div className="mb-12 md:mb-0">
|
<div className="mb-12 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-dark mb-4 text-2xl font-bold">
|
||||||
{t('New size')}
|
{t('New size')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5
|
<h5
|
||||||
className={`text-lg font-medium text-gray-500 mb-0 capitalize ${getSideDeltaColour(
|
className={`mb-0 text-lg font-medium capitalize text-gray-500 ${getSideDeltaColour(
|
||||||
amend.sizeDelta
|
amend.sizeDelta
|
||||||
)}`}
|
)}`}
|
||||||
>
|
>
|
||||||
@@ -96,10 +96,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
|
|
||||||
{amend.price && amend.price !== '0' ? (
|
{amend.price && amend.price !== '0' ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-dark mb-4 text-2xl font-bold">
|
||||||
{t('New price')}
|
{t('New price')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="mb-0 text-lg font-medium text-gray-500">
|
||||||
<PriceInMarket price={amend.price} marketId={o.market.id} />
|
<PriceInMarket price={amend.price} marketId={o.market.id} />
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
@@ -108,10 +108,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
{amend.peggedReference &&
|
{amend.peggedReference &&
|
||||||
amend.peggedReference !== 'PEGGED_REFERENCE_UNSPECIFIED' ? (
|
amend.peggedReference !== 'PEGGED_REFERENCE_UNSPECIFIED' ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-dark mb-4 text-2xl font-bold">
|
||||||
{t('New reference')}
|
{t('New reference')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="mb-0 text-lg font-medium text-gray-500">
|
||||||
{peggedReference[amend.peggedReference]}
|
{peggedReference[amend.peggedReference]}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
@@ -119,10 +119,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
|
|
||||||
{amend.peggedOffset ? (
|
{amend.peggedOffset ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-dark mb-4 text-2xl font-bold">
|
||||||
{t('New offset')}
|
{t('New offset')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="mb-0 text-lg font-medium text-gray-500">
|
||||||
{amend.peggedOffset}
|
{amend.peggedOffset}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Time } from '../time';
|
|||||||
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
||||||
import SizeInMarket from '../size-in-market/size-in-market';
|
import SizeInMarket from '../size-in-market/size-in-market';
|
||||||
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
||||||
|
import { OrderTypeMapping } from '@vegaprotocol/types';
|
||||||
|
|
||||||
export interface DeterministicOrderDetailsProps {
|
export interface DeterministicOrderDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -59,7 +60,7 @@ const DeterministicOrderDetails = ({
|
|||||||
const o = data.orderByID;
|
const o = data.orderByID;
|
||||||
return (
|
return (
|
||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-12 lg:mb-0">
|
<div className="mb-0">
|
||||||
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="text-3xl font-bold mb-4 display-5">
|
<h2 className="text-3xl font-bold mb-4 display-5">
|
||||||
<abbr title={tifFull[o.timeInForce]} className="bb-dotted mr-2">
|
<abbr title={tifFull[o.timeInForce]} className="bb-dotted mr-2">
|
||||||
@@ -69,7 +70,7 @@ const DeterministicOrderDetails = ({
|
|||||||
<span className="mx-5 text-base">@</span>
|
<span className="mx-5 text-base">@</span>
|
||||||
<PriceInMarket price={o.price} marketId={o.market.id} />
|
<PriceInMarket price={o.price} marketId={o.market.id} />
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-200">
|
<p className="text-gray-400 dark:text-gray-600">
|
||||||
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
||||||
</p>
|
</p>
|
||||||
{o.peggedOrder ? (
|
{o.peggedOrder ? (
|
||||||
@@ -83,15 +84,14 @@ const DeterministicOrderDetails = ({
|
|||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{o.reference ? (
|
{o.reference ? (
|
||||||
<p className="text-gray-500 mt-4">
|
<p className="text-gray-500 mt-4">
|
||||||
<span>{t('Reference')}</span>: {o.reference}
|
<span>{t('Reference')}</span>: {o.reference}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="grid md:grid-cols-4 gap-x-6 mt-4">
|
<div className="grid grid-cols-2 md:grid-cols-5 gap-x-6 mt-4">
|
||||||
<div className="mb-12 md:mb-0">
|
<div className="mb-6 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
||||||
{t('Status')}
|
{t('Status')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
||||||
@@ -99,21 +99,33 @@ const DeterministicOrderDetails = ({
|
|||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-12 md:mb-0">
|
<div className="mb-6 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">{t('Size')}</h2>
|
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
||||||
|
{t('Size')}
|
||||||
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
<SizeInMarket size={o.size} marketId={o.market.id} />
|
<SizeInMarket size={o.size} marketId={o.market.id} />
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="">
|
<div className="mb-6 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
||||||
{t('Version')}
|
{t('Version')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
{o.version}
|
{o.version}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
{o.type ? (
|
||||||
|
<div className="mb-6 md:mb-0">
|
||||||
|
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
||||||
|
{t('Type')}
|
||||||
|
</h2>
|
||||||
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
|
{OrderTypeMapping[o.type]}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
import { type ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
||||||
import { VoteProgress } from '@vegaprotocol/proposals';
|
import { VoteProgress } from '@vegaprotocol/proposals';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import { type AgGridReact } from 'ag-grid-react';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type {
|
import {
|
||||||
VegaICellRendererParams,
|
type VegaICellRendererParams,
|
||||||
VegaValueFormatterParams,
|
type VegaValueFormatterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
import { type ColDef } from 'ag-grid-community';
|
||||||
|
import type { RowClickedEvent } from 'ag-grid-community';
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import {
|
import {
|
||||||
@@ -43,11 +44,11 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
const gridRef = useRef<AgGridReact>(null);
|
const gridRef = useRef<AgGridReact>(null);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
gridRef.current?.columnApi.setColumnsVisible(
|
gridRef.current?.api.setColumnsVisible(
|
||||||
['voting', 'cDate', 'eDate', 'type'],
|
['voting', 'cDate', 'eDate', 'type'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
gridRef.current?.columnApi.setColumnWidth(
|
gridRef.current?.api.setColumnWidth(
|
||||||
'actions',
|
'actions',
|
||||||
window.innerWidth > BREAKPOINT_MD ? 221 : 80
|
window.innerWidth > BREAKPOINT_MD ? 221 : 80
|
||||||
);
|
);
|
||||||
@@ -105,7 +106,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
? new BigNumber(0)
|
? new BigNumber(0)
|
||||||
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-full pt-2 uppercase">
|
<div className="flex h-full items-center justify-center pt-2 uppercase">
|
||||||
<VoteProgress
|
<VoteProgress
|
||||||
threshold={requiredMajorityPercentage}
|
threshold={requiredMajorityPercentage}
|
||||||
progress={yesPercentage}
|
progress={yesPercentage}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
||||||
|
import {
|
||||||
|
CopyWithTooltip,
|
||||||
|
VegaIcon,
|
||||||
|
VegaIconNames,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
interface SignatureProps {
|
||||||
|
signature: BlockExplorerTransactionResult['signature'];
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueClass =
|
||||||
|
'font-mono px-2.5 py-0.5 text-xs max-w-[200px] cursor-pointer';
|
||||||
|
const valueClassClosed = 'text-ellipsis overflow-hidden';
|
||||||
|
const valueClassOpen = 'break-words text-left';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Viewer component for a vega signature. Featuers copy and pasting, truncation
|
||||||
|
*
|
||||||
|
* @param signature
|
||||||
|
*/
|
||||||
|
export const Signature = ({ signature }: SignatureProps) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
if (!signature || !signature.value || !signature.version || !signature.algo) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="inline-flex border rounded signature-component relative pr-[20px]">
|
||||||
|
<div
|
||||||
|
className="bg-gray-100 px-2.5 py-0.5 text-xs text-gray-500 select-none cursor-default"
|
||||||
|
title={`${signature.algo}`}
|
||||||
|
>
|
||||||
|
<span>v{signature.version}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
isOpen
|
||||||
|
? `${valueClass} ${valueClassOpen}`
|
||||||
|
: `${valueClass} ${valueClassClosed}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CopyWithTooltip text={signature.value}>
|
||||||
|
<span title={signature.value}>{signature.value}</span>
|
||||||
|
</CopyWithTooltip>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
|
className="absolute top-[-3px] right-0 pr-2"
|
||||||
|
title={t('Show full signature')}
|
||||||
|
>
|
||||||
|
<VegaIcon name={isOpen ? VegaIconNames.EYE_OFF : VegaIconNames.EYE} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -15,6 +15,7 @@ import isUndefined from 'lodash/isUndefined';
|
|||||||
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
||||||
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
|
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
|
||||||
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
|
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
|
||||||
|
import { TxDetailsContractCall } from './tx-contract-call';
|
||||||
|
|
||||||
interface ChainEventProps {
|
interface ChainEventProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -38,7 +39,7 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { builtin, erc20, erc20Multisig, stakingEvent } =
|
const { builtin, erc20, erc20Multisig, stakingEvent, contractCall } =
|
||||||
txData.command.chainEvent;
|
txData.command.chainEvent;
|
||||||
|
|
||||||
// Builtin Asset events
|
// Builtin Asset events
|
||||||
@@ -140,6 +141,10 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contractCall) {
|
||||||
|
return <TxDetailsContractCall contractCall={contractCall} />;
|
||||||
|
}
|
||||||
|
|
||||||
// If we hit this return, tx-shared-details should give a basic overview
|
// If we hit this return, tx-shared-details should give a basic overview
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { decodeEthCallResult } from './tx-contract-call';
|
||||||
|
import { base64 } from 'ethers/lib/utils';
|
||||||
|
import { defaultAbiCoder } from '@ethersproject/abi';
|
||||||
|
import { BigNumber } from '@ethersproject/bignumber';
|
||||||
|
|
||||||
|
describe('decodeEthCallResult', () => {
|
||||||
|
it('should decode contractData correctly (mocked)', () => {
|
||||||
|
const mockContractData = base64.encode(
|
||||||
|
defaultAbiCoder.encode(['int256'], [BigNumber.from(123)])
|
||||||
|
);
|
||||||
|
const result = decodeEthCallResult(mockContractData);
|
||||||
|
expect(result).toBe('123');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decode contractData correctly (known data)', () => {
|
||||||
|
const mockContractData = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADH8cueyY=';
|
||||||
|
const result = decodeEthCallResult(mockContractData);
|
||||||
|
expect(result).toBe('3435020581670');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return "-" when an error occurs', () => {
|
||||||
|
const mockContractData = 'invalid_data';
|
||||||
|
const result = decodeEthCallResult(mockContractData);
|
||||||
|
expect(result).toBe('-');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import { TableCell, TableRow } from '../../../table';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import {
|
||||||
|
ExternalExplorerLink,
|
||||||
|
EthExplorerLinkTypes,
|
||||||
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
import { getExternalChainLabel } from '../../../links/external-explorer-link/external-chain';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
||||||
|
import { BigNumber } from 'ethers';
|
||||||
|
import OracleLink from '../../../links/oracle-link/oracle-link';
|
||||||
|
import { useExplorerOracleSpecByIdQuery } from '../../../../routes/oracles/__generated__/Oracles';
|
||||||
|
import { OracleEthSource } from '../../../../routes/oracles/components/oracle-eth-source';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the b64/ABIcoded result from an eth cal
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function decodeEthCallResult(contractData: string): string {
|
||||||
|
try {
|
||||||
|
const rawResult = defaultAbiCoder.decode(
|
||||||
|
['int256'],
|
||||||
|
base64.decode(contractData)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Finally, convert the resulting BigNumber in to a string
|
||||||
|
const res = BigNumber.from(rawResult[0]).toString();
|
||||||
|
return res;
|
||||||
|
} catch (e) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TxDetailsContractCallProps {
|
||||||
|
contractCall: components['schemas']['vegaEthContractCallEvent'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TxDetailsContractCall = ({
|
||||||
|
contractCall,
|
||||||
|
}: TxDetailsContractCallProps) => {
|
||||||
|
const { data } = useExplorerOracleSpecByIdQuery({
|
||||||
|
variables: {
|
||||||
|
id: contractCall.specId || '1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!contractCall) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const chainLabel = getExternalChainLabel(contractCall.sourceChainId);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{contractCall.specId && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Oracle')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<OracleLink
|
||||||
|
id={contractCall.specId}
|
||||||
|
hasSeenOracleReports={true}
|
||||||
|
status={data?.oracleSpec?.dataSourceSpec.spec.status || '-'}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
{contractCall.blockHeight && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>
|
||||||
|
{chainLabel} {t('block')}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<ExternalExplorerLink
|
||||||
|
chain={contractCall.sourceChainId}
|
||||||
|
id={contractCall.blockHeight}
|
||||||
|
type={EthExplorerLinkTypes.block}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
{data?.oracleSpec?.dataSourceSpec && (
|
||||||
|
<OracleEthSource
|
||||||
|
chain={contractCall.sourceChainId}
|
||||||
|
sourceType={data.oracleSpec.dataSourceSpec.spec.data.sourceType}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{contractCall.error && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Call error')}</TableCell>
|
||||||
|
<TableCell>{contractCall.error}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{contractCall.result && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Result')}</TableCell>
|
||||||
|
<TableCell>{decodeEthCallResult(contractCall.result)}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
+3
-3
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { AssetLink } from '../../../links';
|
import { AssetLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventErc20AssetLimitsUpdatedProps {
|
interface TxDetailsChainEventErc20AssetLimitsUpdatedProps {
|
||||||
assetLimitsUpdated: components['schemas']['vegaERC20AssetLimitsUpdated'];
|
assetLimitsUpdated: components['schemas']['vegaERC20AssetLimitsUpdated'];
|
||||||
@@ -42,7 +42,7 @@ export const TxDetailsChainEventErc20AssetLimitsUpdated = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('ERC20 asset')}</TableCell>
|
<TableCell>{t('ERC20 asset')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={assetLimitsUpdated.sourceEthereumAddress}
|
id={assetLimitsUpdated.sourceEthereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { AssetLink } from '../../../links';
|
import { AssetLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventErc20AssetListProps {
|
interface TxDetailsChainEventErc20AssetListProps {
|
||||||
assetList: components['schemas']['vegaERC20AssetList'];
|
assetList: components['schemas']['vegaERC20AssetList'];
|
||||||
@@ -32,7 +32,7 @@ export const TxDetailsChainEventErc20AssetList = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={assetList.assetSource}
|
id={assetList.assetSource}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { AssetLink, PartyLink } from '../../../links';
|
import { AssetLink, PartyLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventProps {
|
interface TxDetailsChainEventProps {
|
||||||
deposit: components['schemas']['vegaERC20Deposit'];
|
deposit: components['schemas']['vegaERC20Deposit'];
|
||||||
@@ -36,7 +36,7 @@ export const TxDetailsChainEventDeposit = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={deposit.sourceEthereumAddress}
|
id={deposit.sourceEthereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { AssetLink } from '../../../links';
|
import { AssetLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventWithdrawalProps {
|
interface TxDetailsChainEventWithdrawalProps {
|
||||||
withdrawal: components['schemas']['vegaERC20Withdrawal'];
|
withdrawal: components['schemas']['vegaERC20Withdrawal'];
|
||||||
@@ -35,7 +35,7 @@ export const TxDetailsChainEventWithdrawal = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Recipient')}</TableCell>
|
<TableCell>{t('Recipient')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={withdrawal.targetEthereumAddress}
|
id={withdrawal.targetEthereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { PartyLink } from '../../../links';
|
import { PartyLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventStakeDepositProps {
|
interface TxDetailsChainEventStakeDepositProps {
|
||||||
deposit: components['schemas']['vegaStakeDeposited'];
|
deposit: components['schemas']['vegaStakeDeposited'];
|
||||||
@@ -39,7 +39,7 @@ export const TxDetailsChainEventStakeDeposit = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={deposit.ethereumAddress}
|
id={deposit.ethereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { TableRow, TableCell } from '../../../table';
|
|||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import { PartyLink } from '../../../links';
|
import { PartyLink } from '../../../links';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventStakeRemoveProps {
|
interface TxDetailsChainEventStakeRemoveProps {
|
||||||
remove: components['schemas']['vegaStakeRemoved'];
|
remove: components['schemas']['vegaStakeRemoved'];
|
||||||
@@ -39,7 +39,7 @@ export const TxDetailsChainEventStakeRemove = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={remove.ethereumAddress}
|
id={remove.ethereumAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { t } from '@vegaprotocol/i18n';
|
|||||||
import { TableRow, TableCell } from '../../../table';
|
import { TableRow, TableCell } from '../../../table';
|
||||||
import type { components } from '../../../../../types/explorer';
|
import type { components } from '../../../../../types/explorer';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsChainEventStakeTotalSupplyProps {
|
interface TxDetailsChainEventStakeTotalSupplyProps {
|
||||||
update: components['schemas']['vegaStakeTotalSupply'];
|
update: components['schemas']['vegaStakeTotalSupply'];
|
||||||
@@ -38,7 +38,7 @@ export const TxDetailsChainEventStakeTotalSupply = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Source')}</TableCell>
|
<TableCell>{t('Source')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={update.tokenAddress}
|
id={update.tokenAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
query ExplorerProposalStatus($id: ID!) {
|
query ExplorerProposalStatus($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
id
|
... on Proposal {
|
||||||
state
|
id
|
||||||
rejectionReason
|
state
|
||||||
|
rejectionReason
|
||||||
|
}
|
||||||
|
... on BatchProposal {
|
||||||
|
id
|
||||||
|
state
|
||||||
|
rejectionReason
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-4
@@ -8,15 +8,22 @@ export type ExplorerProposalStatusQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerProposalStatusQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, rejectionReason?: Types.ProposalRejectionReason | null } | null };
|
export type ExplorerProposalStatusQuery = { __typename?: 'Query', proposal?: { __typename?: 'BatchProposal', id?: string | null, state: Types.ProposalState, rejectionReason?: Types.ProposalRejectionReason | null } | { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, rejectionReason?: Types.ProposalRejectionReason | null } | null };
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerProposalStatusDocument = gql`
|
export const ExplorerProposalStatusDocument = gql`
|
||||||
query ExplorerProposalStatus($id: ID!) {
|
query ExplorerProposalStatus($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
id
|
... on Proposal {
|
||||||
state
|
id
|
||||||
rejectionReason
|
state
|
||||||
|
rejectionReason
|
||||||
|
}
|
||||||
|
... on BatchProposal {
|
||||||
|
id
|
||||||
|
state
|
||||||
|
rejectionReason
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -0,0 +1,257 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { BatchItem } from './batch-item';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
type Item = components['schemas']['vegaBatchProposalTermsChange'];
|
||||||
|
|
||||||
|
describe('BatchItem', () => {
|
||||||
|
it('Renders "Unknown proposal type" by default', () => {
|
||||||
|
const item = {};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Unknown proposal type')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Unknown proposal type" for unknown items', () => {
|
||||||
|
const item = {
|
||||||
|
newLochNessMonster: {
|
||||||
|
location: 'Loch Ness',
|
||||||
|
},
|
||||||
|
} as unknown as Item;
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Unknown proposal type')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "New spot market"', () => {
|
||||||
|
const item = {
|
||||||
|
newSpotMarket: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('New spot market')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Cancel transfer"', () => {
|
||||||
|
const item = {
|
||||||
|
cancelTransfer: {
|
||||||
|
changes: {
|
||||||
|
transferId: 'transfer123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Cancel transfer')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('transf')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Cancel transfer" without an id', () => {
|
||||||
|
const item = {
|
||||||
|
cancelTransfer: {
|
||||||
|
changes: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Cancel transfer')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "New freeform"', () => {
|
||||||
|
const item = {
|
||||||
|
newFreeform: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('New freeform proposal')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "New market"', () => {
|
||||||
|
const item = {
|
||||||
|
newMarket: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('New market')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "New transfer"', () => {
|
||||||
|
const item = {
|
||||||
|
newTransfer: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('New transfer')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update asset" with assetId', () => {
|
||||||
|
const item = {
|
||||||
|
updateAsset: {
|
||||||
|
assetId: 'asset123',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update asset')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('asset123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update asset" even if assetId is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateAsset: {
|
||||||
|
assetId: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Update asset')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update market state" with marketId', () => {
|
||||||
|
const item = {
|
||||||
|
updateMarketState: {
|
||||||
|
changes: {
|
||||||
|
marketId: 'market123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update market state')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('market123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update market state" even if marketId is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateMarketState: {
|
||||||
|
changes: {
|
||||||
|
marketId: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update market state')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update network parameter" with parameter', () => {
|
||||||
|
const item = {
|
||||||
|
updateNetworkParameter: {
|
||||||
|
changes: {
|
||||||
|
key: 'parameter123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MockedProvider>
|
||||||
|
<MemoryRouter>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update network parameter')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('parameter123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update network parameter" even if parameter is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateNetworkParameter: {
|
||||||
|
changes: {
|
||||||
|
key: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Update network parameter')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update referral program"', () => {
|
||||||
|
const item = {
|
||||||
|
updateReferralProgram: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(screen.getByText('Update referral program')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update spot market" with marketId', () => {
|
||||||
|
const item = {
|
||||||
|
updateSpotMarket: {
|
||||||
|
marketId: 'market123',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update spot market')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('market123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update spot market" even if marketId is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateSpotMarket: {
|
||||||
|
marketId: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update spot market')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
it('Renders "Update market" with marketId', () => {
|
||||||
|
const item = {
|
||||||
|
updateMarket: {
|
||||||
|
marketId: 'market123',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update market')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('market123')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update market" even if marketId is not set', () => {
|
||||||
|
const item = {
|
||||||
|
updateMarket: {
|
||||||
|
marketId: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<MockedProvider>
|
||||||
|
<BatchItem item={item} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Update market')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders "Update volume discount program"', () => {
|
||||||
|
const item = {
|
||||||
|
updateVolumeDiscountProgram: {},
|
||||||
|
};
|
||||||
|
render(<BatchItem item={item} />);
|
||||||
|
expect(
|
||||||
|
screen.getByText('Update volume discount program')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { AssetLink, MarketLink, NetworkParameterLink } from '../../../links';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import Hash from '../../../links/hash';
|
||||||
|
|
||||||
|
type Item = components['schemas']['vegaBatchProposalTermsChange'];
|
||||||
|
|
||||||
|
export interface BatchItemProps {
|
||||||
|
item: Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces a one line summary for an item in a batch proposal. Could
|
||||||
|
* easily be adapted to summarise individual proposals, but there is no
|
||||||
|
* place for that yet.
|
||||||
|
*
|
||||||
|
* Details (like IDs) should be shown and linked if available, but handled
|
||||||
|
* if not available. This is adequate as the ProposalSummary component contains
|
||||||
|
* a JSON viewer for the full proposal.
|
||||||
|
*/
|
||||||
|
export const BatchItem = ({ item }: BatchItemProps) => {
|
||||||
|
if (item.cancelTransfer) {
|
||||||
|
const transferId = item?.cancelTransfer?.changes?.transferId || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Cancel transfer')}
|
||||||
|
{transferId && (
|
||||||
|
<Hash className="ml-1" truncate={true} text={transferId} />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.newFreeform) {
|
||||||
|
return <span>{t('New freeform proposal')}</span>;
|
||||||
|
} else if (item.newMarket) {
|
||||||
|
return <span>{t('New market')}</span>;
|
||||||
|
} else if (item.newSpotMarket) {
|
||||||
|
return <span>{t('New spot market')}</span>;
|
||||||
|
} else if (item.newTransfer) {
|
||||||
|
return <span>{t('New transfer')}</span>;
|
||||||
|
} else if (item.updateAsset) {
|
||||||
|
const assetId = item?.updateAsset?.assetId || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update asset')}
|
||||||
|
{assetId && <AssetLink className="ml-1" assetId={assetId} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateMarket) {
|
||||||
|
const marketId = item?.updateMarket?.marketId || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update market')}{' '}
|
||||||
|
{marketId && <MarketLink className="ml-1" id={marketId} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateMarketState) {
|
||||||
|
const marketId = item?.updateMarketState?.changes?.marketId || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update market state')}
|
||||||
|
{marketId && <MarketLink className="ml-1" id={marketId} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateNetworkParameter) {
|
||||||
|
const param = item?.updateNetworkParameter?.changes?.key || false;
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update network parameter')}
|
||||||
|
{param && <NetworkParameterLink className="ml-1" parameter={param} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateReferralProgram) {
|
||||||
|
return <span>{t('Update referral program')}</span>;
|
||||||
|
} else if (item.updateSpotMarket) {
|
||||||
|
const marketId = item?.updateSpotMarket?.marketId || '';
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{t('Update spot market')}
|
||||||
|
<MarketLink className="ml-1" id={marketId} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (item.updateVolumeDiscountProgram) {
|
||||||
|
return <span>{t('Update volume discount program')}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <span>{t('Unknown proposal type')}</span>;
|
||||||
|
};
|
||||||
@@ -14,16 +14,18 @@ export function format(date: string | undefined, def: string) {
|
|||||||
return new Date().toLocaleDateString() || def;
|
return new Date().toLocaleDateString() || def;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDate(
|
type Proposal = Extract<
|
||||||
data: ExplorerProposalStatusQuery | undefined,
|
ExplorerProposalStatusQuery['proposal'],
|
||||||
terms: Terms
|
{ __typename?: 'Proposal' }
|
||||||
): string {
|
>;
|
||||||
|
|
||||||
|
export function getDate(proposal: Proposal | undefined, terms: Terms): string {
|
||||||
const DEFAULT = t('Unknown');
|
const DEFAULT = t('Unknown');
|
||||||
if (!data?.proposal?.state) {
|
if (!proposal?.state) {
|
||||||
return DEFAULT;
|
return DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data.proposal.state) {
|
switch (proposal.state) {
|
||||||
case 'STATE_DECLINED':
|
case 'STATE_DECLINED':
|
||||||
return `${t('Rejected on')}: ${format(terms.closingTimestamp, DEFAULT)}`;
|
return `${t('Rejected on')}: ${format(terms.closingTimestamp, DEFAULT)}`;
|
||||||
case 'STATE_ENACTED':
|
case 'STATE_ENACTED':
|
||||||
@@ -62,9 +64,11 @@ export const ProposalDate = ({ terms, id }: ProposalDateProps) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const proposal = data?.proposal as Proposal;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Lozenge className="font-sans text-xs float-right">
|
<Lozenge className="font-sans text-xs float-right">
|
||||||
{getDate(data, terms)}
|
{getDate(proposal, terms)}
|
||||||
</Lozenge>
|
</Lozenge>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,17 +2,8 @@ import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
|||||||
import type { IconProps } from '@vegaprotocol/ui-toolkit';
|
import type { IconProps } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useExplorerProposalStatusQuery } from './__generated__/Proposal';
|
import { useExplorerProposalStatusQuery } from './__generated__/Proposal';
|
||||||
import type { ExplorerProposalStatusQuery } from './__generated__/Proposal';
|
import type { ExplorerProposalStatusQuery } from './__generated__/Proposal';
|
||||||
import type * as Apollo from '@apollo/client';
|
|
||||||
import type * as Types from '@vegaprotocol/types';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
type ProposalQueryResult = Apollo.QueryResult<
|
|
||||||
ExplorerProposalStatusQuery,
|
|
||||||
Types.Exact<{
|
|
||||||
id: string;
|
|
||||||
}>
|
|
||||||
>;
|
|
||||||
|
|
||||||
interface ProposalStatusIconProps {
|
interface ProposalStatusIconProps {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
@@ -29,29 +20,38 @@ type IconAndLabel = {
|
|||||||
* @param data a data result from useExplorerProposalStatusQuery
|
* @param data a data result from useExplorerProposalStatusQuery
|
||||||
* @returns Icon name
|
* @returns Icon name
|
||||||
*/
|
*/
|
||||||
export function getIconAndLabelForStatus(
|
export function useIconAndLabelForStatus(id: string): IconAndLabel {
|
||||||
res: ProposalQueryResult
|
const { data, loading, error } = useExplorerProposalStatusQuery({
|
||||||
): IconAndLabel {
|
variables: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const proposal = data?.proposal as Extract<
|
||||||
|
ExplorerProposalStatusQuery['proposal'],
|
||||||
|
{ __typename?: 'Proposal' }
|
||||||
|
>;
|
||||||
|
|
||||||
const DEFAULT: IconAndLabel = {
|
const DEFAULT: IconAndLabel = {
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
label: t('Proposal state unknown'),
|
label: t('Proposal state unknown'),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (res.loading) {
|
if (loading) {
|
||||||
return {
|
return {
|
||||||
icon: 'more',
|
icon: 'more',
|
||||||
label: t('Loading data'),
|
label: t('Loading data'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res?.data?.proposal || res.error) {
|
if (!data?.proposal || error) {
|
||||||
return {
|
return {
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
label: res.error?.message || DEFAULT.label,
|
label: error?.message || DEFAULT.label,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (res.data.proposal.state) {
|
switch (proposal.state) {
|
||||||
case 'STATE_DECLINED':
|
case 'STATE_DECLINED':
|
||||||
return {
|
return {
|
||||||
icon: 'stop',
|
icon: 'stop',
|
||||||
@@ -99,13 +99,7 @@ export function getIconAndLabelForStatus(
|
|||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export const ProposalStatusIcon = ({ id }: ProposalStatusIconProps) => {
|
export const ProposalStatusIcon = ({ id }: ProposalStatusIconProps) => {
|
||||||
const { icon, label } = getIconAndLabelForStatus(
|
const { icon, label } = useIconAndLabelForStatus(id);
|
||||||
useExplorerProposalStatusQuery({
|
|
||||||
variables: {
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="float-left mr-3">
|
<div className="float-left mr-3">
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import type { ProposalTerms } from '../tx-proposal';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import { JsonViewerDialog } from '../../../dialogs/json-viewer-dialog';
|
import { JsonViewerDialog } from '../../../dialogs/json-viewer-dialog';
|
||||||
import ProposalLink from '../../../links/proposal-link/proposal-link';
|
import ProposalLink from '../../../links/proposal-link/proposal-link';
|
||||||
import truncate from 'lodash/truncate';
|
import truncate from 'lodash/truncate';
|
||||||
@@ -9,7 +7,12 @@ import ReactMarkdown from 'react-markdown';
|
|||||||
import { ProposalDate } from './proposal-date';
|
import { ProposalDate } from './proposal-date';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import type { ProposalTerms } from '../tx-proposal';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import { BatchItem } from './batch-item';
|
||||||
|
|
||||||
type Rationale = components['schemas']['vegaProposalRationale'];
|
type Rationale = components['schemas']['vegaProposalRationale'];
|
||||||
|
type Batch = components['schemas']['v1BatchProposalSubmissionTerms']['changes'];
|
||||||
|
|
||||||
type ProposalTermsDialog = {
|
type ProposalTermsDialog = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -21,6 +24,7 @@ interface ProposalSummaryProps {
|
|||||||
id: string;
|
id: string;
|
||||||
rationale?: Rationale;
|
rationale?: Rationale;
|
||||||
terms?: ProposalTerms;
|
terms?: ProposalTerms;
|
||||||
|
batch?: Batch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,6 +35,7 @@ export const ProposalSummary = ({
|
|||||||
id,
|
id,
|
||||||
rationale,
|
rationale,
|
||||||
terms,
|
terms,
|
||||||
|
batch,
|
||||||
}: ProposalSummaryProps) => {
|
}: ProposalSummaryProps) => {
|
||||||
const [dialog, setDialog] = useState<ProposalTermsDialog>({
|
const [dialog, setDialog] = useState<ProposalTermsDialog>({
|
||||||
open: false,
|
open: false,
|
||||||
@@ -72,6 +77,18 @@ export const ProposalSummary = ({
|
|||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{batch && (
|
||||||
|
<section className="pt-2 text-sm leading-tight my-3">
|
||||||
|
<h2 className="text-lg pb-1">{t('Changes')}</h2>
|
||||||
|
<ol>
|
||||||
|
{batch.map((change, index) => (
|
||||||
|
<li className="ml-4 list-decimal" key={`batch-${index}`}>
|
||||||
|
<BatchItem item={change} />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
<div className="pt-5">
|
<div className="pt-5">
|
||||||
<button className="underline max-md:hidden mr-5" onClick={openDialog}>
|
<button className="underline max-md:hidden mr-5" onClick={openDialog}>
|
||||||
{t('View terms')}
|
{t('View terms')}
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type ExplorerReferralCodeOwnerQueryVariables = Types.Exact<{
|
||||||
|
id: Types.Scalars['ID'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ExplorerReferralCodeOwnerQuery = { __typename?: 'Query', referralSets: { __typename?: 'ReferralSetConnection', edges: Array<{ __typename?: 'ReferralSetEdge', node: { __typename?: 'ReferralSet', createdAt: any, updatedAt: any, referrer: string } } | null> } };
|
||||||
|
|
||||||
|
|
||||||
|
export const ExplorerReferralCodeOwnerDocument = gql`
|
||||||
|
query ExplorerReferralCodeOwner($id: ID!) {
|
||||||
|
referralSets(id: $id) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
referrer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useExplorerReferralCodeOwnerQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useExplorerReferralCodeOwnerQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useExplorerReferralCodeOwnerQuery` 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 } = useExplorerReferralCodeOwnerQuery({
|
||||||
|
* variables: {
|
||||||
|
* id: // value for 'id'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useExplorerReferralCodeOwnerQuery(baseOptions: Apollo.QueryHookOptions<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>(ExplorerReferralCodeOwnerDocument, options);
|
||||||
|
}
|
||||||
|
export function useExplorerReferralCodeOwnerLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>(ExplorerReferralCodeOwnerDocument, options);
|
||||||
|
}
|
||||||
|
export type ExplorerReferralCodeOwnerQueryHookResult = ReturnType<typeof useExplorerReferralCodeOwnerQuery>;
|
||||||
|
export type ExplorerReferralCodeOwnerLazyQueryHookResult = ReturnType<typeof useExplorerReferralCodeOwnerLazyQuery>;
|
||||||
|
export type ExplorerReferralCodeOwnerQueryResult = Apollo.QueryResult<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
query ExplorerReferralCodeOwner($id: ID!) {
|
||||||
|
referralSets(id: $id) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
referrer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import { render, waitFor } from '@testing-library/react';
|
||||||
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import { ReferralCodeOwner } from './referral-code-owner';
|
||||||
|
import type { ReferralCodeOwnerProps } from './referral-code-owner';
|
||||||
|
import { ExplorerReferralCodeOwnerDocument } from './__generated__/code-owner';
|
||||||
|
const renderComponent = (
|
||||||
|
props: ReferralCodeOwnerProps,
|
||||||
|
mocks: MockedResponse[]
|
||||||
|
) => {
|
||||||
|
return render(
|
||||||
|
<MockedProvider mocks={mocks}>
|
||||||
|
<MemoryRouter>
|
||||||
|
<ReferralCodeOwner {...props} />
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('ReferralCodeOwner', () => {
|
||||||
|
it('should render loading state', () => {
|
||||||
|
const mocks = [
|
||||||
|
{
|
||||||
|
request: {
|
||||||
|
query: ExplorerReferralCodeOwnerDocument,
|
||||||
|
variables: {
|
||||||
|
id: 'ABC123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
||||||
|
|
||||||
|
expect(getByText('Loading...')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render error state', async () => {
|
||||||
|
const errorMessage = 'Error fetching referrer: ABC123';
|
||||||
|
const mocks = [
|
||||||
|
{
|
||||||
|
request: {
|
||||||
|
query: ExplorerReferralCodeOwnerDocument,
|
||||||
|
variables: {
|
||||||
|
id: 'ABC123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
error: new Error('nope'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(getByText(errorMessage)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render link to referring party', async () => {
|
||||||
|
const referrerId = 'DEF789';
|
||||||
|
|
||||||
|
const mocks = [
|
||||||
|
{
|
||||||
|
request: {
|
||||||
|
query: ExplorerReferralCodeOwnerDocument,
|
||||||
|
variables: {
|
||||||
|
id: 'ABC123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
referralSets: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
__typename: 'ReferralSet',
|
||||||
|
referrer: referrerId,
|
||||||
|
createdAt: '123',
|
||||||
|
updatedAt: '456',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(getByText(referrerId)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { TableCell } from '../../../table';
|
||||||
|
import { useExplorerReferralCodeOwnerQuery } from './__generated__/code-owner';
|
||||||
|
import { PartyLink } from '../../../links';
|
||||||
|
|
||||||
|
export interface ReferralCodeOwnerProps {
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the owner of a referral code
|
||||||
|
*/
|
||||||
|
export const ReferralCodeOwner = ({ code }: ReferralCodeOwnerProps) => {
|
||||||
|
const { data, error, loading } = useExplorerReferralCodeOwnerQuery({
|
||||||
|
variables: {
|
||||||
|
id: code,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const referrer = data?.referralSets.edges[0]?.node.referrer || '';
|
||||||
|
return (
|
||||||
|
<TableCell>
|
||||||
|
{loading && 'Loading...'}
|
||||||
|
{error && `Error fetching referrer: ${code}`}
|
||||||
|
{referrer.length > 0 && <PartyLink id={referrer} />}
|
||||||
|
</TableCell>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { ReferralTeam } from './team';
|
||||||
|
import type { CreateReferralSet } from './team';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
|
||||||
|
describe('ReferralTeam', () => {
|
||||||
|
const team = {
|
||||||
|
name: 'Test Team',
|
||||||
|
teamUrl: 'https://example.com/team',
|
||||||
|
avatarUrl: 'https://example.com/avatar',
|
||||||
|
closed: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockTx: CreateReferralSet = {
|
||||||
|
team,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockId = '123456';
|
||||||
|
const mockCreator = 'JohnDoe';
|
||||||
|
|
||||||
|
it('should render the team name', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Test Team')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the team ID', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Id')).toBeInTheDocument();
|
||||||
|
expect(getByText(mockId)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the creator', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Creator')).toBeInTheDocument();
|
||||||
|
expect(getByText(mockCreator)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the team URL', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Team URL')).toBeInTheDocument();
|
||||||
|
expect(getByText(team.teamUrl)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the avatar URL', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByText('Avatar')).toBeInTheDocument();
|
||||||
|
expect(getByText(team.avatarUrl)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the open status as a tick if closed is falsy', () => {
|
||||||
|
const { getByTestId } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByTestId('open-yes')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the open status as a cross if it is truthy', () => {
|
||||||
|
const m = {
|
||||||
|
team: {
|
||||||
|
closed: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const { getByTestId } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<ReferralTeam tx={m} id={mockId} creator={mockCreator} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
expect(getByTestId('open-no')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import {
|
||||||
|
VegaIcon,
|
||||||
|
Icon,
|
||||||
|
KeyValueTable,
|
||||||
|
KeyValueTableRow,
|
||||||
|
VegaIconNames,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import Hash from '../../../links/hash';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
import { PartyLink } from '../../../links';
|
||||||
|
|
||||||
|
export type CreateReferralSet = components['schemas']['v1CreateReferralSet'];
|
||||||
|
export type ReferralTeam = CreateReferralSet['team'];
|
||||||
|
|
||||||
|
export interface ReferralTeamProps {
|
||||||
|
tx: CreateReferralSet;
|
||||||
|
id: string;
|
||||||
|
creator: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the details for a team in a CreateReferralSet or UpdateReferralSet transaction.
|
||||||
|
*
|
||||||
|
* Intentionally does not render the avatar image or link to the team url.
|
||||||
|
*/
|
||||||
|
export const ReferralTeam = ({ tx, id, creator }: ReferralTeamProps) => {
|
||||||
|
if (!tx.team) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<div className="inline-block mr-2 leading-none">
|
||||||
|
<VegaIcon name={VegaIconNames.TEAM} />
|
||||||
|
</div>
|
||||||
|
{tx.team.name && (
|
||||||
|
<h3 className="inline-block leading-loose">{tx.team.name}</h3>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="min-w-fit max-w-2xl block">
|
||||||
|
<KeyValueTable>
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Id')}
|
||||||
|
<Hash text={id} truncate={false} />
|
||||||
|
</KeyValueTableRow>
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Creator')}
|
||||||
|
<PartyLink id={creator} truncate={false} />
|
||||||
|
</KeyValueTableRow>
|
||||||
|
{tx.team.teamUrl && (
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Team URL')}
|
||||||
|
<Hash text={tx.team.teamUrl} truncate={false} />
|
||||||
|
</KeyValueTableRow>
|
||||||
|
)}
|
||||||
|
{tx.team.avatarUrl && (
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Avatar')}
|
||||||
|
<Hash text={tx.team.avatarUrl} truncate={false} />
|
||||||
|
</KeyValueTableRow>
|
||||||
|
)}
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('Open')}
|
||||||
|
<span data-testid={!tx.team.closed ? 'open-yes' : 'open-no'}>
|
||||||
|
{!tx.team.closed ? <Icon name="tick" /> : <Icon name="cross" />}
|
||||||
|
</span>
|
||||||
|
</KeyValueTableRow>
|
||||||
|
</KeyValueTable>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -9,6 +9,7 @@ import { Time } from '../../../time';
|
|||||||
import { ChainResponseCode } from '../chain-response-code/chain-reponse.code';
|
import { ChainResponseCode } from '../chain-response-code/chain-reponse.code';
|
||||||
import { TxDataView } from '../../tx-data-view';
|
import { TxDataView } from '../../tx-data-view';
|
||||||
import Hash from '../../../links/hash';
|
import Hash from '../../../links/hash';
|
||||||
|
import { Signature } from '../../../signature/signature';
|
||||||
|
|
||||||
interface TxDetailsSharedProps {
|
interface TxDetailsSharedProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -26,7 +27,8 @@ export const sharedHeaderProps = {
|
|||||||
className: 'align-top',
|
className: 'align-top',
|
||||||
};
|
};
|
||||||
|
|
||||||
const Labels: Record<BlockExplorerTransactionResult['type'], string> = {
|
// The incoming type field is usually the right thing to show. Exceptions are listed here
|
||||||
|
const LabelOverrides: Record<BlockExplorerTransactionResult['type'], string> = {
|
||||||
'Stop Orders Submission': 'Stop Order',
|
'Stop Orders Submission': 'Stop Order',
|
||||||
'Stop Orders Cancellation': 'Cancel Stop Order',
|
'Stop Orders Cancellation': 'Cancel Stop Order',
|
||||||
};
|
};
|
||||||
@@ -49,7 +51,7 @@ export const TxDetailsShared = ({
|
|||||||
const time: string = blockData?.result.block.header.time || '';
|
const time: string = blockData?.result.block.header.time || '';
|
||||||
const height: string = blockData?.result.block.header.height || txData.block;
|
const height: string = blockData?.result.block.header.height || txData.block;
|
||||||
|
|
||||||
const type = Labels[txData.type] || txData.type;
|
const type = LabelOverrides[txData.type] || txData.type;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -75,6 +77,12 @@ export const TxDetailsShared = ({
|
|||||||
<BlockLink height={height} />
|
<BlockLink height={height} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell {...sharedHeaderProps}>{t('Signature')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Signature signature={txData.signature} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell {...sharedHeaderProps}>{t('Time')}</TableCell>
|
<TableCell {...sharedHeaderProps}>{t('Time')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const AccountType: Record<AccountTypes, string> = {
|
|||||||
ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY: 'Reward Return Volatility',
|
ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY: 'Reward Return Volatility',
|
||||||
ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING: 'Reward Validator Ranking',
|
ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING: 'Reward Validator Ranking',
|
||||||
ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD: 'Pending Fee Referral Reward',
|
ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD: 'Pending Fee Referral Reward',
|
||||||
|
ACCOUNT_TYPE_ORDER_MARGIN: 'Order Margin',
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TransferParticipantsProps {
|
interface TransferParticipantsProps {
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import { ReferralCodeOwner } from './referrals/referral-code-owner';
|
||||||
|
|
||||||
|
interface TxDetailsApplyReferralCodeProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
||||||
|
*/
|
||||||
|
export const TxDetailsApplyReferralCode = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsApplyReferralCodeProps) => {
|
||||||
|
if (!txData || !txData.command.applyReferralCode || !txData.signature) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const referralCode = txData.command.applyReferralCode.id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Applied Code')}</TableCell>
|
||||||
|
<TableCell>{referralCode}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Referrer')}</TableCell>
|
||||||
|
<ReferralCodeOwner code={referralCode} />
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { sharedHeaderProps, TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import type { components } from '../../../../types/explorer';
|
||||||
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
|
import { ProposalSummary } from './proposal/summary';
|
||||||
|
import Hash from '../../links/hash';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
export type Proposal = components['schemas']['v1BatchProposalSubmission'];
|
||||||
|
export type ProposalTerms = components['schemas']['vegaProposalTerms'];
|
||||||
|
|
||||||
|
interface TxBatchProposalProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const TxBatchProposal = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxBatchProposalProps) => {
|
||||||
|
if (!txData || !txData.command.batchProposalSubmission) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
let deterministicId = '';
|
||||||
|
|
||||||
|
const proposal: Proposal = txData.command.batchProposalSubmission;
|
||||||
|
const sig = txData?.signature?.value;
|
||||||
|
if (sig) {
|
||||||
|
deterministicId = txSignatureToDeterministicId(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell {...sharedHeaderProps}>{t('Type')}</TableCell>
|
||||||
|
<TableCell>{t('Batch proposal')}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
hideTypeRow={true}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Batch size')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{proposal.terms?.changes?.length || t('No changes')}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Proposal ID')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Hash text={deterministicId} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
{proposal && (
|
||||||
|
<ProposalSummary
|
||||||
|
id={deterministicId}
|
||||||
|
rationale={proposal?.rationale}
|
||||||
|
terms={proposal.terms}
|
||||||
|
batch={proposal.terms?.changes}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,51 +1,11 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
import { TableWithTbody } from '../../table';
|
import { TableWithTbody } from '../../table';
|
||||||
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
|
||||||
import { ChainEvent } from './chain-events';
|
import { ChainEvent } from './chain-events';
|
||||||
import { BigNumber } from 'ethers';
|
|
||||||
|
|
||||||
import type { AbiType } from '../../../lib/encoders/abis/abi-types';
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
|
||||||
interface AbiOutput {
|
|
||||||
type: AbiType;
|
|
||||||
internalType: AbiType;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes the b64/ABIcoded result from an eth cal
|
|
||||||
* @param data
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function decodeEthCallResult(
|
|
||||||
data: BlockExplorerTransactionResult
|
|
||||||
): string {
|
|
||||||
const ethResult = data.command.chainEvent?.contractCall.result;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Decode the result string: base64 => uint8array
|
|
||||||
const data = base64.decode(ethResult);
|
|
||||||
|
|
||||||
// Parse the escaped ABI in to an object
|
|
||||||
const abi = JSON.parse(
|
|
||||||
'[{"inputs":[],"name":"latestAnswer","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"}]'
|
|
||||||
);
|
|
||||||
// Pull the expected types out of the Oracles ABI
|
|
||||||
const types: AbiType[] = abi[0].outputs.map((o: AbiOutput) => o.type);
|
|
||||||
|
|
||||||
const rawResult = defaultAbiCoder.decode(types, data);
|
|
||||||
|
|
||||||
// Finally, convert the resulting BigNumber in to a string
|
|
||||||
const res = BigNumber.from(rawResult[0]).toString();
|
|
||||||
return res;
|
|
||||||
} catch (e) {
|
|
||||||
return '-';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TxDetailsChainEventProps {
|
interface TxDetailsChainEventProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
pubKey: string | undefined;
|
pubKey: string | undefined;
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
|
import { ReferralTeam } from './referrals/team';
|
||||||
|
|
||||||
|
interface TxDetailsCreateReferralProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
||||||
|
*/
|
||||||
|
export const TxDetailsCreateReferralSet = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsCreateReferralProps) => {
|
||||||
|
if (!txData || !txData.command.createReferralSet || !txData.signature) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = txSignatureToDeterministicId(txData.signature.value);
|
||||||
|
|
||||||
|
const isTeam = txData.command.createReferralSet.isTeam || false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{isTeam ? t('Team ID') : t('Referral code')}</TableCell>
|
||||||
|
<TableCell>{id}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
|
||||||
|
<ReferralTeam
|
||||||
|
tx={txData.command.createReferralSet}
|
||||||
|
id={id}
|
||||||
|
creator={txData.submitter}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -3,8 +3,8 @@ import { DATA_SOURCES } from '../../../config';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||||
import { TxDetailsOrder } from './tx-order';
|
import { TxDetailsOrder } from './tx-order';
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
import { type BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
import { type TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
import { TxDetailsHeartbeat } from './tx-hearbeat';
|
import { TxDetailsHeartbeat } from './tx-hearbeat';
|
||||||
import { TxDetailsGeneric } from './tx-generic';
|
import { TxDetailsGeneric } from './tx-generic';
|
||||||
import { TxDetailsBatch } from './tx-batch';
|
import { TxDetailsBatch } from './tx-batch';
|
||||||
@@ -28,6 +28,12 @@ import { TxProposal } from './tx-proposal';
|
|||||||
import { TxDetailsTransfer } from './tx-transfer';
|
import { TxDetailsTransfer } from './tx-transfer';
|
||||||
import { TxDetailsStopOrderSubmission } from './tx-stop-order-submission';
|
import { TxDetailsStopOrderSubmission } from './tx-stop-order-submission';
|
||||||
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
||||||
|
import { TxDetailsCreateReferralSet } from './tx-create-referral-set';
|
||||||
|
import { TxDetailsApplyReferralCode } from './tx-apply-referral-code';
|
||||||
|
import { TxDetailsUpdateReferralSet } from './tx-update-referral-set';
|
||||||
|
import { TxDetailsJoinTeam } from './tx-join-team';
|
||||||
|
import { TxDetailsUpdateMarginMode } from './tx-update-margin-mode';
|
||||||
|
import { TxBatchProposal } from './tx-batch-proposal';
|
||||||
|
|
||||||
interface TxDetailsWrapperProps {
|
interface TxDetailsWrapperProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -121,6 +127,18 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
|||||||
return TxDetailsStopOrderSubmission;
|
return TxDetailsStopOrderSubmission;
|
||||||
case 'Transfer Funds':
|
case 'Transfer Funds':
|
||||||
return TxDetailsTransfer;
|
return TxDetailsTransfer;
|
||||||
|
case 'Create Referral Set':
|
||||||
|
return TxDetailsCreateReferralSet;
|
||||||
|
case 'Update Referral Set':
|
||||||
|
return TxDetailsUpdateReferralSet;
|
||||||
|
case 'Apply Referral Code':
|
||||||
|
return TxDetailsApplyReferralCode;
|
||||||
|
case 'Join Team':
|
||||||
|
return TxDetailsJoinTeam;
|
||||||
|
case 'Update Margin Mode':
|
||||||
|
return TxDetailsUpdateMarginMode;
|
||||||
|
case 'Batch Proposal':
|
||||||
|
return TxBatchProposal;
|
||||||
default:
|
default:
|
||||||
return TxDetailsGeneric;
|
return TxDetailsGeneric;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { TxDetailsShared } from './shared/tx-details-shared';
|
|||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
import { BlockLink } from '../../links';
|
import { BlockLink } from '../../links';
|
||||||
|
|
||||||
type EthKeyRotate = components['schemas']['v1EthereumKeyRotateSubmission'];
|
type EthKeyRotate = components['schemas']['v1EthereumKeyRotateSubmission'];
|
||||||
@@ -46,7 +46,7 @@ export const TxDetailsEthKeyRotate = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Old Address')}</TableCell>
|
<TableCell>{t('Old Address')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
id={k.currentAddress}
|
id={k.currentAddress}
|
||||||
/>
|
/>
|
||||||
@@ -57,7 +57,7 @@ export const TxDetailsEthKeyRotate = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('New Address')}</TableCell>
|
<TableCell>{t('New Address')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
id={k.newAddress}
|
id={k.newAddress}
|
||||||
/>
|
/>
|
||||||
@@ -68,7 +68,7 @@ export const TxDetailsEthKeyRotate = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Submitter address')}</TableCell>
|
<TableCell>{t('Submitter address')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
id={k.submitterAddress}
|
id={k.submitterAddress}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import { TableRow, TableCell, TableWithTbody } from '../../table';
|
|||||||
|
|
||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
import { NodeLink } from '../../links';
|
import { NodeLink } from '../../links';
|
||||||
|
|
||||||
type Command = components['schemas']['v1IssueSignatures'];
|
type Command = components['schemas']['v1IssueSignatures'];
|
||||||
@@ -57,7 +57,7 @@ export const TxDetailsIssueSignatures = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('ETH key')}</TableCell>
|
<TableCell>{t('ETH key')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={cmd.submitter}
|
id={cmd.submitter}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import { ReferralCodeOwner } from './referrals/referral-code-owner';
|
||||||
|
|
||||||
|
interface TxDetailsJoinTeamProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
||||||
|
*/
|
||||||
|
export const TxDetailsJoinTeam = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsJoinTeamProps) => {
|
||||||
|
if (!txData || !txData.command.joinTeam || !txData.signature) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const team = txData.command.joinTeam.id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Team')}</TableCell>
|
||||||
|
<TableCell>{team}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Referrer')}</TableCell>
|
||||||
|
<ReferralCodeOwner code={team} />
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -6,9 +6,9 @@ import { TableRow, TableCell, TableWithTbody } from '../../table';
|
|||||||
|
|
||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
import { PartyLink } from '../../links';
|
import { PartyLink } from '../../links';
|
||||||
import Hash from '../../links/hash';
|
import Hash from '../../links/hash';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
@@ -72,7 +72,7 @@ export const TxDetailsNodeAnnounce = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Ethereum Address')}</TableCell>
|
<TableCell>{t('Ethereum Address')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
id={cmd.ethereumAddress}
|
id={cmd.ethereumAddress}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import { useExplorerNodeVoteQuery } from './__generated__/Node-vote';
|
|||||||
import { PartyLink } from '../../links';
|
import { PartyLink } from '../../links';
|
||||||
import { Time } from '../../time';
|
import { Time } from '../../time';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
|
|
||||||
interface TxDetailsNodeVoteProps {
|
interface TxDetailsNodeVoteProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -143,7 +143,7 @@ export function TxHash({ hash }: TxDetailsEthTxHashProps) {
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>Ethereum TX:</TableCell>
|
<TableCell>Ethereum TX:</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink id={hash} type={EthExplorerLinkTypes.tx} />
|
<ExternalExplorerLink id={hash} type={EthExplorerLinkTypes.tx} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import GovernanceAssetBalance from '../../asset-balance/governance-asset-balance
|
|||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
|
|
||||||
export const methodText: Record<
|
export const methodText: Record<
|
||||||
components['schemas']['UndelegateSubmissionMethod'],
|
components['schemas']['v1UndelegateSubmissionMethod'],
|
||||||
string
|
string
|
||||||
> = {
|
> = {
|
||||||
METHOD_NOW: 'Immediate',
|
METHOD_NOW: 'Immediate',
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import type { components } from '../../../../types/explorer';
|
||||||
|
import { MarketLink } from '../../links';
|
||||||
|
|
||||||
|
interface TxDetailsUpdateMarginModeProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mode = components['schemas']['UpdateMarginModeMode'];
|
||||||
|
|
||||||
|
const MarginModeLabels: Record<Mode, string> = {
|
||||||
|
MODE_CROSS_MARGIN: t('Cross margin'),
|
||||||
|
MODE_ISOLATED_MARGIN: t('Isolated margin'),
|
||||||
|
MODE_UNSPECIFIED: t('Unspecified'),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TxDetailsUpdateMarginMode = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsUpdateMarginModeProps) => {
|
||||||
|
if (!txData || !txData.command.updateMarginMode) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u: components['schemas']['v1UpdateMarginMode'] =
|
||||||
|
txData.command.updateMarginMode;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
||||||
|
{u.marketId && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Market ID')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<MarketLink id={u.marketId} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
{u.mode && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('New margin mode')}</TableCell>
|
||||||
|
<TableCell>{MarginModeLabels[u.mode]}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
{u.marginFactor && (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Margin factor')}</TableCell>
|
||||||
|
<TableCell>{u.marginFactor}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableWithTbody>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
|
import { ReferralTeam } from './referrals/team';
|
||||||
|
|
||||||
|
interface TxDetailsUpdateReferralProps {
|
||||||
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A copy of create referral set, effectively.
|
||||||
|
* Updating a referral set without a team doesn't make sense,
|
||||||
|
* but is valid, so this component ignores sense.
|
||||||
|
*/
|
||||||
|
export const TxDetailsUpdateReferralSet = ({
|
||||||
|
txData,
|
||||||
|
pubKey,
|
||||||
|
blockData,
|
||||||
|
}: TxDetailsUpdateReferralProps) => {
|
||||||
|
if (!txData || !txData.command.updateReferralSet || !txData.signature) {
|
||||||
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = txSignatureToDeterministicId(txData.signature.value);
|
||||||
|
|
||||||
|
const isTeam = txData.command.updateReferralSet.isTeam || false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
|
<TxDetailsShared
|
||||||
|
txData={txData}
|
||||||
|
pubKey={pubKey}
|
||||||
|
blockData={blockData}
|
||||||
|
/>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{isTeam ? t('Team ID') : t('Referral code')}</TableCell>
|
||||||
|
<TableCell>{id}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableWithTbody>
|
||||||
|
|
||||||
|
<ReferralTeam
|
||||||
|
tx={txData.command.updateReferralSet}
|
||||||
|
id={id}
|
||||||
|
creator={txData.submitter}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -4,9 +4,9 @@ import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint
|
|||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
import {
|
import {
|
||||||
EthExplorerLink,
|
ExternalExplorerLink,
|
||||||
EthExplorerLinkTypes,
|
EthExplorerLinkTypes,
|
||||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
} from '../../links/external-explorer-link/external-explorer-link';
|
||||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
import AssetBalance from '../../asset-balance/asset-balance';
|
import AssetBalance from '../../asset-balance/asset-balance';
|
||||||
import { useScrollToLocation } from '../../../hooks/scroll-to-location';
|
import { useScrollToLocation } from '../../../hooks/scroll-to-location';
|
||||||
@@ -57,7 +57,7 @@ export const TxDetailsWithdrawSubmission = ({
|
|||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Recipient')}</TableCell>
|
<TableCell>{t('Recipient')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<EthExplorerLink
|
<ExternalExplorerLink
|
||||||
id={w.ext.erc20.receiverAddress}
|
id={w.ext.erc20.receiverAddress}
|
||||||
type={EthExplorerLinkTypes.address}
|
type={EthExplorerLinkTypes.address}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export type FilterOption =
|
|||||||
| 'Amend Order'
|
| 'Amend Order'
|
||||||
| 'Apply Referral Code'
|
| 'Apply Referral Code'
|
||||||
| 'Batch Market Instructions'
|
| 'Batch Market Instructions'
|
||||||
|
| 'Batch Proposal'
|
||||||
| 'Cancel LiquidityProvision Order'
|
| 'Cancel LiquidityProvision Order'
|
||||||
| 'Cancel Order'
|
| 'Cancel Order'
|
||||||
| 'Cancel Transfer Funds'
|
| 'Cancel Transfer Funds'
|
||||||
@@ -28,6 +29,7 @@ export type FilterOption =
|
|||||||
| 'Delegate'
|
| 'Delegate'
|
||||||
| 'Ethereum Key Rotate Submission'
|
| 'Ethereum Key Rotate Submission'
|
||||||
| 'Issue Signatures'
|
| 'Issue Signatures'
|
||||||
|
| 'Join Team'
|
||||||
| 'Key Rotate Submission'
|
| 'Key Rotate Submission'
|
||||||
| 'Liquidity Provision Order'
|
| 'Liquidity Provision Order'
|
||||||
| 'Node Signature'
|
| 'Node Signature'
|
||||||
@@ -43,49 +45,58 @@ export type FilterOption =
|
|||||||
| 'Transfer Funds'
|
| 'Transfer Funds'
|
||||||
| 'Undelegate'
|
| 'Undelegate'
|
||||||
| 'Update Referral Set'
|
| 'Update Referral Set'
|
||||||
|
| 'Update Margin Mode'
|
||||||
| 'Validator Heartbeat'
|
| 'Validator Heartbeat'
|
||||||
| 'Vote on Proposal'
|
| 'Vote on Proposal'
|
||||||
| 'Withdraw';
|
| 'Withdraw';
|
||||||
|
|
||||||
// Alphabetised list of transaction types to appear at the top level
|
export const filterOptions: Record<string, FilterOption[]> = {
|
||||||
export const PrimaryFilterOptions: FilterOption[] = [
|
'Market Instructions': [
|
||||||
'Amend LiquidityProvision Order',
|
'Amend LiquidityProvision Order',
|
||||||
'Amend Order',
|
'Amend Order',
|
||||||
'Batch Market Instructions',
|
'Batch Market Instructions',
|
||||||
'Cancel LiquidityProvision Order',
|
'Cancel LiquidityProvision Order',
|
||||||
'Cancel Order',
|
'Cancel Order',
|
||||||
'Cancel Transfer Funds',
|
'Liquidity Provision Order',
|
||||||
'Delegate',
|
'Stop Orders Submission',
|
||||||
'Liquidity Provision Order',
|
'Stop Orders Cancellation',
|
||||||
'Proposal',
|
'Submit Order',
|
||||||
'Stop Orders Submission',
|
'Update Margin Mode',
|
||||||
'Stop Orders Cancellation',
|
],
|
||||||
'Submit Oracle Data',
|
'Transfers and Withdrawals': [
|
||||||
'Submit Order',
|
'Transfer Funds',
|
||||||
'Transfer Funds',
|
'Cancel Transfer Funds',
|
||||||
'Undelegate',
|
'Withdraw',
|
||||||
'Vote on Proposal',
|
],
|
||||||
'Withdraw',
|
Governance: [
|
||||||
];
|
'Batch Proposal',
|
||||||
|
'Delegate',
|
||||||
|
'Undelegate',
|
||||||
|
'Vote on Proposal',
|
||||||
|
'Proposal',
|
||||||
|
],
|
||||||
|
Referrals: [
|
||||||
|
'Apply Referral Code',
|
||||||
|
'Create Referral Set',
|
||||||
|
'Join Team',
|
||||||
|
'Update Referral Set',
|
||||||
|
],
|
||||||
|
'External Data': ['Chain Event', 'Submit Oracle Data'],
|
||||||
|
Validators: [
|
||||||
|
'Ethereum Key Rotate Submission',
|
||||||
|
'Issue Signatures',
|
||||||
|
'Key Rotate Submission',
|
||||||
|
'Node Signature',
|
||||||
|
'Node Vote',
|
||||||
|
'Protocol Upgrade',
|
||||||
|
'Register new Node',
|
||||||
|
'State Variable Proposal',
|
||||||
|
'Validator Heartbeat',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
// Alphabetised list of transaction types to nest under a 'More...' submenu
|
export const AllFilterOptions: FilterOption[] =
|
||||||
export const SecondaryFilterOptions: FilterOption[] = [
|
Object.values(filterOptions).flat();
|
||||||
'Chain Event',
|
|
||||||
'Ethereum Key Rotate Submission',
|
|
||||||
'Issue Signatures',
|
|
||||||
'Key Rotate Submission',
|
|
||||||
'Node Signature',
|
|
||||||
'Node Vote',
|
|
||||||
'Protocol Upgrade',
|
|
||||||
'Register new Node',
|
|
||||||
'State Variable Proposal',
|
|
||||||
'Validator Heartbeat',
|
|
||||||
];
|
|
||||||
|
|
||||||
export const AllFilterOptions: FilterOption[] = [
|
|
||||||
...PrimaryFilterOptions,
|
|
||||||
...SecondaryFilterOptions,
|
|
||||||
];
|
|
||||||
|
|
||||||
export interface TxFilterProps {
|
export interface TxFilterProps {
|
||||||
filters: Set<FilterOption>;
|
filters: Set<FilterOption>;
|
||||||
@@ -122,46 +133,33 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
|
|||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{PrimaryFilterOptions.map((f) => (
|
|
||||||
<DropdownMenuCheckboxItem
|
{Object.entries(filterOptions).map(([key, value]) => (
|
||||||
key={f}
|
<DropdownMenuSub key={key}>
|
||||||
checked={filters.has(f)}
|
<DropdownMenuSubTrigger>
|
||||||
onCheckedChange={() => {
|
{t(key)}
|
||||||
// NOTE: These act like radio buttons until the API supports multiple filters
|
<Icon name="chevron-right" />
|
||||||
setFilters(new Set([f]));
|
</DropdownMenuSubTrigger>
|
||||||
}}
|
<DropdownMenuSubContent>
|
||||||
id={`radio-${f}`}
|
{value.map((f) => (
|
||||||
>
|
<DropdownMenuCheckboxItem
|
||||||
{f}
|
key={f}
|
||||||
<DropdownMenuItemIndicator>
|
checked={filters.has(f)}
|
||||||
<Icon name="tick-circle" />
|
onCheckedChange={(checked) => {
|
||||||
</DropdownMenuItemIndicator>
|
// NOTE: These act like radio buttons until the API supports multiple filters
|
||||||
</DropdownMenuCheckboxItem>
|
setFilters(new Set([f]));
|
||||||
|
}}
|
||||||
|
id={`radio-${f}`}
|
||||||
|
>
|
||||||
|
{f}
|
||||||
|
<DropdownMenuItemIndicator>
|
||||||
|
<Icon name="tick-circle" className="inline" />
|
||||||
|
</DropdownMenuItemIndicator>
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuSubContent>
|
||||||
|
</DropdownMenuSub>
|
||||||
))}
|
))}
|
||||||
<DropdownMenuSub>
|
|
||||||
<DropdownMenuSubTrigger>
|
|
||||||
{t('More Types')}
|
|
||||||
<Icon name="chevron-right" />
|
|
||||||
</DropdownMenuSubTrigger>
|
|
||||||
<DropdownMenuSubContent>
|
|
||||||
{SecondaryFilterOptions.map((f) => (
|
|
||||||
<DropdownMenuCheckboxItem
|
|
||||||
key={f}
|
|
||||||
checked={filters.has(f)}
|
|
||||||
onCheckedChange={(checked) => {
|
|
||||||
// NOTE: These act like radio buttons until the API supports multiple filters
|
|
||||||
setFilters(new Set([f]));
|
|
||||||
}}
|
|
||||||
id={`radio-${f}`}
|
|
||||||
>
|
|
||||||
{f}
|
|
||||||
<DropdownMenuItemIndicator>
|
|
||||||
<Icon name="tick-circle" className="inline" />
|
|
||||||
</DropdownMenuItemIndicator>
|
|
||||||
</DropdownMenuCheckboxItem>
|
|
||||||
))}
|
|
||||||
</DropdownMenuSubContent>
|
|
||||||
</DropdownMenuSub>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -61,53 +61,4 @@ describe('TxsListNavigation', () => {
|
|||||||
|
|
||||||
expect(nextPageMock).toHaveBeenCalledTimes(1);
|
expect(nextPageMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('disables "Older" button if hasMoreTxs is false', () => {
|
|
||||||
render(
|
|
||||||
<TxsListNavigation
|
|
||||||
refreshTxs={NOOP}
|
|
||||||
nextPage={NOOP}
|
|
||||||
previousPage={NOOP}
|
|
||||||
hasMoreTxs={false}
|
|
||||||
hasPreviousPage={false}
|
|
||||||
>
|
|
||||||
<span></span>
|
|
||||||
</TxsListNavigation>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText('Older')).toBeDisabled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('disables "Newer" button if hasPreviousPage is false', () => {
|
|
||||||
render(
|
|
||||||
<TxsListNavigation
|
|
||||||
refreshTxs={NOOP}
|
|
||||||
nextPage={NOOP}
|
|
||||||
previousPage={NOOP}
|
|
||||||
hasMoreTxs={true}
|
|
||||||
hasPreviousPage={false}
|
|
||||||
>
|
|
||||||
<span></span>
|
|
||||||
</TxsListNavigation>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText('Newer')).toBeDisabled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('disables both buttons when more and previous are false', () => {
|
|
||||||
render(
|
|
||||||
<TxsListNavigation
|
|
||||||
refreshTxs={NOOP}
|
|
||||||
nextPage={NOOP}
|
|
||||||
previousPage={NOOP}
|
|
||||||
hasMoreTxs={false}
|
|
||||||
hasPreviousPage={false}
|
|
||||||
>
|
|
||||||
<span></span>
|
|
||||||
</TxsListNavigation>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText('Newer')).toBeDisabled();
|
|
||||||
expect(screen.getByText('Older')).toBeDisabled();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ export interface TxListNavigationProps {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
hasPreviousPage: boolean;
|
hasPreviousPage: boolean;
|
||||||
hasMoreTxs: boolean;
|
hasMoreTxs: boolean;
|
||||||
children: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
isEmpty?: boolean;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Displays a list of transactions with filters and controls to navigate through the list.
|
* Displays a list of transactions with filters and controls to navigate through the list.
|
||||||
@@ -21,9 +22,8 @@ export const TxsListNavigation = ({
|
|||||||
refreshTxs,
|
refreshTxs,
|
||||||
nextPage,
|
nextPage,
|
||||||
previousPage,
|
previousPage,
|
||||||
hasMoreTxs,
|
|
||||||
hasPreviousPage,
|
|
||||||
children,
|
children,
|
||||||
|
isEmpty,
|
||||||
loading = false,
|
loading = false,
|
||||||
}: TxListNavigationProps) => {
|
}: TxListNavigationProps) => {
|
||||||
return (
|
return (
|
||||||
@@ -35,7 +35,6 @@ export const TxsListNavigation = ({
|
|||||||
<Button
|
<Button
|
||||||
className="mr-2"
|
className="mr-2"
|
||||||
size="xs"
|
size="xs"
|
||||||
disabled={!hasPreviousPage || loading}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
previousPage();
|
previousPage();
|
||||||
}}
|
}}
|
||||||
@@ -44,7 +43,7 @@ export const TxsListNavigation = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="xs"
|
||||||
disabled={!hasMoreTxs}
|
disabled={isEmpty}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
nextPage();
|
nextPage();
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { components } from '../../../types/explorer';
|
import type { components } from '../../../types/explorer';
|
||||||
import { VoteIcon } from '../vote-icon/vote-icon';
|
import { VoteIcon } from '../vote-icon/vote-icon';
|
||||||
|
import { ExternalChainIcon } from '../links/external-explorer-link/external-chain-icon';
|
||||||
|
|
||||||
interface TxOrderTypeProps {
|
interface TxOrderTypeProps {
|
||||||
orderType: string;
|
orderType: string;
|
||||||
@@ -48,6 +49,8 @@ const displayString: StringMap = {
|
|||||||
StopOrdersSubmission: 'Stop',
|
StopOrdersSubmission: 'Stop',
|
||||||
StopOrdersCancellation: 'Cancel stop',
|
StopOrdersCancellation: 'Cancel stop',
|
||||||
'Stop Orders Cancellation': 'Cancel stop',
|
'Stop Orders Cancellation': 'Cancel stop',
|
||||||
|
'Apply Referral Code': 'Referral',
|
||||||
|
'Create Referral Set': 'Create referral',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getLabelForStopOrderType(
|
export function getLabelForStopOrderType(
|
||||||
@@ -80,6 +83,12 @@ export function getLabelForOrderType(
|
|||||||
if (command.orderSubmission.icebergOpts) {
|
if (command.orderSubmission.icebergOpts) {
|
||||||
return 'Iceberg';
|
return 'Iceberg';
|
||||||
}
|
}
|
||||||
|
if (command.orderSubmission.type === 'TYPE_MARKET') {
|
||||||
|
return 'Market order';
|
||||||
|
}
|
||||||
|
if (command.orderSubmission.type === 'TYPE_LIMIT') {
|
||||||
|
return 'Limit order';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 'Order';
|
return 'Order';
|
||||||
}
|
}
|
||||||
@@ -180,6 +189,9 @@ export function getLabelForChainEvent(
|
|||||||
}
|
}
|
||||||
return t('Multisig update');
|
return t('Multisig update');
|
||||||
} else if (chainEvent.contractCall) {
|
} else if (chainEvent.contractCall) {
|
||||||
|
if (chainEvent.contractCall.error) {
|
||||||
|
return t('Call error');
|
||||||
|
}
|
||||||
return t('Contract call');
|
return t('Contract call');
|
||||||
}
|
}
|
||||||
return t('Chain Event');
|
return t('Chain Event');
|
||||||
@@ -249,6 +261,11 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
|||||||
data-testid="tx-type"
|
data-testid="tx-type"
|
||||||
className={`text-sm rounded-md leading-tight px-2 inline-block whitespace-nowrap ${colours}`}
|
className={`text-sm rounded-md leading-tight px-2 inline-block whitespace-nowrap ${colours}`}
|
||||||
>
|
>
|
||||||
|
{command?.chainEvent && (
|
||||||
|
<ExternalChainIcon
|
||||||
|
chainId={command?.chainEvent?.contractCall?.sourceChainId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{type}
|
{type}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ describe('TxDetailsTransfer', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
signature: {
|
signature: {
|
||||||
|
version: '1',
|
||||||
|
algo: 'vega/ed25519',
|
||||||
value:
|
value:
|
||||||
'610c2e196a7d4fed4413b9e82af267b1ff3e30e943df3a3d28096fd60604d430d752fbaf6dd4f84d496be78885bb6118f40560bff7832c06bd7a3d67b718b700',
|
'610c2e196a7d4fed4413b9e82af267b1ff3e30e943df3a3d28096fd60604d430d752fbaf6dd4f84d496be78885bb6118f40560bff7832c06bd7a3d67b718b700',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
|
|||||||
'4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964',
|
'4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964',
|
||||||
type: 'Submit Order',
|
type: 'Submit Order',
|
||||||
signature: {
|
signature: {
|
||||||
|
version: '1',
|
||||||
|
algo: 'vega/ed25519',
|
||||||
value: '123',
|
value: '123',
|
||||||
},
|
},
|
||||||
code: 0,
|
code: 0,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user