Compare commits
54
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffc5cd4a13 | ||
|
|
f440f57be2 | ||
|
|
24067e03e6 | ||
|
|
edbdbcf38e | ||
|
|
94a067e34b | ||
|
|
8b6b904cd6 | ||
|
|
ee38cea4f2 | ||
|
|
93869b178c | ||
|
|
27cd8086e1 | ||
|
|
6aa109131e | ||
|
|
74777e54f9 | ||
|
|
61e7450906 | ||
|
|
6a55319e04 | ||
|
|
5692d4e74c | ||
|
|
ffe89d0fe0 | ||
|
|
57e1ecac6c | ||
|
|
77e1390686 | ||
|
|
981c8649a2 | ||
|
|
694c9765d3 | ||
|
|
501ffbfc80 | ||
|
|
ac11eea37b | ||
|
|
f391e8c351 | ||
|
|
0e10b2108e | ||
|
|
162a934408 | ||
|
|
4581e117c4 | ||
|
|
e89b818e4c | ||
|
|
0665ac85db | ||
|
|
3c71a86b48 | ||
|
|
b381f16ace | ||
|
|
fc6ce9e99b | ||
|
|
f6fc4df1c5 | ||
|
|
fc8f12d6fc | ||
|
|
26f4c1c983 | ||
|
|
efd632f5c6 | ||
|
|
ce3da1762b | ||
|
|
5040fbfd07 | ||
|
|
74f2cfa4a5 | ||
|
|
8c8fe6878a | ||
|
|
6e0577aee4 | ||
|
|
87b41a30d8 | ||
|
|
0850f31855 | ||
|
|
43aff8e359 | ||
|
|
6e9e7c2a5c | ||
|
|
f054f4c516 | ||
|
|
f382078ee6 | ||
|
|
ebc058bcbe | ||
|
|
d3df339696 | ||
|
|
a31008ea26 | ||
|
|
5e93e98f07 | ||
|
|
bf3ff8fb6f | ||
|
|
16538ca3a3 | ||
|
|
2fa00dacaa | ||
|
|
45b7c2ad4d | ||
|
|
44c00f808b |
@@ -0,0 +1 @@
|
|||||||
|
node_modules
|
||||||
+11
-6
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"ignorePatterns": ["**/*"],
|
"ignorePatterns": ["**/*"],
|
||||||
"plugins": ["@nrwl/nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
|
"plugins": ["@nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
|
||||||
"settings": {
|
"settings": {
|
||||||
"jsx-a11y": {
|
"jsx-a11y": {
|
||||||
"components": {
|
"components": {
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
"extends": ["plugin:jsx-a11y/strict"],
|
"extends": ["plugin:jsx-a11y/strict"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"@nrwl/nx/enforce-module-boundaries": [
|
"@nx/enforce-module-boundaries": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"enforceBuildableLibDependency": true,
|
"enforceBuildableLibDependency": true,
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx"],
|
"files": ["*.ts", "*.tsx"],
|
||||||
"extends": ["plugin:@nrwl/nx/typescript"],
|
"extends": ["plugin:@nx/typescript"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/ban-ts-comment": [
|
"@typescript-eslint/ban-ts-comment": [
|
||||||
"error",
|
"error",
|
||||||
@@ -80,14 +80,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": ["*.spec.ts", "*.spec.tsx"],
|
"files": ["*.spec.ts", "*.spec.tsx"],
|
||||||
"extends": ["plugin:@nrwl/nx/typescript", "plugin:jest/recommended"],
|
"extends": ["plugin:@nx/typescript", "plugin:jest/recommended"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"jest/consistent-test-it": ["error", { "fn": "it" }]
|
"jest/consistent-test-it": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"fn": "it"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": ["*.js", "*.jsx"],
|
"files": ["*.js", "*.jsx"],
|
||||||
"extends": ["plugin:@nrwl/nx/javascript"],
|
"extends": ["plugin:@nx/javascript"],
|
||||||
"rules": {}
|
"rules": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,10 +5,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- release/*
|
- release/*
|
||||||
- develop
|
- develop
|
||||||
- main
|
pull_request:
|
||||||
# uncomment pull_request and comment pull_request_target to test CI changes against feature branch not target branch (develop)
|
|
||||||
# pull_request:
|
|
||||||
pull_request_target:
|
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
- ready_for_review
|
- ready_for_review
|
||||||
@@ -49,7 +46,7 @@ jobs:
|
|||||||
|
|
||||||
lint-pr-title:
|
lint-pr-title:
|
||||||
needs: node-modules
|
needs: node-modules
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
name: Verify PR title
|
name: Verify PR title
|
||||||
uses: ./.github/workflows/lint-pr.yml
|
uses: ./.github/workflows/lint-pr.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
@@ -110,6 +107,7 @@ jobs:
|
|||||||
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
||||||
echo "Affected: ${affected}"
|
echo "Affected: ${affected}"
|
||||||
echo "Branch slug: ${branch_slug}"
|
echo "Branch slug: ${branch_slug}"
|
||||||
|
echo "Current ref: ${{ github.ref }}"
|
||||||
echo ">>>> eof debug"
|
echo ">>>> eof debug"
|
||||||
|
|
||||||
projects_array=()
|
projects_array=()
|
||||||
@@ -180,6 +178,31 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# if branch starts with release/ and ends with trading / governance or explorer - overwrite the array of affected projects with fixed single application
|
||||||
|
if [[ "${{ github.ref }}" == *release* ]]; then
|
||||||
|
echo ">> This is a relase branch"
|
||||||
|
case "${{ github.ref }}" in
|
||||||
|
*trading)
|
||||||
|
echo ">> Only trading will be deployed"
|
||||||
|
projects_array=(trading)
|
||||||
|
projects_e2e_array=(trading)
|
||||||
|
;;
|
||||||
|
*governance)
|
||||||
|
echo ">> Only governance will be deployed"
|
||||||
|
projects_array=(governance)
|
||||||
|
projects_e2e_array=(governance)
|
||||||
|
;;
|
||||||
|
*explorer)
|
||||||
|
echo ">> Only explorer will be deployed"
|
||||||
|
projects_array=(explorer)
|
||||||
|
projects_e2e_array=(explorer)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo ">> All apps will be deployed"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Projects: ${projects_array[@]}"
|
echo "Projects: ${projects_array[@]}"
|
||||||
echo "Projects E2E: ${projects_e2e_array[@]}"
|
echo "Projects E2E: ${projects_e2e_array[@]}"
|
||||||
projects_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_array[@]}")
|
projects_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_array[@]}")
|
||||||
@@ -214,7 +237,7 @@ jobs:
|
|||||||
publish-dist:
|
publish-dist:
|
||||||
needs: lint-test-build
|
needs: lint-test-build
|
||||||
name: '(CD) publish dist'
|
name: '(CD) publish dist'
|
||||||
# if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
|
||||||
uses: ./.github/workflows/publish-dist.yml
|
uses: ./.github/workflows/publish-dist.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
@@ -225,7 +248,7 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- publish-dist
|
- publish-dist
|
||||||
- lint-test-build
|
- lint-test-build
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
name: '(CD) comment preview links'
|
name: '(CD) comment preview links'
|
||||||
steps:
|
steps:
|
||||||
@@ -241,26 +264,26 @@ jobs:
|
|||||||
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
||||||
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then
|
||||||
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
|
||||||
echo "waiting for governance preview"
|
echo "waiting for governance preview: ${{ needs.lint-test-build.outputs.preview_governance }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then
|
||||||
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
|
||||||
echo "waiting for explorer preview"
|
echo "waiting for explorer preview: ${{ needs.lint-test-build.outputs.preview_explorer }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then
|
||||||
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
|
||||||
echo "waiting for trading preview"
|
echo "waiting for trading preview: ${{ needs.lint-test-build.outputs.preview_trading }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then
|
||||||
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
|
||||||
echo "waiting for tools preview"
|
echo "waiting for tools preview: ${{ needs.lint-test-build.outputs.preview_tools }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
@@ -271,7 +294,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
issue-number: ${{ github.event.pull_request.number }}
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
body: |
|
body: |
|
||||||
Previews:
|
Previews
|
||||||
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
||||||
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
||||||
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
name: console-test-run
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
github-sha:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
jobs:
|
||||||
|
console-test:
|
||||||
|
timeout-minutes: 5
|
||||||
|
runs-on: self-hosted-runner
|
||||||
|
steps:
|
||||||
|
- name: Checkout console test repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: vegaprotocol/console-test
|
||||||
|
path: './console-test'
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.10.11'
|
||||||
|
|
||||||
|
- name: Install Poetry
|
||||||
|
uses: snok/install-poetry@v1
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
poetry install --no-root
|
||||||
|
working-directory: ./console-test
|
||||||
|
|
||||||
|
- name: load Binaries
|
||||||
|
run: |
|
||||||
|
poetry run python -m vega_sim.tools.load_binaries
|
||||||
|
working-directory: ./console-test
|
||||||
|
|
||||||
|
- name: pull console
|
||||||
|
run: |
|
||||||
|
poetry run docker pull ghcr.io/vegaprotocol/frontend/trading:${{ inputs.github-sha }}
|
||||||
|
|
||||||
|
- name: Update container_name in config.py
|
||||||
|
run: |
|
||||||
|
sed -i "s/container_name = \".*\"/container_name = \"vegaprotocol\/frontend\/trading:${{ inputs.github-sha }}\"/g" config.py
|
||||||
|
|
||||||
|
- name: install playwright
|
||||||
|
run: poetry run playwright install
|
||||||
|
working-directory: ./console-test
|
||||||
|
|
||||||
|
- name: run tests
|
||||||
|
run: poetry run pytest --numprocesses auto
|
||||||
|
working-directory: ./console-test
|
||||||
|
|
||||||
|
- name: Upload Playwright Trace
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: playwright-trace
|
||||||
|
path: ./traces/
|
||||||
|
retention-days: 15
|
||||||
@@ -22,6 +22,39 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
|
- name: Init variables
|
||||||
|
run: |
|
||||||
|
echo IS_PR=false >> $GITHUB_ENV
|
||||||
|
echo IS_MAINNET_RELEASE=false >> $GITHUB_ENV
|
||||||
|
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
||||||
|
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
||||||
|
echo IS_S3_RELASE=false >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is PR
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
echo IS_PR=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is mainnet release
|
||||||
|
if: ${{ contains(github.ref, 'release/mainnnet') && !contains(github.ref, 'mirror') }}
|
||||||
|
run: |
|
||||||
|
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is testnet release
|
||||||
|
if: ${{ contains(github.ref, 'release/testnet') }}
|
||||||
|
run: |
|
||||||
|
echo IS_TESTNET_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is IPFS Release
|
||||||
|
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( env.IS_MAINNET_RELEASE == 'true' || env.IS_TESTNET_RELEASE == 'true' ) }}
|
||||||
|
run: |
|
||||||
|
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Is S3 Release
|
||||||
|
if: ${{ env.IS_IPFS_RELASE == 'false' && github.event_name == 'push' }}
|
||||||
|
run: |
|
||||||
|
echo IS_S3_RELASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
id: quemu
|
id: quemu
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
@@ -33,7 +66,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: Log in to the Container registry (ghcr)
|
- name: Log in to the Container registry (ghcr)
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ env.IS_PR == 'true' }}
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
@@ -42,9 +75,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
- name: Log in to the Container registry (docker hub)
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
with:
|
with:
|
||||||
# registry: registry.hub.docker.com
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
@@ -70,7 +102,8 @@ jobs:
|
|||||||
bucketName=''
|
bucketName=''
|
||||||
|
|
||||||
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
||||||
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
|
# remove prefixing release/ and take the first string limited by - which is supposed to be name of the environment for releasing (format: release/testnet-trading)
|
||||||
|
envName="$(echo ${{ github.ref }} | sed -e "s|refs/heads/release/||" | cut -d '-' -f 1 )"
|
||||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||||
envName="stagnet1"
|
envName="stagnet1"
|
||||||
if [[ "${{ matrix.app }}" = "multisig-signer" ]]; then
|
if [[ "${{ matrix.app }}" = "multisig-signer" ]]; then
|
||||||
@@ -85,7 +118,7 @@ jobs:
|
|||||||
envName="mainnet"
|
envName="mainnet"
|
||||||
bucketName="ui.vega.rocks"
|
bucketName="ui.vega.rocks"
|
||||||
fi
|
fi
|
||||||
elif [[ "${{ github.ref }}" =~ .*main$ ]]; then
|
elif [[ "${{ github.ref }}" =~ .*mainnet$ ]]; then
|
||||||
envName="mainnet"
|
envName="mainnet"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -113,19 +146,19 @@ jobs:
|
|||||||
|
|
||||||
- name: Build local dist
|
- name: Build local dist
|
||||||
run: |
|
run: |
|
||||||
flags=""
|
envCmd=""
|
||||||
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
|
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
|
||||||
flags="--env=${{ env.ENV_NAME }}"
|
envCmd="yarn env-cmd -f ./apps/${{ matrix.app }}/.env.${{ env.ENV_NAME }}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${{ matrix.app }}" = "trading" ]; then
|
if [ "${{ matrix.app }}" = "trading" ]; then
|
||||||
yarn nx export trading $flags || (yarn install && yarn nx export trading $flags)
|
$envCmd yarn nx export trading || (yarn install && $envCmd yarn nx export trading)
|
||||||
DIST_LOCATION=dist/apps/trading/exported
|
DIST_LOCATION=dist/apps/trading/exported
|
||||||
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
||||||
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
||||||
DIST_LOCATION=dist/storybook/ui-toolkit
|
DIST_LOCATION=dist/storybook/ui-toolkit
|
||||||
else
|
else
|
||||||
yarn nx build ${{ matrix.app }} $flags || (yarn install && yarn nx build ${{ matrix.app }} $flags)
|
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
|
||||||
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
||||||
fi
|
fi
|
||||||
mv $DIST_LOCATION dist-result
|
mv $DIST_LOCATION dist-result
|
||||||
@@ -145,7 +178,7 @@ jobs:
|
|||||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||||
|
|
||||||
- name: Image digest
|
- name: Image digest
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ env.IS_PR == 'true' }}
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
|
||||||
- name: Sanity check docker image
|
- name: Sanity check docker image
|
||||||
@@ -160,7 +193,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
id: ghcr-push
|
id: ghcr-push
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ env.IS_PR == 'true' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -175,7 +208,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
id: dockerhub-push
|
id: dockerhub-push
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -185,7 +218,7 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr - retry)
|
- name: Publish dist as docker image (ghcr - retry)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
@@ -212,13 +245,13 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
||||||
|
|
||||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
||||||
- name: Publish dist to s3
|
- name: Publish dist to s3
|
||||||
uses: jakejarvis/s3-sync-action@master
|
uses: jakejarvis/s3-sync-action@master
|
||||||
# s3 releases are not happening for trading on mainnet - it's IPFS
|
# s3 releases are not happening for trading on mainnet - it's IPFS
|
||||||
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
|
if: ${{ env.IS_S3_RELASE == 'true' }}
|
||||||
with:
|
with:
|
||||||
args: --acl private --follow-symlinks --delete
|
args: --acl private --follow-symlinks --delete
|
||||||
env:
|
env:
|
||||||
@@ -228,18 +261,34 @@ jobs:
|
|||||||
AWS_REGION: 'eu-west-1'
|
AWS_REGION: 'eu-west-1'
|
||||||
SOURCE_DIR: 'dist-result'
|
SOURCE_DIR: 'dist-result'
|
||||||
|
|
||||||
|
- name: Install aws CLI
|
||||||
|
if: ${{ env.IS_S3_RELASE == 'true' }}
|
||||||
|
uses: unfor19/install-aws-cli-action@master
|
||||||
|
|
||||||
|
- name: Perform cache invalidation
|
||||||
|
if: ${{ env.IS_S3_RELASE == 'true' }}
|
||||||
|
env:
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
AWS_REGION: 'eu-west-1'
|
||||||
|
run: |
|
||||||
|
echo "Looking for distribution for bucket: ${{ env.BUCKET_NAME }}"
|
||||||
|
id=$(aws cloudfront list-distributions | jq -Mrc '.DistributionList.Items | .[] | select(.DefaultCacheBehavior.TargetOriginId == "${{ env.BUCKET_NAME }}") | .Id')
|
||||||
|
echo "Found id is: ${id}"
|
||||||
|
aws cloudfront create-invalidation --distribution-id $id --paths "/*"
|
||||||
|
|
||||||
- name: Add preview label
|
- name: Add preview label
|
||||||
uses: actions-ecosystem/action-add-labels@v1
|
uses: actions-ecosystem/action-add-labels@v1
|
||||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
if: ${{ env.IS_PR == 'true' }}
|
||||||
with:
|
with:
|
||||||
labels: ${{ matrix.app }}-preview
|
labels: ${{ matrix.app }}-preview
|
||||||
number: ${{ github.event.number }}
|
number: ${{ github.event.number }}
|
||||||
|
|
||||||
- name: Trigger fleek deployment
|
- name: Trigger fleek deployment
|
||||||
# release to ipfs happens only on mainnet (represented by main branch) for trading
|
# release to ipfs happens only on mainnet (represented by main branch) for trading
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
if echo ${{ github.ref }} | grep -q main; then
|
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
|
||||||
# display info about app
|
# display info about app
|
||||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
@@ -252,7 +301,7 @@ jobs:
|
|||||||
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
||||||
https://api.fleek.co/graphql
|
https://api.fleek.co/graphql
|
||||||
|
|
||||||
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
|
||||||
# display info about app
|
# display info about app
|
||||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
@@ -267,7 +316,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Check out ipfs-redirect
|
- name: Check out ipfs-redirect
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: 'vegaprotocol/ipfs-redirect'
|
repository: 'vegaprotocol/ipfs-redirect'
|
||||||
@@ -276,7 +325,7 @@ jobs:
|
|||||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Update interstitial page to point to the new console
|
- name: Update interstitial page to point to the new console
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
@@ -298,11 +347,11 @@ jobs:
|
|||||||
git config --global user.name "vega-ci-bot"
|
git config --global user.name "vega-ci-bot"
|
||||||
|
|
||||||
# update CID files
|
# update CID files
|
||||||
if echo ${{ github.ref }} | grep -q main; then
|
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
|
||||||
echo $new_hash > cidv0-mainnet.txt
|
echo $new_hash > cidv0-mainnet.txt
|
||||||
echo $new_cid > cidv1-mainnet.txt
|
echo $new_cid > cidv1-mainnet.txt
|
||||||
git add cidv0-mainnet.txt cidv1-mainnet.txt
|
git add cidv0-mainnet.txt cidv1-mainnet.txt
|
||||||
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
|
||||||
echo $new_hash > cidv0-fairground.txt
|
echo $new_hash > cidv0-fairground.txt
|
||||||
echo $new_cid > cidv1-fairground.txt
|
echo $new_cid > cidv1-fairground.txt
|
||||||
git add cidv0-fairground.txt cidv1-fairground.txt
|
git add cidv0-fairground.txt cidv1-fairground.txt
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
stories: [],
|
|
||||||
addons: [
|
|
||||||
'@storybook/addon-actions',
|
|
||||||
'@storybook/addon-viewport',
|
|
||||||
{
|
|
||||||
name: '@storybook/addon-docs',
|
|
||||||
options: {
|
|
||||||
configureJSX: true,
|
|
||||||
babelOptions: {},
|
|
||||||
sourceLoaderOptions: null,
|
|
||||||
transcludeMarkdown: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'@storybook/addon-controls',
|
|
||||||
'@storybook/addon-backgrounds',
|
|
||||||
'@storybook/addon-toolbars',
|
|
||||||
'@storybook/addon-measure',
|
|
||||||
'@storybook/addon-outline',
|
|
||||||
'@storybook/addon-a11y',
|
|
||||||
],
|
|
||||||
// uncomment the property below if you want to apply some webpack config globally
|
|
||||||
// webpackFinal: async (config, { configType }) => {
|
|
||||||
// // Make whatever fine-grained changes you need that should apply to all storybook configs
|
|
||||||
|
|
||||||
// // Return the altered config
|
|
||||||
// return config;
|
|
||||||
// },
|
|
||||||
};
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../tsconfig.base.json",
|
|
||||||
"exclude": [
|
|
||||||
"../**/*.spec.js",
|
|
||||||
"../**/*.test.js",
|
|
||||||
"../**/*.spec.ts",
|
|
||||||
"../**/*.test.ts",
|
|
||||||
"../**/*.spec.tsx",
|
|
||||||
"../**/*.test.tsx",
|
|
||||||
"../**/*.spec.jsx",
|
|
||||||
"../**/*.test.jsx"
|
|
||||||
],
|
|
||||||
"include": ["../**/*"]
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"name": "explorer-e2e",
|
||||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
"sourceRoot": "apps/explorer-e2e/src",
|
"sourceRoot": "apps/explorer-e2e/src",
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"targets": {
|
"targets": {
|
||||||
"e2e": {
|
"e2e": {
|
||||||
"executor": "@nrwl/cypress:cypress",
|
"executor": "@nx/cypress:cypress",
|
||||||
"options": {
|
"options": {
|
||||||
"cypressConfig": "apps/explorer-e2e/cypress.config.js",
|
"cypressConfig": "apps/explorer-e2e/cypress.config.js",
|
||||||
"devServerTarget": "explorer:serve"
|
"devServerTarget": "explorer:serve"
|
||||||
@@ -16,14 +17,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nrwl/linter:eslint",
|
"executor": "@nx/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "@nrwl/workspace:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"options": {
|
"options": {
|
||||||
"command": "yarn tsc --project ./apps/explorer-e2e/"
|
"command": "yarn tsc --project ./apps/explorer-e2e/"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ context('Asset page', { tags: '@regression' }, () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should open details page when clicked on "View details"', () => {
|
it.skip('should open details page when clicked on "View details"', () => {
|
||||||
cy.getAssets().then((assets) => {
|
cy.getAssets().then((assets) => {
|
||||||
assets.forEach((asset) => {
|
assets.forEach((asset) => {
|
||||||
cy.get(`[row-id="${asset.id}"] [col-id="actions"] button`)
|
cy.get(`[row-id="${asset.id}"] [col-id="actions"] button`)
|
||||||
|
|||||||
@@ -169,7 +169,6 @@ context.skip('Parties page', { tags: '@regression' }, function () {
|
|||||||
const jsonFields = '.hljs';
|
const jsonFields = '.hljs';
|
||||||
const sideMenuBackground = '.absolute';
|
const sideMenuBackground = '.absolute';
|
||||||
|
|
||||||
// Engage dark mode if not allready set
|
|
||||||
cy.get(sideMenuBackground)
|
cy.get(sideMenuBackground)
|
||||||
.should('have.css', 'background-color')
|
.should('have.css', 'background-color')
|
||||||
.then((background_color) => {
|
.then((background_color) => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
[
|
[
|
||||||
"@nrwl/react/babel",
|
"@nx/react/babel",
|
||||||
{
|
{
|
||||||
"runtime": "automatic"
|
"runtime": "automatic"
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
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_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
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
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
|
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
|
||||||
NX_VEGA_TOKEN_URL=https://governance.stagnet1.vega.rocks
|
NX_VEGA_TOKEN_URL=https://governance.stagnet1.vega.rocks
|
||||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz
|
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.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.rocks/rest
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
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
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/tm
|
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||||
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
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||||
|
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
||||||
|
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
||||||
|
NX_VEGA_ENV=MAINNET-MIRROR
|
||||||
|
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_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
|
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
||||||
|
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
||||||
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
|
"ignorePatterns": ["!**/*", "__generated__"],
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ yarn nx serve explorer
|
|||||||
Example configurations are provided here:
|
Example configurations are provided here:
|
||||||
|
|
||||||
- [Mainnet](./.env.mainnet)
|
- [Mainnet](./.env.mainnet)
|
||||||
|
- [Mainnet-mirror](./.env.mainnet-mirror)
|
||||||
- [Devnet](./.env.devnet)
|
- [Devnet](./.env.devnet)
|
||||||
- [Capsule](./.env.capsule)
|
- [Capsule](./.env.capsule)
|
||||||
- [Testnet](./.env.testnet)
|
- [Testnet](./.env.testnet)
|
||||||
@@ -39,7 +40,7 @@ Example configurations are provided here:
|
|||||||
For convenience, you can boot the app injecting one of the configurations above by running:
|
For convenience, you can boot the app injecting one of the configurations above by running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn nx run explorer:serve --env={env} # e.g. stagnet1
|
yarn env-cmd -f .\apps\explorer\.env.{env} yarn nx run explorer:serve # e.g. stagnet1
|
||||||
```
|
```
|
||||||
|
|
||||||
There are a few different configuration options offered for this app:
|
There are a few different configuration options offered for this app:
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ export default {
|
|||||||
displayName: 'explorer',
|
displayName: 'explorer',
|
||||||
preset: '../../jest.preset.js',
|
preset: '../../jest.preset.js',
|
||||||
transform: {
|
transform: {
|
||||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
|
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
||||||
'^.+\\.[tj]sx?$': 'babel-jest',
|
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
|
||||||
},
|
},
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||||
coverageDirectory: '../../coverage/apps/explorer',
|
coverageDirectory: '../../coverage/apps/explorer',
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"name": "explorer",
|
||||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
"sourceRoot": "apps/explorer/src",
|
"sourceRoot": "apps/explorer/src",
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"targets": {
|
"targets": {
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "./tools/executors/webpack:build",
|
"executor": "@nx/webpack:webpack",
|
||||||
"outputs": ["{options.outputPath}"],
|
"outputs": ["{options.outputPath}"],
|
||||||
"defaultConfiguration": "production",
|
"defaultConfiguration": "production",
|
||||||
"options": {
|
"options": {
|
||||||
@@ -38,7 +39,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"serve": {
|
"serve": {
|
||||||
"executor": "./tools/executors/webpack:serve",
|
"executor": "@nx/webpack:dev-server",
|
||||||
"options": {
|
"options": {
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"buildTarget": "explorer:build:development",
|
"buildTarget": "explorer:build:development",
|
||||||
@@ -52,30 +53,36 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nrwl/linter:eslint",
|
"executor": "@nx/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
"executor": "@nrwl/jest:jest",
|
"executor": "@nx/jest:jest",
|
||||||
"outputs": ["coverage/apps/explorer"],
|
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
||||||
"options": {
|
"options": {
|
||||||
"jestConfig": "apps/explorer/jest.config.ts",
|
"jestConfig": "apps/explorer/jest.config.ts",
|
||||||
"passWithNoTests": true
|
"passWithNoTests": true
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"ci": {
|
||||||
|
"ci": true,
|
||||||
|
"codeCoverage": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generate-types": {
|
"generate-types": {
|
||||||
"executor": "@nrwl/workspace:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.71.4/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/spec-update-v0.72.0-preview.2/specs/v0.72.0-preview.2/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build-netlify": {
|
"build-netlify": {
|
||||||
"executor": "@nrwl/workspace:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
"cp apps/explorer/netlify.toml netlify.toml",
|
"cp apps/explorer/netlify.toml netlify.toml",
|
||||||
@@ -84,7 +91,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build-spec": {
|
"build-spec": {
|
||||||
"executor": "@nrwl/workspace:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"options": {
|
"options": {
|
||||||
"command": "yarn tsc --project ./apps/explorer/tsconfig.spec.json"
|
"command": "yarn tsc --project ./apps/explorer/tsconfig.spec.json"
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||||
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
import { AssetTypeMapping, AssetStatusMapping } 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 { AgGridColumn } from 'ag-grid-react';
|
|
||||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridLazy as 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 } from 'ag-grid-community';
|
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
||||||
|
|
||||||
type AssetsTableProps = {
|
type AssetsTableProps = {
|
||||||
data: AssetFieldsFragment[] | null;
|
data: AssetFieldsFragment[] | null;
|
||||||
@@ -31,6 +31,58 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const columnDefs = useMemo<ColDef[]>(
|
||||||
|
() => [
|
||||||
|
{ headerName: t('Symbol'), field: 'symbol' },
|
||||||
|
{ headerName: t('Name'), field: 'name' },
|
||||||
|
{
|
||||||
|
flex: 2,
|
||||||
|
headerName: t('ID'),
|
||||||
|
field: 'id',
|
||||||
|
hide: window.innerWidth < BREAKPOINT_MD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'type',
|
||||||
|
headerName: t('Type'),
|
||||||
|
field: 'source.__typename',
|
||||||
|
hide: window.innerWidth < BREAKPOINT_MD,
|
||||||
|
valueFormatter: ({ value }: { value?: string }) =>
|
||||||
|
value ? AssetTypeMapping[value].value : '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: t('Status'),
|
||||||
|
field: 'status',
|
||||||
|
hide: window.innerWidth < BREAKPOINT_MD,
|
||||||
|
valueFormatter: ({ value }: { value?: string }) =>
|
||||||
|
value ? AssetStatusMapping[value].value : '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'actions',
|
||||||
|
headerName: '',
|
||||||
|
sortable: false,
|
||||||
|
filter: false,
|
||||||
|
resizable: false,
|
||||||
|
wrapText: true,
|
||||||
|
field: 'id',
|
||||||
|
cellRenderer: ({
|
||||||
|
value,
|
||||||
|
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
||||||
|
value ? (
|
||||||
|
<ButtonLink
|
||||||
|
onClick={(e) => {
|
||||||
|
navigate(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('View details')}
|
||||||
|
</ButtonLink>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[navigate]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AgGrid
|
<AgGrid
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@@ -46,60 +98,11 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
filterParams: { buttons: ['reset'] },
|
filterParams: { buttons: ['reset'] },
|
||||||
autoHeight: true,
|
autoHeight: true,
|
||||||
}}
|
}}
|
||||||
|
columnDefs={columnDefs}
|
||||||
suppressCellFocus={true}
|
suppressCellFocus={true}
|
||||||
onRowClicked={({ data }: RowClickedEvent) => {
|
onRowClicked={({ data }: RowClickedEvent) => {
|
||||||
navigate(data.id);
|
navigate(data.id);
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<AgGridColumn headerName={t('Symbol')} field="symbol" />
|
|
||||||
<AgGridColumn headerName={t('Name')} field="name" />
|
|
||||||
<AgGridColumn
|
|
||||||
flex="2"
|
|
||||||
headerName={t('ID')}
|
|
||||||
field="id"
|
|
||||||
hide={window.innerWidth < BREAKPOINT_MD}
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
colId="type"
|
|
||||||
headerName={t('Type')}
|
|
||||||
field="source.__typename"
|
|
||||||
hide={window.innerWidth < BREAKPOINT_MD}
|
|
||||||
valueFormatter={({ value }: { value?: string }) =>
|
|
||||||
value && AssetTypeMapping[value].value
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
headerName={t('Status')}
|
|
||||||
field="status"
|
|
||||||
hide={window.innerWidth < BREAKPOINT_MD}
|
|
||||||
valueFormatter={({ value }: { value?: string }) =>
|
|
||||||
value && AssetStatusMapping[value].value
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
colId="actions"
|
|
||||||
headerName=""
|
|
||||||
sortable={false}
|
|
||||||
filter={false}
|
|
||||||
resizable={false}
|
|
||||||
wrapText={true}
|
|
||||||
field="id"
|
|
||||||
cellRenderer={({
|
|
||||||
value,
|
|
||||||
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
|
||||||
value ? (
|
|
||||||
<ButtonLink
|
|
||||||
onClick={(e) => {
|
|
||||||
navigate(value);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('View details')}
|
|
||||||
</ButtonLink>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</AgGrid>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export interface InfoBlockProps {
|
export interface InfoBlockProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -1,33 +1,98 @@
|
|||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import PartyLink from './party-link';
|
import PartyLink from './party-link';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { ExplorerNodeNamesDocument } from '../../../routes/validators/__generated__/NodeNames';
|
||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
|
const zeroes =
|
||||||
|
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
|
const mocks = [
|
||||||
|
{
|
||||||
|
request: {
|
||||||
|
query: ExplorerNodeNamesDocument,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
nodesConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '1',
|
||||||
|
name: 'Validator Node',
|
||||||
|
pubkey:
|
||||||
|
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e',
|
||||||
|
tmPubkey: 'tmPubkey1',
|
||||||
|
ethereumAddress: '0x123456789',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '2',
|
||||||
|
name: 'Node 2',
|
||||||
|
pubkey: 'pubkey2',
|
||||||
|
tmPubkey: 'tmPubkey2',
|
||||||
|
ethereumAddress: '0xabcdef123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
describe('PartyLink', () => {
|
describe('PartyLink', () => {
|
||||||
it('renders Network for 000.000 party', () => {
|
it('renders Network for 000.000 party', () => {
|
||||||
const zeroes =
|
const screen = render(
|
||||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
<MockedProvider>
|
||||||
const screen = render(<PartyLink id={zeroes} />);
|
<PartyLink id={zeroes} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
expect(screen.getByText('Network')).toBeInTheDocument();
|
expect(screen.getByText('Network')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders Network for network party', () => {
|
it('renders Network for network party', () => {
|
||||||
const screen = render(<PartyLink id="network" />);
|
const screen = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<PartyLink id="network" />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
expect(screen.getByText('Network')).toBeInTheDocument();
|
expect(screen.getByText('Network')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders ID with no link for invalid party', () => {
|
it('renders ID with no link for invalid party', () => {
|
||||||
const screen = render(<PartyLink id="this-party-is-not-valid" />);
|
const screen = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<PartyLink id="this-party-is-not-valid" />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
expect(screen.getByTestId('invalid-party')).toBeInTheDocument();
|
expect(screen.getByTestId('invalid-party')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('if the key is a validator, render their name instead', async () => {
|
||||||
|
const screen = render(
|
||||||
|
<MockedProvider mocks={mocks}>
|
||||||
|
<MemoryRouter>
|
||||||
|
<PartyLink id="13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e" />
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wait for hook to update with mock data
|
||||||
|
await act(() => new Promise((resolve) => setTimeout(resolve, 0)));
|
||||||
|
await expect(screen.getByText('Validator Node')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('links a valid party to the party page', () => {
|
it('links a valid party to the party page', () => {
|
||||||
const aValidParty =
|
const aValidParty =
|
||||||
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e';
|
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e';
|
||||||
|
|
||||||
const screen = render(
|
const screen = render(
|
||||||
<MemoryRouter>
|
<MockedProvider>
|
||||||
<PartyLink id={aValidParty} />
|
<MemoryRouter>
|
||||||
</MemoryRouter>
|
<PartyLink id={aValidParty} />
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
const el = screen.getByText(aValidParty);
|
const el = screen.getByText(aValidParty);
|
||||||
|
|||||||
@@ -1,22 +1,44 @@
|
|||||||
import { Routes } from '../../../routes/route-names';
|
import { Routes } from '../../../routes/route-names';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import type { ComponentProps } from 'react';
|
import { useMemo, type ComponentProps } from 'react';
|
||||||
import Hash from '../hash';
|
import Hash from '../hash';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { isValidPartyId } from '../../../routes/parties/id/components/party-id-error';
|
import { isValidPartyId } from '../../../routes/parties/id/components/party-id-error';
|
||||||
import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
import { Icon, truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
|
||||||
|
import type { ExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
|
||||||
|
|
||||||
export const SPECIAL_CASE_NETWORK_ID =
|
export const SPECIAL_CASE_NETWORK_ID =
|
||||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
export const SPECIAL_CASE_NETWORK = 'network';
|
export const SPECIAL_CASE_NETWORK = 'network';
|
||||||
|
|
||||||
|
export function getNameForParty(id: string, data?: ExplorerNodeNamesQuery) {
|
||||||
|
if (!data || data?.nodesConnection?.edges?.length === 0) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validator = data.nodesConnection.edges?.find((e) => {
|
||||||
|
return e?.node.pubkey === id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (validator) {
|
||||||
|
return validator.node.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
export type PartyLinkProps = Partial<ComponentProps<typeof Link>> & {
|
export type PartyLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||||
id: string;
|
id: string;
|
||||||
truncate?: boolean;
|
truncate?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
||||||
|
const { data } = useExplorerNodeNamesQuery();
|
||||||
|
const name = useMemo(() => getNameForParty(id, data), [data, id]);
|
||||||
|
const useName = name !== id;
|
||||||
|
|
||||||
// Some transactions will involve the 'network' party, which is alias for '000...000'
|
// Some transactions will involve the 'network' party, which is alias for '000...000'
|
||||||
// The party page does not handle this nicely, so in this case we render the word 'Network'
|
// The party page does not handle this nicely, so in this case we render the word 'Network'
|
||||||
if (id === SPECIAL_CASE_NETWORK || id === SPECIAL_CASE_NETWORK_ID) {
|
if (id === SPECIAL_CASE_NETWORK || id === SPECIAL_CASE_NETWORK_ID) {
|
||||||
@@ -38,13 +60,20 @@ const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<span className="whitespace-nowrap">
|
||||||
className="underline font-mono"
|
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
||||||
{...props}
|
<Link
|
||||||
to={`/${Routes.PARTIES}/${id}`}
|
className="underline font-mono"
|
||||||
>
|
{...props}
|
||||||
<Hash text={truncate ? truncateMiddle(id) : id} />
|
to={`/${Routes.PARTIES}/${id}`}
|
||||||
</Link>
|
>
|
||||||
|
{useName ? (
|
||||||
|
name
|
||||||
|
) : (
|
||||||
|
<Hash text={truncate ? truncateMiddle(id, 4, 4) : id} />
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
import type { MarketFieldsFragment } from '@vegaprotocol/markets';
|
import 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 { AgGridColumn } from 'ag-grid-react';
|
import type { ColDef } from 'ag-grid-community';
|
||||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type {
|
import type {
|
||||||
VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
@@ -39,54 +40,34 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
const columnDefs = useMemo<ColDef[]>(
|
||||||
<AgGrid
|
() => [
|
||||||
ref={gridRef}
|
{
|
||||||
rowData={data}
|
colId: 'code',
|
||||||
getRowId={({ data }: { data: MarketFieldsFragment }) => data.id}
|
headerName: t('Code'),
|
||||||
overlayNoRowsTemplate={t('This chain has no markets')}
|
field: 'tradableInstrument.instrument.code',
|
||||||
domLayout="autoHeight"
|
},
|
||||||
defaultColDef={{
|
{
|
||||||
flex: 1,
|
colId: 'name',
|
||||||
resizable: true,
|
headerName: t('Name'),
|
||||||
sortable: true,
|
field: 'tradableInstrument.instrument.name',
|
||||||
filter: true,
|
},
|
||||||
filterParams: { buttons: ['reset'] },
|
{
|
||||||
autoHeight: true,
|
headerName: t('Status'),
|
||||||
}}
|
field: 'state',
|
||||||
suppressCellFocus={true}
|
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||||
onRowClicked={({ data, event }: RowClickedEvent) => {
|
valueGetter: ({
|
||||||
if ((event?.target as HTMLElement).tagName.toUpperCase() !== 'BUTTON') {
|
|
||||||
navigate(data.id);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<AgGridColumn
|
|
||||||
colId="code"
|
|
||||||
headerName={t('Code')}
|
|
||||||
field="tradableInstrument.instrument.code"
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
colId="name"
|
|
||||||
headerName={t('Name')}
|
|
||||||
field="tradableInstrument.instrument.name"
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
headerName={t('Status')}
|
|
||||||
field="state"
|
|
||||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
|
||||||
valueGetter={({
|
|
||||||
data,
|
data,
|
||||||
}: VegaValueGetterParams<MarketFieldsFragment>) => {
|
}: VegaValueGetterParams<MarketFieldsFragment>) => {
|
||||||
return data?.state ? MarketStateMapping[data?.state] : '-';
|
return data?.state ? MarketStateMapping[data?.state] : '-';
|
||||||
}}
|
},
|
||||||
/>
|
},
|
||||||
<AgGridColumn
|
{
|
||||||
colId="asset"
|
colId: 'asset',
|
||||||
headerName={t('Settlement asset')}
|
headerName: t('Settlement asset'),
|
||||||
field="tradableInstrument.instrument.product.settlementAsset.symbol"
|
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||||
cellRenderer={({
|
cellRenderer: ({
|
||||||
data,
|
data,
|
||||||
}: VegaICellRendererParams<
|
}: VegaICellRendererParams<
|
||||||
MarketFieldsFragment,
|
MarketFieldsFragment,
|
||||||
@@ -105,19 +86,19 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
) : (
|
) : (
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
}}
|
},
|
||||||
/>
|
},
|
||||||
<AgGridColumn
|
{
|
||||||
flex={2}
|
flex: 2,
|
||||||
headerName={t('Market ID')}
|
headerName: t('Market ID'),
|
||||||
field="id"
|
field: 'id',
|
||||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||||
/>
|
},
|
||||||
<AgGridColumn
|
{
|
||||||
colId="actions"
|
colId: 'actions',
|
||||||
headerName=""
|
headerName: '',
|
||||||
field="id"
|
field: 'id',
|
||||||
cellRenderer={({
|
cellRenderer: ({
|
||||||
value,
|
value,
|
||||||
}: VegaICellRendererParams<MarketFieldsFragment, 'id'>) =>
|
}: VegaICellRendererParams<MarketFieldsFragment, 'id'>) =>
|
||||||
value ? (
|
value ? (
|
||||||
@@ -126,9 +107,34 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
''
|
''
|
||||||
)
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[openAssetDetailsDialog]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AgGrid
|
||||||
|
ref={gridRef}
|
||||||
|
rowData={data}
|
||||||
|
getRowId={({ data }: { data: MarketFieldsFragment }) => data.id}
|
||||||
|
overlayNoRowsTemplate={t('This chain has no markets')}
|
||||||
|
domLayout="autoHeight"
|
||||||
|
defaultColDef={{
|
||||||
|
flex: 1,
|
||||||
|
resizable: true,
|
||||||
|
sortable: true,
|
||||||
|
filter: true,
|
||||||
|
filterParams: { buttons: ['reset'] },
|
||||||
|
autoHeight: true,
|
||||||
|
}}
|
||||||
|
columnDefs={columnDefs}
|
||||||
|
suppressCellFocus={true}
|
||||||
|
onRowClicked={({ data, event }: RowClickedEvent) => {
|
||||||
|
if ((event?.target as HTMLElement).tagName.toUpperCase() !== 'BUTTON') {
|
||||||
|
navigate(data.id);
|
||||||
}
|
}
|
||||||
/>
|
}}
|
||||||
</AgGrid>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ fragment ExplorerDeterministicOrderFields on Order {
|
|||||||
remaining
|
remaining
|
||||||
size
|
size
|
||||||
rejectionReason
|
rejectionReason
|
||||||
|
peggedOrder {
|
||||||
|
reference
|
||||||
|
offset
|
||||||
|
}
|
||||||
party {
|
party {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } };
|
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } };
|
||||||
|
|
||||||
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
||||||
orderId: Types.Scalars['ID'];
|
orderId: Types.Scalars['ID'];
|
||||||
@@ -11,7 +11,7 @@ export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } } };
|
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } } };
|
||||||
|
|
||||||
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
||||||
fragment ExplorerDeterministicOrderFields on Order {
|
fragment ExplorerDeterministicOrderFields on Order {
|
||||||
@@ -29,6 +29,10 @@ export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
|||||||
remaining
|
remaining
|
||||||
size
|
size
|
||||||
rejectionReason
|
rejectionReason
|
||||||
|
peggedOrder {
|
||||||
|
reference
|
||||||
|
offset
|
||||||
|
}
|
||||||
party {
|
party {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type Amend = components['schemas']['v1OrderAmendment'];
|
|||||||
|
|
||||||
function renderAmendOrderDetails(
|
function renderAmendOrderDetails(
|
||||||
id: string,
|
id: string,
|
||||||
version: number,
|
version: number | undefined,
|
||||||
amend: Amend,
|
amend: Amend,
|
||||||
mocks: MockedResponse[]
|
mocks: MockedResponse[]
|
||||||
) {
|
) {
|
||||||
@@ -25,7 +25,11 @@ function renderAmendOrderDetails(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderExistingAmend(id: string, version: number, amend: Amend) {
|
function renderExistingAmend(
|
||||||
|
id: string,
|
||||||
|
version: number | undefined,
|
||||||
|
amend: Amend
|
||||||
|
) {
|
||||||
const mocks = [
|
const mocks = [
|
||||||
{
|
{
|
||||||
request: {
|
request: {
|
||||||
@@ -49,6 +53,7 @@ function renderExistingAmend(id: string, version: number, amend: Amend) {
|
|||||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||||
price: '200',
|
price: '200',
|
||||||
side: 'BUY',
|
side: 'BUY',
|
||||||
|
peggedOrder: null,
|
||||||
remaining: '99',
|
remaining: '99',
|
||||||
rejectionReason: 'rejection',
|
rejectionReason: 'rejection',
|
||||||
reference: '123',
|
reference: '123',
|
||||||
@@ -77,6 +82,56 @@ function renderExistingAmend(id: string, version: number, amend: Amend) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
request: {
|
||||||
|
query: ExplorerDeterministicOrderDocument,
|
||||||
|
variables: {
|
||||||
|
orderId: '123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
orderByID: {
|
||||||
|
__typename: 'Order',
|
||||||
|
id: '123',
|
||||||
|
type: 'GTT',
|
||||||
|
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||||
|
version: 100,
|
||||||
|
createdAt: '123',
|
||||||
|
updatedAt: '456',
|
||||||
|
expiresAt: '789',
|
||||||
|
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||||
|
peggedOrder: null,
|
||||||
|
price: '200',
|
||||||
|
side: 'BUY',
|
||||||
|
remaining: '99',
|
||||||
|
rejectionReason: 'rejection',
|
||||||
|
reference: '123',
|
||||||
|
size: '200',
|
||||||
|
party: {
|
||||||
|
__typename: 'Party',
|
||||||
|
id: '234',
|
||||||
|
},
|
||||||
|
market: {
|
||||||
|
__typename: 'Market',
|
||||||
|
id: 'amend-to-order-latest-version',
|
||||||
|
state: 'STATUS_ACTIVE',
|
||||||
|
positionDecimalPlaces: 2,
|
||||||
|
decimalPlaces: '5',
|
||||||
|
tradableInstrument: {
|
||||||
|
instrument: {
|
||||||
|
name: 'amend-to-order-latest-version-test',
|
||||||
|
product: {
|
||||||
|
__typename: 'Future',
|
||||||
|
quoteName: '123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerMarketDocument,
|
query: ExplorerMarketDocument,
|
||||||
@@ -157,4 +212,15 @@ describe('Amend order details', () => {
|
|||||||
expect(await res.findByText('New price')).toBeInTheDocument();
|
expect(await res.findByText('New price')).toBeInTheDocument();
|
||||||
expect(await res.findByText('-7879')).toBeInTheDocument();
|
expect(await res.findByText('-7879')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Fetches latest version when version is not specified', async () => {
|
||||||
|
const amend: Amend = {
|
||||||
|
price: '-7879',
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderExistingAmend('123', undefined, amend);
|
||||||
|
expect(
|
||||||
|
await res.findByText('amend-to-order-latest-version')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { wrapperClasses } from './deterministic-order-details';
|
|||||||
export interface AmendOrderDetailsProps {
|
export interface AmendOrderDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
amend: components['schemas']['v1OrderAmendment'];
|
amend: components['schemas']['v1OrderAmendment'];
|
||||||
// Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0
|
// Version to fetch. Latest is provided by default
|
||||||
version?: number;
|
version?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,13 +34,11 @@ export function getSideDeltaColour(delta: string): string {
|
|||||||
* @param param0
|
* @param param0
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const AmendOrderDetails = ({
|
const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
||||||
id,
|
const variables = version ? { orderId: id, version } : { orderId: id };
|
||||||
version = 0,
|
|
||||||
amend,
|
|
||||||
}: AmendOrderDetailsProps) => {
|
|
||||||
const { data, error } = useExplorerDeterministicOrderQuery({
|
const { data, error } = useExplorerDeterministicOrderQuery({
|
||||||
variables: { orderId: id, version },
|
variables,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error || (data && !data.orderByID)) {
|
if (error || (data && !data.orderByID)) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import PriceInMarket from '../price-in-market/price-in-market';
|
|||||||
import { Time } from '../time';
|
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';
|
||||||
|
|
||||||
export interface DeterministicOrderDetailsProps {
|
export interface DeterministicOrderDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -68,25 +69,35 @@ 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-500 mb-4">
|
<p className="text-gray-200">
|
||||||
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 ? (
|
||||||
|
<p className="text-gray-200">
|
||||||
|
{t('Price peg')}:{' '}
|
||||||
|
<TxOrderPeggedReference
|
||||||
|
side={o.side}
|
||||||
|
reference={o.peggedOrder.reference}
|
||||||
|
offset={o.peggedOrder.offset}
|
||||||
|
marketId={o.market.id}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{o.reference ? (
|
{o.reference ? (
|
||||||
<p className="text-gray-500 mb-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">
|
<div className="grid md:grid-cols-4 gap-x-6 mt-4">
|
||||||
{version !== 0 ? null : (
|
<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-2xl font-bold text-dark 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">
|
{statusText[o.status]}
|
||||||
{statusText[o.status]}
|
</h5>
|
||||||
</h5>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="mb-12 md:mb-0">
|
<div className="mb-12 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-4">{t('Size')}</h2>
|
||||||
@@ -95,17 +106,6 @@ const DeterministicOrderDetails = ({
|
|||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{version !== 0 ? null : (
|
|
||||||
<div className="">
|
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
|
||||||
{t('Remaining')}
|
|
||||||
</h2>
|
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
|
||||||
<SizeInMarket size={o.remaining} marketId={o.market.id} />
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('Version')}
|
{t('Version')}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ const mock = {
|
|||||||
side: 'SIDE_BUY',
|
side: 'SIDE_BUY',
|
||||||
remaining: '100',
|
remaining: '100',
|
||||||
size: '100',
|
size: '100',
|
||||||
|
peggedOrder: null,
|
||||||
party: {
|
party: {
|
||||||
id: '456',
|
id: '456',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
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 { AgGridColumn } from 'ag-grid-react';
|
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type {
|
import type {
|
||||||
@@ -9,7 +8,7 @@ import type {
|
|||||||
VegaValueFormatterParams,
|
VegaValueFormatterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import type { RowClickedEvent } from 'ag-grid-community';
|
import type { RowClickedEvent, ColDef } 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 {
|
||||||
@@ -64,7 +63,128 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
title: '',
|
title: '',
|
||||||
content: null,
|
content: null,
|
||||||
});
|
});
|
||||||
|
const columnDefs = useMemo<ColDef[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
colId: 'title',
|
||||||
|
headerName: t('Title'),
|
||||||
|
field: 'rationale.title',
|
||||||
|
flex: 2,
|
||||||
|
wrapText: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'type',
|
||||||
|
maxWidth: 180,
|
||||||
|
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||||
|
headerName: t('Type'),
|
||||||
|
field: 'terms.change.__typename',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
maxWidth: 100,
|
||||||
|
headerName: t('State'),
|
||||||
|
field: 'state',
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) => {
|
||||||
|
return value ? ProposalStateMapping[value] : '-';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'voting',
|
||||||
|
maxWidth: 100,
|
||||||
|
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||||
|
headerName: t('Voting'),
|
||||||
|
cellRenderer: ({
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
||||||
|
if (data) {
|
||||||
|
const yesTokens = new BigNumber(data.votes.yes.totalTokens);
|
||||||
|
const noTokens = new BigNumber(data.votes.no.totalTokens);
|
||||||
|
const totalTokensVoted = yesTokens.plus(noTokens);
|
||||||
|
const yesPercentage = totalTokensVoted.isZero()
|
||||||
|
? new BigNumber(0)
|
||||||
|
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||||
|
return (
|
||||||
|
<div className="uppercase flex h-full items-center justify-center pt-2">
|
||||||
|
<VoteProgress
|
||||||
|
threshold={requiredMajorityPercentage}
|
||||||
|
progress={yesPercentage}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return '-';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'cDate',
|
||||||
|
maxWidth: 150,
|
||||||
|
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||||
|
headerName: t('Closing date'),
|
||||||
|
field: 'terms.closingDatetime',
|
||||||
|
valueFormatter: ({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<
|
||||||
|
ProposalListFieldsFragment,
|
||||||
|
'terms.closingDatetime'
|
||||||
|
>) => {
|
||||||
|
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'eDate',
|
||||||
|
maxWidth: 150,
|
||||||
|
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||||
|
headerName: t('Enactment date'),
|
||||||
|
field: 'terms.enactmentDatetime',
|
||||||
|
valueFormatte: ({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<
|
||||||
|
ProposalListFieldsFragment,
|
||||||
|
'terms.enactmentDatetime'
|
||||||
|
>) => {
|
||||||
|
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colId: 'actions',
|
||||||
|
minWidth: window.innerWidth > BREAKPOINT_MD ? 221 : 80,
|
||||||
|
maxWidth: 221,
|
||||||
|
sortable: false,
|
||||||
|
filter: false,
|
||||||
|
resizable: false,
|
||||||
|
cellRenderer: ({
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
||||||
|
const proposalPage = tokenLink(
|
||||||
|
TOKEN_PROPOSAL.replace(':id', data?.id || '')
|
||||||
|
);
|
||||||
|
const openDialog = () => {
|
||||||
|
if (!data) return;
|
||||||
|
setDialog({
|
||||||
|
open: true,
|
||||||
|
title: data.rationale.title,
|
||||||
|
content: data.terms,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="pb-1">
|
||||||
|
<button className="underline max-md:hidden" onClick={openDialog}>
|
||||||
|
{t('View terms')}
|
||||||
|
</button>{' '}
|
||||||
|
<ExternalLink className="max-md:hidden" href={proposalPage}>
|
||||||
|
{t('Open in Governance')}
|
||||||
|
</ExternalLink>
|
||||||
|
<ExternalLink className="md:hidden" href={proposalPage}>
|
||||||
|
{t('Open')}
|
||||||
|
</ExternalLink>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[requiredMajorityPercentage, tokenLink]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AgGrid
|
<AgGrid
|
||||||
@@ -83,6 +203,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
filterParams: { buttons: ['reset'] },
|
filterParams: { buttons: ['reset'] },
|
||||||
autoHeight: true,
|
autoHeight: true,
|
||||||
}}
|
}}
|
||||||
|
columnDefs={columnDefs}
|
||||||
suppressCellFocus={true}
|
suppressCellFocus={true}
|
||||||
onRowClicked={({ data, event }: RowClickedEvent) => {
|
onRowClicked={({ data, event }: RowClickedEvent) => {
|
||||||
if (
|
if (
|
||||||
@@ -94,128 +215,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
window.open(proposalPage, '_blank');
|
window.open(proposalPage, '_blank');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<AgGridColumn
|
|
||||||
colId="title"
|
|
||||||
headerName={t('Title')}
|
|
||||||
field="rationale.title"
|
|
||||||
flex={2}
|
|
||||||
wrapText={true}
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
colId="type"
|
|
||||||
maxWidth={180}
|
|
||||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
|
||||||
headerName={t('Type')}
|
|
||||||
field="terms.change.__typename"
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
maxWidth={100}
|
|
||||||
headerName={t('State')}
|
|
||||||
field="state"
|
|
||||||
valueFormatter={({
|
|
||||||
value,
|
|
||||||
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) => {
|
|
||||||
return value ? ProposalStateMapping[value] : '-';
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
colId="voting"
|
|
||||||
maxWidth={100}
|
|
||||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
|
||||||
headerName={t('Voting')}
|
|
||||||
cellRenderer={({
|
|
||||||
data,
|
|
||||||
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
|
||||||
if (data) {
|
|
||||||
const yesTokens = new BigNumber(data.votes.yes.totalTokens);
|
|
||||||
const noTokens = new BigNumber(data.votes.no.totalTokens);
|
|
||||||
const totalTokensVoted = yesTokens.plus(noTokens);
|
|
||||||
const yesPercentage = totalTokensVoted.isZero()
|
|
||||||
? new BigNumber(0)
|
|
||||||
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
|
||||||
return (
|
|
||||||
<div className="uppercase flex h-full items-center justify-center pt-2">
|
|
||||||
<VoteProgress
|
|
||||||
threshold={requiredMajorityPercentage}
|
|
||||||
progress={yesPercentage}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return '-';
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
colId="cDate"
|
|
||||||
maxWidth={150}
|
|
||||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
|
||||||
headerName={t('Closing date')}
|
|
||||||
field="terms.closingDatetime"
|
|
||||||
valueFormatter={({
|
|
||||||
value,
|
|
||||||
}: VegaValueFormatterParams<
|
|
||||||
ProposalListFieldsFragment,
|
|
||||||
'terms.closingDatetime'
|
|
||||||
>) => {
|
|
||||||
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
colId="eDate"
|
|
||||||
maxWidth={150}
|
|
||||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
|
||||||
headerName={t('Enactment date')}
|
|
||||||
field="terms.enactmentDatetime"
|
|
||||||
valueFormatter={({
|
|
||||||
value,
|
|
||||||
}: VegaValueFormatterParams<
|
|
||||||
ProposalListFieldsFragment,
|
|
||||||
'terms.enactmentDatetime'
|
|
||||||
>) => {
|
|
||||||
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<AgGridColumn
|
|
||||||
colId="actions"
|
|
||||||
minWidth={window.innerWidth > BREAKPOINT_MD ? 221 : 80}
|
|
||||||
maxWidth={221}
|
|
||||||
sortable={false}
|
|
||||||
filter={false}
|
|
||||||
resizable={false}
|
|
||||||
cellRenderer={({
|
|
||||||
data,
|
|
||||||
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
|
||||||
const proposalPage = tokenLink(
|
|
||||||
TOKEN_PROPOSAL.replace(':id', data?.id || '')
|
|
||||||
);
|
|
||||||
const openDialog = () => {
|
|
||||||
if (!data) return;
|
|
||||||
setDialog({
|
|
||||||
open: true,
|
|
||||||
title: data.rationale.title,
|
|
||||||
content: data.terms,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="pb-1">
|
|
||||||
<button
|
|
||||||
className="underline max-md:hidden"
|
|
||||||
onClick={openDialog}
|
|
||||||
>
|
|
||||||
{t('View terms')}
|
|
||||||
</button>{' '}
|
|
||||||
<ExternalLink className="max-md:hidden" href={proposalPage}>
|
|
||||||
{t('Open in Governance')}
|
|
||||||
</ExternalLink>
|
|
||||||
<ExternalLink className="md:hidden" href={proposalPage}>
|
|
||||||
{t('Open')}
|
|
||||||
</ExternalLink>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</AgGrid>
|
|
||||||
<JsonViewerDialog
|
<JsonViewerDialog
|
||||||
open={dialog.open}
|
open={dialog.open}
|
||||||
onChange={(isOpen) => setDialog({ ...dialog, open: isOpen })}
|
onChange={(isOpen) => setDialog({ ...dialog, open: isOpen })}
|
||||||
|
|||||||
+36
-17
@@ -1,4 +1,4 @@
|
|||||||
import { Icon } from '@vegaprotocol/ui-toolkit';
|
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
// https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go
|
// https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go
|
||||||
export const ErrorCodes = new Map([
|
export const ErrorCodes = new Map([
|
||||||
@@ -17,6 +17,8 @@ interface ChainResponseCodeProps {
|
|||||||
code: number;
|
code: number;
|
||||||
hideLabel?: boolean;
|
hideLabel?: boolean;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
hideIfOk?: boolean;
|
||||||
|
small?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,14 +30,21 @@ export const ChainResponseCode = ({
|
|||||||
code,
|
code,
|
||||||
hideLabel = false,
|
hideLabel = false,
|
||||||
error,
|
error,
|
||||||
|
hideIfOk = false,
|
||||||
|
small = false,
|
||||||
}: ChainResponseCodeProps) => {
|
}: ChainResponseCodeProps) => {
|
||||||
|
if (hideIfOk && code === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const isSuccess = successCodes.has(code);
|
const isSuccess = successCodes.has(code);
|
||||||
|
const size = small ? 3 : 4;
|
||||||
const successColour =
|
const successColour =
|
||||||
code === 71 ? 'fill-vega-orange' : 'fill-vega-green-600';
|
code === 71 ? '!fill-vega-orange' : '!fill-vega-green-600';
|
||||||
const icon = isSuccess ? (
|
const icon = isSuccess ? (
|
||||||
<Icon name="tick-circle" className={successColour} />
|
<Icon size={size} name="tick-circle" className={`${successColour}`} />
|
||||||
) : (
|
) : (
|
||||||
<Icon name="cross" className="fill-vega-pink-600" />
|
<Icon size={size} name="cross" className="!fill-vega-pink-500" />
|
||||||
);
|
);
|
||||||
const label = ErrorCodes.get(code) || 'Unknown response code';
|
const label = ErrorCodes.get(code) || 'Unknown response code';
|
||||||
|
|
||||||
@@ -44,18 +53,28 @@ export const ChainResponseCode = ({
|
|||||||
error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error;
|
error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div title={`Response code: ${code} - ${label}`} className=" inline-block">
|
<Tooltip
|
||||||
<span
|
description={
|
||||||
className="mr-2"
|
<span>
|
||||||
aria-label={isSuccess ? 'Success' : 'Warning'}
|
Response code: {code} - {label}
|
||||||
role="img"
|
</span>
|
||||||
>
|
}
|
||||||
{icon}
|
>
|
||||||
</span>
|
<div className="mt-[-1px] inline-block">
|
||||||
{hideLabel ? null : <span>{label}</span>}
|
<span
|
||||||
{!hideLabel && !!displayError ? (
|
className="mr-2"
|
||||||
<span className="ml-1 whitespace-pre">— {displayError}</span>
|
aria-label={isSuccess ? 'Success' : 'Warning'}
|
||||||
) : null}
|
role="img"
|
||||||
</div>
|
>
|
||||||
|
{icon}
|
||||||
|
</span>
|
||||||
|
{hideLabel ? null : <span>{label}</span>}
|
||||||
|
{!hideLabel && !!displayError ? (
|
||||||
|
<span className="ml-1 whitespace-pre">
|
||||||
|
— {displayError}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import type { TxDetailsOrderProps } from './tx-order-peg';
|
||||||
|
import { TxOrderPeggedReference, getMarketDecimals } from './tx-order-peg';
|
||||||
|
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
||||||
|
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
||||||
|
import { PeggedReference, Side } from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
// Mock the useExplorerMarketQuery hook
|
||||||
|
jest.mock('../../../links/market-link/__generated__/Market', () => ({
|
||||||
|
useExplorerMarketQuery: jest.fn().mockReturnValue({
|
||||||
|
data: {
|
||||||
|
market: { decimalPlaces: 0 },
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('getSettlementAsset', () => {
|
||||||
|
it('should return the decimal places if data is defined', () => {
|
||||||
|
const data = {
|
||||||
|
market: {
|
||||||
|
__typename: 'Market',
|
||||||
|
id: '123',
|
||||||
|
decimalPlaces: 8,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getMarketDecimals(data as Partial<ExplorerMarketQuery>);
|
||||||
|
|
||||||
|
expect(result).toEqual(8);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 0 if data is undefined', () => {
|
||||||
|
const result = getMarketDecimals(undefined);
|
||||||
|
|
||||||
|
expect(result).toEqual(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('TxOrderPeggedReference', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// Mock the useExplorerMarketQuery hook return value
|
||||||
|
(useExplorerMarketQuery as jest.Mock).mockReturnValue({
|
||||||
|
data: {
|
||||||
|
settlementAsset: 'some-settlement-asset',
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the offset and reference correctly', () => {
|
||||||
|
const props: TxDetailsOrderProps = {
|
||||||
|
side: Side.SIDE_BUY,
|
||||||
|
offset: '10',
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
marketId: 'some-market-id',
|
||||||
|
};
|
||||||
|
|
||||||
|
const { getByTestId } = render(<TxOrderPeggedReference {...props} />);
|
||||||
|
|
||||||
|
expect(getByTestId('pegged-reference')).toHaveTextContent('Mid + 10');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return null if the reference is "PEGGED_REFERENCE_UNSPECIFIED"', () => {
|
||||||
|
const props: TxDetailsOrderProps = {
|
||||||
|
side: Side.SIDE_BUY,
|
||||||
|
offset: '10',
|
||||||
|
reference: 'PEGGED_REFERENCE_UNSPECIFIED',
|
||||||
|
marketId: 'some-market-id',
|
||||||
|
};
|
||||||
|
|
||||||
|
const { container } = render(<TxOrderPeggedReference {...props} />);
|
||||||
|
|
||||||
|
expect(container.firstChild).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the offset without formatting initially, then render the formatted version', () => {
|
||||||
|
const props: TxDetailsOrderProps = {
|
||||||
|
side: Side.SIDE_BUY,
|
||||||
|
offset: '10',
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_BEST_ASK,
|
||||||
|
marketId: 'some-market-id',
|
||||||
|
};
|
||||||
|
|
||||||
|
(useExplorerMarketQuery as jest.Mock).mockReturnValue({
|
||||||
|
data: null,
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const screen = render(<TxOrderPeggedReference {...props} />);
|
||||||
|
expect(screen.getByTestId('pegged-reference')).toHaveTextContent(
|
||||||
|
'Ask + 10'
|
||||||
|
);
|
||||||
|
|
||||||
|
(useExplorerMarketQuery as jest.Mock).mockReturnValue({
|
||||||
|
data: {
|
||||||
|
market: {
|
||||||
|
decimalPlaces: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
screen.rerender(<TxOrderPeggedReference {...props} />);
|
||||||
|
expect(screen.getByTestId('pegged-reference')).toHaveTextContent(
|
||||||
|
'Ask + 0.000000001'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { TableCell, TableRow } from '../../../table';
|
||||||
|
import type { VegaPeggedReference } from '../liquidity-provision/liquidity-provision-details';
|
||||||
|
import { Side, PeggedReferenceMapping } from '@vegaprotocol/types';
|
||||||
|
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
||||||
|
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
||||||
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
|
export interface TxDetailsOrderProps {
|
||||||
|
offset: string;
|
||||||
|
reference: VegaPeggedReference;
|
||||||
|
marketId: string;
|
||||||
|
side: Side;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMarketDecimals(
|
||||||
|
data: ExplorerMarketQuery | undefined
|
||||||
|
): number {
|
||||||
|
return data?.market?.decimalPlaces || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Summarises an order's peg
|
||||||
|
*/
|
||||||
|
export const TxOrderPeggedReferenceRow = ({
|
||||||
|
offset,
|
||||||
|
reference,
|
||||||
|
marketId,
|
||||||
|
side,
|
||||||
|
}: TxDetailsOrderProps) => {
|
||||||
|
return (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Pegged order')}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<TxOrderPeggedReference
|
||||||
|
side={side}
|
||||||
|
offset={offset}
|
||||||
|
reference={reference}
|
||||||
|
marketId={marketId}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TxOrderPeggedReference = ({
|
||||||
|
offset,
|
||||||
|
reference,
|
||||||
|
marketId,
|
||||||
|
side,
|
||||||
|
}: TxDetailsOrderProps) => {
|
||||||
|
const { data, loading } = useExplorerMarketQuery({
|
||||||
|
variables: { id: marketId },
|
||||||
|
});
|
||||||
|
|
||||||
|
const direction = side === Side.SIDE_BUY ? '+' : '-';
|
||||||
|
const decimalPlaces = getMarketDecimals(data);
|
||||||
|
|
||||||
|
if (reference === 'PEGGED_REFERENCE_UNSPECIFIED') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span data-testid="pegged-reference">
|
||||||
|
{PeggedReferenceMapping[reference]}
|
||||||
|
{direction}
|
||||||
|
{!loading && data
|
||||||
|
? addDecimalsFormatNumber(offset, decimalPlaces)
|
||||||
|
: offset}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
+34
-12
@@ -6,10 +6,32 @@ import {
|
|||||||
SPECIAL_CASE_NETWORK_ID,
|
SPECIAL_CASE_NETWORK_ID,
|
||||||
} from '../../../../links/party-link/party-link';
|
} from '../../../../links/party-link/party-link';
|
||||||
import SizeInAsset from '../../../../size-in-asset/size-in-asset';
|
import SizeInAsset from '../../../../size-in-asset/size-in-asset';
|
||||||
import { AccountTypeMapping } from '@vegaprotocol/types';
|
|
||||||
import { AccountType } from '@vegaprotocol/types';
|
|
||||||
import { headerClasses, wrapperClasses } from '../transfer-details';
|
import { headerClasses, wrapperClasses } from '../transfer-details';
|
||||||
import type { Transfer } from '../transfer-details';
|
import type { components } from '../../../../../../types/explorer';
|
||||||
|
|
||||||
|
type Transfer = components['schemas']['commandsv1Transfer'];
|
||||||
|
type AccountTypes = components['schemas']['vegaAccountType'];
|
||||||
|
|
||||||
|
const AccountType: Record<AccountTypes, string> = {
|
||||||
|
ACCOUNT_TYPE_UNSPECIFIED: 'Unspecified',
|
||||||
|
ACCOUNT_TYPE_INSURANCE: 'Insurance',
|
||||||
|
ACCOUNT_TYPE_SETTLEMENT: 'Settlement',
|
||||||
|
ACCOUNT_TYPE_MARGIN: 'Margin',
|
||||||
|
ACCOUNT_TYPE_GENERAL: 'General',
|
||||||
|
ACCOUNT_TYPE_FEES_INFRASTRUCTURE: 'Infrastructure',
|
||||||
|
ACCOUNT_TYPE_FEES_LIQUIDITY: 'Liquidity',
|
||||||
|
ACCOUNT_TYPE_FEES_MAKER: 'Maker',
|
||||||
|
ACCOUNT_TYPE_BOND: 'Bond',
|
||||||
|
ACCOUNT_TYPE_EXTERNAL: 'External',
|
||||||
|
ACCOUNT_TYPE_GLOBAL_INSURANCE: 'Global Insurance',
|
||||||
|
ACCOUNT_TYPE_GLOBAL_REWARD: 'Global Reward',
|
||||||
|
ACCOUNT_TYPE_PENDING_TRANSFERS: 'Pending Transfers',
|
||||||
|
ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: 'Maker Paid Fees',
|
||||||
|
ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: 'Maker Received Fees',
|
||||||
|
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: 'LP Received Fees',
|
||||||
|
ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: 'Market Proposers',
|
||||||
|
ACCOUNT_TYPE_HOLDING: 'Holding',
|
||||||
|
};
|
||||||
|
|
||||||
interface TransferParticipantsProps {
|
interface TransferParticipantsProps {
|
||||||
transfer: Transfer;
|
transfer: Transfer;
|
||||||
@@ -30,22 +52,22 @@ export function TransferParticipants({
|
|||||||
}: TransferParticipantsProps) {
|
}: TransferParticipantsProps) {
|
||||||
// This mapping is required as the global account types require a type to be set, while
|
// This mapping is required as the global account types require a type to be set, while
|
||||||
// the underlying protobufs allow for every field to be undefined.
|
// the underlying protobufs allow for every field to be undefined.
|
||||||
const fromAcct =
|
const fromAcct: AccountTypes =
|
||||||
transfer.fromAccountType &&
|
transfer.fromAccountType &&
|
||||||
transfer.fromAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
transfer.fromAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
||||||
? AccountType[transfer.fromAccountType]
|
? transfer.fromAccountType
|
||||||
: AccountType.ACCOUNT_TYPE_GENERAL;
|
: 'ACCOUNT_TYPE_GENERAL';
|
||||||
const fromAccountTypeLabel = transfer.fromAccountType
|
const fromAccountTypeLabel: string = transfer.fromAccountType
|
||||||
? AccountTypeMapping[fromAcct]
|
? AccountType[fromAcct]
|
||||||
: 'Unknown';
|
: 'Unknown';
|
||||||
|
|
||||||
const toAcct =
|
const toAcct: AccountTypes =
|
||||||
transfer.toAccountType &&
|
transfer.toAccountType &&
|
||||||
transfer.toAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
transfer.toAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
||||||
? AccountType[transfer.toAccountType]
|
? transfer.toAccountType
|
||||||
: AccountType.ACCOUNT_TYPE_GENERAL;
|
: 'ACCOUNT_TYPE_GENERAL';
|
||||||
const toAccountTypeLabel = transfer.fromAccountType
|
const toAccountTypeLabel = transfer.fromAccountType
|
||||||
? AccountTypeMapping[toAcct]
|
? AccountType[toAcct]
|
||||||
: 'Unknown';
|
: 'Unknown';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
|
|||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<h2 className={headerClasses}>{t('Active epochs')}</h2>
|
<h2 className={headerClasses}>{t('Active epochs')}</h2>
|
||||||
<div className="relative block rounded-lg py-6 text-center p-6">
|
<div className="relative block rounded-lg py-6 text-center p-6">
|
||||||
<p>
|
<div>
|
||||||
<EpochOverview id={recurring.startEpoch} />
|
<EpochOverview id={recurring.startEpoch} />
|
||||||
</p>
|
</div>
|
||||||
<p className="leading-10 my-2">
|
<p className="leading-10 my-2">
|
||||||
<IconForEpoch
|
<IconForEpoch
|
||||||
start={recurring.startEpoch}
|
start={recurring.startEpoch}
|
||||||
@@ -37,13 +37,13 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
|
|||||||
current={data?.epoch.id}
|
current={data?.epoch.id}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<div>
|
||||||
{recurring.endEpoch ? (
|
{recurring.endEpoch ? (
|
||||||
<EpochOverview id={recurring.endEpoch} />
|
<EpochOverview id={recurring.endEpoch} />
|
||||||
) : (
|
) : (
|
||||||
<span>{t('Forever')}</span>
|
<span>{t('Forever')}</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { DispatchMetricLabels } from '@vegaprotocol/types';
|
|||||||
export type Metric = components['schemas']['vegaDispatchMetric'];
|
export type Metric = components['schemas']['vegaDispatchMetric'];
|
||||||
export type Strategy = components['schemas']['vegaDispatchStrategy'];
|
export type Strategy = components['schemas']['vegaDispatchStrategy'];
|
||||||
|
|
||||||
const metricLabels = {
|
const metricLabels: Record<Metric, string> = {
|
||||||
DISPATCH_METRIC_UNSPECIFIED: 'Unknown metric',
|
DISPATCH_METRIC_UNSPECIFIED: 'Unknown metric',
|
||||||
...DispatchMetricLabels,
|
...DispatchMetricLabels,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { TransferRepeat } from './blocks/transfer-repeat';
|
|||||||
import { TransferRewards } from './blocks/transfer-rewards';
|
import { TransferRewards } from './blocks/transfer-rewards';
|
||||||
import { TransferParticipants } from './blocks/transfer-participants';
|
import { TransferParticipants } from './blocks/transfer-participants';
|
||||||
|
|
||||||
export type Recurring = components['schemas']['v1RecurringTransfer'];
|
export type Recurring = components['schemas']['commandsv1RecurringTransfer'];
|
||||||
export type Metric = components['schemas']['vegaDispatchMetric'];
|
export type Metric = components['schemas']['vegaDispatchMetric'];
|
||||||
|
|
||||||
export const wrapperClasses =
|
export const wrapperClasses =
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
|
|||||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
|
import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
|
||||||
import Hash from '../../links/hash';
|
import Hash from '../../links/hash';
|
||||||
|
import { TxOrderPeggedReferenceRow } from './order/tx-order-peg';
|
||||||
|
|
||||||
interface TxDetailsOrderProps {
|
interface TxDetailsOrderProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -29,6 +30,8 @@ export const TxDetailsOrder = ({
|
|||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
}
|
}
|
||||||
const marketId = txData.command.orderSubmission.marketId || '-';
|
const marketId = txData.command.orderSubmission.marketId || '-';
|
||||||
|
const reference = txData.command.orderSubmission.peggedOrder;
|
||||||
|
const side = txData.command.orderSubmission.side;
|
||||||
|
|
||||||
let deterministicId = '';
|
let deterministicId = '';
|
||||||
|
|
||||||
@@ -63,6 +66,14 @@ export const TxDetailsOrder = ({
|
|||||||
<MarketLink id={marketId} />
|
<MarketLink id={marketId} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
{reference ? (
|
||||||
|
<TxOrderPeggedReferenceRow
|
||||||
|
side={side}
|
||||||
|
offset={reference.offset}
|
||||||
|
reference={reference.reference}
|
||||||
|
marketId={marketId}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</TableWithTbody>
|
</TableWithTbody>
|
||||||
|
|
||||||
{deterministicId.length > 0 ? (
|
{deterministicId.length > 0 ? (
|
||||||
|
|||||||
@@ -10,13 +10,17 @@ export interface FilterLabelProps {
|
|||||||
*/
|
*/
|
||||||
export function FilterLabel({ filters }: FilterLabelProps) {
|
export function FilterLabel({ filters }: FilterLabelProps) {
|
||||||
if (!filters || filters.size !== 1) {
|
if (!filters || filters.size !== 1) {
|
||||||
return <span className="uppercase">{t('Filter')}</span>;
|
return (
|
||||||
|
<span data-testid="filter-empty" className="uppercase">
|
||||||
|
{t('Filter')}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div data-testid="filter-selected">
|
||||||
<span className="uppercase">{t('Filters')}:</span>
|
<span className="uppercase">{t('Filters')}:</span>
|
||||||
<code className="bg-vega-light-150 px-2 rounded-md capitalize">
|
<code className="bg-vega-light-150 dark:bg-vega-light-300 px-2 rounded-md capitalize dark:text-black">
|
||||||
{Array.from(filters)[0]}
|
{Array.from(filters)[0]}
|
||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { TxsFilter } from './tx-filter';
|
||||||
|
import type { FilterOption } from './tx-filter';
|
||||||
|
|
||||||
|
describe('TxsFilter', () => {
|
||||||
|
it('renders holding text when nothing is selected', () => {
|
||||||
|
const filters: Set<FilterOption> = new Set([]);
|
||||||
|
const setFilters = jest.fn();
|
||||||
|
render(<TxsFilter filters={filters} setFilters={setFilters} />);
|
||||||
|
expect(screen.getByTestId('filter-empty')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Filter')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the submit order filter as selected', () => {
|
||||||
|
const filters: Set<FilterOption> = new Set(['Submit Order']);
|
||||||
|
const setFilters = jest.fn();
|
||||||
|
render(<TxsFilter filters={filters} setFilters={setFilters} />);
|
||||||
|
expect(screen.getByTestId('filter-selected')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Submit Order')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -91,7 +91,7 @@ export interface TxFilterProps {
|
|||||||
* types. It allows a user to select one transaction type to view. Later
|
* types. It allows a user to select one transaction type to view. Later
|
||||||
* it will support multiple selection, but until the API supports that it is
|
* it will support multiple selection, but until the API supports that it is
|
||||||
* one or all.
|
* one or all.
|
||||||
* @param filters null or Set of tranaction types
|
* @param filters null or Set of transaction types
|
||||||
* @param setFilters A function to update the filters prop
|
* @param setFilters A function to update the filters prop
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
@@ -100,15 +100,15 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
|
|||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
modal={false}
|
modal={false}
|
||||||
trigger={
|
trigger={
|
||||||
<DropdownMenuTrigger className="ml-2">
|
<DropdownMenuTrigger className="ml-0">
|
||||||
<Button size="xs">
|
<Button size="xs" data-testid="filter-trigger">
|
||||||
<FilterLabel filters={filters} />
|
<FilterLabel filters={filters} />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
{filters.size > 1 ? null : (
|
{filters.size > 0 ? null : (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuCheckboxItem
|
<DropdownMenuCheckboxItem
|
||||||
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
|
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||||||
|
import { TxsListNavigation } from './tx-list-navigation';
|
||||||
|
|
||||||
|
const NOOP = () => {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
describe('TxsListNavigation', () => {
|
||||||
|
it('renders transaction list navigation', () => {
|
||||||
|
render(
|
||||||
|
<TxsListNavigation
|
||||||
|
refreshTxs={NOOP}
|
||||||
|
nextPage={NOOP}
|
||||||
|
previousPage={NOOP}
|
||||||
|
hasMoreTxs={true}
|
||||||
|
hasPreviousPage={true}
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</TxsListNavigation>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Newer')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Older')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls previousPage when "Newer" button is clicked', () => {
|
||||||
|
const previousPageMock = jest.fn();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<TxsListNavigation
|
||||||
|
refreshTxs={NOOP}
|
||||||
|
nextPage={NOOP}
|
||||||
|
previousPage={previousPageMock}
|
||||||
|
hasMoreTxs={true}
|
||||||
|
hasPreviousPage={true}
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</TxsListNavigation>
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText('Newer'));
|
||||||
|
|
||||||
|
expect(previousPageMock).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls nextPage when "Older" button is clicked', () => {
|
||||||
|
const nextPageMock = jest.fn();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<TxsListNavigation
|
||||||
|
refreshTxs={NOOP}
|
||||||
|
nextPage={nextPageMock}
|
||||||
|
previousPage={NOOP}
|
||||||
|
hasMoreTxs={true}
|
||||||
|
hasPreviousPage={true}
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</TxsListNavigation>
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText('Older'));
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { BlocksRefetch } from '../blocks';
|
||||||
|
|
||||||
|
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
export interface TxListNavigationProps {
|
||||||
|
refreshTxs: () => void;
|
||||||
|
nextPage: () => void;
|
||||||
|
previousPage: () => void;
|
||||||
|
loading?: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
hasMoreTxs: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Displays a list of transactions with filters and controls to navigate through the list.
|
||||||
|
*
|
||||||
|
* @returns {JSX.Element} Transaction List and controls
|
||||||
|
*/
|
||||||
|
export const TxsListNavigation = ({
|
||||||
|
refreshTxs,
|
||||||
|
nextPage,
|
||||||
|
previousPage,
|
||||||
|
hasMoreTxs,
|
||||||
|
hasPreviousPage,
|
||||||
|
children,
|
||||||
|
loading = false,
|
||||||
|
}: TxListNavigationProps) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<menu className="mb-2 w-full ">{children}</menu>
|
||||||
|
<menu className="mb-2 w-full">
|
||||||
|
<BlocksRefetch refetch={refreshTxs} />
|
||||||
|
<div className="float-right">
|
||||||
|
<Button
|
||||||
|
className="mr-2"
|
||||||
|
size="xs"
|
||||||
|
disabled={!hasPreviousPage || loading}
|
||||||
|
onClick={() => {
|
||||||
|
previousPage();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('Newer')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
disabled={!hasMoreTxs || loading}
|
||||||
|
onClick={() => {
|
||||||
|
nextPage();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('Older')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="float-right mr-2">
|
||||||
|
{loading ? (
|
||||||
|
<span className="text-vega-light-300">{t('Loading...')}</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</menu>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -16,7 +16,7 @@ interface StringMap {
|
|||||||
const displayString: StringMap = {
|
const displayString: StringMap = {
|
||||||
OrderSubmission: 'Order Submission',
|
OrderSubmission: 'Order Submission',
|
||||||
'Submit Order': 'Order',
|
'Submit Order': 'Order',
|
||||||
OrderCancellation: 'Order Cancellation',
|
OrderCancellation: 'Cancel order',
|
||||||
OrderAmendment: 'Order Amendment',
|
OrderAmendment: 'Order Amendment',
|
||||||
VoteSubmission: 'Vote Submission',
|
VoteSubmission: 'Vote Submission',
|
||||||
WithdrawSubmission: 'Withdraw Submission',
|
WithdrawSubmission: 'Withdraw Submission',
|
||||||
@@ -24,6 +24,7 @@ const displayString: StringMap = {
|
|||||||
LiquidityProvisionSubmission: 'LP order',
|
LiquidityProvisionSubmission: 'LP order',
|
||||||
'Liquidity Provision Order': 'LP order',
|
'Liquidity Provision Order': 'LP order',
|
||||||
LiquidityProvisionCancellation: 'LP cancel',
|
LiquidityProvisionCancellation: 'LP cancel',
|
||||||
|
'Cancel LiquidityProvision Order': 'LP cancel',
|
||||||
LiquidityProvisionAmendment: 'LP update',
|
LiquidityProvisionAmendment: 'LP update',
|
||||||
'Amend LiquidityProvision Order': 'Amend LP',
|
'Amend LiquidityProvision Order': 'Amend LP',
|
||||||
ProposalSubmission: 'Governance Proposal',
|
ProposalSubmission: 'Governance Proposal',
|
||||||
@@ -36,12 +37,34 @@ const displayString: StringMap = {
|
|||||||
UndelegateSubmission: 'Undelegation',
|
UndelegateSubmission: 'Undelegation',
|
||||||
KeyRotateSubmission: 'Key Rotation',
|
KeyRotateSubmission: 'Key Rotation',
|
||||||
StateVariableProposal: 'State Variable',
|
StateVariableProposal: 'State Variable',
|
||||||
|
'State Variable Proposal': 'State Variable',
|
||||||
Transfer: 'Transfer',
|
Transfer: 'Transfer',
|
||||||
CancelTransfer: 'Cancel Transfer',
|
CancelTransfer: 'Cancel Transfer',
|
||||||
|
'Cancel Transfer Funds': 'Cancel Transfer',
|
||||||
ValidatorHeartbeat: 'Heartbeat',
|
ValidatorHeartbeat: 'Heartbeat',
|
||||||
|
'Validator Heartbeat': 'Heartbeat',
|
||||||
'Batch Market Instructions': 'Batch',
|
'Batch Market Instructions': 'Batch',
|
||||||
|
'Stop Orders Submission': 'Stop',
|
||||||
|
StopOrdersSubmission: 'Stop',
|
||||||
|
StopOrdersCancellation: 'Cancel stop',
|
||||||
|
'Stop Orders Cancellation': 'Cancel stop',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getLabelForOrderType(
|
||||||
|
orderType: string,
|
||||||
|
command: components['schemas']['v1InputData']
|
||||||
|
): string {
|
||||||
|
if (command.orderSubmission) {
|
||||||
|
if (command.orderSubmission.peggedOrder) {
|
||||||
|
return 'Peg';
|
||||||
|
}
|
||||||
|
if (command.orderSubmission.icebergOpts) {
|
||||||
|
return 'Iceberg';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'Order';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a proposal, will return a specific label
|
* Given a proposal, will return a specific label
|
||||||
* @param chainEvent
|
* @param chainEvent
|
||||||
@@ -113,6 +136,8 @@ export function getLabelForChainEvent(
|
|||||||
return t('Signer threshold');
|
return t('Signer threshold');
|
||||||
}
|
}
|
||||||
return t('Multisig update');
|
return t('Multisig update');
|
||||||
|
} else if (chainEvent.contractCall) {
|
||||||
|
return t('Contract call');
|
||||||
}
|
}
|
||||||
return t('Chain Event');
|
return t('Chain Event');
|
||||||
}
|
}
|
||||||
@@ -172,7 +197,7 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-testid="tx-type"
|
data-testid="tx-type"
|
||||||
className={`text-sm rounded-md leading-none px-2 py-2 inline-block ${colours}`}
|
className={`text-sm rounded-md leading-tight px-2 inline-block whitespace-nowrap ${colours}`}
|
||||||
>
|
>
|
||||||
{type}
|
{type}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
@@ -83,21 +84,22 @@ describe('Txs infinite list item', () => {
|
|||||||
|
|
||||||
it('renders data correctly', () => {
|
it('renders data correctly', () => {
|
||||||
render(
|
render(
|
||||||
<MemoryRouter>
|
<MockedProvider>
|
||||||
<TxsInfiniteListItem
|
<MemoryRouter>
|
||||||
type="testType"
|
<TxsInfiniteListItem
|
||||||
submitter="testPubKey"
|
type="testType"
|
||||||
hash="testTxHash"
|
submitter="testPubKey"
|
||||||
block="1"
|
hash="testTxHash"
|
||||||
code={0}
|
block="1"
|
||||||
command={{}}
|
code={0}
|
||||||
/>
|
command={{}}
|
||||||
</MemoryRouter>
|
/>
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
expect(screen.getByTestId('tx-hash')).toHaveTextContent('testTxHash');
|
expect(screen.getByTestId('tx-hash')).toHaveTextContent('testTxHash');
|
||||||
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
|
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
|
||||||
expect(screen.getByTestId('tx-type')).toHaveTextContent('testType');
|
expect(screen.getByTestId('tx-type')).toHaveTextContent('testType');
|
||||||
expect(screen.getByTestId('tx-block')).toHaveTextContent('1');
|
expect(screen.getByTestId('tx-block')).toHaveTextContent('1');
|
||||||
expect(screen.getByTestId('tx-success')).toHaveTextContent('Success');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import React from 'react';
|
|
||||||
import { TruncatedLink } from '../truncate/truncated-link';
|
import { TruncatedLink } from '../truncate/truncated-link';
|
||||||
import { Routes } from '../../routes/route-names';
|
import { Routes } from '../../routes/route-names';
|
||||||
import { TxOrderType } from './tx-order-type';
|
import { TxOrderType } from './tx-order-type';
|
||||||
@@ -6,8 +5,25 @@ import type { BlockExplorerTransactionResult } from '../../routes/types/block-ex
|
|||||||
import { toHex } from '../search/detect-search';
|
import { toHex } from '../search/detect-search';
|
||||||
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
|
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
|
||||||
import isNumber from 'lodash/isNumber';
|
import isNumber from 'lodash/isNumber';
|
||||||
|
import { PartyLink } from '../links';
|
||||||
|
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||||
|
import type { Screen } from '@vegaprotocol/react-helpers';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
const TRUNCATE_LENGTH = 10;
|
const DEFAULT_TRUNCATE_LENGTH = 7;
|
||||||
|
|
||||||
|
export function getIdTruncateLength(screen: Screen): number {
|
||||||
|
if (['xxxl', 'xxl'].includes(screen)) {
|
||||||
|
return 64;
|
||||||
|
} else if (['xl', 'lg', 'md'].includes(screen)) {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
return DEFAULT_TRUNCATE_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldTruncateParty(screen: Screen): boolean {
|
||||||
|
return !['xxxl', 'xxl', 'xl'].includes(screen);
|
||||||
|
}
|
||||||
|
|
||||||
export const TxsInfiniteListItem = ({
|
export const TxsInfiniteListItem = ({
|
||||||
hash,
|
hash,
|
||||||
@@ -17,6 +33,12 @@ export const TxsInfiniteListItem = ({
|
|||||||
block,
|
block,
|
||||||
command,
|
command,
|
||||||
}: Partial<BlockExplorerTransactionResult>) => {
|
}: Partial<BlockExplorerTransactionResult>) => {
|
||||||
|
const { screenSize } = useScreenDimensions();
|
||||||
|
const idTruncateLength = useMemo(
|
||||||
|
() => getIdTruncateLength(screenSize),
|
||||||
|
[screenSize]
|
||||||
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!hash ||
|
!hash ||
|
||||||
!submitter ||
|
!submitter ||
|
||||||
@@ -29,68 +51,40 @@ export const TxsInfiniteListItem = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<tr
|
||||||
data-testid="transaction-row"
|
data-testid="transaction-row"
|
||||||
className="flex items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item grid grid-cols-10"
|
className="transaction-row text-left items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item py-[2px]"
|
||||||
>
|
>
|
||||||
<div
|
<td
|
||||||
className="text-sm col-span-10 md:col-span-3 leading-none"
|
className="text-sm leading-none whitespace-nowrap font-mono"
|
||||||
data-testid="tx-hash"
|
data-testid="tx-hash"
|
||||||
>
|
>
|
||||||
<span className="md:hidden uppercase text-vega-dark-300">
|
|
||||||
ID:
|
|
||||||
</span>
|
|
||||||
<TruncatedLink
|
|
||||||
to={`/${Routes.TX}/${toHex(hash)}`}
|
|
||||||
text={hash}
|
|
||||||
startChars={TRUNCATE_LENGTH}
|
|
||||||
endChars={TRUNCATE_LENGTH}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-sm col-span-10 md:col-span-3 leading-none"
|
|
||||||
data-testid="pub-key"
|
|
||||||
>
|
|
||||||
<span className="md:hidden uppercase text-vega-dark-300">
|
|
||||||
By:
|
|
||||||
</span>
|
|
||||||
<TruncatedLink
|
|
||||||
to={`/${Routes.PARTIES}/${submitter}`}
|
|
||||||
text={submitter}
|
|
||||||
startChars={TRUNCATE_LENGTH}
|
|
||||||
endChars={TRUNCATE_LENGTH}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="text-sm col-span-5 md:col-span-2 leading-none flex items-center">
|
|
||||||
<TxOrderType orderType={type} command={command} />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-sm col-span-3 md:col-span-1 leading-none flex items-center"
|
|
||||||
data-testid="tx-block"
|
|
||||||
>
|
|
||||||
<span className="md:hidden uppercase text-vega-dark-300">
|
|
||||||
Block:
|
|
||||||
</span>
|
|
||||||
<TruncatedLink
|
|
||||||
to={`/${Routes.BLOCKS}/${block}`}
|
|
||||||
text={block}
|
|
||||||
startChars={TRUNCATE_LENGTH}
|
|
||||||
endChars={TRUNCATE_LENGTH}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-sm col-span-2 md:col-span-1 leading-none flex items-center"
|
|
||||||
data-testid="tx-success"
|
|
||||||
>
|
|
||||||
<span className="md:hidden uppercase text-vega-dark-300">
|
|
||||||
Success
|
|
||||||
</span>
|
|
||||||
{isNumber(code) ? (
|
{isNumber(code) ? (
|
||||||
<ChainResponseCode code={code} hideLabel={true} />
|
<ChainResponseCode code={code} hideLabel={true} hideIfOk={true} />
|
||||||
) : (
|
) : (
|
||||||
code
|
code
|
||||||
)}
|
)}
|
||||||
</div>
|
<TruncatedLink
|
||||||
</div>
|
to={`/${Routes.TX}/${toHex(hash)}`}
|
||||||
|
text={hash}
|
||||||
|
startChars={idTruncateLength}
|
||||||
|
endChars={0}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td className="text-sm leading-none">
|
||||||
|
<TxOrderType orderType={type} command={command} />
|
||||||
|
</td>
|
||||||
|
<td className="text-sm leading-none" data-testid="pub-key">
|
||||||
|
<PartyLink truncate={shouldTruncateParty(screenSize)} id={submitter} />
|
||||||
|
</td>
|
||||||
|
<td className="text-sm items-center font-mono" data-testid="tx-block">
|
||||||
|
<TruncatedLink
|
||||||
|
to={`/${Routes.BLOCKS}/${block}`}
|
||||||
|
text={block}
|
||||||
|
startChars={5}
|
||||||
|
endChars={5}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { TxsInfiniteList } from './txs-infinite-list';
|
import { TxsInfiniteList } from './txs-infinite-list';
|
||||||
import { render, screen, fireEvent, act } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
||||||
import { Side } from '@vegaprotocol/types';
|
import { Side } from '@vegaprotocol/types';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
|
||||||
const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
|
const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
|
||||||
return Array.from(Array(number)).map((_) => ({
|
return Array.from(Array(number)).map((_) => ({
|
||||||
@@ -40,7 +41,7 @@ describe('Txs infinite list', () => {
|
|||||||
it('should display a "no items" message when no items provided', () => {
|
it('should display a "no items" message when no items provided', () => {
|
||||||
render(
|
render(
|
||||||
<TxsInfiniteList
|
<TxsInfiniteList
|
||||||
txs={undefined}
|
txs={undefined as unknown as BlockExplorerTransactionResult[]}
|
||||||
areTxsLoading={false}
|
areTxsLoading={false}
|
||||||
hasMoreTxs={false}
|
hasMoreTxs={false}
|
||||||
loadMoreTxs={() => null}
|
loadMoreTxs={() => null}
|
||||||
@@ -48,23 +49,7 @@ describe('Txs infinite list', () => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(screen.getByTestId('emptylist')).toBeInTheDocument();
|
expect(screen.getByTestId('emptylist')).toBeInTheDocument();
|
||||||
expect(
|
expect(screen.getByText('No transactions found')).toBeInTheDocument();
|
||||||
screen.getByText('This chain has 0 transactions')
|
|
||||||
).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('error is displayed at item level', () => {
|
|
||||||
const txs = generateTxs(1);
|
|
||||||
render(
|
|
||||||
<TxsInfiniteList
|
|
||||||
txs={txs}
|
|
||||||
areTxsLoading={false}
|
|
||||||
hasMoreTxs={false}
|
|
||||||
loadMoreTxs={() => null}
|
|
||||||
error={Error('test error!')}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
expect(screen.getByText('Cannot fetch transaction')).toBeInTheDocument();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('item renders data of n length into list of n length', () => {
|
it('item renders data of n length into list of n length', () => {
|
||||||
@@ -73,85 +58,22 @@ describe('Txs infinite list', () => {
|
|||||||
const txs = generateTxs(7);
|
const txs = generateTxs(7);
|
||||||
render(
|
render(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<TxsInfiniteList
|
<MockedProvider>
|
||||||
txs={txs}
|
<TxsInfiniteList
|
||||||
areTxsLoading={false}
|
txs={txs}
|
||||||
hasMoreTxs={false}
|
areTxsLoading={false}
|
||||||
loadMoreTxs={() => null}
|
hasMoreTxs={false}
|
||||||
error={undefined}
|
loadMoreTxs={() => null}
|
||||||
/>
|
error={undefined}
|
||||||
|
/>
|
||||||
|
</MockedProvider>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen
|
screen
|
||||||
.getByTestId('infinite-scroll-wrapper')
|
.getByTestId('transactions-list')
|
||||||
.querySelectorAll('.txs-infinite-list-item')
|
.querySelectorAll('.transaction-row')
|
||||||
).toHaveLength(7);
|
).toHaveLength(7);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tries to load more items when required to initially fill the list', () => {
|
|
||||||
// For example, if initially rendering 15, the bottom of the list is
|
|
||||||
// in view of the viewport, and the callback should be executed
|
|
||||||
const txs = generateTxs(15);
|
|
||||||
const callback = jest.fn();
|
|
||||||
|
|
||||||
render(
|
|
||||||
<MemoryRouter>
|
|
||||||
<TxsInfiniteList
|
|
||||||
txs={txs}
|
|
||||||
areTxsLoading={false}
|
|
||||||
hasMoreTxs={true}
|
|
||||||
loadMoreTxs={callback}
|
|
||||||
error={undefined}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(callback.mock.calls.length).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not try to load more items if there are no more', () => {
|
|
||||||
const txs = generateTxs(3);
|
|
||||||
const callback = jest.fn();
|
|
||||||
|
|
||||||
render(
|
|
||||||
<MemoryRouter>
|
|
||||||
<TxsInfiniteList
|
|
||||||
txs={txs}
|
|
||||||
areTxsLoading={false}
|
|
||||||
hasMoreTxs={false}
|
|
||||||
loadMoreTxs={callback}
|
|
||||||
error={undefined}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(callback.mock.calls.length).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('loads more items is called when scrolled', () => {
|
|
||||||
const txs = generateTxs(14);
|
|
||||||
const callback = jest.fn();
|
|
||||||
|
|
||||||
render(
|
|
||||||
<MemoryRouter>
|
|
||||||
<TxsInfiniteList
|
|
||||||
txs={txs}
|
|
||||||
areTxsLoading={false}
|
|
||||||
hasMoreTxs={true}
|
|
||||||
loadMoreTxs={callback}
|
|
||||||
error={undefined}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
fireEvent.scroll(screen.getByTestId('infinite-scroll-wrapper'), {
|
|
||||||
target: { scrollY: 2000 },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(callback.mock.calls.length).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import React, { useEffect, useRef } from 'react';
|
|
||||||
import { FixedSizeList as List } from 'react-window';
|
|
||||||
import InfiniteLoader from 'react-window-infinite-loader';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
|
||||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
||||||
import EmptyList from '../empty-list/empty-list';
|
import EmptyList from '../empty-list/empty-list';
|
||||||
@@ -11,82 +7,46 @@ import { Loader } from '@vegaprotocol/ui-toolkit';
|
|||||||
interface TxsInfiniteListProps {
|
interface TxsInfiniteListProps {
|
||||||
hasMoreTxs: boolean;
|
hasMoreTxs: boolean;
|
||||||
areTxsLoading: boolean | undefined;
|
areTxsLoading: boolean | undefined;
|
||||||
txs: BlockExplorerTransactionResult[] | undefined;
|
txs: BlockExplorerTransactionResult[];
|
||||||
loadMoreTxs: () => void;
|
loadMoreTxs: () => void;
|
||||||
error: Error | undefined;
|
error: Error | undefined;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
hasFilters?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ItemProps {
|
interface ItemProps {
|
||||||
index: BlockExplorerTransactionResult;
|
tx: BlockExplorerTransactionResult;
|
||||||
style: React.CSSProperties;
|
|
||||||
isLoading: boolean;
|
|
||||||
error: Error | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
const Item = ({ tx }: ItemProps) => {
|
||||||
const NOOP = () => {};
|
const { hash, submitter, type, command, block, code, index: blockIndex } = tx;
|
||||||
|
return (
|
||||||
const Item = ({ index, style, isLoading, error }: ItemProps) => {
|
<TxsInfiniteListItem
|
||||||
let content;
|
type={type}
|
||||||
if (error) {
|
code={code}
|
||||||
content = t(`Cannot fetch transaction`);
|
command={command}
|
||||||
} else if (isLoading) {
|
submitter={submitter}
|
||||||
content = <Loader />;
|
hash={hash}
|
||||||
} else {
|
block={block}
|
||||||
const {
|
index={blockIndex}
|
||||||
hash,
|
/>
|
||||||
submitter,
|
);
|
||||||
type,
|
|
||||||
command,
|
|
||||||
block,
|
|
||||||
code,
|
|
||||||
index: blockIndex,
|
|
||||||
} = index;
|
|
||||||
content = (
|
|
||||||
<TxsInfiniteListItem
|
|
||||||
type={type}
|
|
||||||
code={code}
|
|
||||||
command={command}
|
|
||||||
submitter={submitter}
|
|
||||||
hash={hash}
|
|
||||||
block={block}
|
|
||||||
index={blockIndex}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div style={style}>{content}</div>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TxsInfiniteList = ({
|
export const TxsInfiniteList = ({
|
||||||
hasMoreTxs,
|
|
||||||
areTxsLoading,
|
areTxsLoading,
|
||||||
txs,
|
txs,
|
||||||
loadMoreTxs,
|
|
||||||
error,
|
|
||||||
className,
|
className,
|
||||||
|
hasFilters = false,
|
||||||
}: TxsInfiniteListProps) => {
|
}: TxsInfiniteListProps) => {
|
||||||
const { screenSize } = useScreenDimensions();
|
if (!txs || txs.length === 0) {
|
||||||
const isStacked = ['xs', 'sm'].includes(screenSize);
|
|
||||||
const infiniteLoaderRef = useRef<InfiniteLoader>(null);
|
|
||||||
const hasMountedRef = useRef(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (hasMountedRef.current) {
|
|
||||||
if (infiniteLoaderRef.current) {
|
|
||||||
infiniteLoaderRef.current.resetloadMoreItemsCache(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hasMountedRef.current = true;
|
|
||||||
}, [loadMoreTxs]);
|
|
||||||
|
|
||||||
if (!txs) {
|
|
||||||
if (!areTxsLoading) {
|
if (!areTxsLoading) {
|
||||||
return (
|
return (
|
||||||
<EmptyList
|
<EmptyList
|
||||||
heading={t('This chain has 0 transactions')}
|
heading={t('No transactions found')}
|
||||||
label={t('Check back soon')}
|
label={
|
||||||
|
hasFilters ? t('Try a different filter') : t('Check back soon')
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -94,57 +54,26 @@ export const TxsInfiniteList = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are more items to be loaded then add an extra row to hold a loading indicator.
|
|
||||||
const itemCount = hasMoreTxs ? txs.length + 1 : txs.length;
|
|
||||||
|
|
||||||
// Pass an empty callback to InfiniteLoader in case it asks us to load more than once.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
||||||
const loadMoreItems = areTxsLoading ? NOOP : loadMoreTxs;
|
|
||||||
|
|
||||||
// Every row is loaded except for our loading indicator row.
|
|
||||||
const isItemLoaded = (index: number) => !hasMoreTxs || index < txs.length;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} data-testid="transactions-list">
|
<div className="overflow-scroll">
|
||||||
<div className="lg:grid grid-cols-10 w-full mb-3 hidden text-vega-dark-300 uppercase">
|
<table className={className} data-testid="transactions-list">
|
||||||
<div className="col-span-3">
|
<thead>
|
||||||
<span className="hidden xl:inline">{t('Transaction')} </span>
|
<tr className="w-full mb-3 text-vega-dark-300 uppercase text-left">
|
||||||
<span>ID</span>
|
<th>
|
||||||
</div>
|
<span className="hidden xl:inline">{t('Txn')} </span>
|
||||||
<div className="col-span-3">{t('Submitted By')}</div>
|
<span>ID</span>
|
||||||
<div className="col-span-2">{t('Type')}</div>
|
</th>
|
||||||
<div className="col-span-1">{t('Block')}</div>
|
<th>{t('Type')}</th>
|
||||||
<div className="col-span-1">{t('Success')}</div>
|
<th className="text-left">{t('From')}</th>
|
||||||
</div>
|
<th>{t('Block')}</th>
|
||||||
<div data-testid="infinite-scroll-wrapper">
|
</tr>
|
||||||
<InfiniteLoader
|
</thead>
|
||||||
isItemLoaded={isItemLoaded}
|
<tbody>
|
||||||
itemCount={itemCount}
|
{txs.map((t) => (
|
||||||
loadMoreItems={loadMoreItems}
|
<Item key={t.hash} tx={t} />
|
||||||
ref={infiniteLoaderRef}
|
))}
|
||||||
>
|
</tbody>
|
||||||
{({ onItemsRendered, ref }) => (
|
</table>
|
||||||
<List
|
|
||||||
className="List"
|
|
||||||
height={995}
|
|
||||||
itemCount={itemCount}
|
|
||||||
itemSize={isStacked ? 134 : 50}
|
|
||||||
onItemsRendered={onItemsRendered}
|
|
||||||
ref={ref}
|
|
||||||
width={'100%'}
|
|
||||||
>
|
|
||||||
{({ index, style }) => (
|
|
||||||
<Item
|
|
||||||
index={txs[index]}
|
|
||||||
style={style}
|
|
||||||
isLoading={!isItemLoaded(index)}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
)}
|
|
||||||
</InfiniteLoader>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
import { Routes } from '../../routes/route-names';
|
import { Table, TableRow } from '../table';
|
||||||
import { TruncatedLink } from '../truncate/truncated-link';
|
|
||||||
import { TxOrderType } from './tx-order-type';
|
|
||||||
import { Table, TableRow, TableCell } from '../table';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||||
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
|
||||||
import isNumber from 'lodash/isNumber';
|
|
||||||
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
|
|
||||||
import { getTxsDataUrl } from '../../hooks/use-txs-data';
|
import { getTxsDataUrl } from '../../hooks/use-txs-data';
|
||||||
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
|
||||||
import EmptyList from '../empty-list/empty-list';
|
import EmptyList from '../empty-list/empty-list';
|
||||||
|
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||||
|
|
||||||
interface TxsPerBlockProps {
|
interface TxsPerBlockProps {
|
||||||
blockHeight: string;
|
blockHeight: string;
|
||||||
txCount: number;
|
txCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const truncateLength = 5;
|
|
||||||
|
|
||||||
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||||
const filters = `filters[block.height]=${blockHeight}`;
|
const filters = `filters[block.height]=${blockHeight}`;
|
||||||
const url = getTxsDataUrl({ limit: txCount.toString(), filters });
|
const url = getTxsDataUrl({ limit: txCount.toString(), filters });
|
||||||
@@ -33,53 +27,23 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
|||||||
<thead>
|
<thead>
|
||||||
<TableRow modifier="bordered" className="font-mono">
|
<TableRow modifier="bordered" className="font-mono">
|
||||||
<td>{t('Transaction')}</td>
|
<td>{t('Transaction')}</td>
|
||||||
<td>{t('From')}</td>
|
|
||||||
<td>{t('Type')}</td>
|
<td>{t('Type')}</td>
|
||||||
<td>{t('Status')}</td>
|
<td>{t('From')}</td>
|
||||||
|
<td>{t('Block')}</td>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{data.transactions.map(
|
{data.transactions.map(
|
||||||
({ hash, submitter, type, command, code }) => {
|
({ hash, submitter, type, command, code, block }) => {
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<TxsInfiniteListItem
|
||||||
modifier="bordered"
|
block={block}
|
||||||
key={hash}
|
hash={hash}
|
||||||
data-testid="transaction-row"
|
submitter={submitter}
|
||||||
>
|
type={type}
|
||||||
<TableCell
|
command={command}
|
||||||
modifier="bordered"
|
code={code}
|
||||||
className="pr-12 font-mono"
|
/>
|
||||||
>
|
|
||||||
<TruncatedLink
|
|
||||||
to={`/${Routes.TX}/${hash}`}
|
|
||||||
text={hash}
|
|
||||||
startChars={truncateLength}
|
|
||||||
endChars={truncateLength}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell
|
|
||||||
modifier="bordered"
|
|
||||||
className="pr-12 font-mono"
|
|
||||||
>
|
|
||||||
<TruncatedLink
|
|
||||||
to={`/${Routes.PARTIES}/${submitter}`}
|
|
||||||
text={submitter}
|
|
||||||
startChars={truncateLength}
|
|
||||||
endChars={truncateLength}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell modifier="bordered">
|
|
||||||
<TxOrderType orderType={type} command={command} />
|
|
||||||
</TableCell>
|
|
||||||
<TableCell modifier="bordered" className="text">
|
|
||||||
{isNumber(code) ? (
|
|
||||||
<ChainResponseCode code={code} hideLabel={true} />
|
|
||||||
) : (
|
|
||||||
code
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -56,10 +56,14 @@ export function VoteIcon({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`voteicon inline-block my-1 py-1 px-2 py rounded-md text-white leading-one sm align-top ${bg}`}
|
className={`voteicon inline-block py-0 px-2 py rounded-md text-white whitespace-nowrap leading-tight sm align-top ${bg}`}
|
||||||
>
|
>
|
||||||
<Icon name={icon} size={3} className={`mr-2 p-0 fill-${fill}`} />
|
<Icon
|
||||||
<span className={`text-base text-${text}`} data-testid="label">
|
name={icon}
|
||||||
|
size={3}
|
||||||
|
className={`mr-2 p-0 mb-[-1px] fill-${fill}`}
|
||||||
|
/>
|
||||||
|
<span className={`text-${text}`} data-testid="label">
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,16 +10,18 @@ import isNumber from 'lodash/isNumber';
|
|||||||
export interface TxsStateProps {
|
export interface TxsStateProps {
|
||||||
txsData: BlockExplorerTransactionResult[];
|
txsData: BlockExplorerTransactionResult[];
|
||||||
hasMoreTxs: boolean;
|
hasMoreTxs: boolean;
|
||||||
lastCursor: string;
|
cursor: string;
|
||||||
|
previousCursors: string[];
|
||||||
|
hasPreviousPage: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUseTxsData {
|
export interface IUseTxsData {
|
||||||
limit?: number;
|
limit: number;
|
||||||
filters?: string;
|
filters?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IGetTxsDataUrl {
|
interface IGetTxsDataUrl {
|
||||||
limit?: string;
|
limit: string;
|
||||||
filters?: string;
|
filters?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,63 +42,89 @@ export const getTxsDataUrl = ({ limit, filters }: IGetTxsDataUrl) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useTxsData = ({ limit, filters }: IUseTxsData) => {
|
export const useTxsData = ({ limit, filters }: IUseTxsData) => {
|
||||||
const [{ txsData, hasMoreTxs, lastCursor }, setTxsState] =
|
const [
|
||||||
useState<TxsStateProps>({
|
{ txsData, hasMoreTxs, cursor, previousCursors, hasPreviousPage },
|
||||||
txsData: [],
|
setTxsState,
|
||||||
hasMoreTxs: true,
|
] = useState<TxsStateProps>({
|
||||||
lastCursor: '',
|
txsData: [],
|
||||||
});
|
hasMoreTxs: false,
|
||||||
|
previousCursors: [],
|
||||||
|
cursor: '',
|
||||||
|
hasPreviousPage: false,
|
||||||
|
});
|
||||||
|
|
||||||
const url = getTxsDataUrl({ limit: limit?.toString(), filters });
|
const url = getTxsDataUrl({ limit: limit.toString(), filters });
|
||||||
|
|
||||||
const {
|
const {
|
||||||
state: { data, error, loading },
|
state: { data, error, loading },
|
||||||
refetch,
|
refetch,
|
||||||
} = useFetch<BlockExplorerTransactions>(url, {}, false);
|
} = useFetch<BlockExplorerTransactions>(url, {}, true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data && isNumber(data?.transactions?.length)) {
|
if (!loading && data && isNumber(data.transactions.length)) {
|
||||||
setTxsState((prev) => ({
|
setTxsState((prev) => {
|
||||||
txsData: [...prev.txsData, ...data.transactions],
|
return {
|
||||||
hasMoreTxs: data.transactions.length > 0,
|
...prev,
|
||||||
lastCursor:
|
txsData: data.transactions,
|
||||||
data.transactions[data.transactions.length - 1]?.cursor || '',
|
hasMoreTxs: data.transactions.length >= limit,
|
||||||
}));
|
cursor: data?.transactions.at(-1)?.cursor || '',
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [setTxsState, data]);
|
}, [loading, setTxsState, data, limit]);
|
||||||
|
|
||||||
useEffect(() => {
|
const nextPage = useCallback(() => {
|
||||||
setTxsState((prev) => ({
|
const c = data?.transactions.at(0)?.cursor;
|
||||||
txsData: [],
|
const newPreviousCursors = c ? [...previousCursors, c] : previousCursors;
|
||||||
hasMoreTxs: true,
|
|
||||||
lastCursor: '',
|
|
||||||
}));
|
|
||||||
}, [filters]);
|
|
||||||
|
|
||||||
const loadTxs = useCallback(() => {
|
|
||||||
return refetch({
|
|
||||||
limit: limit,
|
|
||||||
before: lastCursor,
|
|
||||||
});
|
|
||||||
}, [lastCursor, limit, refetch]);
|
|
||||||
|
|
||||||
const refreshTxs = useCallback(async () => {
|
|
||||||
setTxsState((prev) => ({
|
setTxsState((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
lastCursor: '',
|
hasPreviousPage: true,
|
||||||
hasMoreTxs: true,
|
previousCursors: newPreviousCursors,
|
||||||
txsData: [],
|
|
||||||
}));
|
}));
|
||||||
}, [setTxsState]);
|
|
||||||
|
return refetch({
|
||||||
|
limit,
|
||||||
|
before: cursor,
|
||||||
|
});
|
||||||
|
}, [data, previousCursors, cursor, limit, refetch]);
|
||||||
|
|
||||||
|
const previousPage = useCallback(() => {
|
||||||
|
const previousCursor = [...previousCursors].pop();
|
||||||
|
const newPreviousCursors = previousCursors.slice(0, -1);
|
||||||
|
setTxsState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
hasPreviousPage: newPreviousCursors.length > 0,
|
||||||
|
previousCursors: newPreviousCursors,
|
||||||
|
}));
|
||||||
|
return refetch({
|
||||||
|
limit,
|
||||||
|
before: previousCursor,
|
||||||
|
});
|
||||||
|
}, [previousCursors, limit, refetch]);
|
||||||
|
|
||||||
|
const refreshTxs = useCallback(async () => {
|
||||||
|
setTxsState(() => ({
|
||||||
|
txsData: [],
|
||||||
|
cursor: '',
|
||||||
|
previousCursors: [],
|
||||||
|
hasMoreTxs: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
}));
|
||||||
|
|
||||||
|
refetch({ limit });
|
||||||
|
}, [setTxsState, limit, refetch, filters]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data,
|
txsData,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
txsData,
|
|
||||||
hasMoreTxs,
|
hasMoreTxs,
|
||||||
lastCursor,
|
hasPreviousPage,
|
||||||
|
previousCursors,
|
||||||
|
cursor,
|
||||||
refreshTxs,
|
refreshTxs,
|
||||||
loadTxs,
|
nextPage,
|
||||||
|
previousPage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
import { Footer } from '../components/footer/footer';
|
import { Footer } from '../components/footer/footer';
|
||||||
import { Header } from '../components/header';
|
import { Header } from '../components/header';
|
||||||
import { Routes } from './route-names';
|
import { Routes } from './route-names';
|
||||||
|
import { useExplorerNodeNamesLazyQuery } from './validators/__generated__/NodeNames';
|
||||||
|
|
||||||
const DialogsContainer = () => {
|
const DialogsContainer = () => {
|
||||||
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
|
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
|
||||||
@@ -39,6 +40,7 @@ export const Layout = () => {
|
|||||||
const isHome = Boolean(useMatch(Routes.HOME));
|
const isHome = Boolean(useMatch(Routes.HOME));
|
||||||
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||||
const fixedWidthClasses = 'w-full max-w-[1500px] mx-auto';
|
const fixedWidthClasses = 'w-full max-w-[1500px] mx-auto';
|
||||||
|
useExplorerNodeNamesLazyQuery();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -49,7 +51,7 @@ export const Layout = () => {
|
|||||||
'grid grid-rows-[auto_1fr_auto] grid-cols-1',
|
'grid grid-rows-[auto_1fr_auto] grid-cols-1',
|
||||||
'border-vega-light-200 dark:border-vega-dark-200',
|
'border-vega-light-200 dark:border-vega-dark-200',
|
||||||
'antialiased text-black dark:text-white',
|
'antialiased text-black dark:text-white',
|
||||||
'overflow-hidden relative'
|
'relative'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -2,12 +2,15 @@ import { render } from '@testing-library/react';
|
|||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import type { SourceType } from './oracle';
|
import type { SourceType } from './oracle';
|
||||||
import { OracleSigners } from './oracle-signers';
|
import { OracleSigners } from './oracle-signers';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
|
||||||
function renderComponent(sourceType: SourceType) {
|
function renderComponent(sourceType: SourceType) {
|
||||||
return (
|
return (
|
||||||
<MemoryRouter>
|
<MockedProvider>
|
||||||
<OracleSigners sourceType={sourceType} />
|
<MemoryRouter>
|
||||||
</MemoryRouter>
|
<OracleSigners sourceType={sourceType} />
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||||
import { useMemo } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { SubHeading } from '../../../components/sub-heading';
|
import { SubHeading } from '../../../components/sub-heading';
|
||||||
import { toNonHex } from '../../../components/search/detect-search';
|
import { toNonHex } from '../../../components/search/detect-search';
|
||||||
@@ -14,8 +14,11 @@ import { PartyBlockStake } from './components/party-block-stake';
|
|||||||
import { PartyBlockAccounts } from './components/party-block-accounts';
|
import { PartyBlockAccounts } from './components/party-block-accounts';
|
||||||
import { isValidPartyId } from './components/party-id-error';
|
import { isValidPartyId } from './components/party-id-error';
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
|
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
|
||||||
|
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
||||||
|
|
||||||
const Party = () => {
|
const Party = () => {
|
||||||
|
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
||||||
const { party } = useParams<{ party: string }>();
|
const { party } = useParams<{ party: string }>();
|
||||||
|
|
||||||
useDocumentTitle(['Public keys', party || '-']);
|
useDocumentTitle(['Public keys', party || '-']);
|
||||||
@@ -24,10 +27,24 @@ const Party = () => {
|
|||||||
const partyId = toNonHex(party ? party : '');
|
const partyId = toNonHex(party ? party : '');
|
||||||
const { isMobile } = useScreenDimensions();
|
const { isMobile } = useScreenDimensions();
|
||||||
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
|
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
|
||||||
const filters = `filters[tx.submitter]=${partyId}`;
|
const baseFilters = `filters[tx.submitter]=${partyId}`;
|
||||||
const { hasMoreTxs, loadTxs, error, txsData, loading } = useTxsData({
|
const f =
|
||||||
limit: 10,
|
filters && filters.size === 1
|
||||||
filters,
|
? `${baseFilters}&filters[cmd.type]=${Array.from(filters)[0]}`
|
||||||
|
: baseFilters;
|
||||||
|
|
||||||
|
const {
|
||||||
|
hasMoreTxs,
|
||||||
|
nextPage,
|
||||||
|
previousPage,
|
||||||
|
error,
|
||||||
|
refreshTxs,
|
||||||
|
loading,
|
||||||
|
txsData,
|
||||||
|
hasPreviousPage,
|
||||||
|
} = useTxsData({
|
||||||
|
limit: 25,
|
||||||
|
filters: f,
|
||||||
});
|
});
|
||||||
|
|
||||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||||
@@ -81,14 +98,24 @@ const Party = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SubHeading>{t('Transactions')}</SubHeading>
|
<SubHeading>{t('Transactions')}</SubHeading>
|
||||||
|
<TxsListNavigation
|
||||||
|
refreshTxs={refreshTxs}
|
||||||
|
nextPage={nextPage}
|
||||||
|
previousPage={previousPage}
|
||||||
|
hasPreviousPage={hasPreviousPage}
|
||||||
|
loading={loading}
|
||||||
|
hasMoreTxs={hasMoreTxs}
|
||||||
|
>
|
||||||
|
<TxsFilter filters={filters} setFilters={setFilters} />
|
||||||
|
</TxsListNavigation>
|
||||||
{!error && txsData ? (
|
{!error && txsData ? (
|
||||||
<TxsInfiniteList
|
<TxsInfiniteList
|
||||||
hasMoreTxs={hasMoreTxs}
|
hasMoreTxs={hasMoreTxs}
|
||||||
areTxsLoading={loading}
|
areTxsLoading={loading}
|
||||||
txs={txsData}
|
txs={txsData}
|
||||||
loadMoreTxs={loadTxs}
|
loadMoreTxs={nextPage}
|
||||||
error={error}
|
error={error}
|
||||||
className="mb-28"
|
className="mb-28 w-full"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Splash>
|
<Splash>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { RouteTitle } from '../../../components/route-title';
|
import { RouteTitle } from '../../../components/route-title';
|
||||||
import { BlocksRefetch } from '../../../components/blocks';
|
|
||||||
import { TxsInfiniteList } from '../../../components/txs';
|
import { TxsInfiniteList } from '../../../components/txs';
|
||||||
import { useTxsData } from '../../../hooks/use-txs-data';
|
import { useTxsData } from '../../../hooks/use-txs-data';
|
||||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
||||||
|
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
|
||||||
|
|
||||||
const BE_TXS_PER_REQUEST = 15;
|
const BE_TXS_PER_REQUEST = 25;
|
||||||
|
|
||||||
export const TxsList = () => {
|
export const TxsList = () => {
|
||||||
useDocumentTitle(['Transactions']);
|
useDocumentTitle(['Transactions']);
|
||||||
@@ -21,6 +21,11 @@ export const TxsList = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a list of transactions with filters and controls to navigate through the list.
|
||||||
|
*
|
||||||
|
* @returns {JSX.Element} Transaction List and controls
|
||||||
|
*/
|
||||||
export const TxsListFiltered = () => {
|
export const TxsListFiltered = () => {
|
||||||
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
||||||
|
|
||||||
@@ -29,26 +34,40 @@ export const TxsListFiltered = () => {
|
|||||||
? `filters[cmd.type]=${Array.from(filters)[0]}`
|
? `filters[cmd.type]=${Array.from(filters)[0]}`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
const { hasMoreTxs, loadTxs, error, txsData, refreshTxs, loading } =
|
const {
|
||||||
useTxsData({
|
hasMoreTxs,
|
||||||
limit: BE_TXS_PER_REQUEST,
|
nextPage,
|
||||||
filters: f,
|
previousPage,
|
||||||
});
|
error,
|
||||||
|
refreshTxs,
|
||||||
|
loading,
|
||||||
|
txsData,
|
||||||
|
hasPreviousPage,
|
||||||
|
} = useTxsData({
|
||||||
|
limit: BE_TXS_PER_REQUEST,
|
||||||
|
filters: f,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<menu className="mb-2">
|
<TxsListNavigation
|
||||||
<BlocksRefetch refetch={refreshTxs} />
|
refreshTxs={refreshTxs}
|
||||||
|
nextPage={nextPage}
|
||||||
|
previousPage={previousPage}
|
||||||
|
hasPreviousPage={hasPreviousPage}
|
||||||
|
loading={loading}
|
||||||
|
hasMoreTxs={hasMoreTxs}
|
||||||
|
>
|
||||||
<TxsFilter filters={filters} setFilters={setFilters} />
|
<TxsFilter filters={filters} setFilters={setFilters} />
|
||||||
</menu>
|
</TxsListNavigation>
|
||||||
|
|
||||||
<TxsInfiniteList
|
<TxsInfiniteList
|
||||||
|
hasFilters={filters.size > 0}
|
||||||
hasMoreTxs={hasMoreTxs}
|
hasMoreTxs={hasMoreTxs}
|
||||||
areTxsLoading={loading}
|
areTxsLoading={loading}
|
||||||
txs={txsData}
|
txs={txsData}
|
||||||
loadMoreTxs={loadTxs}
|
loadMoreTxs={nextPage}
|
||||||
error={error}
|
error={error}
|
||||||
className="mb-28"
|
className="mb-28 w-full min-w-[400px]"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { TxDetails } from './tx-details';
|
import { TxDetails } from './tx-details';
|
||||||
import type {
|
import type {
|
||||||
BlockExplorerTransactionResult,
|
BlockExplorerTransactionResult,
|
||||||
ValidatorHeartbeat,
|
ValidatorHeartbeat,
|
||||||
} from '../../../routes/types/block-explorer-response';
|
} from '../../../routes/types/block-explorer-response';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
|
||||||
// Note: Long enough that there is a truncated output and a full output
|
// Note: Long enough that there is a truncated output and a full output
|
||||||
const pubKey =
|
const pubKey =
|
||||||
@@ -27,9 +28,11 @@ const txData: BlockExplorerTransactionResult = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderComponent = (txData: BlockExplorerTransactionResult) => (
|
const renderComponent = (txData: BlockExplorerTransactionResult) => (
|
||||||
<Router>
|
<MemoryRouter>
|
||||||
<TxDetails txData={txData} pubKey={pubKey} />
|
<MockedProvider>
|
||||||
</Router>
|
<TxDetails txData={txData} pubKey={pubKey} />
|
||||||
|
</MockedProvider>
|
||||||
|
</MemoryRouter>
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('Transaction details', () => {
|
describe('Transaction details', () => {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
query ExplorerNodeNames {
|
||||||
|
nodesConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
pubkey
|
||||||
|
tmPubkey
|
||||||
|
ethereumAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type ExplorerNodeNamesQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ExplorerNodeNamesQuery = { __typename?: 'Query', nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, pubkey: string, tmPubkey: string, ethereumAddress: string } } | null> | null } };
|
||||||
|
|
||||||
|
|
||||||
|
export const ExplorerNodeNamesDocument = gql`
|
||||||
|
query ExplorerNodeNames {
|
||||||
|
nodesConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
pubkey
|
||||||
|
tmPubkey
|
||||||
|
ethereumAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useExplorerNodeNamesQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useExplorerNodeNamesQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useExplorerNodeNamesQuery` 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 } = useExplorerNodeNamesQuery({
|
||||||
|
* variables: {
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useExplorerNodeNamesQuery(baseOptions?: Apollo.QueryHookOptions<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>(ExplorerNodeNamesDocument, options);
|
||||||
|
}
|
||||||
|
export function useExplorerNodeNamesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>(ExplorerNodeNamesDocument, options);
|
||||||
|
}
|
||||||
|
export type ExplorerNodeNamesQueryHookResult = ReturnType<typeof useExplorerNodeNamesQuery>;
|
||||||
|
export type ExplorerNodeNamesLazyQueryHookResult = ReturnType<typeof useExplorerNodeNamesLazyQuery>;
|
||||||
|
export type ExplorerNodeNamesQueryResult = Apollo.QueryResult<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>;
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
@import 'ag-grid-community/dist/styles/ag-grid.css';
|
@import 'ag-grid-community/styles/ag-grid.css';
|
||||||
@import 'ag-grid-community/dist/styles/ag-theme-balham.css';
|
@import 'ag-grid-community/styles/ag-theme-balham.css';
|
||||||
@import 'ag-grid-community/dist/styles/ag-theme-balham-dark.css';
|
|
||||||
|
|
||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
|
|||||||
+398
-72
@@ -3,7 +3,7 @@
|
|||||||
* Do not make direct changes to the file.
|
* Do not make direct changes to the file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Type helpers */
|
/** OneOf type helpers */
|
||||||
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||||
type XOR<T, U> = T | U extends object
|
type XOR<T, U> = T | U extends object
|
||||||
? (Without<T, U> & U) | (Without<U, T> & T)
|
? (Without<T, U> & U) | (Without<U, T> & T)
|
||||||
@@ -41,6 +41,8 @@ export interface paths {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type webhooks = Record<string, never>;
|
||||||
|
|
||||||
export interface components {
|
export interface components {
|
||||||
schemas: {
|
schemas: {
|
||||||
/**
|
/**
|
||||||
@@ -101,6 +103,17 @@ export interface components {
|
|||||||
| 'TIME_IN_FORCE_FOK'
|
| 'TIME_IN_FORCE_FOK'
|
||||||
| 'TIME_IN_FORCE_GFA'
|
| 'TIME_IN_FORCE_GFA'
|
||||||
| 'TIME_IN_FORCE_GFN';
|
| 'TIME_IN_FORCE_GFN';
|
||||||
|
/**
|
||||||
|
* @description - EXPIRY_STRATEGY_UNSPECIFIED: Never valid
|
||||||
|
* - EXPIRY_STRATEGY_CANCELS: Stop order should be cancelled if the expiry time is reached.
|
||||||
|
* - EXPIRY_STRATEGY_SUBMIT: Order should be submitted if the expiry time is reached.
|
||||||
|
* @default EXPIRY_STRATEGY_UNSPECIFIED
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
readonly StopOrderExpiryStrategy:
|
||||||
|
| 'EXPIRY_STRATEGY_UNSPECIFIED'
|
||||||
|
| 'EXPIRY_STRATEGY_CANCELS'
|
||||||
|
| 'EXPIRY_STRATEGY_SUBMIT';
|
||||||
/**
|
/**
|
||||||
* @default METHOD_UNSPECIFIED
|
* @default METHOD_UNSPECIFIED
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
@@ -143,6 +156,36 @@ export interface components {
|
|||||||
/** Type of transaction */
|
/** Type of transaction */
|
||||||
readonly type?: string;
|
readonly type?: string;
|
||||||
};
|
};
|
||||||
|
/** Request for cancelling a recurring transfer */
|
||||||
|
readonly commandsv1CancelTransfer: {
|
||||||
|
/** @description Transfer ID of the transfer to cancel. */
|
||||||
|
readonly transferId?: string;
|
||||||
|
};
|
||||||
|
/** Specific details for a one off transfer */
|
||||||
|
readonly commandsv1OneOffTransfer: {
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description Timestamp in Unix nanoseconds for when the transfer should be delivered into the receiver's account.
|
||||||
|
*/
|
||||||
|
readonly deliverOn?: string;
|
||||||
|
};
|
||||||
|
/** Specific details for a recurring transfer */
|
||||||
|
readonly commandsv1RecurringTransfer: {
|
||||||
|
/** @description Optional parameter defining how a transfer is dispatched. */
|
||||||
|
readonly dispatchStrategy?: components['schemas']['vegaDispatchStrategy'];
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description Last epoch at which this transfer shall be paid.
|
||||||
|
*/
|
||||||
|
readonly endEpoch?: string;
|
||||||
|
/** @description Factor needs to be > 0. */
|
||||||
|
readonly factor?: string;
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description First epoch from which this transfer shall be paid.
|
||||||
|
*/
|
||||||
|
readonly startEpoch?: string;
|
||||||
|
};
|
||||||
/** Transfer initiated by a party */
|
/** Transfer initiated by a party */
|
||||||
readonly commandsv1Transfer: {
|
readonly commandsv1Transfer: {
|
||||||
/** @description Amount to be taken from the source account. This field is an unsigned integer scaled to the asset's decimal places. */
|
/** @description Amount to be taken from the source account. This field is an unsigned integer scaled to the asset's decimal places. */
|
||||||
@@ -154,8 +197,8 @@ export interface components {
|
|||||||
* should be taken.
|
* should be taken.
|
||||||
*/
|
*/
|
||||||
readonly fromAccountType?: components['schemas']['vegaAccountType'];
|
readonly fromAccountType?: components['schemas']['vegaAccountType'];
|
||||||
readonly oneOff?: components['schemas']['v1OneOffTransfer'];
|
readonly oneOff?: components['schemas']['commandsv1OneOffTransfer'];
|
||||||
readonly recurring?: components['schemas']['v1RecurringTransfer'];
|
readonly recurring?: components['schemas']['commandsv1RecurringTransfer'];
|
||||||
/** @description Reference to be attached to the transfer. */
|
/** @description Reference to be attached to the transfer. */
|
||||||
readonly reference?: string;
|
readonly reference?: string;
|
||||||
/** @description Public key of the destination account. */
|
/** @description Public key of the destination account. */
|
||||||
@@ -171,8 +214,19 @@ export interface components {
|
|||||||
};
|
};
|
||||||
readonly protobufAny: {
|
readonly protobufAny: {
|
||||||
readonly '@type'?: string;
|
readonly '@type'?: string;
|
||||||
[key: string]: unknown | undefined;
|
[key: string]: unknown;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* @description `NullValue` is a singleton enumeration to represent the null value for the
|
||||||
|
* `Value` type union.
|
||||||
|
*
|
||||||
|
* The JSON representation for `NullValue` is JSON `null`.
|
||||||
|
*
|
||||||
|
* - NULL_VALUE: Null value.
|
||||||
|
* @default NULL_VALUE
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
readonly protobufNullValue: 'NULL_VALUE';
|
||||||
/** Used to announce a node as a new pending validator */
|
/** Used to announce a node as a new pending validator */
|
||||||
readonly v1AnnounceNode: {
|
readonly v1AnnounceNode: {
|
||||||
/** @description AvatarURL of the validator. */
|
/** @description AvatarURL of the validator. */
|
||||||
@@ -225,18 +279,19 @@ export interface components {
|
|||||||
readonly amendments?: readonly components['schemas']['v1OrderAmendment'][];
|
readonly amendments?: readonly components['schemas']['v1OrderAmendment'][];
|
||||||
/** @description List of order cancellations to be processed sequentially. */
|
/** @description List of order cancellations to be processed sequentially. */
|
||||||
readonly cancellations?: readonly components['schemas']['v1OrderCancellation'][];
|
readonly cancellations?: readonly components['schemas']['v1OrderCancellation'][];
|
||||||
|
/** @description List of stop order cancellations to be processed sequentially. */
|
||||||
|
readonly stopOrdersCancellation?: readonly components['schemas']['v1StopOrdersCancellation'][];
|
||||||
|
/** @description List of stop order submissions to be processed sequentially. */
|
||||||
|
readonly stopOrdersSubmission?: readonly components['schemas']['v1StopOrdersSubmission'][];
|
||||||
/** @description List of order submissions to be processed sequentially. */
|
/** @description List of order submissions to be processed sequentially. */
|
||||||
readonly submissions?: readonly components['schemas']['v1OrderSubmission'][];
|
readonly submissions?: readonly components['schemas']['v1OrderSubmission'][];
|
||||||
};
|
};
|
||||||
/** Request for cancelling a recurring transfer */
|
|
||||||
readonly v1CancelTransfer: {
|
|
||||||
/** @description Transfer ID of the transfer to cancel. */
|
|
||||||
readonly transferId?: string;
|
|
||||||
};
|
|
||||||
/** Event forwarded to the Vega network to provide information on events happening on other networks */
|
/** Event forwarded to the Vega network to provide information on events happening on other networks */
|
||||||
readonly v1ChainEvent: {
|
readonly v1ChainEvent: {
|
||||||
/** @description Built-in asset event. */
|
/** @description Built-in asset event. */
|
||||||
readonly builtin?: components['schemas']['vegaBuiltinAssetEvent'];
|
readonly builtin?: components['schemas']['vegaBuiltinAssetEvent'];
|
||||||
|
/** Arbitrary contract call */
|
||||||
|
readonly contractCall?: components['schemas']['vegaEthContractCallEvent'];
|
||||||
/** @description Ethereum ERC20 event. */
|
/** @description Ethereum ERC20 event. */
|
||||||
readonly erc20?: components['schemas']['vegaERC20Event'];
|
readonly erc20?: components['schemas']['vegaERC20Event'];
|
||||||
/** @description Ethereum ERC20 multisig event. */
|
/** @description Ethereum ERC20 multisig event. */
|
||||||
@@ -301,6 +356,19 @@ export interface components {
|
|||||||
/** Transaction corresponding to the hash */
|
/** Transaction corresponding to the hash */
|
||||||
readonly transaction?: components['schemas']['blockexplorerapiv1Transaction'];
|
readonly transaction?: components['schemas']['blockexplorerapiv1Transaction'];
|
||||||
};
|
};
|
||||||
|
/** Iceberg order options */
|
||||||
|
readonly v1IcebergOpts: {
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description Minimum allowed remaining size of the order before it is replenished back to its peak size.
|
||||||
|
*/
|
||||||
|
readonly minimumVisibleSize?: string;
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description Size of the order that is made visible and can be traded with during the execution of a single order.
|
||||||
|
*/
|
||||||
|
readonly peakSize?: string;
|
||||||
|
};
|
||||||
readonly v1InfoResponse: {
|
readonly v1InfoResponse: {
|
||||||
/** Commit hash from which the data node was built */
|
/** Commit hash from which the data node was built */
|
||||||
readonly commitHash?: string;
|
readonly commitHash?: string;
|
||||||
@@ -325,7 +393,7 @@ export interface components {
|
|||||||
*/
|
*/
|
||||||
readonly blockHeight?: string;
|
readonly blockHeight?: string;
|
||||||
/** @description Command to request cancelling a recurring transfer. */
|
/** @description Command to request cancelling a recurring transfer. */
|
||||||
readonly cancelTransfer?: components['schemas']['v1CancelTransfer'];
|
readonly cancelTransfer?: components['schemas']['commandsv1CancelTransfer'];
|
||||||
/**
|
/**
|
||||||
* @description Command used by a validator to submit an event forwarded to the Vega network to provide information
|
* @description Command used by a validator to submit an event forwarded to the Vega network to provide information
|
||||||
* on events happening on other networks, to be used by a foreign chain
|
* on events happening on other networks, to be used by a foreign chain
|
||||||
@@ -381,6 +449,10 @@ export interface components {
|
|||||||
readonly protocolUpgradeProposal?: components['schemas']['v1ProtocolUpgradeProposal'];
|
readonly protocolUpgradeProposal?: components['schemas']['v1ProtocolUpgradeProposal'];
|
||||||
/** @description Command used by a validator to submit a floating point value. */
|
/** @description Command used by a validator to submit a floating point value. */
|
||||||
readonly stateVariableProposal?: components['schemas']['v1StateVariableProposal'];
|
readonly stateVariableProposal?: components['schemas']['v1StateVariableProposal'];
|
||||||
|
/** @description Command to cancel stop orders. */
|
||||||
|
readonly stopOrdersCancellation?: components['schemas']['v1StopOrdersCancellation'];
|
||||||
|
/** @description Command to submit a pair of stop orders. */
|
||||||
|
readonly stopOrdersSubmission?: components['schemas']['v1StopOrdersSubmission'];
|
||||||
/** @description Command to submit a transfer. */
|
/** @description Command to submit a transfer. */
|
||||||
readonly transfer?: components['schemas']['commandsv1Transfer'];
|
readonly transfer?: components['schemas']['commandsv1Transfer'];
|
||||||
/** @description Command to remove tokens delegated to a validator. */
|
/** @description Command to remove tokens delegated to a validator. */
|
||||||
@@ -448,9 +520,9 @@ export interface components {
|
|||||||
readonly commitmentAmount?: string;
|
readonly commitmentAmount?: string;
|
||||||
/** @description Nominated liquidity fee factor, which is an input to the calculation of taker fees on the market, as per setting fees and rewarding liquidity providers. */
|
/** @description Nominated liquidity fee factor, which is an input to the calculation of taker fees on the market, as per setting fees and rewarding liquidity providers. */
|
||||||
readonly fee?: string;
|
readonly fee?: string;
|
||||||
/** @description Market ID for the order, required field. */
|
/** @description Market ID for the order. */
|
||||||
readonly marketId?: string;
|
readonly marketId?: string;
|
||||||
/** @description Reference to be added to every order created out of this liquidityProvisionSubmission. */
|
/** @description Reference to be added to every order created out of this liquidity provision submission. */
|
||||||
readonly reference?: string;
|
readonly reference?: string;
|
||||||
/** @description Set of liquidity sell orders to meet the liquidity provision obligation. */
|
/** @description Set of liquidity sell orders to meet the liquidity provision obligation. */
|
||||||
readonly sells?: readonly components['schemas']['vegaLiquidityOrder'][];
|
readonly sells?: readonly components['schemas']['vegaLiquidityOrder'][];
|
||||||
@@ -530,15 +602,6 @@ export interface components {
|
|||||||
| 'TYPE_STAKE_TOTAL_SUPPLY'
|
| 'TYPE_STAKE_TOTAL_SUPPLY'
|
||||||
| 'TYPE_SIGNER_THRESHOLD_SET'
|
| 'TYPE_SIGNER_THRESHOLD_SET'
|
||||||
| 'TYPE_GOVERNANCE_VALIDATE_ASSET';
|
| 'TYPE_GOVERNANCE_VALIDATE_ASSET';
|
||||||
/** Specific details for a one off transfer */
|
|
||||||
readonly v1OneOffTransfer: {
|
|
||||||
/**
|
|
||||||
* Format: int64
|
|
||||||
* @description Unix timestamp in nanoseconds. Time at which the
|
|
||||||
* transfer should be delivered into the To account.
|
|
||||||
*/
|
|
||||||
readonly deliverOn?: string;
|
|
||||||
};
|
|
||||||
/** Command to submit new Oracle data from third party providers */
|
/** Command to submit new Oracle data from third party providers */
|
||||||
readonly v1OracleDataSubmission: {
|
readonly v1OracleDataSubmission: {
|
||||||
/**
|
/**
|
||||||
@@ -596,10 +659,12 @@ export interface components {
|
|||||||
readonly v1OrderSubmission: {
|
readonly v1OrderSubmission: {
|
||||||
/**
|
/**
|
||||||
* Format: int64
|
* Format: int64
|
||||||
* @description Timestamp for when the order will expire, in nanoseconds,
|
* @description Timestamp in Unix nanoseconds for when the order will expire,
|
||||||
* required field only for `Order.TimeInForce`.TIME_IN_FORCE_GTT`.
|
* required field only for `Order.TimeInForce`.TIME_IN_FORCE_GTT`.
|
||||||
*/
|
*/
|
||||||
readonly expiresAt?: string;
|
readonly expiresAt?: string;
|
||||||
|
/** @description Parameters used to specify an iceberg order. */
|
||||||
|
readonly icebergOpts?: components['schemas']['v1IcebergOpts'];
|
||||||
/** @description Market ID for the order, required field. */
|
/** @description Market ID for the order, required field. */
|
||||||
readonly marketId?: string;
|
readonly marketId?: string;
|
||||||
/** @description Used to specify the details for a pegged order. */
|
/** @description Used to specify the details for a pegged order. */
|
||||||
@@ -699,23 +764,6 @@ export interface components {
|
|||||||
readonly v1PubKey: {
|
readonly v1PubKey: {
|
||||||
readonly key?: string;
|
readonly key?: string;
|
||||||
};
|
};
|
||||||
/** Specific details for a recurring transfer */
|
|
||||||
readonly v1RecurringTransfer: {
|
|
||||||
/** @description Optional parameter defining how a transfer is dispatched. */
|
|
||||||
readonly dispatchStrategy?: components['schemas']['vegaDispatchStrategy'];
|
|
||||||
/**
|
|
||||||
* Format: uint64
|
|
||||||
* @description Last epoch at which this transfer shall be paid.
|
|
||||||
*/
|
|
||||||
readonly endEpoch?: string;
|
|
||||||
/** @description Factor needs to be > 0. */
|
|
||||||
readonly factor?: string;
|
|
||||||
/**
|
|
||||||
* Format: uint64
|
|
||||||
* @description First epoch from which this transfer shall be paid.
|
|
||||||
*/
|
|
||||||
readonly startEpoch?: string;
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* @description Signature to authenticate a transaction and to be verified by the Vega
|
* @description Signature to authenticate a transaction and to be verified by the Vega
|
||||||
* network.
|
* network.
|
||||||
@@ -732,7 +780,7 @@ export interface components {
|
|||||||
readonly version?: number;
|
readonly version?: number;
|
||||||
};
|
};
|
||||||
readonly v1Signer: {
|
readonly v1Signer: {
|
||||||
/** In case of an open oracle - Ethereum address will be submitted */
|
/** @description In case of an open oracle - Ethereum address will be submitted. */
|
||||||
readonly ethAddress?: components['schemas']['v1ETHAddress'];
|
readonly ethAddress?: components['schemas']['v1ETHAddress'];
|
||||||
/**
|
/**
|
||||||
* @description List of authorized public keys that signed the data for this
|
* @description List of authorized public keys that signed the data for this
|
||||||
@@ -746,6 +794,55 @@ export interface components {
|
|||||||
/** @description State value proposal details. */
|
/** @description State value proposal details. */
|
||||||
readonly proposal?: components['schemas']['vegaStateValueProposal'];
|
readonly proposal?: components['schemas']['vegaStateValueProposal'];
|
||||||
};
|
};
|
||||||
|
/** Price and expiry configuration for a stop order */
|
||||||
|
readonly v1StopOrderSetup: {
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description Optional expiry timestamp.
|
||||||
|
*/
|
||||||
|
readonly expiresAt?: string;
|
||||||
|
/** @description Strategy to adopt if the expiry time is reached. */
|
||||||
|
readonly expiryStrategy?: components['schemas']['StopOrderExpiryStrategy'];
|
||||||
|
/** @description Order to be submitted once the trigger is breached. */
|
||||||
|
readonly orderSubmission?: components['schemas']['v1OrderSubmission'];
|
||||||
|
/** @description Fixed price at which the order will be submitted. */
|
||||||
|
readonly price?: string;
|
||||||
|
/** @description Trailing percentage at which the order will be submitted. */
|
||||||
|
readonly trailingPercentOffset?: string;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Cancel a stop order.
|
||||||
|
* The following combinations are available:
|
||||||
|
* Empty object will cancel all stop orders for the party
|
||||||
|
* Market ID alone will cancel all stop orders in a market
|
||||||
|
* Market ID and order ID will cancel a specific stop order in a market
|
||||||
|
* If the stop order is part of an OCO, both stop orders will be cancelled
|
||||||
|
*/
|
||||||
|
readonly v1StopOrdersCancellation: {
|
||||||
|
/** @description Optional market ID. */
|
||||||
|
readonly marketId?: string;
|
||||||
|
/** @description Optional order ID. */
|
||||||
|
readonly stopOrderId?: string;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Stop order submission submits stops orders.
|
||||||
|
* It is possible to make a single stop order submission by
|
||||||
|
* specifying a single direction,
|
||||||
|
* or an OCO (One Cancels the Other) stop order submission
|
||||||
|
* by specifying a configuration for both directions
|
||||||
|
*/
|
||||||
|
readonly v1StopOrdersSubmission: {
|
||||||
|
/**
|
||||||
|
* @description Stop order that will be triggered
|
||||||
|
* if the price falls below a given trigger price.
|
||||||
|
*/
|
||||||
|
readonly fallsBelow?: components['schemas']['v1StopOrderSetup'];
|
||||||
|
/**
|
||||||
|
* @description Stop order that will be triggered
|
||||||
|
* if the price rises above a given trigger price.
|
||||||
|
*/
|
||||||
|
readonly risesAbove?: components['schemas']['v1StopOrderSetup'];
|
||||||
|
};
|
||||||
readonly v1UndelegateSubmission: {
|
readonly v1UndelegateSubmission: {
|
||||||
/**
|
/**
|
||||||
* @description Optional, if not specified = ALL.
|
* @description Optional, if not specified = ALL.
|
||||||
@@ -822,6 +919,7 @@ export interface components {
|
|||||||
* - ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: Per asset reward account for fees received by makers
|
* - ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: Per asset reward account for fees received by makers
|
||||||
* - ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: Per asset reward account for fees received by liquidity providers
|
* - ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: Per asset reward account for fees received by liquidity providers
|
||||||
* - ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: Per asset reward account for market proposers when the market goes above some trading threshold
|
* - ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: Per asset reward account for market proposers when the market goes above some trading threshold
|
||||||
|
* - ACCOUNT_TYPE_HOLDING: Per asset account for holding in-flight unfilled orders' funds
|
||||||
* @default ACCOUNT_TYPE_UNSPECIFIED
|
* @default ACCOUNT_TYPE_UNSPECIFIED
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
@@ -842,7 +940,8 @@ export interface components {
|
|||||||
| 'ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES'
|
| 'ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES'
|
||||||
| 'ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES'
|
| 'ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES'
|
||||||
| 'ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES'
|
| 'ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES'
|
||||||
| 'ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS';
|
| 'ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS'
|
||||||
|
| 'ACCOUNT_TYPE_HOLDING';
|
||||||
/** Vega representation of an external asset */
|
/** Vega representation of an external asset */
|
||||||
readonly vegaAssetDetails: {
|
readonly vegaAssetDetails: {
|
||||||
/** @description Vega built-in asset. */
|
/** @description Vega built-in asset. */
|
||||||
@@ -898,6 +997,14 @@ export interface components {
|
|||||||
/** @description Vega network internal asset ID. */
|
/** @description Vega network internal asset ID. */
|
||||||
readonly vegaAssetId?: string;
|
readonly vegaAssetId?: string;
|
||||||
};
|
};
|
||||||
|
readonly vegaCancelTransfer: {
|
||||||
|
/** Configuration for cancellation of a governance-initiated transfer */
|
||||||
|
readonly changes?: components['schemas']['vegaCancelTransferConfiguration'];
|
||||||
|
};
|
||||||
|
readonly vegaCancelTransferConfiguration: {
|
||||||
|
/** @description ID of the governance transfer proposal. */
|
||||||
|
readonly transferId?: string;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* @description DataSourceDefinition represents the top level object that deals with data sources.
|
* @description DataSourceDefinition represents the top level object that deals with data sources.
|
||||||
* DataSourceDefinition can be external or internal, with whatever number of data sources are defined
|
* DataSourceDefinition can be external or internal, with whatever number of data sources are defined
|
||||||
@@ -912,6 +1019,7 @@ export interface components {
|
|||||||
* It contains one of any of the defined `SourceType` variants.
|
* It contains one of any of the defined `SourceType` variants.
|
||||||
*/
|
*/
|
||||||
readonly vegaDataSourceDefinitionExternal: {
|
readonly vegaDataSourceDefinitionExternal: {
|
||||||
|
readonly ethCall?: components['schemas']['vegaEthCallSpec'];
|
||||||
readonly oracle?: components['schemas']['vegaDataSourceSpecConfiguration'];
|
readonly oracle?: components['schemas']['vegaDataSourceSpecConfiguration'];
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
@@ -1147,6 +1255,64 @@ export interface components {
|
|||||||
/** @description Address into which the bridge will release the funds. */
|
/** @description Address into which the bridge will release the funds. */
|
||||||
readonly receiverAddress?: string;
|
readonly receiverAddress?: string;
|
||||||
};
|
};
|
||||||
|
/** @description Specifies a data source that derives its content from calling a read method on an Ethereum contract. */
|
||||||
|
readonly vegaEthCallSpec: {
|
||||||
|
/** @description The ABI of that contract. */
|
||||||
|
readonly abi?: readonly Record<string, never>[];
|
||||||
|
/** @description Ethereum address of the contract to call. */
|
||||||
|
readonly address?: string;
|
||||||
|
/**
|
||||||
|
* @description List of arguments to pass to method call.
|
||||||
|
* Protobuf 'Value' wraps an arbitrary JSON type that is mapped to an Ethereum type according to the ABI.
|
||||||
|
*/
|
||||||
|
readonly args?: readonly Record<string, never>[];
|
||||||
|
/** @description Name of the method on the contract to call. */
|
||||||
|
readonly method?: string;
|
||||||
|
/** @description Conditions for determining when to call the contract method. */
|
||||||
|
readonly trigger?: components['schemas']['vegaEthCallTrigger'];
|
||||||
|
};
|
||||||
|
/** @description Determines when the contract method should be called. */
|
||||||
|
readonly vegaEthCallTrigger: {
|
||||||
|
readonly timeTrigger?: components['schemas']['vegaEthTimeTrigger'];
|
||||||
|
};
|
||||||
|
/** Result of calling an arbitrary Ethereum contract method */
|
||||||
|
readonly vegaEthContractCallEvent: {
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description Ethereum block height.
|
||||||
|
*/
|
||||||
|
readonly blockHeight?: string;
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description Ethereum block time in Unix seconds.
|
||||||
|
*/
|
||||||
|
readonly blockTime?: string;
|
||||||
|
/**
|
||||||
|
* Format: byte
|
||||||
|
* @description Result of contract call, packed according to the ABI stored in the associated data source spec.
|
||||||
|
*/
|
||||||
|
readonly result?: string;
|
||||||
|
/** @description ID of the data source spec that triggered this contract call. */
|
||||||
|
readonly specId?: string;
|
||||||
|
};
|
||||||
|
/** @description Trigger for an Ethereum call based on the Ethereum block timestamp. Can be one-off or repeating. */
|
||||||
|
readonly vegaEthTimeTrigger: {
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description Repeat the call every n seconds after the inital call. If no time for initial call was specified, begin repeating immediately.
|
||||||
|
*/
|
||||||
|
readonly every?: string;
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description Trigger when the Ethereum time is greater or equal to this time, in Unix seconds.
|
||||||
|
*/
|
||||||
|
readonly initial?: string;
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description If repeating, stop once Ethereum time is greater than this time, in Unix seconds. If not set, then repeat indefinitely.
|
||||||
|
*/
|
||||||
|
readonly until?: string;
|
||||||
|
};
|
||||||
/** Future product configuration */
|
/** Future product configuration */
|
||||||
readonly vegaFutureProduct: {
|
readonly vegaFutureProduct: {
|
||||||
/** @description Binding between the data source spec and the settlement data. */
|
/** @description Binding between the data source spec and the settlement data. */
|
||||||
@@ -1160,6 +1326,14 @@ export interface components {
|
|||||||
/** @description Asset ID for the product's settlement asset. */
|
/** @description Asset ID for the product's settlement asset. */
|
||||||
readonly settlementAsset?: string;
|
readonly settlementAsset?: string;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* @default GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
readonly vegaGovernanceTransferType:
|
||||||
|
| 'GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED'
|
||||||
|
| 'GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING'
|
||||||
|
| 'GOVERNANCE_TRANSFER_TYPE_BEST_EFFORT';
|
||||||
/** Instrument configuration */
|
/** Instrument configuration */
|
||||||
readonly vegaInstrumentConfiguration: {
|
readonly vegaInstrumentConfiguration: {
|
||||||
/** @description Instrument code, human-readable shortcode used to describe the instrument. */
|
/** @description Instrument code, human-readable shortcode used to describe the instrument. */
|
||||||
@@ -1168,6 +1342,8 @@ export interface components {
|
|||||||
readonly future?: components['schemas']['vegaFutureProduct'];
|
readonly future?: components['schemas']['vegaFutureProduct'];
|
||||||
/** @description Instrument name. */
|
/** @description Instrument name. */
|
||||||
readonly name?: string;
|
readonly name?: string;
|
||||||
|
/** @description Spot. */
|
||||||
|
readonly spot?: components['schemas']['vegaSpotProduct'];
|
||||||
};
|
};
|
||||||
readonly vegaKeyValueBundle: {
|
readonly vegaKeyValueBundle: {
|
||||||
readonly key?: string;
|
readonly key?: string;
|
||||||
@@ -1258,14 +1434,14 @@ export interface components {
|
|||||||
/** @description Configuration of the new market. */
|
/** @description Configuration of the new market. */
|
||||||
readonly changes?: components['schemas']['vegaNewMarketConfiguration'];
|
readonly changes?: components['schemas']['vegaNewMarketConfiguration'];
|
||||||
};
|
};
|
||||||
/** Configuration for a new market on Vega */
|
/** Configuration for a new futures market on Vega */
|
||||||
readonly vegaNewMarketConfiguration: {
|
readonly vegaNewMarketConfiguration: {
|
||||||
/**
|
/**
|
||||||
* Format: uint64
|
* Format: uint64
|
||||||
* @description Decimal places used for the new market, sets the smallest price increment on the book.
|
* @description Decimal places used for the new futures market, sets the smallest price increment on the book.
|
||||||
*/
|
*/
|
||||||
readonly decimalPlaces?: string;
|
readonly decimalPlaces?: string;
|
||||||
/** @description New market instrument configuration. */
|
/** @description New futures market instrument configuration. */
|
||||||
readonly instrument?: components['schemas']['vegaInstrumentConfiguration'];
|
readonly instrument?: components['schemas']['vegaInstrumentConfiguration'];
|
||||||
/** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */
|
/** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */
|
||||||
readonly linearSlippageFactor?: string;
|
readonly linearSlippageFactor?: string;
|
||||||
@@ -1278,11 +1454,11 @@ export interface components {
|
|||||||
* price levels over which automated liquidity provision orders will be deployed.
|
* price levels over which automated liquidity provision orders will be deployed.
|
||||||
*/
|
*/
|
||||||
readonly lpPriceRange?: string;
|
readonly lpPriceRange?: string;
|
||||||
/** @description Optional new market metadata, tags. */
|
/** @description Optional new futures market metadata, tags. */
|
||||||
readonly metadata?: readonly string[];
|
readonly metadata?: readonly string[];
|
||||||
/**
|
/**
|
||||||
* Format: int64
|
* Format: int64
|
||||||
* @description Decimal places for order sizes, sets what size the smallest order / position on the market can be.
|
* @description Decimal places for order sizes, sets what size the smallest order / position on the futures market can be.
|
||||||
*/
|
*/
|
||||||
readonly positionDecimalPlaces?: string;
|
readonly positionDecimalPlaces?: string;
|
||||||
/** @description Price monitoring parameters. */
|
/** @description Price monitoring parameters. */
|
||||||
@@ -1291,6 +1467,80 @@ export interface components {
|
|||||||
readonly quadraticSlippageFactor?: string;
|
readonly quadraticSlippageFactor?: string;
|
||||||
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
|
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
|
||||||
readonly simple?: components['schemas']['vegaSimpleModelParams'];
|
readonly simple?: components['schemas']['vegaSimpleModelParams'];
|
||||||
|
/** @description Successor configuration. If this proposal is meant to succeed a given market, then this should be set. */
|
||||||
|
readonly successor?: components['schemas']['vegaSuccessorConfiguration'];
|
||||||
|
};
|
||||||
|
/** New spot market on Vega */
|
||||||
|
readonly vegaNewSpotMarket: {
|
||||||
|
/** @description Configuration of the new spot market. */
|
||||||
|
readonly changes?: components['schemas']['vegaNewSpotMarketConfiguration'];
|
||||||
|
};
|
||||||
|
/** Configuration for a new spot market on Vega */
|
||||||
|
readonly vegaNewSpotMarketConfiguration: {
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description Decimal places used for the new spot market, sets the smallest price increment on the book.
|
||||||
|
*/
|
||||||
|
readonly decimalPlaces?: string;
|
||||||
|
/** @description New spot market instrument configuration. */
|
||||||
|
readonly instrument?: components['schemas']['vegaInstrumentConfiguration'];
|
||||||
|
/** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */
|
||||||
|
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
|
||||||
|
/** @description Optional new spot market metadata, tags. */
|
||||||
|
readonly metadata?: readonly string[];
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description Decimal places for order sizes, sets what size the smallest order / position on the spot market can be.
|
||||||
|
*/
|
||||||
|
readonly positionDecimalPlaces?: string;
|
||||||
|
/** @description Price monitoring parameters. */
|
||||||
|
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
|
||||||
|
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
|
||||||
|
readonly simple?: components['schemas']['vegaSimpleModelParams'];
|
||||||
|
/** @description Specifies parameters related to target stake calculation. */
|
||||||
|
readonly targetStakeParameters?: components['schemas']['vegaTargetStakeParameters'];
|
||||||
|
};
|
||||||
|
/** New governance transfer */
|
||||||
|
readonly vegaNewTransfer: {
|
||||||
|
/** @description Configuration for a new transfer. */
|
||||||
|
readonly changes?: components['schemas']['vegaNewTransferConfiguration'];
|
||||||
|
};
|
||||||
|
readonly vegaNewTransferConfiguration: {
|
||||||
|
/** Maximum amount to transfer */
|
||||||
|
readonly amount?: string;
|
||||||
|
/** ID of asset to transfer */
|
||||||
|
readonly asset?: string;
|
||||||
|
/**
|
||||||
|
* Specifies the account to transfer to, depending on the account type:
|
||||||
|
* Network treasury: leave empty
|
||||||
|
* Party: party's public key
|
||||||
|
* Market insurance pool: market ID
|
||||||
|
*/
|
||||||
|
readonly destination?: string;
|
||||||
|
/** Specifies the account type to transfer to: reward pool, party, network insurance pool, market insurance pool */
|
||||||
|
readonly destinationType?: components['schemas']['vegaAccountType'];
|
||||||
|
/** Maximum fraction of the source account's balance to transfer as a decimal - i.e. 0.1 = 10% of the balance */
|
||||||
|
readonly fractionOfBalance?: string;
|
||||||
|
readonly oneOff?: components['schemas']['vegaOneOffTransfer'];
|
||||||
|
readonly recurring?: components['schemas']['vegaRecurringTransfer'];
|
||||||
|
/** If network treasury, field is empty, otherwise uses the market ID */
|
||||||
|
readonly source?: string;
|
||||||
|
/** Source account type, such as network treasury, market insurance pool */
|
||||||
|
readonly sourceType?: components['schemas']['vegaAccountType'];
|
||||||
|
/**
|
||||||
|
* "All or nothing" or "best effort":
|
||||||
|
* All or nothing: Transfers the specified amount or does not transfer anything
|
||||||
|
* Best effort: Transfers the specified amount or the max allowable amount if this is less than the specified amount
|
||||||
|
*/
|
||||||
|
readonly transferType?: components['schemas']['vegaGovernanceTransferType'];
|
||||||
|
};
|
||||||
|
/** Specific details for a one off transfer */
|
||||||
|
readonly vegaOneOffTransfer: {
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description Timestamp in Unix nanoseconds for when the transfer should be delivered into the receiver's account.
|
||||||
|
*/
|
||||||
|
readonly deliverOn?: string;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Type values for an order
|
* Type values for an order
|
||||||
@@ -1369,6 +1619,8 @@ export interface components {
|
|||||||
};
|
};
|
||||||
/** Terms for a governance proposal on Vega */
|
/** Terms for a governance proposal on Vega */
|
||||||
readonly vegaProposalTerms: {
|
readonly vegaProposalTerms: {
|
||||||
|
/** @description Cancel a governance transfer. */
|
||||||
|
readonly cancelTransfer?: components['schemas']['vegaCancelTransfer'];
|
||||||
/**
|
/**
|
||||||
* Format: int64
|
* Format: int64
|
||||||
* @description Timestamp as Unix time in seconds when voting closes for this proposal,
|
* @description Timestamp as Unix time in seconds when voting closes for this proposal,
|
||||||
@@ -1388,20 +1640,39 @@ export interface components {
|
|||||||
* and can be used to gauge community sentiment.
|
* and can be used to gauge community sentiment.
|
||||||
*/
|
*/
|
||||||
readonly newFreeform?: components['schemas']['vegaNewFreeform'];
|
readonly newFreeform?: components['schemas']['vegaNewFreeform'];
|
||||||
/** @description Proposal change for creating new market on Vega. */
|
/** @description Proposal change for creating new futures market on Vega. */
|
||||||
readonly newMarket?: components['schemas']['vegaNewMarket'];
|
readonly newMarket?: components['schemas']['vegaNewMarket'];
|
||||||
|
/** @description Proposal change for creating new spot market on Vega. */
|
||||||
|
readonly newSpotMarket?: components['schemas']['vegaNewSpotMarket'];
|
||||||
|
/** @description Proposal change for a governance transfer. */
|
||||||
|
readonly newTransfer?: components['schemas']['vegaNewTransfer'];
|
||||||
/** @description Proposal change for updating an asset. */
|
/** @description Proposal change for updating an asset. */
|
||||||
readonly updateAsset?: components['schemas']['vegaUpdateAsset'];
|
readonly updateAsset?: components['schemas']['vegaUpdateAsset'];
|
||||||
/** @description Proposal change for modifying an existing market on Vega. */
|
/** @description Proposal change for modifying an existing futures market on Vega. */
|
||||||
readonly updateMarket?: components['schemas']['vegaUpdateMarket'];
|
readonly updateMarket?: components['schemas']['vegaUpdateMarket'];
|
||||||
/** @description Proposal change for updating Vega network parameters. */
|
/** @description Proposal change for updating Vega network parameters. */
|
||||||
readonly updateNetworkParameter?: components['schemas']['vegaUpdateNetworkParameter'];
|
readonly updateNetworkParameter?: components['schemas']['vegaUpdateNetworkParameter'];
|
||||||
|
/** @description Proposal change for modifying an existing spot market on Vega. */
|
||||||
|
readonly updateSpotMarket?: components['schemas']['vegaUpdateSpotMarket'];
|
||||||
/**
|
/**
|
||||||
* Format: int64
|
* Format: int64
|
||||||
* @description Validation timestamp as Unix time in seconds.
|
* @description Validation timestamp as Unix time in seconds.
|
||||||
*/
|
*/
|
||||||
readonly validationTimestamp?: string;
|
readonly validationTimestamp?: string;
|
||||||
};
|
};
|
||||||
|
/** Specific details for a recurring transfer */
|
||||||
|
readonly vegaRecurringTransfer: {
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description Last epoch at which this transfer shall be paid.
|
||||||
|
*/
|
||||||
|
readonly endEpoch?: string;
|
||||||
|
/**
|
||||||
|
* Format: uint64
|
||||||
|
* @description First epoch from which this transfer shall be paid.
|
||||||
|
*/
|
||||||
|
readonly startEpoch?: string;
|
||||||
|
};
|
||||||
readonly vegaScalarValue: {
|
readonly vegaScalarValue: {
|
||||||
readonly value?: string;
|
readonly value?: string;
|
||||||
};
|
};
|
||||||
@@ -1442,6 +1713,15 @@ export interface components {
|
|||||||
*/
|
*/
|
||||||
readonly probabilityOfTrading?: number;
|
readonly probabilityOfTrading?: number;
|
||||||
};
|
};
|
||||||
|
/** Spot product configuration */
|
||||||
|
readonly vegaSpotProduct: {
|
||||||
|
/** @description Base asset ID. */
|
||||||
|
readonly baseAsset?: string;
|
||||||
|
/** @description Product name. */
|
||||||
|
readonly name?: string;
|
||||||
|
/** @description Quote asset ID. */
|
||||||
|
readonly quoteAsset?: string;
|
||||||
|
};
|
||||||
readonly vegaStakeDeposited: {
|
readonly vegaStakeDeposited: {
|
||||||
/** @description Amount deposited as an unsigned base 10 integer scaled to the asset's decimal places. */
|
/** @description Amount deposited as an unsigned base 10 integer scaled to the asset's decimal places. */
|
||||||
readonly amount?: string;
|
readonly amount?: string;
|
||||||
@@ -1507,6 +1787,13 @@ export interface components {
|
|||||||
readonly scalarVal?: components['schemas']['vegaScalarValue'];
|
readonly scalarVal?: components['schemas']['vegaScalarValue'];
|
||||||
readonly vectorVal?: components['schemas']['vegaVectorValue'];
|
readonly vectorVal?: components['schemas']['vegaVectorValue'];
|
||||||
};
|
};
|
||||||
|
/** @description Configuration required to turn a new market proposal in to a successor market proposal. */
|
||||||
|
readonly vegaSuccessorConfiguration: {
|
||||||
|
/** @description A decimal value between or equal to 0 and 1, specifying the fraction of the insurance pool balance that is carried over from the parent market to the successor. */
|
||||||
|
readonly insurancePoolFraction?: string;
|
||||||
|
/** @description ID of the market that the successor should take over from. */
|
||||||
|
readonly parentMarketId?: string;
|
||||||
|
};
|
||||||
/** TargetStakeParameters contains parameters used in target stake calculation */
|
/** TargetStakeParameters contains parameters used in target stake calculation */
|
||||||
readonly vegaTargetStakeParameters: {
|
readonly vegaTargetStakeParameters: {
|
||||||
/**
|
/**
|
||||||
@@ -1547,14 +1834,14 @@ export interface components {
|
|||||||
};
|
};
|
||||||
/** Update an existing market on Vega */
|
/** Update an existing market on Vega */
|
||||||
readonly vegaUpdateMarket: {
|
readonly vegaUpdateMarket: {
|
||||||
/** @description Updated configuration of the market. */
|
/** @description Updated configuration of the futures market. */
|
||||||
readonly changes?: components['schemas']['vegaUpdateMarketConfiguration'];
|
readonly changes?: components['schemas']['vegaUpdateMarketConfiguration'];
|
||||||
/** @description Market ID the update is for. */
|
/** @description Market ID the update is for. */
|
||||||
readonly marketId?: string;
|
readonly marketId?: string;
|
||||||
};
|
};
|
||||||
/** Configuration to update a market on Vega */
|
/** Configuration to update a futures market on Vega */
|
||||||
readonly vegaUpdateMarketConfiguration: {
|
readonly vegaUpdateMarketConfiguration: {
|
||||||
/** @description Updated market instrument configuration. */
|
/** @description Updated futures market instrument configuration. */
|
||||||
readonly instrument?: components['schemas']['vegaUpdateInstrumentConfiguration'];
|
readonly instrument?: components['schemas']['vegaUpdateInstrumentConfiguration'];
|
||||||
/** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */
|
/** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */
|
||||||
readonly linearSlippageFactor?: string;
|
readonly linearSlippageFactor?: string;
|
||||||
@@ -1567,7 +1854,7 @@ export interface components {
|
|||||||
* price levels over which automated liquidity provision orders will be deployed.
|
* price levels over which automated liquidity provision orders will be deployed.
|
||||||
*/
|
*/
|
||||||
readonly lpPriceRange?: string;
|
readonly lpPriceRange?: string;
|
||||||
/** @description Optional market metadata, tags. */
|
/** @description Optional futures market metadata, tags. */
|
||||||
readonly metadata?: readonly string[];
|
readonly metadata?: readonly string[];
|
||||||
/** @description Price monitoring parameters. */
|
/** @description Price monitoring parameters. */
|
||||||
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
|
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
|
||||||
@@ -1581,6 +1868,26 @@ export interface components {
|
|||||||
/** @description The network parameter to update. */
|
/** @description The network parameter to update. */
|
||||||
readonly changes?: components['schemas']['vegaNetworkParameter'];
|
readonly changes?: components['schemas']['vegaNetworkParameter'];
|
||||||
};
|
};
|
||||||
|
/** Update an existing spot market on Vega */
|
||||||
|
readonly vegaUpdateSpotMarket: {
|
||||||
|
/** @description Updated configuration of the spot market. */
|
||||||
|
readonly changes?: components['schemas']['vegaUpdateSpotMarketConfiguration'];
|
||||||
|
/** @description Market ID the update is for. */
|
||||||
|
readonly marketId?: string;
|
||||||
|
};
|
||||||
|
/** Configuration to update a spot market on Vega */
|
||||||
|
readonly vegaUpdateSpotMarketConfiguration: {
|
||||||
|
/** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */
|
||||||
|
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
|
||||||
|
/** @description Optional spot market metadata, tags. */
|
||||||
|
readonly metadata?: readonly string[];
|
||||||
|
/** @description Price monitoring parameters. */
|
||||||
|
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
|
||||||
|
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
|
||||||
|
readonly simple?: components['schemas']['vegaSimpleModelParams'];
|
||||||
|
/** @description Specifies parameters related to target stake calculation. */
|
||||||
|
readonly targetStakeParameters?: components['schemas']['vegaTargetStakeParameters'];
|
||||||
|
};
|
||||||
readonly vegaVectorValue: {
|
readonly vegaVectorValue: {
|
||||||
readonly value?: readonly string[];
|
readonly value?: readonly string[];
|
||||||
};
|
};
|
||||||
@@ -1609,12 +1916,12 @@ export interface components {
|
|||||||
export type external = Record<string, never>;
|
export type external = Record<string, never>;
|
||||||
|
|
||||||
export interface operations {
|
export interface operations {
|
||||||
|
/**
|
||||||
|
* Info
|
||||||
|
* @description Get information about the block explorer.
|
||||||
|
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built
|
||||||
|
*/
|
||||||
BlockExplorer_Info: {
|
BlockExplorer_Info: {
|
||||||
/**
|
|
||||||
* Info
|
|
||||||
* @description Get information about the block explorer.
|
|
||||||
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built
|
|
||||||
*/
|
|
||||||
responses: {
|
responses: {
|
||||||
/** @description A successful response. */
|
/** @description A successful response. */
|
||||||
200: {
|
200: {
|
||||||
@@ -1630,19 +1937,38 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* List transactions
|
||||||
|
* @description List transactions from the Vega blockchain
|
||||||
|
*/
|
||||||
BlockExplorer_ListTransactions: {
|
BlockExplorer_ListTransactions: {
|
||||||
/**
|
parameters: {
|
||||||
* List transactions
|
query?: {
|
||||||
* @description List transactions from the Vega blockchain
|
/**
|
||||||
*/
|
* @description Number of transactions to be returned from the blockchain.
|
||||||
parameters?: {
|
* This is deprecated, use first and last instead.
|
||||||
/** @description Number of transactions to be returned from the blockchain. */
|
*/
|
||||||
/** @description Optional cursor to paginate the request. */
|
|
||||||
/** @description Optional cursor to paginate the request. */
|
|
||||||
readonly query?: {
|
|
||||||
limit?: number;
|
limit?: number;
|
||||||
|
/** @description Optional cursor to paginate the request. */
|
||||||
before?: string;
|
before?: string;
|
||||||
|
/** @description Optional cursor to paginate the request. */
|
||||||
after?: string;
|
after?: string;
|
||||||
|
/** @description Transaction command types filter, for listing transactions with specified command types. */
|
||||||
|
cmdTypes?: readonly string[];
|
||||||
|
/** @description Transaction command types exclusion filter, for listing all the transactions except the ones with specified command types. */
|
||||||
|
excludeCmdTypes?: readonly string[];
|
||||||
|
/** @description Party IDs filter, can be sender or receiver. */
|
||||||
|
parties?: readonly string[];
|
||||||
|
/**
|
||||||
|
* @description Number of transactions to be returned from the blockchain. Use in conjunction with the `after` cursor to paginate forwards.
|
||||||
|
* On its own, this will return the first `first` transactions.
|
||||||
|
*/
|
||||||
|
first?: number;
|
||||||
|
/**
|
||||||
|
* @description Number of transactions to be returned from the blockchain. Use in conjunction with the `before` cursor to paginate backwards.
|
||||||
|
* On its own, this will return the last `last` transactions.
|
||||||
|
*/
|
||||||
|
last?: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
responses: {
|
responses: {
|
||||||
@@ -1660,14 +1986,14 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* Get transaction
|
||||||
|
* @description Get a transaction from the Vega blockchain
|
||||||
|
*/
|
||||||
BlockExplorer_GetTransaction: {
|
BlockExplorer_GetTransaction: {
|
||||||
/**
|
|
||||||
* Get transaction
|
|
||||||
* @description Get a transaction from the Vega blockchain
|
|
||||||
*/
|
|
||||||
parameters: {
|
parameters: {
|
||||||
/** @description Hash of the transaction */
|
path: {
|
||||||
readonly path: {
|
/** @description Hash of the transaction */
|
||||||
hash: string;
|
hash: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const { join } = require('path');
|
const { join } = require('path');
|
||||||
const { createGlobPatternsForDependencies } = require('@nrwl/next/tailwind');
|
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
||||||
const theme = require('../../libs/tailwindcss-config/src/theme');
|
const theme = require('../../libs/tailwindcss-config/src/theme');
|
||||||
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
"types": ["node"]
|
"types": ["node"]
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
|
||||||
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
"../../node_modules/@nx/react/typings/image.d.ts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"**/*.spec.ts",
|
"**/*.spec.ts",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"jest.config.ts"
|
"jest.config.ts"
|
||||||
],
|
],
|
||||||
"files": [
|
"files": [
|
||||||
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
|
||||||
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
"../../node_modules/@nx/react/typings/image.d.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
const { composePlugins, withNx } = require('@nx/webpack');
|
||||||
|
const { withReact } = require('@nx/react');
|
||||||
const SentryPlugin = require('@sentry/webpack-plugin');
|
const SentryPlugin = require('@sentry/webpack-plugin');
|
||||||
|
|
||||||
module.exports = (config, context) => {
|
module.exports = composePlugins(withNx(), withReact(), (config) => {
|
||||||
const additionalPlugins = process.env.SENTRY_AUTH_TOKEN
|
const additionalPlugins = process.env.SENTRY_AUTH_TOKEN
|
||||||
? [
|
? [
|
||||||
new SentryPlugin({
|
new SentryPlugin({
|
||||||
@@ -13,5 +15,6 @@ module.exports = (config, context) => {
|
|||||||
return {
|
return {
|
||||||
...config,
|
...config,
|
||||||
plugins: [...additionalPlugins, ...config.plugins],
|
plugins: [...additionalPlugins, ...config.plugins],
|
||||||
|
ignoreWarnings: [/Failed to parse source map/],
|
||||||
};
|
};
|
||||||
};
|
});
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"name": "governance-e2e",
|
||||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
"sourceRoot": "apps/governance-e2e/src",
|
"sourceRoot": "apps/governance-e2e/src",
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"targets": {
|
"targets": {
|
||||||
"e2e": {
|
"e2e": {
|
||||||
"executor": "@nrwl/cypress:cypress",
|
"executor": "@nx/cypress:cypress",
|
||||||
"options": {
|
"options": {
|
||||||
"cypressConfig": "apps/governance-e2e/cypress.config.js",
|
"cypressConfig": "apps/governance-e2e/cypress.config.js",
|
||||||
"devServerTarget": "governance:serve"
|
"devServerTarget": "governance:serve"
|
||||||
@@ -16,14 +17,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nrwl/linter:eslint",
|
"executor": "@nx/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/governance-e2e/**/*.{js,ts}"]
|
"lintFilePatterns": ["apps/governance-e2e/**/*.{js,ts}"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "@nrwl/workspace:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"options": {
|
"options": {
|
||||||
"command": "yarn tsc --project ./apps/governance-e2e/"
|
"command": "yarn tsc --project ./apps/governance-e2e/"
|
||||||
|
|||||||
@@ -320,8 +320,8 @@ context(
|
|||||||
// 3001-VOTE-076
|
// 3001-VOTE-076
|
||||||
cy.getByTestId(connectToVegaWalletButton)
|
cy.getByTestId(connectToVegaWalletButton)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.and('have.text', 'Connect Vega wallet')
|
.and('have.text', 'Connect Vega wallet');
|
||||||
.click();
|
cy.getByTestId(connectToVegaWalletButton).click();
|
||||||
cy.getByTestId('connector-jsonRpc').click();
|
cy.getByTestId('connector-jsonRpc').click();
|
||||||
cy.getByTestId(vegaWalletNameElement).should('be.visible');
|
cy.getByTestId(vegaWalletNameElement).should('be.visible');
|
||||||
cy.getByTestId(connectToVegaWalletButton).should('not.exist');
|
cy.getByTestId(connectToVegaWalletButton).should('not.exist');
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ context(
|
|||||||
|
|
||||||
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
|
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
|
||||||
// 3002-PROP-022
|
// 3002-PROP-022
|
||||||
it('Unable to submit update market proposal without equity-like share in the market', function () {
|
it.skip('Unable to submit update market proposal without equity-like share in the market', function () {
|
||||||
switchVegaWalletPubKey();
|
switchVegaWalletPubKey();
|
||||||
stakingPageAssociateTokens('1');
|
stakingPageAssociateTokens('1');
|
||||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||||
|
|||||||
@@ -116,7 +116,6 @@ context(
|
|||||||
cy.getByTestId(amountInput).click().type('120');
|
cy.getByTestId(amountInput).click().type('120');
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
});
|
});
|
||||||
// assert withdrawal request
|
|
||||||
cy.getByTestId(toast)
|
cy.getByTestId(toast)
|
||||||
.first(txTimeout)
|
.first(txTimeout)
|
||||||
.should('contain.text', 'Funds unlocked')
|
.should('contain.text', 'Funds unlocked')
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
|||||||
cy.getByTestId('menu-drawer').should('be.visible');
|
cy.getByTestId('menu-drawer').should('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should have link for proposal page', function () {
|
it('should have link for proposal page', function () {
|
||||||
cy.getByTestId('menu-drawer').within(() => {
|
cy.getByTestId('menu-drawer').within(() => {
|
||||||
cy.get('[href="/proposals"]')
|
cy.get('[href="/proposals"]')
|
||||||
.should('exist')
|
.should('exist')
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ const proposalDocsLink = 'proposal-docs-link';
|
|||||||
const proposalDocumentationLink = 'proposal-documentation-link';
|
const proposalDocumentationLink = 'proposal-documentation-link';
|
||||||
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
|
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
|
||||||
const governanceDocsUrl = 'https://vega.xyz/governance';
|
const governanceDocsUrl = 'https://vega.xyz/governance';
|
||||||
|
const networkUpgradeProposalListItem = 'protocol-upgrade-proposals-list-item';
|
||||||
|
const closedProposals = 'closed-proposals';
|
||||||
|
const closedProposalToggle = 'closed-proposals-toggle-networkUpgrades';
|
||||||
|
|
||||||
context(
|
context(
|
||||||
'Governance Page - verify elements on page',
|
'Governance Page - verify elements on page',
|
||||||
@@ -127,7 +130,7 @@ context(
|
|||||||
mockNetworkUpgradeProposal();
|
mockNetworkUpgradeProposal();
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.getByTestId('home-proposal-list').within(() => {
|
cy.getByTestId('home-proposal-list').within(() => {
|
||||||
cy.getByTestId('protocol-upgrade-proposals-list-item').should('exist');
|
cy.getByTestId(networkUpgradeProposalListItem).should('exist');
|
||||||
cy.getByTestId('protocol-upgrade-proposal-title').should(
|
cy.getByTestId('protocol-upgrade-proposal-title').should(
|
||||||
'have.text',
|
'have.text',
|
||||||
'Vega release v1'
|
'Vega release v1'
|
||||||
@@ -141,11 +144,7 @@ context(
|
|||||||
cy.getByTestId('open-proposals').within(() => {
|
cy.getByTestId('open-proposals').within(() => {
|
||||||
cy.get('li')
|
cy.get('li')
|
||||||
.eq(0)
|
.eq(0)
|
||||||
.should(
|
.should('have.attr', 'data-testid', networkUpgradeProposalListItem)
|
||||||
'have.attr',
|
|
||||||
'data-testid',
|
|
||||||
'protocol-upgrade-proposals-list-item'
|
|
||||||
)
|
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get('h2').should('have.text', 'Vega release v1');
|
cy.get('h2').should('have.text', 'Vega release v1');
|
||||||
cy.getByTestId('protocol-upgrade-proposal-type').should(
|
cy.getByTestId('protocol-upgrade-proposal-type').should(
|
||||||
@@ -166,19 +165,19 @@ context(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cy.get('[data-testid="closed-proposals-toggle-networkUpgrades"]').click();
|
cy.getByTestId(closedProposals).within(() => {
|
||||||
cy.getByTestId('closed-proposals').within(() => {
|
cy.getByTestId(networkUpgradeProposalListItem).should('not.exist');
|
||||||
cy.getByTestId('protocol-upgrade-proposals-list-item').should(
|
});
|
||||||
'have.length',
|
cy.getByTestId(closedProposalToggle).click();
|
||||||
1
|
cy.getByTestId(closedProposals).within(() => {
|
||||||
);
|
cy.getByTestId(networkUpgradeProposalListItem).should('have.length', 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should see details of network upgrade proposal', function () {
|
it('should see details of network upgrade proposal', function () {
|
||||||
mockNetworkUpgradeProposal();
|
mockNetworkUpgradeProposal();
|
||||||
navigateTo(navigation.proposals);
|
navigateTo(navigation.proposals);
|
||||||
cy.getByTestId('protocol-upgrade-proposals-list-item')
|
cy.getByTestId(networkUpgradeProposalListItem)
|
||||||
.first()
|
.first()
|
||||||
.find('[data-testid="view-proposal-btn"]')
|
.find('[data-testid="view-proposal-btn"]')
|
||||||
.click();
|
.click();
|
||||||
@@ -215,5 +214,18 @@ context(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('filtering proposal should not display any network upgrade proposals', function () {
|
||||||
|
const proposalId =
|
||||||
|
'd848fc7881f13d366df5f61ab139d5fcfa72bf838151bb51b54381870e357931';
|
||||||
|
|
||||||
|
mockNetworkUpgradeProposal();
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
cy.get('[data-testid="proposal-filter-toggle"]').click();
|
||||||
|
cy.get('[data-testid="filter-input"]').type(proposalId);
|
||||||
|
cy.getByTestId(closedProposals).should('have.length', 1);
|
||||||
|
cy.getByTestId(networkUpgradeProposalListItem).should('not.exist');
|
||||||
|
cy.getByTestId(closedProposalToggle).should('not.exist');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import {
|
import {
|
||||||
navigateTo,
|
|
||||||
navigation,
|
|
||||||
turnTelemetryOff,
|
turnTelemetryOff,
|
||||||
waitForSpinner,
|
waitForSpinner,
|
||||||
} from '../../support/common.functions';
|
} from '../../support/common.functions';
|
||||||
import {
|
import {
|
||||||
enterUniqueFreeFormProposalBody,
|
createTenDigitUnixTimeStampForSpecifiedDays,
|
||||||
|
enterRawProposalBody,
|
||||||
goToMakeNewProposal,
|
goToMakeNewProposal,
|
||||||
governanceProposalType,
|
governanceProposalType,
|
||||||
} from '../../support/governance.functions';
|
} from '../../support/governance.functions';
|
||||||
@@ -47,12 +46,11 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
|
|||||||
.and('contain.text', 'USDC (fake)');
|
.and('contain.text', 'USDC (fake)');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('Unable to submit proposal with public key', function () {
|
it('Unable to submit proposal with public key', function () {
|
||||||
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
|
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
|
||||||
|
|
||||||
navigateTo(navigation.proposals);
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||||
enterUniqueFreeFormProposalBody('50', 'pub key proposal test');
|
|
||||||
cy.getByTestId('dialog-content')
|
cy.getByTestId('dialog-content')
|
||||||
.first()
|
.first()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ context(
|
|||||||
cy.getByTestId('connector-jsonRpc')
|
cy.getByTestId('connector-jsonRpc')
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.and('have.text', 'Connect Vega wallet');
|
.and('have.text', 'Connect Vega wallet');
|
||||||
cy.getByTestId('connector-hosted')
|
cy.getByTestId('connector-rest')
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.and('have.text', 'Hosted Fairground wallet');
|
.and('have.text', 'Hosted Fairground wallet');
|
||||||
});
|
});
|
||||||
@@ -94,7 +94,7 @@ context(
|
|||||||
describe('when rest connector form opened', function () {
|
describe('when rest connector form opened', function () {
|
||||||
before('click hosted wallet app button', function () {
|
before('click hosted wallet app button', function () {
|
||||||
cy.getByTestId(connectorsList).within(() => {
|
cy.getByTestId(connectorsList).within(() => {
|
||||||
cy.getByTestId('connector-hosted').click();
|
cy.getByTestId('connector-rest').click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@ context(
|
|||||||
.contains(name)
|
.contains(name)
|
||||||
.parent()
|
.parent()
|
||||||
.siblings()
|
.siblings()
|
||||||
.then((elementAmount) => {
|
.should((elementAmount) => {
|
||||||
const displayedAmount = parseFloat(elementAmount.text());
|
const displayedAmount = parseFloat(elementAmount.text());
|
||||||
expect(displayedAmount).be.gte(expectedAmount);
|
expect(displayedAmount).be.gte(expectedAmount);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
[
|
[
|
||||||
"@nrwl/react/babel",
|
"@nx/react/babel",
|
||||||
{
|
{
|
||||||
"runtime": "automatic"
|
"runtime": "automatic"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_VEGA_ENV=MAINNET-MIRROR
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
||||||
|
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
||||||
|
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz","MAINNET-MIRROR":"https://governance.mainnet-mirror.vega.rocks","STAGNET1":"https://trading.stagnet1.vega.rocks"}'
|
||||||
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
|
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||||
|
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks
|
||||||
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||||
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
|
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-mirror-k8s.ops.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
|
NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
||||||
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
|
"ignorePatterns": ["!**/*", "__generated__"],
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
|
|||||||
@@ -25,13 +25,14 @@ yarn nx serve governance
|
|||||||
Example configurations are provided here:
|
Example configurations are provided here:
|
||||||
|
|
||||||
- [Mainnet](./.env.mainnet)
|
- [Mainnet](./.env.mainnet)
|
||||||
|
- [Mainnet-mirror](./.env.mainnet-mirror)
|
||||||
- [Devnet](./.env.devnet)
|
- [Devnet](./.env.devnet)
|
||||||
- [Testnet](./.env.testnet)
|
- [Testnet](./.env.testnet)
|
||||||
|
|
||||||
For convenience, you can boot the app injecting one of the configurations above by running:
|
For convenience, you can boot the app injecting one of the configurations above by running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn nx run governance:serve --env={env} # e.g. stagnet1
|
yarn env-cmd -f .\apps\governance\.env.{env} yarn nx run governance:serve # e.g. stagnet1
|
||||||
```
|
```
|
||||||
|
|
||||||
There are a few different configuration options offered for this app:
|
There are a few different configuration options offered for this app:
|
||||||
|
|||||||
-6
@@ -1,6 +0,0 @@
|
|||||||
function ReactMarkdown({ children }) {
|
|
||||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
|
||||||
return <>{children}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ReactMarkdown;
|
|
||||||
@@ -3,8 +3,8 @@ export default {
|
|||||||
displayName: 'governance',
|
displayName: 'governance',
|
||||||
preset: '../../jest.preset.js',
|
preset: '../../jest.preset.js',
|
||||||
transform: {
|
transform: {
|
||||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
|
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
||||||
'^.+\\.[tj]sx?$': 'babel-jest',
|
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
|
||||||
},
|
},
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||||
coverageDirectory: '../../coverage/apps/governance',
|
coverageDirectory: '../../coverage/apps/governance',
|
||||||
@@ -16,6 +16,5 @@ export default {
|
|||||||
'**/*.{ts,tsx}',
|
'**/*.{ts,tsx}',
|
||||||
'!**/node_modules/**',
|
'!**/node_modules/**',
|
||||||
'!**/__generated__/**',
|
'!**/__generated__/**',
|
||||||
'!**/__generated___/**',
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"name": "governance",
|
||||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
"sourceRoot": "apps/governance/src",
|
"sourceRoot": "apps/governance/src",
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"targets": {
|
"targets": {
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "./tools/executors/webpack:build",
|
"executor": "@nx/webpack:webpack",
|
||||||
"outputs": ["{options.outputPath}"],
|
"outputs": ["{options.outputPath}"],
|
||||||
"defaultConfiguration": "production",
|
"defaultConfiguration": "production",
|
||||||
"options": {
|
"options": {
|
||||||
@@ -41,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"serve": {
|
"serve": {
|
||||||
"executor": "./tools/executors/webpack:serve",
|
"executor": "@nx/webpack:dev-server",
|
||||||
"options": {
|
"options": {
|
||||||
"port": 4210,
|
"port": 4210,
|
||||||
"buildTarget": "governance:build:development",
|
"buildTarget": "governance:build:development",
|
||||||
@@ -55,22 +56,28 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nrwl/linter:eslint",
|
"executor": "@nx/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/governance/**/*.{ts,tsx,js,jsx}"]
|
"lintFilePatterns": ["apps/governance/**/*.{ts,tsx,js,jsx}"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
"executor": "@nrwl/jest:jest",
|
"executor": "@nx/jest:jest",
|
||||||
"outputs": ["coverage/apps/governance"],
|
"outputs": ["{workspaceRoot}/coverage/apps/governance"],
|
||||||
"options": {
|
"options": {
|
||||||
"jestConfig": "apps/governance/jest.config.ts",
|
"jestConfig": "apps/governance/jest.config.ts",
|
||||||
"passWithNoTests": true
|
"passWithNoTests": true
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"ci": {
|
||||||
|
"ci": true,
|
||||||
|
"codeCoverage": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build-netlify": {
|
"build-netlify": {
|
||||||
"executor": "@nrwl/workspace:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
"cp apps/governance/netlify.toml netlify.toml",
|
"cp apps/governance/netlify.toml netlify.toml",
|
||||||
@@ -79,7 +86,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build-spec": {
|
"build-spec": {
|
||||||
"executor": "@nrwl/workspace:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"options": {
|
"options": {
|
||||||
"command": "yarn tsc --project ./apps/governance/tsconfig.spec.json"
|
"command": "yarn tsc --project ./apps/governance/tsconfig.spec.json"
|
||||||
|
|||||||
@@ -2,13 +2,8 @@ import { Button } from '@vegaprotocol/ui-toolkit';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||||
import {
|
|
||||||
AppStateActionType,
|
|
||||||
useAppState,
|
|
||||||
} from '../../contexts/app-state/app-state-context';
|
|
||||||
|
|
||||||
export const ConnectToVega = () => {
|
export const ConnectToVega = () => {
|
||||||
const { appDispatch } = useAppState();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||||
@@ -16,10 +11,6 @@ export const ConnectToVega = () => {
|
|||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
appDispatch({
|
|
||||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
|
||||||
isOpen: true,
|
|
||||||
});
|
|
||||||
openVegaWalletDialog();
|
openVegaWalletDialog();
|
||||||
}}
|
}}
|
||||||
data-testid="connect-to-vega-wallet-btn"
|
data-testid="connect-to-vega-wallet-btn"
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import {
|
|
||||||
AppStateActionType,
|
|
||||||
useAppState,
|
|
||||||
} from '../../contexts/app-state/app-state-context';
|
|
||||||
|
|
||||||
interface VegaWalletContainerProps {
|
interface VegaWalletContainerProps {
|
||||||
children: (key: string) => React.ReactElement;
|
children: (key: string) => React.ReactElement;
|
||||||
}
|
}
|
||||||
@@ -15,7 +10,6 @@ interface VegaWalletContainerProps {
|
|||||||
export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => {
|
export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { pubKey } = useVegaWallet();
|
const { pubKey } = useVegaWallet();
|
||||||
const { appDispatch } = useAppState();
|
|
||||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||||
}));
|
}));
|
||||||
@@ -25,10 +19,6 @@ export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => {
|
|||||||
<Button
|
<Button
|
||||||
data-testid="connect-to-vega-wallet-btn"
|
data-testid="connect-to-vega-wallet-btn"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
appDispatch({
|
|
||||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
|
||||||
isOpen: true,
|
|
||||||
});
|
|
||||||
openVegaWalletDialog();
|
openVegaWalletDialog();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ export const VegaWalletDialogs = () => {
|
|||||||
<>
|
<>
|
||||||
<VegaConnectDialog
|
<VegaConnectDialog
|
||||||
connectors={Connectors}
|
connectors={Connectors}
|
||||||
onChangeOpen={(open) =>
|
|
||||||
appDispatch({
|
|
||||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
|
||||||
isOpen: open,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
riskMessage={<RiskMessage />}
|
riskMessage={<RiskMessage />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ export const VegaWallet = () => {
|
|||||||
|
|
||||||
const VegaWalletNotConnected = () => {
|
const VegaWalletNotConnected = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { appDispatch } = useAppState();
|
|
||||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||||
}));
|
}));
|
||||||
@@ -79,10 +78,6 @@ const VegaWalletNotConnected = () => {
|
|||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
appDispatch({
|
|
||||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
|
||||||
isOpen: true,
|
|
||||||
});
|
|
||||||
openVegaWalletDialog();
|
openVegaWalletDialog();
|
||||||
}}
|
}}
|
||||||
fill={true}
|
fill={true}
|
||||||
|
|||||||
@@ -28,9 +28,6 @@ export interface AppState {
|
|||||||
/** Total number of VEGA Tokens, both vesting and unlocked, associated for staking */
|
/** Total number of VEGA Tokens, both vesting and unlocked, associated for staking */
|
||||||
totalAssociated: BigNumber;
|
totalAssociated: BigNumber;
|
||||||
|
|
||||||
/** Whether or not the connect to VEGA wallet overlay is open */
|
|
||||||
vegaWalletOverlay: boolean;
|
|
||||||
|
|
||||||
/** Whether or not the manage VEGA wallet overlay is open */
|
/** Whether or not the manage VEGA wallet overlay is open */
|
||||||
vegaWalletManageOverlay: boolean;
|
vegaWalletManageOverlay: boolean;
|
||||||
|
|
||||||
@@ -52,9 +49,7 @@ export enum AppStateActionType {
|
|||||||
SET_TOKEN,
|
SET_TOKEN,
|
||||||
SET_ALLOWANCE,
|
SET_ALLOWANCE,
|
||||||
REFRESH_BALANCES,
|
REFRESH_BALANCES,
|
||||||
SET_VEGA_WALLET_OVERLAY,
|
|
||||||
SET_VEGA_WALLET_MANAGE_OVERLAY,
|
SET_VEGA_WALLET_MANAGE_OVERLAY,
|
||||||
SET_DRAWER,
|
|
||||||
REFRESH_ASSOCIATED_BALANCES,
|
REFRESH_ASSOCIATED_BALANCES,
|
||||||
SET_ASSOCIATION_BREAKDOWN,
|
SET_ASSOCIATION_BREAKDOWN,
|
||||||
SET_TRANSACTION_OVERLAY,
|
SET_TRANSACTION_OVERLAY,
|
||||||
@@ -69,18 +64,10 @@ export type AppStateAction =
|
|||||||
totalSupply: BigNumber;
|
totalSupply: BigNumber;
|
||||||
totalAssociated: BigNumber;
|
totalAssociated: BigNumber;
|
||||||
}
|
}
|
||||||
| {
|
|
||||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY;
|
|
||||||
isOpen: boolean;
|
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
type: AppStateActionType.SET_VEGA_WALLET_MANAGE_OVERLAY;
|
type: AppStateActionType.SET_VEGA_WALLET_MANAGE_OVERLAY;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
}
|
}
|
||||||
| {
|
|
||||||
type: AppStateActionType.SET_DRAWER;
|
|
||||||
isOpen: boolean;
|
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
type: AppStateActionType.SET_TRANSACTION_OVERLAY;
|
type: AppStateActionType.SET_TRANSACTION_OVERLAY;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ const initialAppState: AppState = {
|
|||||||
totalAssociated: new BigNumber(0),
|
totalAssociated: new BigNumber(0),
|
||||||
decimals: 0,
|
decimals: 0,
|
||||||
totalSupply: new BigNumber(0),
|
totalSupply: new BigNumber(0),
|
||||||
vegaWalletOverlay: false,
|
|
||||||
vegaWalletManageOverlay: false,
|
vegaWalletManageOverlay: false,
|
||||||
transactionOverlay: false,
|
transactionOverlay: false,
|
||||||
bannerMessage: '',
|
bannerMessage: '',
|
||||||
@@ -31,23 +30,10 @@ function appStateReducer(state: AppState, action: AppStateAction): AppState {
|
|||||||
totalAssociated: action.totalAssociated,
|
totalAssociated: action.totalAssociated,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case AppStateActionType.SET_VEGA_WALLET_OVERLAY: {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
vegaWalletOverlay: action.isOpen,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case AppStateActionType.SET_VEGA_WALLET_MANAGE_OVERLAY: {
|
case AppStateActionType.SET_VEGA_WALLET_MANAGE_OVERLAY: {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
vegaWalletManageOverlay: action.isOpen,
|
vegaWalletManageOverlay: action.isOpen,
|
||||||
vegaWalletOverlay: action.isOpen ? false : state.vegaWalletOverlay,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case AppStateActionType.SET_DRAWER: {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
vegaWalletOverlay: false,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case AppStateActionType.SET_TRANSACTION_OVERLAY: {
|
case AppStateActionType.SET_TRANSACTION_OVERLAY: {
|
||||||
|
|||||||
@@ -836,5 +836,6 @@
|
|||||||
"AllProposals": "All proposals",
|
"AllProposals": "All proposals",
|
||||||
"RejectedProposals": "Rejected proposals",
|
"RejectedProposals": "Rejected proposals",
|
||||||
"networkGovernance": "Network governance",
|
"networkGovernance": "Network governance",
|
||||||
"networkUpgrades": "Network upgrades"
|
"networkUpgrades": "Network upgrades",
|
||||||
|
"assetSpecification": "Asset specification"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,18 @@ import {
|
|||||||
RestConnector,
|
RestConnector,
|
||||||
JsonRpcConnector,
|
JsonRpcConnector,
|
||||||
ViewConnector,
|
ViewConnector,
|
||||||
|
InjectedConnector,
|
||||||
} from '@vegaprotocol/wallet';
|
} from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
export const injected = new InjectedConnector();
|
||||||
export const rest = new RestConnector();
|
export const rest = new RestConnector();
|
||||||
export const jsonRpc = new JsonRpcConnector();
|
export const jsonRpc = new JsonRpcConnector();
|
||||||
export const view = new ViewConnector(urlParams.get('address'));
|
export const view = new ViewConnector(urlParams.get('address'));
|
||||||
|
|
||||||
export const Connectors = {
|
export const Connectors = {
|
||||||
|
injected,
|
||||||
rest,
|
rest,
|
||||||
jsonRpc,
|
jsonRpc,
|
||||||
view,
|
view,
|
||||||
|
|||||||
@@ -1,159 +0,0 @@
|
|||||||
import * as Types from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client';
|
|
||||||
import * as Apollo from '@apollo/client';
|
|
||||||
const defaultOptions = {} as const;
|
|
||||||
export type ProposalAssetQueryVariables = Types.Exact<{
|
|
||||||
assetId: Types.Scalars['ID'];
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type ProposalAssetQuery = {
|
|
||||||
__typename?: 'Query';
|
|
||||||
asset?: {
|
|
||||||
__typename?: 'Asset';
|
|
||||||
status: Types.AssetStatus;
|
|
||||||
source:
|
|
||||||
| { __typename?: 'BuiltinAsset' }
|
|
||||||
| { __typename?: 'ERC20'; contractAddress: string };
|
|
||||||
} | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AssetListBundleQueryVariables = Types.Exact<{
|
|
||||||
assetId: Types.Scalars['ID'];
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type AssetListBundleQuery = {
|
|
||||||
__typename?: 'Query';
|
|
||||||
erc20ListAssetBundle?: {
|
|
||||||
__typename?: 'Erc20ListAssetBundle';
|
|
||||||
assetSource: string;
|
|
||||||
vegaAssetId: string;
|
|
||||||
nonce: string;
|
|
||||||
signatures: string;
|
|
||||||
} | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ProposalAssetDocument = gql`
|
|
||||||
query ProposalAsset($assetId: ID!) {
|
|
||||||
asset(id: $assetId) {
|
|
||||||
status
|
|
||||||
source {
|
|
||||||
... on ERC20 {
|
|
||||||
contractAddress
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __useProposalAssetQuery__
|
|
||||||
*
|
|
||||||
* To run a query within a React component, call `useProposalAssetQuery` and pass it any options that fit your needs.
|
|
||||||
* When your component renders, `useProposalAssetQuery` 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 } = useProposalAssetQuery({
|
|
||||||
* variables: {
|
|
||||||
* assetId: // value for 'assetId'
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function useProposalAssetQuery(
|
|
||||||
baseOptions: Apollo.QueryHookOptions<
|
|
||||||
ProposalAssetQuery,
|
|
||||||
ProposalAssetQueryVariables
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useQuery<ProposalAssetQuery, ProposalAssetQueryVariables>(
|
|
||||||
ProposalAssetDocument,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export function useProposalAssetLazyQuery(
|
|
||||||
baseOptions?: Apollo.LazyQueryHookOptions<
|
|
||||||
ProposalAssetQuery,
|
|
||||||
ProposalAssetQueryVariables
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useLazyQuery<ProposalAssetQuery, ProposalAssetQueryVariables>(
|
|
||||||
ProposalAssetDocument,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export type ProposalAssetQueryHookResult = ReturnType<
|
|
||||||
typeof useProposalAssetQuery
|
|
||||||
>;
|
|
||||||
export type ProposalAssetLazyQueryHookResult = ReturnType<
|
|
||||||
typeof useProposalAssetLazyQuery
|
|
||||||
>;
|
|
||||||
export type ProposalAssetQueryResult = Apollo.QueryResult<
|
|
||||||
ProposalAssetQuery,
|
|
||||||
ProposalAssetQueryVariables
|
|
||||||
>;
|
|
||||||
export const AssetListBundleDocument = gql`
|
|
||||||
query AssetListBundle($assetId: ID!) {
|
|
||||||
erc20ListAssetBundle(assetId: $assetId) {
|
|
||||||
assetSource
|
|
||||||
vegaAssetId
|
|
||||||
nonce
|
|
||||||
signatures
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __useAssetListBundleQuery__
|
|
||||||
*
|
|
||||||
* To run a query within a React component, call `useAssetListBundleQuery` and pass it any options that fit your needs.
|
|
||||||
* When your component renders, `useAssetListBundleQuery` 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 } = useAssetListBundleQuery({
|
|
||||||
* variables: {
|
|
||||||
* assetId: // value for 'assetId'
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function useAssetListBundleQuery(
|
|
||||||
baseOptions: Apollo.QueryHookOptions<
|
|
||||||
AssetListBundleQuery,
|
|
||||||
AssetListBundleQueryVariables
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useQuery<AssetListBundleQuery, AssetListBundleQueryVariables>(
|
|
||||||
AssetListBundleDocument,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export function useAssetListBundleLazyQuery(
|
|
||||||
baseOptions?: Apollo.LazyQueryHookOptions<
|
|
||||||
AssetListBundleQuery,
|
|
||||||
AssetListBundleQueryVariables
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useLazyQuery<
|
|
||||||
AssetListBundleQuery,
|
|
||||||
AssetListBundleQueryVariables
|
|
||||||
>(AssetListBundleDocument, options);
|
|
||||||
}
|
|
||||||
export type AssetListBundleQueryHookResult = ReturnType<
|
|
||||||
typeof useAssetListBundleQuery
|
|
||||||
>;
|
|
||||||
export type AssetListBundleLazyQueryHookResult = ReturnType<
|
|
||||||
typeof useAssetListBundleLazyQuery
|
|
||||||
>;
|
|
||||||
export type AssetListBundleQueryResult = Apollo.QueryResult<
|
|
||||||
AssetListBundleQuery,
|
|
||||||
AssetListBundleQueryVariables
|
|
||||||
>;
|
|
||||||
@@ -5,13 +5,11 @@ import { MockedProvider } from '@apollo/client/testing';
|
|||||||
import type {
|
import type {
|
||||||
AssetListBundleQuery,
|
AssetListBundleQuery,
|
||||||
ProposalAssetQuery,
|
ProposalAssetQuery,
|
||||||
} from './__generated___/Asset';
|
} from './__generated__/Asset';
|
||||||
import { AssetListBundleDocument } from './__generated___/Asset';
|
import { AssetListBundleDocument } from './__generated__/Asset';
|
||||||
import { ProposalAssetDocument } from './__generated___/Asset';
|
import { ProposalAssetDocument } from './__generated__/Asset';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import type { useWeb3React } from '@web3-react/core';
|
import type { useWeb3React } from '@web3-react/core';
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
import type { AppState } from '../../../../contexts/app-state/app-state-context';
|
|
||||||
|
|
||||||
const mockUseEthTx = {
|
const mockUseEthTx = {
|
||||||
perform: jest.fn(),
|
perform: jest.fn(),
|
||||||
@@ -47,23 +45,6 @@ jest.mock('@web3-react/core', () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockAppState: AppState = {
|
|
||||||
totalAssociated: new BigNumber('50063005'),
|
|
||||||
decimals: 18,
|
|
||||||
totalSupply: new BigNumber(65000000),
|
|
||||||
vegaWalletOverlay: false,
|
|
||||||
vegaWalletManageOverlay: false,
|
|
||||||
transactionOverlay: false,
|
|
||||||
bannerMessage: '',
|
|
||||||
disconnectNotice: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
jest.mock('../../../contexts/app-state/app-state-context', () => ({
|
|
||||||
useAppState: () => ({
|
|
||||||
appState: mockAppState,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const ASSET_ID = 'foo';
|
const ASSET_ID = 'foo';
|
||||||
|
|
||||||
const DEFAULT__ASSET: ProposalAssetQuery = {
|
const DEFAULT__ASSET: ProposalAssetQuery = {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import {
|
import {
|
||||||
useAssetListBundleQuery,
|
useAssetListBundleQuery,
|
||||||
useProposalAssetQuery,
|
useProposalAssetQuery,
|
||||||
} from './__generated___/Asset';
|
} from './__generated__/Asset';
|
||||||
import { EthWalletContainer } from '../../../../components/eth-wallet-container';
|
import { EthWalletContainer } from '../../../../components/eth-wallet-container';
|
||||||
|
|
||||||
const useListAsset = (assetId: string) => {
|
const useListAsset = (assetId: string) => {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './proposal-asset-details';
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { SubHeading } from '../../../../components/heading';
|
||||||
|
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||||
|
import { AssetDetail, AssetDetailsTable } from '@vegaprotocol/assets';
|
||||||
|
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||||
|
|
||||||
|
export const ProposalAssetDetails = ({
|
||||||
|
asset,
|
||||||
|
}: {
|
||||||
|
asset: AssetFieldsFragment;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [showAssetDetails, setShowAssetDetails] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section data-testid="proposal-asset-details">
|
||||||
|
<CollapsibleToggle
|
||||||
|
toggleState={showAssetDetails}
|
||||||
|
setToggleState={setShowAssetDetails}
|
||||||
|
dataTestId={'proposal-asset-details-toggle'}
|
||||||
|
>
|
||||||
|
<SubHeading title={t('assetSpecification')} />
|
||||||
|
</CollapsibleToggle>
|
||||||
|
|
||||||
|
{showAssetDetails && (
|
||||||
|
<div className="mb-10 pb-4">
|
||||||
|
<AssetDetailsTable
|
||||||
|
asset={asset}
|
||||||
|
omitRows={[
|
||||||
|
AssetDetail.STATUS,
|
||||||
|
AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
|
||||||
|
AssetDetail.GLOBAL_REWARD_POOL_ACCOUNT_BALANCE,
|
||||||
|
AssetDetail.MAKER_PAID_FEES_ACCOUNT_BALANCE,
|
||||||
|
AssetDetail.MAKER_RECEIVED_FEES_ACCOUNT_BALANCE,
|
||||||
|
AssetDetail.LP_FEE_REWARD_ACCOUNT_BALANCE,
|
||||||
|
AssetDetail.MARKET_PROPOSER_REWARD_ACCOUNT_BALANCE,
|
||||||
|
]}
|
||||||
|
inline={true}
|
||||||
|
noBorder={true}
|
||||||
|
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
|
||||||
|
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -10,6 +10,7 @@ import { ProposalDescription } from '../proposal-description';
|
|||||||
import { ProposalChangeTable } from '../proposal-change-table';
|
import { ProposalChangeTable } from '../proposal-change-table';
|
||||||
import { ProposalJson } from '../proposal-json';
|
import { ProposalJson } from '../proposal-json';
|
||||||
import { ProposalVotesTable } from '../proposal-votes-table';
|
import { ProposalVotesTable } from '../proposal-votes-table';
|
||||||
|
import { ProposalAssetDetails } from '../proposal-asset-details';
|
||||||
import { VoteDetails } from '../vote-details';
|
import { VoteDetails } from '../vote-details';
|
||||||
import { ListAsset } from '../list-asset';
|
import { ListAsset } from '../list-asset';
|
||||||
import Routes from '../../../routes';
|
import Routes from '../../../routes';
|
||||||
@@ -17,6 +18,8 @@ import { ProposalMarketData } from '../proposal-market-data';
|
|||||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
|
import type { AssetQuery } from '@vegaprotocol/assets';
|
||||||
|
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||||
import { ProposalState } from '@vegaprotocol/types';
|
import { ProposalState } from '@vegaprotocol/types';
|
||||||
|
|
||||||
export enum ProposalType {
|
export enum ProposalType {
|
||||||
@@ -30,6 +33,7 @@ export enum ProposalType {
|
|||||||
export interface ProposalProps {
|
export interface ProposalProps {
|
||||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||||
newMarketData?: MarketInfoWithData | null;
|
newMarketData?: MarketInfoWithData | null;
|
||||||
|
assetData?: AssetQuery | null;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
restData: any;
|
restData: any;
|
||||||
}
|
}
|
||||||
@@ -38,6 +42,7 @@ export const Proposal = ({
|
|||||||
proposal,
|
proposal,
|
||||||
restData,
|
restData,
|
||||||
newMarketData,
|
newMarketData,
|
||||||
|
assetData,
|
||||||
}: ProposalProps) => {
|
}: ProposalProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { params, loading, error } = useNetworkParams([
|
const { params, loading, error } = useNetworkParams([
|
||||||
@@ -54,6 +59,23 @@ export const Proposal = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let asset = assetData
|
||||||
|
? removePaginationWrapper(assetData.assetsConnection?.edges)[0]
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (proposal.terms.change.__typename === 'UpdateAsset' && asset) {
|
||||||
|
asset = {
|
||||||
|
...asset,
|
||||||
|
quantum: proposal.terms.change.quantum,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (asset.source.__typename === 'ERC20') {
|
||||||
|
asset.source.lifetimeLimit = proposal.terms.change.source.lifetimeLimit;
|
||||||
|
asset.source.withdrawThreshold =
|
||||||
|
proposal.terms.change.source.withdrawThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let minVoterBalance = null;
|
let minVoterBalance = null;
|
||||||
let proposalType = null;
|
let proposalType = null;
|
||||||
|
|
||||||
@@ -138,6 +160,14 @@ export const Proposal = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{(proposal.terms.change.__typename === 'NewAsset' ||
|
||||||
|
proposal.terms.change.__typename === 'UpdateAsset') &&
|
||||||
|
asset && (
|
||||||
|
<div className="mb-4">
|
||||||
|
<ProposalAssetDetails asset={asset} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<ProposalJson proposal={restData?.data?.proposal} />
|
<ProposalJson proposal={restData?.data?.proposal} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -191,12 +191,13 @@ export const ProposalsList = ({
|
|||||||
{sortedProposals.open.length > 0 ||
|
{sortedProposals.open.length > 0 ||
|
||||||
sortedProtocolUpgradeProposals.open.length > 0 ? (
|
sortedProtocolUpgradeProposals.open.length > 0 ? (
|
||||||
<ul data-testid="open-proposals">
|
<ul data-testid="open-proposals">
|
||||||
{sortedProtocolUpgradeProposals.open.map((proposal) => (
|
{filterString.length < 1 &&
|
||||||
<ProtocolUpgradeProposalsListItem
|
sortedProtocolUpgradeProposals.open.map((proposal) => (
|
||||||
key={proposal.upgradeBlockHeight}
|
<ProtocolUpgradeProposalsListItem
|
||||||
proposal={proposal}
|
key={proposal.upgradeBlockHeight}
|
||||||
/>
|
proposal={proposal}
|
||||||
))}
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
{sortedProposals.open.filter(filterPredicate).map((proposal) => (
|
{sortedProposals.open.filter(filterPredicate).map((proposal) => (
|
||||||
<ProposalsListItem key={proposal?.id} proposal={proposal} />
|
<ProposalsListItem key={proposal?.id} proposal={proposal} />
|
||||||
|
|||||||
@@ -10,10 +10,7 @@ import {
|
|||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { addDecimal, toBigNum } from '@vegaprotocol/utils';
|
import { addDecimal, toBigNum } from '@vegaprotocol/utils';
|
||||||
import { ProposalState, VoteValue } from '@vegaprotocol/types';
|
import { ProposalState, VoteValue } from '@vegaprotocol/types';
|
||||||
import {
|
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||||
AppStateActionType,
|
|
||||||
useAppState,
|
|
||||||
} from '../../../../contexts/app-state/app-state-context';
|
|
||||||
import { BigNumber } from '../../../../lib/bignumber';
|
import { BigNumber } from '../../../../lib/bignumber';
|
||||||
import { DATE_FORMAT_LONG } from '../../../../lib/date-formats';
|
import { DATE_FORMAT_LONG } from '../../../../lib/date-formats';
|
||||||
import { VoteState } from './use-user-vote';
|
import { VoteState } from './use-user-vote';
|
||||||
@@ -73,7 +70,6 @@ export const VoteButtons = ({
|
|||||||
dialog: Dialog,
|
dialog: Dialog,
|
||||||
}: VoteButtonsProps) => {
|
}: VoteButtonsProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { appDispatch } = useAppState();
|
|
||||||
const { pubKey } = useVegaWallet();
|
const { pubKey } = useVegaWallet();
|
||||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||||
@@ -98,10 +94,6 @@ export const VoteButtons = ({
|
|||||||
<div data-testid="connect-wallet">
|
<div data-testid="connect-wallet">
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
appDispatch({
|
|
||||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
|
||||||
isOpen: true,
|
|
||||||
});
|
|
||||||
openVegaWalletDialog();
|
openVegaWalletDialog();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -142,7 +134,6 @@ export const VoteButtons = ({
|
|||||||
minVoterBalance,
|
minVoterBalance,
|
||||||
spamProtectionMinTokens,
|
spamProtectionMinTokens,
|
||||||
t,
|
t,
|
||||||
appDispatch,
|
|
||||||
openVegaWalletDialog,
|
openVegaWalletDialog,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ const mockAppState: AppState = {
|
|||||||
totalAssociated: new BigNumber('50063005'),
|
totalAssociated: new BigNumber('50063005'),
|
||||||
decimals: 18,
|
decimals: 18,
|
||||||
totalSupply: mockTotalSupply,
|
totalSupply: mockTotalSupply,
|
||||||
vegaWalletOverlay: false,
|
|
||||||
vegaWalletManageOverlay: false,
|
vegaWalletManageOverlay: false,
|
||||||
transactionOverlay: false,
|
transactionOverlay: false,
|
||||||
bannerMessage: '',
|
bannerMessage: '',
|
||||||
|
|||||||
@@ -91,46 +91,46 @@ query Proposal($proposalId: ID!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataSourceSpecForTradingTermination {
|
# dataSourceSpecForTradingTermination {
|
||||||
sourceType {
|
# sourceType {
|
||||||
... on DataSourceDefinitionInternal {
|
# ... on DataSourceDefinitionInternal {
|
||||||
sourceType {
|
# sourceType {
|
||||||
... on DataSourceSpecConfigurationTime {
|
# ... on DataSourceSpecConfigurationTime {
|
||||||
conditions {
|
# conditions {
|
||||||
operator
|
# operator
|
||||||
value
|
# value
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
... on DataSourceDefinitionExternal {
|
# ... on DataSourceDefinitionExternal {
|
||||||
sourceType {
|
# sourceType {
|
||||||
... on DataSourceSpecConfiguration {
|
# ... on DataSourceSpecConfiguration {
|
||||||
signers {
|
# signers {
|
||||||
signer {
|
# signer {
|
||||||
... on PubKey {
|
# ... on PubKey {
|
||||||
key
|
# key
|
||||||
}
|
# }
|
||||||
... on ETHAddress {
|
# ... on ETHAddress {
|
||||||
address
|
# address
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
filters {
|
# filters {
|
||||||
key {
|
# key {
|
||||||
name
|
# name
|
||||||
type
|
# type
|
||||||
}
|
# }
|
||||||
conditions {
|
# conditions {
|
||||||
operator
|
# operator
|
||||||
value
|
# value
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
dataSourceSpecBinding {
|
dataSourceSpecBinding {
|
||||||
settlementDataProperty
|
settlementDataProperty
|
||||||
tradingTerminationProperty
|
tradingTerminationProperty
|
||||||
@@ -203,46 +203,46 @@ query Proposal($proposalId: ID!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataSourceSpecForTradingTermination {
|
# dataSourceSpecForTradingTermination {
|
||||||
sourceType {
|
# sourceType {
|
||||||
... on DataSourceDefinitionInternal {
|
# ... on DataSourceDefinitionInternal {
|
||||||
sourceType {
|
# sourceType {
|
||||||
... on DataSourceSpecConfigurationTime {
|
# ... on DataSourceSpecConfigurationTime {
|
||||||
conditions {
|
# conditions {
|
||||||
operator
|
# operator
|
||||||
value
|
# value
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
... on DataSourceDefinitionExternal {
|
# ... on DataSourceDefinitionExternal {
|
||||||
sourceType {
|
# sourceType {
|
||||||
... on DataSourceSpecConfiguration {
|
# ... on DataSourceSpecConfiguration {
|
||||||
signers {
|
# signers {
|
||||||
signer {
|
# signer {
|
||||||
... on PubKey {
|
# ... on PubKey {
|
||||||
key
|
# key
|
||||||
}
|
# }
|
||||||
... on ETHAddress {
|
# ... on ETHAddress {
|
||||||
address
|
# address
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
filters {
|
# filters {
|
||||||
key {
|
# key {
|
||||||
name
|
# name
|
||||||
type
|
# type
|
||||||
}
|
# }
|
||||||
conditions {
|
# conditions {
|
||||||
operator
|
# operator
|
||||||
value
|
# value
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
dataSourceSpecBinding {
|
dataSourceSpecBinding {
|
||||||
settlementDataProperty
|
settlementDataProperty
|
||||||
tradingTerminationProperty
|
tradingTerminationProperty
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -9,6 +9,7 @@ import { useFetch } from '@vegaprotocol/react-helpers';
|
|||||||
import { ENV } from '../../../config';
|
import { ENV } from '../../../config';
|
||||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||||
import { marketInfoWithDataProvider } from '@vegaprotocol/markets';
|
import { marketInfoWithDataProvider } from '@vegaprotocol/markets';
|
||||||
|
import { useAssetQuery } from '@vegaprotocol/assets';
|
||||||
|
|
||||||
export const ProposalContainer = () => {
|
export const ProposalContainer = () => {
|
||||||
const params = useParams<{ proposalId: string }>();
|
const params = useParams<{ proposalId: string }>();
|
||||||
@@ -35,6 +36,25 @@ export const ProposalContainer = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: assetData,
|
||||||
|
loading: assetLoading,
|
||||||
|
error: assetError,
|
||||||
|
} = useAssetQuery({
|
||||||
|
fetchPolicy: 'network-only',
|
||||||
|
variables: {
|
||||||
|
assetId:
|
||||||
|
(data?.proposal?.terms.change.__typename === 'NewAsset' &&
|
||||||
|
data?.proposal?.id) ||
|
||||||
|
(data?.proposal?.terms.change.__typename === 'UpdateAsset' &&
|
||||||
|
data.proposal.terms.change.assetId) ||
|
||||||
|
'',
|
||||||
|
},
|
||||||
|
skip: !['NewAsset', 'UpdateAsset'].includes(
|
||||||
|
data?.proposal?.terms?.change?.__typename || ''
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(refetch, 2000);
|
const interval = setInterval(refetch, 2000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
@@ -42,15 +62,20 @@ export const ProposalContainer = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer
|
<AsyncRenderer
|
||||||
loading={loading || newMarketLoading}
|
loading={loading || newMarketLoading || assetLoading}
|
||||||
error={error || newMarketError}
|
error={error || newMarketError || assetError}
|
||||||
data={newMarketData ? { newMarketData, data } : data}
|
data={{
|
||||||
|
...data,
|
||||||
|
...(newMarketData ? { newMarketData } : {}),
|
||||||
|
...(assetData ? { assetData } : {}),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{data?.proposal ? (
|
{data?.proposal ? (
|
||||||
<Proposal
|
<Proposal
|
||||||
proposal={data.proposal}
|
proposal={data.proposal}
|
||||||
restData={restData}
|
restData={restData}
|
||||||
newMarketData={newMarketData}
|
newMarketData={newMarketData}
|
||||||
|
assetData={assetData}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ProposalNotFound />
|
<ProposalNotFound />
|
||||||
|
|||||||
@@ -2,14 +2,9 @@ import classNames from 'classnames';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||||
import {
|
|
||||||
AppStateActionType,
|
|
||||||
useAppState,
|
|
||||||
} from '../../contexts/app-state/app-state-context';
|
|
||||||
import { SubHeading } from '../../components/heading';
|
import { SubHeading } from '../../components/heading';
|
||||||
|
|
||||||
export const ConnectToSeeRewards = () => {
|
export const ConnectToSeeRewards = () => {
|
||||||
const { appDispatch } = useAppState();
|
|
||||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||||
}));
|
}));
|
||||||
@@ -26,10 +21,6 @@ export const ConnectToSeeRewards = () => {
|
|||||||
<Button
|
<Button
|
||||||
data-testid="connect-to-vega-wallet-btn"
|
data-testid="connect-to-vega-wallet-btn"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
appDispatch({
|
|
||||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
|
||||||
isOpen: true,
|
|
||||||
});
|
|
||||||
openVegaWalletDialog();
|
openVegaWalletDialog();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user