Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d959e37e59 | ||
|
|
64db83fe52 |
@@ -1 +0,0 @@
|
||||
node_modules
|
||||
+6
-11
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": ["**/*"],
|
||||
"plugins": ["@nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
|
||||
"plugins": ["@nrwl/nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
|
||||
"settings": {
|
||||
"jsx-a11y": {
|
||||
"components": {
|
||||
@@ -18,7 +18,7 @@
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"extends": ["plugin:jsx-a11y/strict"],
|
||||
"rules": {
|
||||
"@nx/enforce-module-boundaries": [
|
||||
"@nrwl/nx/enforce-module-boundaries": [
|
||||
"error",
|
||||
{
|
||||
"enforceBuildableLibDependency": true,
|
||||
@@ -56,7 +56,7 @@
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"extends": ["plugin:@nx/typescript"],
|
||||
"extends": ["plugin:@nrwl/nx/typescript"],
|
||||
"rules": {
|
||||
"@typescript-eslint/ban-ts-comment": [
|
||||
"error",
|
||||
@@ -80,19 +80,14 @@
|
||||
},
|
||||
{
|
||||
"files": ["*.spec.ts", "*.spec.tsx"],
|
||||
"extends": ["plugin:@nx/typescript", "plugin:jest/recommended"],
|
||||
"extends": ["plugin:@nrwl/nx/typescript", "plugin:jest/recommended"],
|
||||
"rules": {
|
||||
"jest/consistent-test-it": [
|
||||
"error",
|
||||
{
|
||||
"fn": "it"
|
||||
}
|
||||
]
|
||||
"jest/consistent-test-it": ["error", { "fn": "it" }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"extends": ["plugin:@nx/javascript"],
|
||||
"extends": ["plugin:@nrwl/nx/javascript"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -6,7 +6,7 @@ name: 'Add Issues To Project Board'
|
||||
types:
|
||||
- opened
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PROJECT_MANAGE_ACTION }}
|
||||
GH_TOKEN: ${{ secrets.GH_NEW_CARD_TO_PROJECT }}
|
||||
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
|
||||
ISSUE_ID: ${{ github.event.issue.node_id }}
|
||||
USER: ${{ github.actor }}
|
||||
|
||||
@@ -5,7 +5,10 @@ on:
|
||||
branches:
|
||||
- release/*
|
||||
- develop
|
||||
pull_request:
|
||||
- main
|
||||
# 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:
|
||||
- opened
|
||||
- ready_for_review
|
||||
@@ -81,22 +84,6 @@ jobs:
|
||||
with:
|
||||
main-branch-name: develop
|
||||
|
||||
# See affected apps
|
||||
- name: See affected apps
|
||||
run: |
|
||||
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
|
||||
python3 tools/ci/check-affected.py --github-ref="${{ github.ref }}" --branch-slug="$branch_slug" --event-name="${{ github.event_name }}"
|
||||
|
||||
- name: Verify script result
|
||||
run: |
|
||||
echo "Check outputs from script"
|
||||
echo "projects: ${{ env.PROJECTS }}"
|
||||
echo "projects-e2e: ${{ env.PROJECTS_E2E }}"
|
||||
echo "preview_governance: ${{ env.PREVIEW_GOVERNANCE }}"
|
||||
echo "preview_trading: ${{ env.PREVIEW_TRADING }}"
|
||||
echo "preview_explorer: ${{ env.PREVIEW_EXPLORER }}"
|
||||
echo "preview_tools: ${{ env.PREVIEW_TOOLS }}"
|
||||
|
||||
- name: Check formatting
|
||||
run: yarn nx format:check
|
||||
|
||||
@@ -112,6 +99,100 @@ jobs:
|
||||
- name: Build affected
|
||||
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
||||
|
||||
# See affected apps
|
||||
- name: See affected apps
|
||||
run: |
|
||||
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
|
||||
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
|
||||
|
||||
echo ">>>> debug"
|
||||
echo "NX_BASE: ${{ env.NX_BASE }}"
|
||||
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
||||
echo "Affected: ${affected}"
|
||||
echo "Branch slug: ${branch_slug}"
|
||||
echo ">>>> eof debug"
|
||||
|
||||
projects_array=()
|
||||
|
||||
preview_governance="not deployed"
|
||||
preview_trading="not deployed"
|
||||
preview_explorer="not deployed"
|
||||
preview_tools="not deployed"
|
||||
|
||||
# parse if affected is any of three main applications, if none - use all of them
|
||||
if echo "$affected" | grep -q governance; then
|
||||
echo "Governance is affected"
|
||||
projects_array+=("governance")
|
||||
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
||||
fi
|
||||
if echo "$affected" | grep -q trading; then
|
||||
echo "Trading is affected"
|
||||
projects_array+=("trading")
|
||||
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
||||
fi
|
||||
if echo "$affected" | grep -q explorer; then
|
||||
echo "Explorer is affected"
|
||||
projects_array+=("explorer")
|
||||
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
||||
fi
|
||||
if [[ ${#projects_array[@]} -eq 0 ]]; then
|
||||
projects_array=("governance" "trading" "explorer")
|
||||
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
||||
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
||||
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
||||
fi
|
||||
|
||||
# applications parsed before this loop are applicable for running e2e-tests
|
||||
projects_e2e_array=()
|
||||
for project in "${projects_array[@]}"; do
|
||||
projects_e2e_array+=("${project}-e2e")
|
||||
done
|
||||
# all applications below this loop are not applicable for running e2e-test
|
||||
|
||||
# check if pull request event to deploy tools
|
||||
if [[ "${{ github.event_name }}" = "pull_request" ]]; then
|
||||
if echo "$affected" | grep -q multisig-signer; then
|
||||
echo "Tools are affected"
|
||||
echo "Deploying tools on preview"
|
||||
preview_tools=$(printf "https://%s.%s.vega.rocks" "tools" "$branch_slug")
|
||||
|
||||
projects_array+=("multisig-signer")
|
||||
fi
|
||||
# those apps deploy only from develop to mainnet
|
||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||
if echo "$affected" | grep -q multisig-signer; then
|
||||
echo "Tools are affected"
|
||||
echo "Deploying tools on s3"
|
||||
|
||||
projects_array+=("multisig-signer")
|
||||
fi
|
||||
if echo "$affected" | grep -q static; then
|
||||
echo "static is affected"
|
||||
echo "Deploying static on s3"
|
||||
|
||||
projects_array+=("static")
|
||||
fi
|
||||
if echo "$affected" | grep -q ui-toolkit; then
|
||||
echo "ui-toolkit is affected"
|
||||
echo "Deploying ui-toolkit on s3"
|
||||
|
||||
projects_array+=("ui-toolkit")
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Projects: ${projects_array[@]}"
|
||||
echo "Projects E2E: ${projects_e2e_array[@]}"
|
||||
projects_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_array[@]}")
|
||||
projects_e2e_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_e2e_array[@]}")
|
||||
|
||||
echo PROJECTS_E2E=$projects_e2e_json >> $GITHUB_ENV
|
||||
echo PROJECTS=$projects_json >> $GITHUB_ENV
|
||||
|
||||
echo PREVIEW_GOVERNANCE=$preview_governance >> $GITHUB_ENV
|
||||
echo PREVIEW_TRADING=$preview_trading >> $GITHUB_ENV
|
||||
echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
|
||||
echo PREVIEW_TOOLS=$preview_tools >> $GITHUB_ENV
|
||||
|
||||
outputs:
|
||||
projects: ${{ env.PROJECTS }}
|
||||
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||
@@ -123,7 +204,7 @@ jobs:
|
||||
cypress:
|
||||
needs: lint-test-build
|
||||
name: '(CI) cypress'
|
||||
# if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
|
||||
if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
|
||||
uses: ./.github/workflows/cypress-run.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
@@ -133,7 +214,7 @@ jobs:
|
||||
publish-dist:
|
||||
needs: lint-test-build
|
||||
name: '(CD) publish dist'
|
||||
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
|
||||
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/publish-dist.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
@@ -144,7 +225,7 @@ jobs:
|
||||
needs:
|
||||
- publish-dist
|
||||
- lint-test-build
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
timeout-minutes: 60
|
||||
name: '(CD) comment preview links'
|
||||
steps:
|
||||
@@ -160,26 +241,26 @@ jobs:
|
||||
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
||||
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
||||
if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then
|
||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
|
||||
echo "waiting for governance preview: ${{ needs.lint-test-build.outputs.preview_governance }}"
|
||||
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
|
||||
echo "waiting for governance preview"
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then
|
||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
|
||||
echo "waiting for explorer preview: ${{ needs.lint-test-build.outputs.preview_explorer }}"
|
||||
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
|
||||
echo "waiting for explorer preview"
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then
|
||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
|
||||
echo "waiting for trading preview: ${{ needs.lint-test-build.outputs.preview_trading }}"
|
||||
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
|
||||
echo "waiting for trading preview"
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then
|
||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
|
||||
echo "waiting for tools preview: ${{ needs.lint-test-build.outputs.preview_tools }}"
|
||||
until curl -L --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
|
||||
echo "waiting for tools preview"
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
@@ -190,7 +271,7 @@ jobs:
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
Previews
|
||||
Previews:
|
||||
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
||||
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
||||
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
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,39 +22,6 @@ jobs:
|
||||
with:
|
||||
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_RELEASE=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_RELEASE == 'false' && github.event_name == 'push' }}
|
||||
run: |
|
||||
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Set up QEMU
|
||||
id: quemu
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -66,7 +33,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to the Container registry (ghcr)
|
||||
if: ${{ env.IS_PR == 'true' }}
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
@@ -75,8 +42,9 @@ jobs:
|
||||
|
||||
- name: Log in to the Container registry (docker hub)
|
||||
uses: docker/login-action@v2
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
||||
with:
|
||||
# registry: registry.hub.docker.com
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
@@ -97,33 +65,67 @@ jobs:
|
||||
- name: Define dist variables
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
run: |
|
||||
python3 tools/ci/define-dist-variables.py --github-ref="${{ github.ref }}" --app="${{ matrix.app }}"
|
||||
envName=''
|
||||
domain="vega.rocks"
|
||||
bucketName=''
|
||||
|
||||
- name: Verify script result
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
run: |
|
||||
echo "BUCKET_NAME=${{ env.BUCKET_NAME }}"
|
||||
echo "ENV_NAME=${{ env.ENV_NAME }}"
|
||||
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
||||
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
|
||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||
envName="stagnet1"
|
||||
if [[ "${{ matrix.app }}" = "multisig-signer" ]]; then
|
||||
envName="mainnet"
|
||||
bucketName="tools.vega.xyz"
|
||||
fi
|
||||
if [[ "${{ matrix.app }}" = "static" ]]; then
|
||||
envName="mainnet"
|
||||
bucketName="static.vega.xyz"
|
||||
fi
|
||||
if [[ "${{ matrix.app }}" = "ui-toolkit" ]]; then
|
||||
envName="mainnet"
|
||||
bucketName="ui.vega.rocks"
|
||||
fi
|
||||
elif [[ "${{ github.ref }}" =~ .*main$ ]]; then
|
||||
envName="mainnet"
|
||||
fi
|
||||
|
||||
if [[ "${envName}" = "mainnet" ]]; then
|
||||
domain="vega.xyz"
|
||||
if [[ -z "${bucketName}" ]]; then
|
||||
bucketName="${{ matrix.app }}.${domain}"
|
||||
fi
|
||||
elif [[ "${envName}" = "testnet" ]]; then
|
||||
domain="fairground.wtf"
|
||||
if [[ -z "${bucketName}" ]]; then
|
||||
bucketName="${{ matrix.app }}.${domain}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "${bucketName}" ]]; then
|
||||
bucketName="${{ matrix.app }}.${envName}.${domain}"
|
||||
fi
|
||||
|
||||
echo "bucket name: ${bucketName}"
|
||||
echo "env name: ${envName}"
|
||||
|
||||
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
|
||||
echo ENV_NAME=${envName} >> $GITHUB_ENV
|
||||
|
||||
- name: Build local dist
|
||||
run: |
|
||||
envCmd=""
|
||||
flags=""
|
||||
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
|
||||
envCmd="yarn env-cmd -f ./apps/${{ matrix.app }}/.env.${{ env.ENV_NAME }}"
|
||||
flags="--env=${{ env.ENV_NAME }}"
|
||||
fi
|
||||
|
||||
if [ "${{ matrix.app }}" = "trading" ]; then
|
||||
$envCmd yarn nx export trading || (yarn install && $envCmd yarn nx export trading)
|
||||
yarn nx export trading $flags || (yarn install && yarn nx export trading $flags)
|
||||
DIST_LOCATION=dist/apps/trading/exported
|
||||
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
||||
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
||||
DIST_LOCATION=dist/storybook/ui-toolkit
|
||||
elif [ "${{ matrix.app }}" = "static" ]; then
|
||||
yarn nx build static || (yarn install && yarn nx build static)
|
||||
else
|
||||
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
|
||||
fi
|
||||
if [[ -z "$DIST_LOCATION" ]]; then
|
||||
yarn nx build ${{ matrix.app }} $flags || (yarn install && yarn nx build ${{ matrix.app }} $flags)
|
||||
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
||||
fi
|
||||
mv $DIST_LOCATION dist-result
|
||||
@@ -143,7 +145,7 @@ jobs:
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||
|
||||
- name: Image digest
|
||||
if: ${{ env.IS_PR == 'true' }}
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
|
||||
- name: Sanity check docker image
|
||||
@@ -158,7 +160,7 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
continue-on-error: true
|
||||
id: ghcr-push
|
||||
if: ${{ env.IS_PR == 'true' }}
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
@@ -173,7 +175,7 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
continue-on-error: true
|
||||
id: dockerhub-push
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
@@ -183,7 +185,7 @@ jobs:
|
||||
ENV_NAME=${{ env.ENV_NAME }}
|
||||
tags: |
|
||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
||||
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
||||
|
||||
- name: Publish dist as docker image (ghcr - retry)
|
||||
uses: docker/build-push-action@v3
|
||||
@@ -210,13 +212,13 @@ jobs:
|
||||
ENV_NAME=${{ env.ENV_NAME }}
|
||||
tags: |
|
||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
||||
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
||||
|
||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
||||
- name: Publish dist to s3
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
# s3 releases are not happening for trading on mainnet - it's IPFS
|
||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
|
||||
with:
|
||||
args: --acl private --follow-symlinks --delete
|
||||
env:
|
||||
@@ -226,34 +228,18 @@ jobs:
|
||||
AWS_REGION: 'eu-west-1'
|
||||
SOURCE_DIR: 'dist-result'
|
||||
|
||||
- name: Install aws CLI
|
||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||
uses: unfor19/install-aws-cli-action@master
|
||||
|
||||
- name: Perform cache invalidation
|
||||
if: ${{ env.IS_S3_RELEASE == '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
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
if: ${{ env.IS_PR == 'true' }}
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
labels: ${{ matrix.app }}-preview
|
||||
number: ${{ github.event.number }}
|
||||
|
||||
- name: Trigger fleek deployment
|
||||
# release to ipfs happens only on mainnet (represented by main branch) for trading
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
||||
run: |
|
||||
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
|
||||
if echo ${{ github.ref }} | grep -q main; then
|
||||
# display info about app
|
||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -266,7 +252,7 @@ jobs:
|
||||
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
||||
https://api.fleek.co/graphql
|
||||
|
||||
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
|
||||
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
||||
# display info about app
|
||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -281,7 +267,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Check out ipfs-redirect
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: 'vegaprotocol/ipfs-redirect'
|
||||
@@ -290,7 +276,7 @@ jobs:
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
|
||||
- name: Update interstitial page to point to the new console
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
run: |
|
||||
@@ -312,11 +298,11 @@ jobs:
|
||||
git config --global user.name "vega-ci-bot"
|
||||
|
||||
# update CID files
|
||||
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
|
||||
if echo ${{ github.ref }} | grep -q main; then
|
||||
echo $new_hash > cidv0-mainnet.txt
|
||||
echo $new_cid > cidv1-mainnet.txt
|
||||
git add cidv0-mainnet.txt cidv1-mainnet.txt
|
||||
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
|
||||
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
||||
echo $new_hash > cidv0-fairground.txt
|
||||
echo $new_cid > cidv1-fairground.txt
|
||||
git add cidv0-fairground.txt cidv1-fairground.txt
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
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;
|
||||
// },
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"exclude": [
|
||||
"../**/*.spec.js",
|
||||
"../**/*.test.js",
|
||||
"../**/*.spec.ts",
|
||||
"../**/*.test.ts",
|
||||
"../**/*.spec.tsx",
|
||||
"../**/*.test.tsx",
|
||||
"../**/*.spec.jsx",
|
||||
"../**/*.test.jsx"
|
||||
],
|
||||
"include": ["../**/*"]
|
||||
}
|
||||
@@ -16,10 +16,5 @@ NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
NX_EXPLORER_VALIDATORS=1
|
||||
|
||||
CYPRESS_VEGA_URL=http://localhost:3008/graphql
|
||||
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
||||
CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545
|
||||
CYPRESS_FAUCET_URL=http://localhost:1790/api/v1/mint
|
||||
CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65
|
||||
CYPRESS_VEGA_WALLET_URL=http://localhost:1789
|
||||
CYPRESS_VEGA_WALLET_API_TOKEN=
|
||||
CYPRESS_VEGA_URL=http://localhost:3008/graphql
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"name": "explorer-e2e",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/explorer-e2e/src",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"e2e": {
|
||||
"executor": "@nx/cypress:cypress",
|
||||
"executor": "@nrwl/cypress:cypress",
|
||||
"options": {
|
||||
"cypressConfig": "apps/explorer-e2e/cypress.config.js",
|
||||
"devServerTarget": "explorer:serve"
|
||||
@@ -17,14 +16,14 @@
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/linter:eslint",
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "nx:run-commands",
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"outputs": [],
|
||||
"options": {
|
||||
"command": "yarn tsc --project ./apps/explorer-e2e/"
|
||||
|
||||
@@ -31,7 +31,7 @@ context('Asset page', { tags: '@regression' }, () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should open details page when clicked on "View details"', () => {
|
||||
it('should open details page when clicked on "View details"', () => {
|
||||
cy.getAssets().then((assets) => {
|
||||
assets.forEach((asset) => {
|
||||
cy.get(`[row-id="${asset.id}"] [col-id="actions"] button`)
|
||||
|
||||
@@ -1,130 +1,19 @@
|
||||
context('Market page', { tags: '@regression' }, function () {
|
||||
//Tests set to skip until market bug for capsule checkpoint is fixed
|
||||
context.skip('Market page', { tags: '@regression' }, function () {
|
||||
describe('Verify elements on page', function () {
|
||||
const marketHeaders = 'markets-heading';
|
||||
const createdMarketId =
|
||||
'2eab0e66545a789047561bc5a2e5cbc3b19eb708da41104e3cac2474ee36c4d4';
|
||||
const marketHeaders = '[data-testid="markets-header"]';
|
||||
const marketNavigation = 'a[href="/markets"]';
|
||||
|
||||
before('Create market', function () {
|
||||
it('Markets page is displayed', function () {
|
||||
cy.visit('/');
|
||||
cy.createMarket();
|
||||
cy.get(marketNavigation).click();
|
||||
cy.common_validate_blocks_data_displayed(marketHeaders);
|
||||
});
|
||||
|
||||
beforeEach('Get market id', function () {
|
||||
cy.navigate_to('markets');
|
||||
cy.get('[col-id="id"]').eq(1).invoke('text').as('createdMarketId');
|
||||
});
|
||||
|
||||
it('Market displayed on market page', function () {
|
||||
cy.navigate_to('markets');
|
||||
cy.getByTestId(marketHeaders).should('be.visible');
|
||||
cy.get(`[row-id="${this.createdMarketId}"]`)
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.get_element_by_col_id('code').should('have.text', 'TEST.24h');
|
||||
cy.get_element_by_col_id('name').should('have.text', 'Test market 1');
|
||||
cy.get_element_by_col_id('state').should('have.text', 'Pending');
|
||||
cy.get_element_by_col_id('asset').should('have.text', 'fUSDC');
|
||||
cy.get_element_by_col_id('id').should(
|
||||
'have.text',
|
||||
this.createdMarketId
|
||||
);
|
||||
cy.get_element_by_col_id('actions')
|
||||
.find('a')
|
||||
.should('have.attr', 'href', `/markets/${this.createdMarketId}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to go to market details page', function () {
|
||||
cy.navigate_to('markets');
|
||||
cy.get_element_by_col_id('actions').eq(1).click();
|
||||
cy.getByTestId(marketHeaders).should('have.text', 'Test market 1');
|
||||
cy.validate_element_from_table('Name', 'Test market 1');
|
||||
cy.validate_element_from_table('Market ID', this.createdMarketId);
|
||||
cy.validate_element_from_table('Trading Mode', 'Opening auction');
|
||||
cy.validate_element_from_table('Market Decimal Places', '5');
|
||||
cy.validate_element_from_table('Position Decimal Places', '5');
|
||||
cy.validate_element_from_table('Settlement Asset Decimal Places', '5');
|
||||
// Instrument
|
||||
cy.validate_element_from_table('Market Name', 'Test market 1');
|
||||
cy.validate_element_from_table('Code', 'TEST.24h');
|
||||
cy.validate_element_from_table('Product Type', 'Future');
|
||||
cy.validate_element_from_table('Quote Name', 'fUSDC');
|
||||
// Settlement Asset
|
||||
cy.validate_element_from_table('Quote Name', 'fUSDC');
|
||||
cy.validate_element_from_table('Symbol', 'fUSDC');
|
||||
cy.validate_element_from_table('Decimals', '5');
|
||||
cy.validate_element_from_table('Quantum', '0.00');
|
||||
cy.validate_element_from_table('Status', 'Enabled');
|
||||
cy.validate_element_from_table('Max faucet amount', '10,000,000.00');
|
||||
cy.validate_element_from_table(
|
||||
'Infrastructure fee account balance',
|
||||
'0.00'
|
||||
);
|
||||
cy.validate_element_from_table(
|
||||
'Global reward pool account balance',
|
||||
'0.00'
|
||||
);
|
||||
// Metadata
|
||||
cy.validate_element_from_table('Sector', 'tech');
|
||||
cy.validate_element_from_table('Source', 'docs.vega.xyz');
|
||||
// Risk model
|
||||
cy.validate_element_from_table('Tau', '0.0001140771161');
|
||||
cy.validate_element_from_table('Risk Aversion Parameter', '0.01');
|
||||
// Risk parameters
|
||||
// cy.validate_element_from_table('R', '0.016')
|
||||
cy.validate_element_from_table('Sigma', '0.5');
|
||||
// Risk factors
|
||||
cy.validate_element_from_table('Short', '0.0143218738374871');
|
||||
cy.validate_element_from_table('Long', '0.0141450471498822');
|
||||
// Price monitoring settings 1
|
||||
cy.validate_element_from_table('Horizon Secs', '43,200');
|
||||
cy.validate_element_from_table('Probability', '1');
|
||||
cy.validate_element_from_table('Auction Extension Secs', '600');
|
||||
// Liquidity Monitoring
|
||||
cy.validate_element_from_table('Triggering Ratio', '0.7');
|
||||
cy.validate_element_from_table('Time Window', '3,600');
|
||||
cy.validate_element_from_table('Scaling Factor', '10');
|
||||
// Liquidity
|
||||
cy.validate_element_from_table('Target Stake', '0.00 fUSDC');
|
||||
cy.validate_element_from_table('Supplied Stake', '0.00 fUSDC');
|
||||
cy.validate_element_from_table('Market Value Proxy', '0.00 fUSDC');
|
||||
// Liquidity price range
|
||||
cy.validate_element_from_table(
|
||||
'Liquidity Price Range',
|
||||
'1,000.00% of mid price'
|
||||
);
|
||||
cy.validate_element_from_table('Lowest Price', '0.00 fUSDC');
|
||||
cy.validate_element_from_table('Highest Price', '0.00 fUSDC');
|
||||
|
||||
cy.getByTestId('oracle-spec-links')
|
||||
.should('have.attr', 'href')
|
||||
.and(
|
||||
'contain',
|
||||
'/oracles/bf242aa5c9f64fcbb77808aa8582e73711519f4b35264eb797a80f1803590a24'
|
||||
);
|
||||
|
||||
// Able to view Json
|
||||
cy.contains('View JSON').click();
|
||||
cy.get('.language-json').should('exist');
|
||||
});
|
||||
|
||||
// Skipping due to resize observer loop limit error
|
||||
it.skip('Markets page displayed on mobile', function () {
|
||||
it('Markets page displayed on mobile', function () {
|
||||
cy.common_switch_to_mobile_and_click_toggle();
|
||||
cy.navigate_to('markets', true);
|
||||
cy.getByTestId(marketHeaders).should('be.visible');
|
||||
cy.get(`[row-id="${createdMarketId}"]`)
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.get_element_by_col_id('code').should('have.text', 'TEST.24h');
|
||||
cy.get_element_by_col_id('name').should('have.text', 'Test market 1');
|
||||
cy.get_element_by_col_id('state').should('have.text', 'Pending');
|
||||
cy.get_element_by_col_id('asset').should('have.text', 'fUSDC');
|
||||
cy.get_element_by_col_id('id').should('have.text', createdMarketId);
|
||||
cy.get_element_by_col_id('actions')
|
||||
.find('a')
|
||||
.should('have.attr', 'href', `/markets/${createdMarketId}`);
|
||||
});
|
||||
cy.get(marketNavigation).click();
|
||||
cy.common_validate_blocks_data_displayed(marketHeaders);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -169,6 +169,7 @@ context.skip('Parties page', { tags: '@regression' }, function () {
|
||||
const jsonFields = '.hljs';
|
||||
const sideMenuBackground = '.absolute';
|
||||
|
||||
// Engage dark mode if not allready set
|
||||
cy.get(sideMenuBackground)
|
||||
.should('have.css', 'background-color')
|
||||
.then((background_color) => {
|
||||
|
||||
@@ -40,7 +40,7 @@ context.skip('Transactions page', function () {
|
||||
.first()
|
||||
.click({ force: true });
|
||||
} else {
|
||||
cy.log('Unable to find any transactions on page');
|
||||
cy.slack('Unable to find any transactions on page');
|
||||
cy.screenshot();
|
||||
}
|
||||
});
|
||||
@@ -78,7 +78,7 @@ context.skip('Transactions page', function () {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cy.log('Unable to find any transactions on page');
|
||||
cy.slack('Unable to find any transactions on page');
|
||||
cy.screenshot();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,11 +7,7 @@ context('Validator page', { tags: '@smoke' }, function () {
|
||||
it('should be able to see validator tiles', function () {
|
||||
cy.getNodes().then((nodes) => {
|
||||
nodes.forEach((node) => {
|
||||
if (node.rankingScore.performanceScore > 0) {
|
||||
cy.get(`[validator-id="${node.id}"]`).should('be.visible');
|
||||
} else {
|
||||
cy.get(`[validator-id="${node.id}"]`).should('not.exist');
|
||||
}
|
||||
cy.get(`[validator-id="${node.id}"]`).should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ Cypress.Commands.add('switchToMobile', () => {
|
||||
Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () {
|
||||
cy.viewport('iphone-x');
|
||||
cy.visit('/');
|
||||
cy.get('[data-testid="button-menu-drawer"]').click();
|
||||
cy.get('[data-testid="open-menu"]').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('monitor_clipboard', () => {
|
||||
@@ -88,42 +88,3 @@ Cypress.Commands.add('convert_number_to_max_four_decimal', (number) => {
|
||||
maximumFractionDigits: 4,
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('navigate_to', (page, mobileView = false) => {
|
||||
const navigation = {
|
||||
transactions: '/txs',
|
||||
blocks: '/blocks',
|
||||
oracles: '/oracles',
|
||||
validators: '/validators',
|
||||
parties: '/parties',
|
||||
assets: '/assets',
|
||||
markets: '/markets',
|
||||
governanceProposals: '/governance',
|
||||
networkParameters: '/network-parameters',
|
||||
genesisParameters: '/genesis',
|
||||
};
|
||||
|
||||
const topLevelRoutes = ['transactions', 'blocks', 'oracles', 'validators'];
|
||||
|
||||
cy.getByTestId('navigation').within(() => {
|
||||
if (!topLevelRoutes.includes(page) && mobileView === false) {
|
||||
cy.getByTestId('other').first().click();
|
||||
}
|
||||
cy.get(`[href="${navigation[page]}"]`).first().click();
|
||||
});
|
||||
cy.url().should('include', navigation[page]);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('get_element_by_col_id', (elementName) => {
|
||||
cy.get(`[col-id="${elementName}"]`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
'validate_element_from_table',
|
||||
(tableRowName, tableRowValue) => {
|
||||
cy.contains(tableRowName)
|
||||
.parentsUntil("[data-testid='key-value-table-row']")
|
||||
.siblings()
|
||||
.should('have.text', tableRowValue);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
"@nrwl/react/babel",
|
||||
{
|
||||
"runtime": "automatic"
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,14 +1,14 @@
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.rocks
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
|
||||
NX_VEGA_ENV=STAGNET1
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
|
||||
NX_VEGA_TOKEN_URL=https://governance.stagnet1.vega.rocks
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.rocks/rest
|
||||
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/tm
|
||||
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_ENV=DEVNET
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# 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:@nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*", "__generated__"],
|
||||
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
|
||||
@@ -32,7 +32,6 @@ yarn nx serve explorer
|
||||
Example configurations are provided here:
|
||||
|
||||
- [Mainnet](./.env.mainnet)
|
||||
- [Mainnet-mirror](./.env.mainnet-mirror)
|
||||
- [Devnet](./.env.devnet)
|
||||
- [Capsule](./.env.capsule)
|
||||
- [Testnet](./.env.testnet)
|
||||
@@ -40,7 +39,7 @@ Example configurations are provided here:
|
||||
For convenience, you can boot the app injecting one of the configurations above by running:
|
||||
|
||||
```bash
|
||||
yarn env-cmd -f .\apps\explorer\.env.{env} yarn nx run explorer:serve # e.g. stagnet1
|
||||
yarn nx run explorer:serve --env={env} # e.g. stagnet1
|
||||
```
|
||||
|
||||
There are a few different configuration options offered for this app:
|
||||
|
||||
@@ -4,8 +4,8 @@ export default {
|
||||
displayName: 'explorer',
|
||||
preset: '../../jest.preset.js',
|
||||
transform: {
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
||||
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
|
||||
'^.+\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/apps/explorer',
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"name": "explorer",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/explorer/src",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/webpack:webpack",
|
||||
"executor": "./tools/executors/webpack:build",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
@@ -39,7 +38,7 @@
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nx/webpack:dev-server",
|
||||
"executor": "./tools/executors/webpack:serve",
|
||||
"options": {
|
||||
"port": 3000,
|
||||
"buildTarget": "explorer:build:development",
|
||||
@@ -53,36 +52,30 @@
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/linter:eslint",
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/apps/explorer"],
|
||||
"options": {
|
||||
"jestConfig": "apps/explorer/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"ci": true,
|
||||
"codeCoverage": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"generate-types": {
|
||||
"executor": "nx:run-commands",
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"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"
|
||||
"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"
|
||||
]
|
||||
}
|
||||
},
|
||||
"build-netlify": {
|
||||
"executor": "nx:run-commands",
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"cp apps/explorer/netlify.toml netlify.toml",
|
||||
@@ -91,7 +84,7 @@
|
||||
}
|
||||
},
|
||||
"build-spec": {
|
||||
"executor": "nx:run-commands",
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"outputs": [],
|
||||
"options": {
|
||||
"command": "yarn tsc --project ./apps/explorer/tsconfig.spec.json"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridColumn } from 'ag-grid-react';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
||||
import { useRef, useLayoutEffect } from 'react';
|
||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
||||
import type { RowClickedEvent } from 'ag-grid-community';
|
||||
|
||||
type AssetsTableProps = {
|
||||
data: AssetFieldsFragment[] | null;
|
||||
@@ -31,58 +31,6 @@ 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 (
|
||||
<AgGrid
|
||||
ref={ref}
|
||||
@@ -98,11 +46,60 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||
filterParams: { buttons: ['reset'] },
|
||||
autoHeight: true,
|
||||
}}
|
||||
columnDefs={columnDefs}
|
||||
suppressCellFocus={true}
|
||||
onRowClicked={({ data }: RowClickedEvent) => {
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -95,10 +95,7 @@ export const Header = () => {
|
||||
{mainItems.map(routeToNavigationItem)}
|
||||
{groupedItems && groupedItems.length > 0 && (
|
||||
<NavigationItem>
|
||||
<NavigationTrigger
|
||||
isActive={Boolean(isOnOther)}
|
||||
data-testid="other"
|
||||
>
|
||||
<NavigationTrigger isActive={Boolean(isOnOther)}>
|
||||
{t('Other')}
|
||||
</NavigationTrigger>
|
||||
<NavigationContent>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import React from 'react';
|
||||
|
||||
export interface InfoBlockProps {
|
||||
title: string;
|
||||
|
||||
@@ -1,98 +1,33 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
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', () => {
|
||||
it('renders Network for 000.000 party', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<PartyLink id={zeroes} />
|
||||
</MockedProvider>
|
||||
);
|
||||
const zeroes =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const screen = render(<PartyLink id={zeroes} />);
|
||||
expect(screen.getByText('Network')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders Network for network party', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<PartyLink id="network" />
|
||||
</MockedProvider>
|
||||
);
|
||||
const screen = render(<PartyLink id="network" />);
|
||||
expect(screen.getByText('Network')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders ID with no link for invalid party', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<PartyLink id="this-party-is-not-valid" />
|
||||
</MockedProvider>
|
||||
);
|
||||
const screen = render(<PartyLink id="this-party-is-not-valid" />);
|
||||
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', () => {
|
||||
const aValidParty =
|
||||
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e';
|
||||
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<PartyLink id={aValidParty} />
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
<MemoryRouter>
|
||||
<PartyLink id={aValidParty} />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const el = screen.getByText(aValidParty);
|
||||
|
||||
@@ -1,44 +1,22 @@
|
||||
import { Routes } from '../../../routes/route-names';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useMemo, type ComponentProps } from 'react';
|
||||
import type { ComponentProps } from 'react';
|
||||
import Hash from '../hash';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { isValidPartyId } from '../../../routes/parties/id/components/party-id-error';
|
||||
import { Icon, truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
||||
import { useExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
|
||||
import type { ExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
|
||||
import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const SPECIAL_CASE_NETWORK_ID =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
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>> & {
|
||||
id: string;
|
||||
truncate?: boolean;
|
||||
};
|
||||
|
||||
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'
|
||||
// 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) {
|
||||
@@ -60,20 +38,13 @@ const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
||||
<Link
|
||||
className="underline font-mono"
|
||||
{...props}
|
||||
to={`/${Routes.PARTIES}/${id}`}
|
||||
>
|
||||
{useName ? (
|
||||
name
|
||||
) : (
|
||||
<Hash text={truncate ? truncateMiddle(id, 4, 4) : id} />
|
||||
)}
|
||||
</Link>
|
||||
</span>
|
||||
<Link
|
||||
className="underline font-mono"
|
||||
{...props}
|
||||
to={`/${Routes.PARTIES}/${id}`}
|
||||
>
|
||||
<Hash text={truncate ? truncateMiddle(id) : id} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { MarketFieldsFragment } from '@vegaprotocol/markets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
import { AgGridColumn } from 'ag-grid-react';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import type {
|
||||
VegaICellRendererParams,
|
||||
@@ -40,34 +39,54 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const columnDefs = useMemo<ColDef[]>(
|
||||
() => [
|
||||
{
|
||||
colId: 'code',
|
||||
headerName: t('Code'),
|
||||
field: 'tradableInstrument.instrument.code',
|
||||
},
|
||||
{
|
||||
colId: 'name',
|
||||
headerName: t('Name'),
|
||||
field: 'tradableInstrument.instrument.name',
|
||||
},
|
||||
{
|
||||
headerName: t('Status'),
|
||||
field: 'state',
|
||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||
valueGetter: ({
|
||||
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,
|
||||
}}
|
||||
suppressCellFocus={true}
|
||||
onRowClicked={({ data, event }: RowClickedEvent) => {
|
||||
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,
|
||||
}: VegaValueGetterParams<MarketFieldsFragment>) => {
|
||||
return data?.state ? MarketStateMapping[data?.state] : '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'asset',
|
||||
headerName: t('Settlement asset'),
|
||||
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||
cellRenderer: ({
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
colId="asset"
|
||||
headerName={t('Settlement asset')}
|
||||
field="tradableInstrument.instrument.product.settlementAsset.symbol"
|
||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||
cellRenderer={({
|
||||
data,
|
||||
}: VegaICellRendererParams<
|
||||
MarketFieldsFragment,
|
||||
@@ -86,19 +105,19 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
||||
) : (
|
||||
''
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
flex: 2,
|
||||
headerName: t('Market ID'),
|
||||
field: 'id',
|
||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||
},
|
||||
{
|
||||
colId: 'actions',
|
||||
headerName: '',
|
||||
field: 'id',
|
||||
cellRenderer: ({
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
flex={2}
|
||||
headerName={t('Market ID')}
|
||||
field="id"
|
||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||
/>
|
||||
<AgGridColumn
|
||||
colId="actions"
|
||||
headerName=""
|
||||
field="id"
|
||||
cellRenderer={({
|
||||
value,
|
||||
}: VegaICellRendererParams<MarketFieldsFragment, 'id'>) =>
|
||||
value ? (
|
||||
@@ -107,34 +126,9 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
||||
</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,10 +13,6 @@ fragment ExplorerDeterministicOrderFields on Order {
|
||||
remaining
|
||||
size
|
||||
rejectionReason
|
||||
peggedOrder {
|
||||
reference
|
||||
offset
|
||||
}
|
||||
party {
|
||||
id
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
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, 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 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 ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
||||
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, 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 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 const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
||||
fragment ExplorerDeterministicOrderFields on Order {
|
||||
@@ -29,10 +29,6 @@ export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
||||
remaining
|
||||
size
|
||||
rejectionReason
|
||||
peggedOrder {
|
||||
reference
|
||||
offset
|
||||
}
|
||||
party {
|
||||
id
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ type Amend = components['schemas']['v1OrderAmendment'];
|
||||
|
||||
function renderAmendOrderDetails(
|
||||
id: string,
|
||||
version: number | undefined,
|
||||
version: number,
|
||||
amend: Amend,
|
||||
mocks: MockedResponse[]
|
||||
) {
|
||||
@@ -25,11 +25,7 @@ function renderAmendOrderDetails(
|
||||
);
|
||||
}
|
||||
|
||||
function renderExistingAmend(
|
||||
id: string,
|
||||
version: number | undefined,
|
||||
amend: Amend
|
||||
) {
|
||||
function renderExistingAmend(id: string, version: number, amend: Amend) {
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
@@ -53,7 +49,6 @@ function renderExistingAmend(
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
price: '200',
|
||||
side: 'BUY',
|
||||
peggedOrder: null,
|
||||
remaining: '99',
|
||||
rejectionReason: 'rejection',
|
||||
reference: '123',
|
||||
@@ -82,56 +77,6 @@ function renderExistingAmend(
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
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: {
|
||||
query: ExplorerMarketDocument,
|
||||
@@ -212,15 +157,4 @@ describe('Amend order details', () => {
|
||||
expect(await res.findByText('New price')).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 {
|
||||
id: string;
|
||||
amend: components['schemas']['v1OrderAmendment'];
|
||||
// Version to fetch. Latest is provided by default
|
||||
// Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0
|
||||
version?: number;
|
||||
}
|
||||
|
||||
@@ -34,11 +34,13 @@ export function getSideDeltaColour(delta: string): string {
|
||||
* @param param0
|
||||
* @returns
|
||||
*/
|
||||
const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
||||
const variables = version ? { orderId: id, version } : { orderId: id };
|
||||
|
||||
const AmendOrderDetails = ({
|
||||
id,
|
||||
version = 0,
|
||||
amend,
|
||||
}: AmendOrderDetailsProps) => {
|
||||
const { data, error } = useExplorerDeterministicOrderQuery({
|
||||
variables,
|
||||
variables: { orderId: id, version },
|
||||
});
|
||||
|
||||
if (error || (data && !data.orderByID)) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import PriceInMarket from '../price-in-market/price-in-market';
|
||||
import { Time } from '../time';
|
||||
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
||||
import SizeInMarket from '../size-in-market/size-in-market';
|
||||
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
||||
|
||||
export interface DeterministicOrderDetailsProps {
|
||||
id: string;
|
||||
@@ -69,35 +68,25 @@ const DeterministicOrderDetails = ({
|
||||
<span className="mx-5 text-base">@</span>
|
||||
<PriceInMarket price={o.price} marketId={o.market.id} />
|
||||
</h2>
|
||||
<p className="text-gray-200">
|
||||
<p className="text-gray-500 mb-4">
|
||||
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
||||
</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 ? (
|
||||
<p className="text-gray-500 mt-4">
|
||||
<p className="text-gray-500 mb-4">
|
||||
<span>{t('Reference')}</span>: {o.reference}
|
||||
</p>
|
||||
) : null}
|
||||
<div className="grid md:grid-cols-4 gap-x-6 mt-4">
|
||||
<div className="mb-12 md:mb-0">
|
||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||
{t('Status')}
|
||||
</h2>
|
||||
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
||||
{statusText[o.status]}
|
||||
</h5>
|
||||
</div>
|
||||
<div className="grid md:grid-cols-4 gap-x-6">
|
||||
{version !== 0 ? null : (
|
||||
<div className="mb-12 md:mb-0">
|
||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||
{t('Status')}
|
||||
</h2>
|
||||
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
||||
{statusText[o.status]}
|
||||
</h5>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-12 md:mb-0">
|
||||
<h2 className="text-2xl font-bold text-dark mb-4">{t('Size')}</h2>
|
||||
@@ -106,6 +95,17 @@ const DeterministicOrderDetails = ({
|
||||
</h5>
|
||||
</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="">
|
||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||
{t('Version')}
|
||||
|
||||
@@ -31,7 +31,6 @@ const mock = {
|
||||
side: 'SIDE_BUY',
|
||||
remaining: '100',
|
||||
size: '100',
|
||||
peggedOrder: null,
|
||||
party: {
|
||||
id: '456',
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
||||
import { VoteProgress } from '@vegaprotocol/proposals';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridColumn } from 'ag-grid-react';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import type {
|
||||
@@ -8,7 +9,7 @@ import type {
|
||||
VegaValueFormatterParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
||||
import type { RowClickedEvent } from 'ag-grid-community';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
@@ -63,128 +64,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
||||
title: '',
|
||||
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',
|
||||
valueFormatter: ({
|
||||
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 (
|
||||
<>
|
||||
<AgGrid
|
||||
@@ -203,7 +83,6 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
||||
filterParams: { buttons: ['reset'] },
|
||||
autoHeight: true,
|
||||
}}
|
||||
columnDefs={columnDefs}
|
||||
suppressCellFocus={true}
|
||||
onRowClicked={({ data, event }: RowClickedEvent) => {
|
||||
if (
|
||||
@@ -215,7 +94,128 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
||||
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
|
||||
open={dialog.open}
|
||||
onChange={(isOpen) => setDialog({ ...dialog, open: isOpen })}
|
||||
|
||||
+17
-36
@@ -1,4 +1,4 @@
|
||||
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { Icon } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
// https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go
|
||||
export const ErrorCodes = new Map([
|
||||
@@ -17,8 +17,6 @@ interface ChainResponseCodeProps {
|
||||
code: number;
|
||||
hideLabel?: boolean;
|
||||
error?: string;
|
||||
hideIfOk?: boolean;
|
||||
small?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,21 +28,14 @@ export const ChainResponseCode = ({
|
||||
code,
|
||||
hideLabel = false,
|
||||
error,
|
||||
hideIfOk = false,
|
||||
small = false,
|
||||
}: ChainResponseCodeProps) => {
|
||||
if (hideIfOk && code === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isSuccess = successCodes.has(code);
|
||||
const size = small ? 3 : 4;
|
||||
const successColour =
|
||||
code === 71 ? '!fill-vega-orange' : '!fill-vega-green-600';
|
||||
code === 71 ? 'fill-vega-orange' : 'fill-vega-green-600';
|
||||
const icon = isSuccess ? (
|
||||
<Icon size={size} name="tick-circle" className={`${successColour}`} />
|
||||
<Icon name="tick-circle" className={successColour} />
|
||||
) : (
|
||||
<Icon size={size} name="cross" className="!fill-vega-pink-500" />
|
||||
<Icon name="cross" className="fill-vega-pink-600" />
|
||||
);
|
||||
const label = ErrorCodes.get(code) || 'Unknown response code';
|
||||
|
||||
@@ -53,28 +44,18 @@ export const ChainResponseCode = ({
|
||||
error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error;
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
description={
|
||||
<span>
|
||||
Response code: {code} - {label}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<div className="mt-[-1px] inline-block">
|
||||
<span
|
||||
className="mr-2"
|
||||
aria-label={isSuccess ? 'Success' : 'Warning'}
|
||||
role="img"
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
{hideLabel ? null : <span>{label}</span>}
|
||||
{!hideLabel && !!displayError ? (
|
||||
<span className="ml-1 whitespace-pre">
|
||||
— {displayError}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div title={`Response code: ${code} - ${label}`} className=" inline-block">
|
||||
<span
|
||||
className="mr-2"
|
||||
aria-label={isSuccess ? 'Success' : 'Warning'}
|
||||
role="img"
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
{hideLabel ? null : <span>{label}</span>}
|
||||
{!hideLabel && !!displayError ? (
|
||||
<span className="ml-1 whitespace-pre">— {displayError}</span>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export interface TxDetailsOrderIcebergDetailsProps {
|
||||
iceberg: components['schemas']['v1IcebergOpts'];
|
||||
size: components['schemas']['v1OrderSubmission']['size'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
.iceberg .sub {
|
||||
vertical-align: bottom;
|
||||
color: #954F01;
|
||||
}
|
||||
|
||||
.iceberg .sup {
|
||||
vertical-align: top;
|
||||
color: #515E1E;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Visualises the iceberg details of an order, showing the minimum visible size,
|
||||
* the full size and the peak size.
|
||||
*/
|
||||
export const TxOrderIcebergDetails = ({
|
||||
iceberg,
|
||||
size,
|
||||
}: TxDetailsOrderIcebergDetailsProps) => {
|
||||
return (
|
||||
<div
|
||||
className="inline-block iceberg bg-vega-blue-300 border-vega-blue-350 border-[1px] text-[70%] font-mono py-[2px] pl-2 pr-3 height-[1em] leading-[1em] cursor-pointer"
|
||||
style={{ clipPath: 'polygon(10% 0%, 100% 0%, 90% 100%, 0% 100%)' }}
|
||||
>
|
||||
<Tooltip description={t('Iceberg: Minimum visible size')}>
|
||||
<span className="align-bottom text-vega-orange-650">
|
||||
{iceberg.minimumVisibleSize || '-'}
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip description={t('Iceberg: Total size')}>
|
||||
<span className="text-sm text-vega-blue-600 mx-3">{size}</span>
|
||||
</Tooltip>
|
||||
<Tooltip description={t('Iceberg: Visible peak')}>
|
||||
<span className="align-top text-vega-yellow-600">
|
||||
{iceberg.peakSize || '-'}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,113 +0,0 @@
|
||||
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'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,72 +0,0 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
+12
-34
@@ -6,32 +6,10 @@ import {
|
||||
SPECIAL_CASE_NETWORK_ID,
|
||||
} from '../../../../links/party-link/party-link';
|
||||
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 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',
|
||||
};
|
||||
import type { Transfer } from '../transfer-details';
|
||||
|
||||
interface TransferParticipantsProps {
|
||||
transfer: Transfer;
|
||||
@@ -52,22 +30,22 @@ export function TransferParticipants({
|
||||
}: TransferParticipantsProps) {
|
||||
// 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.
|
||||
const fromAcct: AccountTypes =
|
||||
const fromAcct =
|
||||
transfer.fromAccountType &&
|
||||
transfer.fromAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
||||
? transfer.fromAccountType
|
||||
: 'ACCOUNT_TYPE_GENERAL';
|
||||
const fromAccountTypeLabel: string = transfer.fromAccountType
|
||||
? AccountType[fromAcct]
|
||||
? AccountType[transfer.fromAccountType]
|
||||
: AccountType.ACCOUNT_TYPE_GENERAL;
|
||||
const fromAccountTypeLabel = transfer.fromAccountType
|
||||
? AccountTypeMapping[fromAcct]
|
||||
: 'Unknown';
|
||||
|
||||
const toAcct: AccountTypes =
|
||||
const toAcct =
|
||||
transfer.toAccountType &&
|
||||
transfer.toAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
||||
? transfer.toAccountType
|
||||
: 'ACCOUNT_TYPE_GENERAL';
|
||||
? AccountType[transfer.toAccountType]
|
||||
: AccountType.ACCOUNT_TYPE_GENERAL;
|
||||
const toAccountTypeLabel = transfer.fromAccountType
|
||||
? AccountType[toAcct]
|
||||
? AccountTypeMapping[toAcct]
|
||||
: 'Unknown';
|
||||
|
||||
return (
|
||||
|
||||
@@ -27,9 +27,9 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
|
||||
<div className={wrapperClasses}>
|
||||
<h2 className={headerClasses}>{t('Active epochs')}</h2>
|
||||
<div className="relative block rounded-lg py-6 text-center p-6">
|
||||
<div>
|
||||
<p>
|
||||
<EpochOverview id={recurring.startEpoch} />
|
||||
</div>
|
||||
</p>
|
||||
<p className="leading-10 my-2">
|
||||
<IconForEpoch
|
||||
start={recurring.startEpoch}
|
||||
@@ -37,13 +37,13 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
|
||||
current={data?.epoch.id}
|
||||
/>
|
||||
</p>
|
||||
<div>
|
||||
<p>
|
||||
{recurring.endEpoch ? (
|
||||
<EpochOverview id={recurring.endEpoch} />
|
||||
) : (
|
||||
<span>{t('Forever')}</span>
|
||||
)}
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { DispatchMetricLabels } from '@vegaprotocol/types';
|
||||
export type Metric = components['schemas']['vegaDispatchMetric'];
|
||||
export type Strategy = components['schemas']['vegaDispatchStrategy'];
|
||||
|
||||
const metricLabels: Record<Metric, string> = {
|
||||
const metricLabels = {
|
||||
DISPATCH_METRIC_UNSPECIFIED: 'Unknown metric',
|
||||
...DispatchMetricLabels,
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { TransferRepeat } from './blocks/transfer-repeat';
|
||||
import { TransferRewards } from './blocks/transfer-rewards';
|
||||
import { TransferParticipants } from './blocks/transfer-participants';
|
||||
|
||||
export type Recurring = components['schemas']['commandsv1RecurringTransfer'];
|
||||
export type Recurring = components['schemas']['v1RecurringTransfer'];
|
||||
export type Metric = components['schemas']['vegaDispatchMetric'];
|
||||
|
||||
export const wrapperClasses =
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { TxDetailsLiquidityAmendment } from './tx-liquidity-amend';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
describe('TxDetailsLiquidityAmendment', () => {
|
||||
const mockTxData = {
|
||||
hash: 'test',
|
||||
command: {
|
||||
liquidityProvisionAmendment: {
|
||||
marketId: 'BTC-USD',
|
||||
commitmentAmount: 100,
|
||||
fee: '0.01',
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockPubKey = '123';
|
||||
const mockBlockData = {
|
||||
result: {
|
||||
block: {
|
||||
header: {
|
||||
height: '123',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it('should render the component with correct data', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<TxDetailsLiquidityAmendment
|
||||
txData={mockTxData as BlockExplorerTransactionResult}
|
||||
pubKey={mockPubKey}
|
||||
blockData={mockBlockData as TendermintBlocksResponse}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(getByText('Market')).toBeInTheDocument();
|
||||
expect(getByText('BTC-USD')).toBeInTheDocument();
|
||||
expect(getByText('Commitment amount')).toBeInTheDocument();
|
||||
expect(getByText('100')).toBeInTheDocument();
|
||||
expect(getByText('Fee')).toBeInTheDocument();
|
||||
expect(getByText('1%')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display awaiting message when tx data is undefined', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<TxDetailsLiquidityAmendment
|
||||
txData={undefined}
|
||||
pubKey={mockPubKey}
|
||||
blockData={mockBlockData as TendermintBlocksResponse}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(
|
||||
getByText('Awaiting Block Explorer transaction details')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display awaiting message when liquidityProvisionAmendment is undefined', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<TxDetailsLiquidityAmendment
|
||||
txData={{ command: {} } as BlockExplorerTransactionResult}
|
||||
pubKey={mockPubKey}
|
||||
blockData={mockBlockData as TendermintBlocksResponse}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(
|
||||
getByText('Awaiting Block Explorer transaction details')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,6 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import type { components } from '../../../../types/explorer';
|
||||
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
||||
import PriceInMarket from '../../price-in-market/price-in-market';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
export type LiquidityAmendment =
|
||||
components['schemas']['v1LiquidityProvisionAmendment'];
|
||||
@@ -35,10 +34,6 @@ export const TxDetailsLiquidityAmendment = ({
|
||||
txData.command.liquidityProvisionAmendment;
|
||||
const marketId: string = amendment.marketId || '-';
|
||||
|
||||
const fee = amendment.fee
|
||||
? new BigNumber(amendment.fee).times(100).toString()
|
||||
: '-';
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
@@ -68,7 +63,7 @@ export const TxDetailsLiquidityAmendment = ({
|
||||
{amendment.fee ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Fee')}</TableCell>
|
||||
<TableCell>{fee}%</TableCell>
|
||||
<TableCell>{amendment.fee}%</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
describe('TxDetailsLiquiditySubmission', () => {
|
||||
const mockTxData = {
|
||||
hash: 'test',
|
||||
command: {
|
||||
liquidityProvisionSubmission: {
|
||||
marketId: 'BTC-USD',
|
||||
commitmentAmount: 100,
|
||||
fee: '0.01',
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockPubKey = '123';
|
||||
const mockBlockData = {
|
||||
result: {
|
||||
block: {
|
||||
header: {
|
||||
height: '123',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it('should render the component with correct data', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<TxDetailsLiquiditySubmission
|
||||
txData={mockTxData as BlockExplorerTransactionResult}
|
||||
pubKey={mockPubKey}
|
||||
blockData={mockBlockData as TendermintBlocksResponse}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(getByText('Market')).toBeInTheDocument();
|
||||
expect(getByText('BTC-USD')).toBeInTheDocument();
|
||||
expect(getByText('Commitment amount')).toBeInTheDocument();
|
||||
expect(getByText('100')).toBeInTheDocument();
|
||||
expect(getByText('Fee')).toBeInTheDocument();
|
||||
expect(getByText('1%')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display awaiting message when tx data is undefined', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<TxDetailsLiquiditySubmission
|
||||
txData={undefined}
|
||||
pubKey={mockPubKey}
|
||||
blockData={mockBlockData as TendermintBlocksResponse}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(
|
||||
getByText('Awaiting Block Explorer transaction details')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display awaiting message when liquidityProvisionSubmission is undefined', () => {
|
||||
const { getByText } = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<TxDetailsLiquiditySubmission
|
||||
txData={{ command: {} } as BlockExplorerTransactionResult}
|
||||
pubKey={mockPubKey}
|
||||
blockData={mockBlockData as TendermintBlocksResponse}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
expect(
|
||||
getByText('Awaiting Block Explorer transaction details')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,6 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import type { components } from '../../../../types/explorer';
|
||||
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
||||
import PriceInMarket from '../../price-in-market/price-in-market';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
export type LiquiditySubmission =
|
||||
components['schemas']['v1LiquidityProvisionSubmission'];
|
||||
@@ -34,10 +33,6 @@ export const TxDetailsLiquiditySubmission = ({
|
||||
txData.command.liquidityProvisionSubmission;
|
||||
const marketId: string = submission.marketId || '-';
|
||||
|
||||
const fee = submission.fee
|
||||
? new BigNumber(submission.fee).times(100).toString()
|
||||
: '-';
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
@@ -67,7 +62,7 @@ export const TxDetailsLiquiditySubmission = ({
|
||||
{submission.fee ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Fee')}</TableCell>
|
||||
<TableCell>{fee}%</TableCell>
|
||||
<TableCell>{submission.fee}%</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
|
||||
@@ -7,8 +7,6 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||
import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
|
||||
import Hash from '../../links/hash';
|
||||
import { TxOrderPeggedReferenceRow } from './order/tx-order-peg';
|
||||
import { TxOrderIcebergDetails } from './order/tx-order-iceberg';
|
||||
|
||||
interface TxDetailsOrderProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
@@ -31,10 +29,6 @@ export const TxDetailsOrder = ({
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
const marketId = txData.command.orderSubmission.marketId || '-';
|
||||
const reference = txData.command.orderSubmission.peggedOrder;
|
||||
const side = txData.command.orderSubmission.side;
|
||||
const iceberg = txData.command.orderSubmission.icebergOpts;
|
||||
const size = txData.command.orderSubmission.size;
|
||||
|
||||
let deterministicId = '';
|
||||
|
||||
@@ -69,22 +63,6 @@ export const TxDetailsOrder = ({
|
||||
<MarketLink id={marketId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{reference ? (
|
||||
<TxOrderPeggedReferenceRow
|
||||
side={side}
|
||||
offset={reference.offset}
|
||||
reference={reference.reference}
|
||||
marketId={marketId}
|
||||
/>
|
||||
) : null}
|
||||
{iceberg ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Iceberg details')}</TableCell>
|
||||
<TableCell>
|
||||
<TxOrderIcebergDetails iceberg={iceberg} size={size} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
|
||||
{deterministicId.length > 0 ? (
|
||||
|
||||
@@ -10,17 +10,13 @@ export interface FilterLabelProps {
|
||||
*/
|
||||
export function FilterLabel({ filters }: FilterLabelProps) {
|
||||
if (!filters || filters.size !== 1) {
|
||||
return (
|
||||
<span data-testid="filter-empty" className="uppercase">
|
||||
{t('Filter')}
|
||||
</span>
|
||||
);
|
||||
return <span className="uppercase">{t('Filter')}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div data-testid="filter-selected">
|
||||
<div>
|
||||
<span className="uppercase">{t('Filters')}:</span>
|
||||
<code className="bg-vega-light-150 dark:bg-vega-light-300 px-2 rounded-md capitalize dark:text-black">
|
||||
<code className="bg-vega-light-150 px-2 rounded-md capitalize">
|
||||
{Array.from(filters)[0]}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
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
|
||||
* it will support multiple selection, but until the API supports that it is
|
||||
* one or all.
|
||||
* @param filters null or Set of transaction types
|
||||
* @param filters null or Set of tranaction types
|
||||
* @param setFilters A function to update the filters prop
|
||||
* @returns
|
||||
*/
|
||||
@@ -100,15 +100,15 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
|
||||
<DropdownMenu
|
||||
modal={false}
|
||||
trigger={
|
||||
<DropdownMenuTrigger className="ml-0">
|
||||
<Button size="xs" data-testid="filter-trigger">
|
||||
<DropdownMenuTrigger className="ml-2">
|
||||
<Button size="xs">
|
||||
<FilterLabel filters={filters} />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
<DropdownMenuContent>
|
||||
{filters.size > 0 ? null : (
|
||||
{filters.size > 1 ? null : (
|
||||
<>
|
||||
<DropdownMenuCheckboxItem
|
||||
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -1,63 +0,0 @@
|
||||
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 = {
|
||||
OrderSubmission: 'Order Submission',
|
||||
'Submit Order': 'Order',
|
||||
OrderCancellation: 'Cancel order',
|
||||
OrderCancellation: 'Order Cancellation',
|
||||
OrderAmendment: 'Order Amendment',
|
||||
VoteSubmission: 'Vote Submission',
|
||||
WithdrawSubmission: 'Withdraw Submission',
|
||||
@@ -24,7 +24,6 @@ const displayString: StringMap = {
|
||||
LiquidityProvisionSubmission: 'LP order',
|
||||
'Liquidity Provision Order': 'LP order',
|
||||
LiquidityProvisionCancellation: 'LP cancel',
|
||||
'Cancel LiquidityProvision Order': 'LP cancel',
|
||||
LiquidityProvisionAmendment: 'LP update',
|
||||
'Amend LiquidityProvision Order': 'Amend LP',
|
||||
ProposalSubmission: 'Governance Proposal',
|
||||
@@ -37,34 +36,12 @@ const displayString: StringMap = {
|
||||
UndelegateSubmission: 'Undelegation',
|
||||
KeyRotateSubmission: 'Key Rotation',
|
||||
StateVariableProposal: 'State Variable',
|
||||
'State Variable Proposal': 'State Variable',
|
||||
Transfer: 'Transfer',
|
||||
CancelTransfer: 'Cancel Transfer',
|
||||
'Cancel Transfer Funds': 'Cancel Transfer',
|
||||
ValidatorHeartbeat: 'Heartbeat',
|
||||
'Validator Heartbeat': 'Heartbeat',
|
||||
'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
|
||||
* @param chainEvent
|
||||
@@ -136,8 +113,6 @@ export function getLabelForChainEvent(
|
||||
return t('Signer threshold');
|
||||
}
|
||||
return t('Multisig update');
|
||||
} else if (chainEvent.contractCall) {
|
||||
return t('Contract call');
|
||||
}
|
||||
return t('Chain Event');
|
||||
}
|
||||
@@ -166,7 +141,6 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
||||
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-250';
|
||||
|
||||
// This will get unwieldy and should probably produce a different colour of tag
|
||||
// Note that colours are currently arbitrary
|
||||
if (type === 'Chain Event' && !!command?.chainEvent) {
|
||||
type = getLabelForChainEvent(command.chainEvent);
|
||||
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
|
||||
@@ -178,9 +152,6 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
||||
type = getLabelForProposal(command.proposalSubmission);
|
||||
}
|
||||
colours = 'text-black bg-vega-yellow';
|
||||
} else if (type === 'Order' && command) {
|
||||
type = getLabelForOrderType(orderType, command);
|
||||
colours = 'text-white dark-text-white bg-vega-blue dark:bg-vega-blue';
|
||||
}
|
||||
|
||||
if (type === 'Vote on Proposal') {
|
||||
@@ -201,7 +172,7 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
|
||||
return (
|
||||
<div
|
||||
data-testid="tx-type"
|
||||
className={`text-sm rounded-md leading-tight px-2 inline-block whitespace-nowrap ${colours}`}
|
||||
className={`text-sm rounded-md leading-none px-2 py-2 inline-block ${colours}`}
|
||||
>
|
||||
{type}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
@@ -84,22 +83,21 @@ describe('Txs infinite list item', () => {
|
||||
|
||||
it('renders data correctly', () => {
|
||||
render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<TxsInfiniteListItem
|
||||
type="testType"
|
||||
submitter="testPubKey"
|
||||
hash="testTxHash"
|
||||
block="1"
|
||||
code={0}
|
||||
command={{}}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
<MemoryRouter>
|
||||
<TxsInfiniteListItem
|
||||
type="testType"
|
||||
submitter="testPubKey"
|
||||
hash="testTxHash"
|
||||
block="1"
|
||||
code={0}
|
||||
command={{}}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
expect(screen.getByTestId('tx-hash')).toHaveTextContent('testTxHash');
|
||||
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
|
||||
expect(screen.getByTestId('tx-type')).toHaveTextContent('testType');
|
||||
expect(screen.getByTestId('tx-block')).toHaveTextContent('1');
|
||||
expect(screen.getByTestId('tx-success')).toHaveTextContent('Success');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import React from 'react';
|
||||
import { TruncatedLink } from '../truncate/truncated-link';
|
||||
import { Routes } from '../../routes/route-names';
|
||||
import { TxOrderType } from './tx-order-type';
|
||||
@@ -5,25 +6,8 @@ import type { BlockExplorerTransactionResult } from '../../routes/types/block-ex
|
||||
import { toHex } from '../search/detect-search';
|
||||
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
|
||||
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 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);
|
||||
}
|
||||
const TRUNCATE_LENGTH = 10;
|
||||
|
||||
export const TxsInfiniteListItem = ({
|
||||
hash,
|
||||
@@ -33,12 +17,6 @@ export const TxsInfiniteListItem = ({
|
||||
block,
|
||||
command,
|
||||
}: Partial<BlockExplorerTransactionResult>) => {
|
||||
const { screenSize } = useScreenDimensions();
|
||||
const idTruncateLength = useMemo(
|
||||
() => getIdTruncateLength(screenSize),
|
||||
[screenSize]
|
||||
);
|
||||
|
||||
if (
|
||||
!hash ||
|
||||
!submitter ||
|
||||
@@ -51,40 +29,68 @@ export const TxsInfiniteListItem = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<tr
|
||||
<div
|
||||
data-testid="transaction-row"
|
||||
className="transaction-row text-left items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item py-[2px]"
|
||||
className="flex items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item grid grid-cols-10"
|
||||
>
|
||||
<td
|
||||
className="text-sm leading-none whitespace-nowrap font-mono"
|
||||
<div
|
||||
className="text-sm col-span-10 md:col-span-3 leading-none"
|
||||
data-testid="tx-hash"
|
||||
>
|
||||
{isNumber(code) ? (
|
||||
<ChainResponseCode code={code} hideLabel={true} hideIfOk={true} />
|
||||
) : (
|
||||
code
|
||||
)}
|
||||
<span className="md:hidden uppercase text-vega-dark-300">
|
||||
ID:
|
||||
</span>
|
||||
<TruncatedLink
|
||||
to={`/${Routes.TX}/${toHex(hash)}`}
|
||||
text={hash}
|
||||
startChars={idTruncateLength}
|
||||
endChars={0}
|
||||
startChars={TRUNCATE_LENGTH}
|
||||
endChars={TRUNCATE_LENGTH}
|
||||
/>
|
||||
</td>
|
||||
<td className="text-sm leading-none">
|
||||
</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} />
|
||||
</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">
|
||||
</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={5}
|
||||
endChars={5}
|
||||
startChars={TRUNCATE_LENGTH}
|
||||
endChars={TRUNCATE_LENGTH}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</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) ? (
|
||||
<ChainResponseCode code={code} hideLabel={true} />
|
||||
) : (
|
||||
code
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { TxsInfiniteList } from './txs-infinite-list';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, fireEvent, act } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
|
||||
return Array.from(Array(number)).map((_) => ({
|
||||
@@ -41,7 +40,7 @@ describe('Txs infinite list', () => {
|
||||
it('should display a "no items" message when no items provided', () => {
|
||||
render(
|
||||
<TxsInfiniteList
|
||||
txs={undefined as unknown as BlockExplorerTransactionResult[]}
|
||||
txs={undefined}
|
||||
areTxsLoading={false}
|
||||
hasMoreTxs={false}
|
||||
loadMoreTxs={() => null}
|
||||
@@ -49,7 +48,23 @@ describe('Txs infinite list', () => {
|
||||
/>
|
||||
);
|
||||
expect(screen.getByTestId('emptylist')).toBeInTheDocument();
|
||||
expect(screen.getByText('No transactions found')).toBeInTheDocument();
|
||||
expect(
|
||||
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', () => {
|
||||
@@ -58,22 +73,85 @@ describe('Txs infinite list', () => {
|
||||
const txs = generateTxs(7);
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider>
|
||||
<TxsInfiniteList
|
||||
txs={txs}
|
||||
areTxsLoading={false}
|
||||
hasMoreTxs={false}
|
||||
loadMoreTxs={() => null}
|
||||
error={undefined}
|
||||
/>
|
||||
</MockedProvider>
|
||||
<TxsInfiniteList
|
||||
txs={txs}
|
||||
areTxsLoading={false}
|
||||
hasMoreTxs={false}
|
||||
loadMoreTxs={() => null}
|
||||
error={undefined}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(
|
||||
screen
|
||||
.getByTestId('transactions-list')
|
||||
.querySelectorAll('.transaction-row')
|
||||
.getByTestId('infinite-scroll-wrapper')
|
||||
.querySelectorAll('.txs-infinite-list-item')
|
||||
).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,4 +1,8 @@
|
||||
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 { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
||||
import EmptyList from '../empty-list/empty-list';
|
||||
@@ -7,46 +11,82 @@ import { Loader } from '@vegaprotocol/ui-toolkit';
|
||||
interface TxsInfiniteListProps {
|
||||
hasMoreTxs: boolean;
|
||||
areTxsLoading: boolean | undefined;
|
||||
txs: BlockExplorerTransactionResult[];
|
||||
txs: BlockExplorerTransactionResult[] | undefined;
|
||||
loadMoreTxs: () => void;
|
||||
error: Error | undefined;
|
||||
className?: string;
|
||||
hasFilters?: boolean;
|
||||
}
|
||||
|
||||
interface ItemProps {
|
||||
tx: BlockExplorerTransactionResult;
|
||||
index: BlockExplorerTransactionResult;
|
||||
style: React.CSSProperties;
|
||||
isLoading: boolean;
|
||||
error: Error | undefined;
|
||||
}
|
||||
|
||||
const Item = ({ tx }: ItemProps) => {
|
||||
const { hash, submitter, type, command, block, code, index: blockIndex } = tx;
|
||||
return (
|
||||
<TxsInfiniteListItem
|
||||
type={type}
|
||||
code={code}
|
||||
command={command}
|
||||
submitter={submitter}
|
||||
hash={hash}
|
||||
block={block}
|
||||
index={blockIndex}
|
||||
/>
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const NOOP = () => {};
|
||||
|
||||
const Item = ({ index, style, isLoading, error }: ItemProps) => {
|
||||
let content;
|
||||
if (error) {
|
||||
content = t(`Cannot fetch transaction`);
|
||||
} else if (isLoading) {
|
||||
content = <Loader />;
|
||||
} else {
|
||||
const {
|
||||
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 = ({
|
||||
hasMoreTxs,
|
||||
areTxsLoading,
|
||||
txs,
|
||||
loadMoreTxs,
|
||||
error,
|
||||
className,
|
||||
hasFilters = false,
|
||||
}: TxsInfiniteListProps) => {
|
||||
if (!txs || txs.length === 0) {
|
||||
const { screenSize } = useScreenDimensions();
|
||||
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) {
|
||||
return (
|
||||
<EmptyList
|
||||
heading={t('No transactions found')}
|
||||
label={
|
||||
hasFilters ? t('Try a different filter') : t('Check back soon')
|
||||
}
|
||||
heading={t('This chain has 0 transactions')}
|
||||
label={t('Check back soon')}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
@@ -54,26 +94,57 @@ 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 (
|
||||
<div className="overflow-scroll">
|
||||
<table className={className} data-testid="transactions-list">
|
||||
<thead>
|
||||
<tr className="w-full mb-3 text-vega-dark-300 uppercase text-left">
|
||||
<th>
|
||||
<span className="hidden xl:inline">{t('Txn')} </span>
|
||||
<span>ID</span>
|
||||
</th>
|
||||
<th>{t('Type')}</th>
|
||||
<th className="text-left">{t('From')}</th>
|
||||
<th>{t('Block')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{txs.map((t) => (
|
||||
<Item key={t.hash} tx={t} />
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className={className} data-testid="transactions-list">
|
||||
<div className="lg:grid grid-cols-10 w-full mb-3 hidden text-vega-dark-300 uppercase">
|
||||
<div className="col-span-3">
|
||||
<span className="hidden xl:inline">{t('Transaction')} </span>
|
||||
<span>ID</span>
|
||||
</div>
|
||||
<div className="col-span-3">{t('Submitted By')}</div>
|
||||
<div className="col-span-2">{t('Type')}</div>
|
||||
<div className="col-span-1">{t('Block')}</div>
|
||||
<div className="col-span-1">{t('Success')}</div>
|
||||
</div>
|
||||
<div data-testid="infinite-scroll-wrapper">
|
||||
<InfiniteLoader
|
||||
isItemLoaded={isItemLoaded}
|
||||
itemCount={itemCount}
|
||||
loadMoreItems={loadMoreItems}
|
||||
ref={infiniteLoaderRef}
|
||||
>
|
||||
{({ onItemsRendered, ref }) => (
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
import { Table, TableRow } from '../table';
|
||||
import { Routes } from '../../routes/route-names';
|
||||
import { TruncatedLink } from '../truncate/truncated-link';
|
||||
import { TxOrderType } from './tx-order-type';
|
||||
import { Table, TableRow, TableCell } from '../table';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
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 { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
|
||||
import EmptyList from '../empty-list/empty-list';
|
||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||
|
||||
interface TxsPerBlockProps {
|
||||
blockHeight: string;
|
||||
txCount: number;
|
||||
}
|
||||
|
||||
const truncateLength = 5;
|
||||
|
||||
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||
const filters = `filters[block.height]=${blockHeight}`;
|
||||
const url = getTxsDataUrl({ limit: txCount.toString(), filters });
|
||||
@@ -27,23 +33,53 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||
<thead>
|
||||
<TableRow modifier="bordered" className="font-mono">
|
||||
<td>{t('Transaction')}</td>
|
||||
<td>{t('Type')}</td>
|
||||
<td>{t('From')}</td>
|
||||
<td>{t('Block')}</td>
|
||||
<td>{t('Type')}</td>
|
||||
<td>{t('Status')}</td>
|
||||
</TableRow>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.transactions.map(
|
||||
({ hash, submitter, type, command, code, block }) => {
|
||||
({ hash, submitter, type, command, code }) => {
|
||||
return (
|
||||
<TxsInfiniteListItem
|
||||
block={block}
|
||||
hash={hash}
|
||||
submitter={submitter}
|
||||
type={type}
|
||||
command={command}
|
||||
code={code}
|
||||
/>
|
||||
<TableRow
|
||||
modifier="bordered"
|
||||
key={hash}
|
||||
data-testid="transaction-row"
|
||||
>
|
||||
<TableCell
|
||||
modifier="bordered"
|
||||
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,14 +56,10 @@ export function VoteIcon({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`voteicon inline-block py-0 px-2 py rounded-md text-white whitespace-nowrap leading-tight sm align-top ${bg}`}
|
||||
className={`voteicon inline-block my-1 py-1 px-2 py rounded-md text-white leading-one sm align-top ${bg}`}
|
||||
>
|
||||
<Icon
|
||||
name={icon}
|
||||
size={3}
|
||||
className={`mr-2 p-0 mb-[-1px] fill-${fill}`}
|
||||
/>
|
||||
<span className={`text-${text}`} data-testid="label">
|
||||
<Icon name={icon} size={3} className={`mr-2 p-0 fill-${fill}`} />
|
||||
<span className={`text-base text-${text}`} data-testid="label">
|
||||
{label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,8 @@ const windowOrDefault = (key: string) => {
|
||||
return (process.env[key] as string) || '';
|
||||
};
|
||||
|
||||
const truthy = ['1', 'true'];
|
||||
|
||||
export const ENV = {
|
||||
// Data sources
|
||||
// Environment
|
||||
@@ -18,6 +20,19 @@ export const ENV = {
|
||||
governanceUrl: windowOrDefault('NX_VEGA_GOVERNANCE_URL'),
|
||||
vegaRepoUrl: windowOrDefault('NX_VEGA_REPO_URL'),
|
||||
},
|
||||
flags: {
|
||||
assets: truthy.includes(windowOrDefault('NX_EXPLORER_ASSETS')),
|
||||
genesis: truthy.includes(windowOrDefault('NX_EXPLORER_GENESIS')),
|
||||
governance: truthy.includes(windowOrDefault('NX_EXPLORER_GOVERNANCE')),
|
||||
markets: truthy.includes(windowOrDefault('NX_EXPLORER_MARKETS')),
|
||||
oracles: truthy.includes(windowOrDefault('NX_EXPLORER_ORACLES')),
|
||||
txsList: truthy.includes(windowOrDefault('NX_EXPLORER_TXS_LIST')),
|
||||
networkParameters: truthy.includes(
|
||||
windowOrDefault('NX_EXPLORER_NETWORK_PARAMETERS')
|
||||
),
|
||||
parties: truthy.includes(windowOrDefault('NX_EXPLORER_PARTIES')),
|
||||
validators: truthy.includes(windowOrDefault('NX_EXPLORER_VALIDATORS')),
|
||||
},
|
||||
addresses: {
|
||||
feedback: windowOrDefault('NX_GITHUB_FEEDBACK_URL'),
|
||||
},
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { ENV } from './env';
|
||||
|
||||
export default {
|
||||
...ENV.flags,
|
||||
};
|
||||
@@ -10,18 +10,16 @@ import isNumber from 'lodash/isNumber';
|
||||
export interface TxsStateProps {
|
||||
txsData: BlockExplorerTransactionResult[];
|
||||
hasMoreTxs: boolean;
|
||||
cursor: string;
|
||||
previousCursors: string[];
|
||||
hasPreviousPage: boolean;
|
||||
lastCursor: string;
|
||||
}
|
||||
|
||||
export interface IUseTxsData {
|
||||
limit: number;
|
||||
limit?: number;
|
||||
filters?: string;
|
||||
}
|
||||
|
||||
interface IGetTxsDataUrl {
|
||||
limit: string;
|
||||
limit?: string;
|
||||
filters?: string;
|
||||
}
|
||||
|
||||
@@ -42,89 +40,63 @@ export const getTxsDataUrl = ({ limit, filters }: IGetTxsDataUrl) => {
|
||||
};
|
||||
|
||||
export const useTxsData = ({ limit, filters }: IUseTxsData) => {
|
||||
const [
|
||||
{ txsData, hasMoreTxs, cursor, previousCursors, hasPreviousPage },
|
||||
setTxsState,
|
||||
] = useState<TxsStateProps>({
|
||||
txsData: [],
|
||||
hasMoreTxs: false,
|
||||
previousCursors: [],
|
||||
cursor: '',
|
||||
hasPreviousPage: false,
|
||||
});
|
||||
const [{ txsData, hasMoreTxs, lastCursor }, setTxsState] =
|
||||
useState<TxsStateProps>({
|
||||
txsData: [],
|
||||
hasMoreTxs: true,
|
||||
lastCursor: '',
|
||||
});
|
||||
|
||||
const url = getTxsDataUrl({ limit: limit.toString(), filters });
|
||||
const url = getTxsDataUrl({ limit: limit?.toString(), filters });
|
||||
|
||||
const {
|
||||
state: { data, error, loading },
|
||||
refetch,
|
||||
} = useFetch<BlockExplorerTransactions>(url, {}, true);
|
||||
} = useFetch<BlockExplorerTransactions>(url, {}, false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && data && isNumber(data.transactions.length)) {
|
||||
setTxsState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
txsData: data.transactions,
|
||||
hasMoreTxs: data.transactions.length >= limit,
|
||||
cursor: data?.transactions.at(-1)?.cursor || '',
|
||||
};
|
||||
});
|
||||
if (data && isNumber(data?.transactions?.length)) {
|
||||
setTxsState((prev) => ({
|
||||
txsData: [...prev.txsData, ...data.transactions],
|
||||
hasMoreTxs: data.transactions.length > 0,
|
||||
lastCursor:
|
||||
data.transactions[data.transactions.length - 1]?.cursor || '',
|
||||
}));
|
||||
}
|
||||
}, [loading, setTxsState, data, limit]);
|
||||
|
||||
const nextPage = useCallback(() => {
|
||||
const c = data?.transactions.at(0)?.cursor;
|
||||
const newPreviousCursors = c ? [...previousCursors, c] : previousCursors;
|
||||
}, [setTxsState, data]);
|
||||
|
||||
useEffect(() => {
|
||||
setTxsState((prev) => ({
|
||||
...prev,
|
||||
hasPreviousPage: true,
|
||||
previousCursors: newPreviousCursors,
|
||||
txsData: [],
|
||||
hasMoreTxs: true,
|
||||
lastCursor: '',
|
||||
}));
|
||||
}, [filters]);
|
||||
|
||||
const loadTxs = useCallback(() => {
|
||||
return refetch({
|
||||
limit,
|
||||
before: cursor,
|
||||
limit: limit,
|
||||
before: lastCursor,
|
||||
});
|
||||
}, [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]);
|
||||
}, [lastCursor, limit, refetch]);
|
||||
|
||||
const refreshTxs = useCallback(async () => {
|
||||
setTxsState(() => ({
|
||||
setTxsState((prev) => ({
|
||||
...prev,
|
||||
lastCursor: '',
|
||||
hasMoreTxs: true,
|
||||
txsData: [],
|
||||
cursor: '',
|
||||
previousCursors: [],
|
||||
hasMoreTxs: false,
|
||||
hasPreviousPage: false,
|
||||
}));
|
||||
|
||||
refetch({ limit });
|
||||
}, [setTxsState, limit, refetch, filters]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}, [setTxsState]);
|
||||
|
||||
return {
|
||||
txsData,
|
||||
data,
|
||||
loading,
|
||||
error,
|
||||
txsData,
|
||||
hasMoreTxs,
|
||||
hasPreviousPage,
|
||||
previousCursors,
|
||||
cursor,
|
||||
lastCursor,
|
||||
refreshTxs,
|
||||
nextPage,
|
||||
previousPage,
|
||||
loadTxs,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { DATA_SOURCES } from '../../../config';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||
import type { TendermintBlocksResponse } from '../tendermint-blocks-response';
|
||||
import { RouteTitle } from '../../../components/route-title';
|
||||
import { TimeAgo } from '../../../components/time-ago';
|
||||
import {
|
||||
@@ -12,7 +14,7 @@ import { TxsPerBlock } from '../../../components/txs/txs-per-block';
|
||||
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { Routes } from '../../route-names';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useBlockInfo } from '@vegaprotocol/tendermint';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { NodeLink } from '../../../components/links';
|
||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||
import EmptyList from '../../../components/empty-list/empty-list';
|
||||
@@ -22,7 +24,10 @@ const Block = () => {
|
||||
useDocumentTitle(['Blocks', `Block #${block}`]);
|
||||
const {
|
||||
state: { data: blockData, loading, error },
|
||||
} = useBlockInfo(Number(block));
|
||||
} = useFetch<TendermintBlocksResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/block?height=${block}`,
|
||||
{ cache: 'force-cache' }
|
||||
);
|
||||
|
||||
return (
|
||||
<section>
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
import { Footer } from '../components/footer/footer';
|
||||
import { Header } from '../components/header';
|
||||
import { Routes } from './route-names';
|
||||
import { useExplorerNodeNamesLazyQuery } from './validators/__generated__/NodeNames';
|
||||
|
||||
const DialogsContainer = () => {
|
||||
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
|
||||
@@ -40,7 +39,6 @@ export const Layout = () => {
|
||||
const isHome = Boolean(useMatch(Routes.HOME));
|
||||
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||
const fixedWidthClasses = 'w-full max-w-[1500px] mx-auto';
|
||||
useExplorerNodeNamesLazyQuery();
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -51,7 +49,7 @@ export const Layout = () => {
|
||||
'grid grid-rows-[auto_1fr_auto] grid-cols-1',
|
||||
'border-vega-light-200 dark:border-vega-dark-200',
|
||||
'antialiased text-black dark:text-white',
|
||||
'relative'
|
||||
'overflow-hidden relative'
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
|
||||
@@ -2,15 +2,12 @@ import { render } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import type { SourceType } from './oracle';
|
||||
import { OracleSigners } from './oracle-signers';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
function renderComponent(sourceType: SourceType) {
|
||||
return (
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<OracleSigners sourceType={sourceType} />
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
<MemoryRouter>
|
||||
<OracleSigners sourceType={sourceType} />
|
||||
</MemoryRouter>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ export const PartyBlockStake = ({
|
||||
{p?.stakingSummary.currentStakeAvailable ? (
|
||||
<KeyValueTable>
|
||||
<KeyValueTableRow noBorder={true}>
|
||||
<div>{t('Associated to key')}</div>
|
||||
<div>{t('Available stake')}</div>
|
||||
<div>
|
||||
<GovernanceAssetBalance
|
||||
price={p.stakingSummary.currentStakeAvailable}
|
||||
@@ -62,7 +62,7 @@ export const PartyBlockStake = ({
|
||||
</div>
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow noBorder={true}>
|
||||
<div>{t('Staked to validator')}</div>
|
||||
<div>{t('Active stake')}</div>
|
||||
<div>
|
||||
<GovernanceAssetBalance price={linkedStake || '0'} />
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { SubHeading } from '../../../components/sub-heading';
|
||||
import { toNonHex } from '../../../components/search/detect-search';
|
||||
@@ -14,11 +14,8 @@ import { PartyBlockStake } from './components/party-block-stake';
|
||||
import { PartyBlockAccounts } from './components/party-block-accounts';
|
||||
import { isValidPartyId } from './components/party-id-error';
|
||||
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 [filters, setFilters] = useState(new Set(AllFilterOptions));
|
||||
const { party } = useParams<{ party: string }>();
|
||||
|
||||
useDocumentTitle(['Public keys', party || '-']);
|
||||
@@ -27,24 +24,10 @@ const Party = () => {
|
||||
const partyId = toNonHex(party ? party : '');
|
||||
const { isMobile } = useScreenDimensions();
|
||||
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
|
||||
const baseFilters = `filters[tx.submitter]=${partyId}`;
|
||||
const f =
|
||||
filters && filters.size === 1
|
||||
? `${baseFilters}&filters[cmd.type]=${Array.from(filters)[0]}`
|
||||
: baseFilters;
|
||||
|
||||
const {
|
||||
hasMoreTxs,
|
||||
nextPage,
|
||||
previousPage,
|
||||
error,
|
||||
refreshTxs,
|
||||
loading,
|
||||
txsData,
|
||||
hasPreviousPage,
|
||||
} = useTxsData({
|
||||
limit: 25,
|
||||
filters: f,
|
||||
const filters = `filters[tx.submitter]=${partyId}`;
|
||||
const { hasMoreTxs, loadTxs, error, txsData, loading } = useTxsData({
|
||||
limit: 10,
|
||||
filters,
|
||||
});
|
||||
|
||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||
@@ -67,7 +50,7 @@ const Party = () => {
|
||||
text: t('Go back'),
|
||||
action: () => navigate(-1),
|
||||
className: 'py-1',
|
||||
size: 'small',
|
||||
size: 'sm',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -98,24 +81,14 @@ const Party = () => {
|
||||
</div>
|
||||
|
||||
<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 ? (
|
||||
<TxsInfiniteList
|
||||
hasMoreTxs={hasMoreTxs}
|
||||
areTxsLoading={loading}
|
||||
txs={txsData}
|
||||
loadMoreTxs={nextPage}
|
||||
loadMoreTxs={loadTxs}
|
||||
error={error}
|
||||
className="mb-28 w-full"
|
||||
className="mb-28"
|
||||
/>
|
||||
) : (
|
||||
<Splash>
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Block } from './blocks/id';
|
||||
import { Blocks } from './blocks/home';
|
||||
import { Tx } from './txs/id';
|
||||
import { TxsList } from './txs/home';
|
||||
import flags from '../config/flags';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Routes } from './route-names';
|
||||
import { NetworkParameters } from './network-parameters';
|
||||
@@ -29,7 +30,6 @@ import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
||||
import { remove0x } from '@vegaprotocol/utils';
|
||||
import { PartyAccountsByAsset } from './parties/id/accounts';
|
||||
import { Disclaimer } from './pages/disclaimer';
|
||||
import { FLAGS } from '@vegaprotocol/environment';
|
||||
|
||||
export type Navigable = {
|
||||
path: string;
|
||||
@@ -59,7 +59,7 @@ type Route = RouteItem & {
|
||||
children?: RouteItem[];
|
||||
};
|
||||
|
||||
const partiesRoutes: Route[] = FLAGS.EXPLORER_PARTIES
|
||||
const partiesRoutes: Route[] = flags.parties
|
||||
? [
|
||||
{
|
||||
path: Routes.PARTIES,
|
||||
@@ -119,7 +119,7 @@ const partiesRoutes: Route[] = FLAGS.EXPLORER_PARTIES
|
||||
]
|
||||
: [];
|
||||
|
||||
const assetsRoutes: Route[] = FLAGS.EXPLORER_ASSETS
|
||||
const assetsRoutes: Route[] = flags.assets
|
||||
? [
|
||||
{
|
||||
path: Routes.ASSETS,
|
||||
@@ -147,7 +147,7 @@ const assetsRoutes: Route[] = FLAGS.EXPLORER_ASSETS
|
||||
]
|
||||
: [];
|
||||
|
||||
const genesisRoutes: Route[] = FLAGS.EXPLORER_GENESIS
|
||||
const genesisRoutes: Route[] = flags.genesis
|
||||
? [
|
||||
{
|
||||
path: Routes.GENESIS,
|
||||
@@ -163,7 +163,7 @@ const genesisRoutes: Route[] = FLAGS.EXPLORER_GENESIS
|
||||
]
|
||||
: [];
|
||||
|
||||
const governanceRoutes: Route[] = FLAGS.EXPLORER_GOVERNANCE
|
||||
const governanceRoutes: Route[] = flags.governance
|
||||
? [
|
||||
{
|
||||
path: Routes.GOVERNANCE,
|
||||
@@ -179,7 +179,7 @@ const governanceRoutes: Route[] = FLAGS.EXPLORER_GOVERNANCE
|
||||
]
|
||||
: [];
|
||||
|
||||
const marketsRoutes: Route[] = FLAGS.EXPLORER_MARKETS
|
||||
const marketsRoutes: Route[] = flags.markets
|
||||
? [
|
||||
{
|
||||
path: Routes.MARKETS,
|
||||
@@ -207,7 +207,7 @@ const marketsRoutes: Route[] = FLAGS.EXPLORER_MARKETS
|
||||
]
|
||||
: [];
|
||||
|
||||
const networkParametersRoutes: Route[] = FLAGS.EXPLORER_NETWORK_PARAMETERS
|
||||
const networkParametersRoutes: Route[] = flags.networkParameters
|
||||
? [
|
||||
{
|
||||
path: Routes.NETWORK_PARAMETERS,
|
||||
@@ -225,7 +225,7 @@ const networkParametersRoutes: Route[] = FLAGS.EXPLORER_NETWORK_PARAMETERS
|
||||
]
|
||||
: [];
|
||||
|
||||
const validators: Route[] = FLAGS.EXPLORER_VALIDATORS
|
||||
const validators: Route[] = flags.validators
|
||||
? [
|
||||
{
|
||||
path: Routes.VALIDATORS,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { RouteTitle } from '../../../components/route-title';
|
||||
import { BlocksRefetch } from '../../../components/blocks';
|
||||
import { TxsInfiniteList } from '../../../components/txs';
|
||||
import { useTxsData } from '../../../hooks/use-txs-data';
|
||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
||||
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
|
||||
|
||||
const BE_TXS_PER_REQUEST = 25;
|
||||
const BE_TXS_PER_REQUEST = 15;
|
||||
|
||||
export const TxsList = () => {
|
||||
useDocumentTitle(['Transactions']);
|
||||
@@ -21,11 +21,6 @@ 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 = () => {
|
||||
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
||||
|
||||
@@ -34,40 +29,26 @@ export const TxsListFiltered = () => {
|
||||
? `filters[cmd.type]=${Array.from(filters)[0]}`
|
||||
: '';
|
||||
|
||||
const {
|
||||
hasMoreTxs,
|
||||
nextPage,
|
||||
previousPage,
|
||||
error,
|
||||
refreshTxs,
|
||||
loading,
|
||||
txsData,
|
||||
hasPreviousPage,
|
||||
} = useTxsData({
|
||||
limit: BE_TXS_PER_REQUEST,
|
||||
filters: f,
|
||||
});
|
||||
const { hasMoreTxs, loadTxs, error, txsData, refreshTxs, loading } =
|
||||
useTxsData({
|
||||
limit: BE_TXS_PER_REQUEST,
|
||||
filters: f,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<TxsListNavigation
|
||||
refreshTxs={refreshTxs}
|
||||
nextPage={nextPage}
|
||||
previousPage={previousPage}
|
||||
hasPreviousPage={hasPreviousPage}
|
||||
loading={loading}
|
||||
hasMoreTxs={hasMoreTxs}
|
||||
>
|
||||
<menu className="mb-2">
|
||||
<BlocksRefetch refetch={refreshTxs} />
|
||||
<TxsFilter filters={filters} setFilters={setFilters} />
|
||||
</TxsListNavigation>
|
||||
</menu>
|
||||
|
||||
<TxsInfiniteList
|
||||
hasFilters={filters.size > 0}
|
||||
hasMoreTxs={hasMoreTxs}
|
||||
areTxsLoading={loading}
|
||||
txs={txsData}
|
||||
loadMoreTxs={nextPage}
|
||||
loadMoreTxs={loadTxs}
|
||||
error={error}
|
||||
className="mb-28 w-full min-w-[400px]"
|
||||
className="mb-28"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { TxDetails } from './tx-details';
|
||||
import type {
|
||||
BlockExplorerTransactionResult,
|
||||
ValidatorHeartbeat,
|
||||
} 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
|
||||
const pubKey =
|
||||
@@ -28,11 +27,9 @@ const txData: BlockExplorerTransactionResult = {
|
||||
};
|
||||
|
||||
const renderComponent = (txData: BlockExplorerTransactionResult) => (
|
||||
<MemoryRouter>
|
||||
<MockedProvider>
|
||||
<TxDetails txData={txData} pubKey={pubKey} />
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
<Router>
|
||||
<TxDetails txData={txData} pubKey={pubKey} />
|
||||
</Router>
|
||||
);
|
||||
|
||||
describe('Transaction details', () => {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
query ExplorerNodeNames {
|
||||
nodesConnection {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
pubkey
|
||||
tmPubkey
|
||||
ethereumAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,6 @@ query ExplorerNodes {
|
||||
stakedByDelegates
|
||||
stakedTotal
|
||||
pendingStake
|
||||
rankingScore {
|
||||
performanceScore
|
||||
}
|
||||
epochData {
|
||||
total
|
||||
offline
|
||||
|
||||
@@ -1,53 +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 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>;
|
||||
@@ -6,7 +6,7 @@ const defaultOptions = {} as const;
|
||||
export type ExplorerNodesQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type ExplorerNodesQuery = { __typename?: 'Query', nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, infoUrl: string, avatarUrl?: string | null, pubkey: string, tmPubkey: string, ethereumAddress: string, location: string, status: Types.NodeStatus, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, rankingScore: { __typename?: 'RankingScore', performanceScore: string }, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null } } | null> | null } };
|
||||
export type ExplorerNodesQuery = { __typename?: 'Query', nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, infoUrl: string, avatarUrl?: string | null, pubkey: string, tmPubkey: string, ethereumAddress: string, location: string, status: Types.NodeStatus, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null } } | null> | null } };
|
||||
|
||||
|
||||
export const ExplorerNodesDocument = gql`
|
||||
@@ -27,9 +27,6 @@ export const ExplorerNodesDocument = gql`
|
||||
stakedByDelegates
|
||||
stakedTotal
|
||||
pendingStake
|
||||
rankingScore {
|
||||
performanceScore
|
||||
}
|
||||
epochData {
|
||||
total
|
||||
offline
|
||||
|
||||
@@ -91,15 +91,7 @@ export const ValidatorsPage = () => {
|
||||
const { data: tmData } = useTendermintValidators(5000);
|
||||
const { data, loading, error, refetch } = useExplorerNodesQuery();
|
||||
|
||||
const validators = compact(
|
||||
data?.nodesConnection.edges
|
||||
?.map((e) => e?.node)
|
||||
.filter(
|
||||
(node) =>
|
||||
node?.rankingScore?.performanceScore &&
|
||||
new BigNumber(node.rankingScore.performanceScore).isGreaterThan(0)
|
||||
)
|
||||
);
|
||||
const validators = compact(data?.nodesConnection.edges?.map((e) => e?.node));
|
||||
|
||||
// voting power
|
||||
const powers = compact(tmData?.result.validators).map(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@import 'ag-grid-community/styles/ag-grid.css';
|
||||
@import 'ag-grid-community/styles/ag-theme-balham.css';
|
||||
@import 'ag-grid-community/dist/styles/ag-grid.css';
|
||||
@import 'ag-grid-community/dist/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 */
|
||||
@tailwind base;
|
||||
|
||||
+72
-398
@@ -3,7 +3,7 @@
|
||||
* Do not make direct changes to the file.
|
||||
*/
|
||||
|
||||
/** OneOf type helpers */
|
||||
/** Type helpers */
|
||||
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||
type XOR<T, U> = T | U extends object
|
||||
? (Without<T, U> & U) | (Without<U, T> & T)
|
||||
@@ -41,8 +41,6 @@ export interface paths {
|
||||
};
|
||||
}
|
||||
|
||||
export type webhooks = Record<string, never>;
|
||||
|
||||
export interface components {
|
||||
schemas: {
|
||||
/**
|
||||
@@ -103,17 +101,6 @@ export interface components {
|
||||
| 'TIME_IN_FORCE_FOK'
|
||||
| 'TIME_IN_FORCE_GFA'
|
||||
| '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
|
||||
* @enum {string}
|
||||
@@ -156,36 +143,6 @@ export interface components {
|
||||
/** Type of transaction */
|
||||
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 */
|
||||
readonly commandsv1Transfer: {
|
||||
/** @description Amount to be taken from the source account. This field is an unsigned integer scaled to the asset's decimal places. */
|
||||
@@ -197,8 +154,8 @@ export interface components {
|
||||
* should be taken.
|
||||
*/
|
||||
readonly fromAccountType?: components['schemas']['vegaAccountType'];
|
||||
readonly oneOff?: components['schemas']['commandsv1OneOffTransfer'];
|
||||
readonly recurring?: components['schemas']['commandsv1RecurringTransfer'];
|
||||
readonly oneOff?: components['schemas']['v1OneOffTransfer'];
|
||||
readonly recurring?: components['schemas']['v1RecurringTransfer'];
|
||||
/** @description Reference to be attached to the transfer. */
|
||||
readonly reference?: string;
|
||||
/** @description Public key of the destination account. */
|
||||
@@ -214,19 +171,8 @@ export interface components {
|
||||
};
|
||||
readonly protobufAny: {
|
||||
readonly '@type'?: string;
|
||||
[key: string]: unknown;
|
||||
[key: string]: unknown | undefined;
|
||||
};
|
||||
/**
|
||||
* @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 */
|
||||
readonly v1AnnounceNode: {
|
||||
/** @description AvatarURL of the validator. */
|
||||
@@ -279,19 +225,18 @@ export interface components {
|
||||
readonly amendments?: readonly components['schemas']['v1OrderAmendment'][];
|
||||
/** @description List of order cancellations to be processed sequentially. */
|
||||
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. */
|
||||
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 */
|
||||
readonly v1ChainEvent: {
|
||||
/** @description Built-in asset event. */
|
||||
readonly builtin?: components['schemas']['vegaBuiltinAssetEvent'];
|
||||
/** Arbitrary contract call */
|
||||
readonly contractCall?: components['schemas']['vegaEthContractCallEvent'];
|
||||
/** @description Ethereum ERC20 event. */
|
||||
readonly erc20?: components['schemas']['vegaERC20Event'];
|
||||
/** @description Ethereum ERC20 multisig event. */
|
||||
@@ -356,19 +301,6 @@ export interface components {
|
||||
/** Transaction corresponding to the hash */
|
||||
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: {
|
||||
/** Commit hash from which the data node was built */
|
||||
readonly commitHash?: string;
|
||||
@@ -393,7 +325,7 @@ export interface components {
|
||||
*/
|
||||
readonly blockHeight?: string;
|
||||
/** @description Command to request cancelling a recurring transfer. */
|
||||
readonly cancelTransfer?: components['schemas']['commandsv1CancelTransfer'];
|
||||
readonly cancelTransfer?: components['schemas']['v1CancelTransfer'];
|
||||
/**
|
||||
* @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
|
||||
@@ -449,10 +381,6 @@ export interface components {
|
||||
readonly protocolUpgradeProposal?: components['schemas']['v1ProtocolUpgradeProposal'];
|
||||
/** @description Command used by a validator to submit a floating point value. */
|
||||
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. */
|
||||
readonly transfer?: components['schemas']['commandsv1Transfer'];
|
||||
/** @description Command to remove tokens delegated to a validator. */
|
||||
@@ -520,9 +448,9 @@ export interface components {
|
||||
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. */
|
||||
readonly fee?: string;
|
||||
/** @description Market ID for the order. */
|
||||
/** @description Market ID for the order, required field. */
|
||||
readonly marketId?: string;
|
||||
/** @description Reference to be added to every order created out of this liquidity provision submission. */
|
||||
/** @description Reference to be added to every order created out of this liquidityProvisionSubmission. */
|
||||
readonly reference?: string;
|
||||
/** @description Set of liquidity sell orders to meet the liquidity provision obligation. */
|
||||
readonly sells?: readonly components['schemas']['vegaLiquidityOrder'][];
|
||||
@@ -602,6 +530,15 @@ export interface components {
|
||||
| 'TYPE_STAKE_TOTAL_SUPPLY'
|
||||
| 'TYPE_SIGNER_THRESHOLD_SET'
|
||||
| '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 */
|
||||
readonly v1OracleDataSubmission: {
|
||||
/**
|
||||
@@ -659,12 +596,10 @@ export interface components {
|
||||
readonly v1OrderSubmission: {
|
||||
/**
|
||||
* Format: int64
|
||||
* @description Timestamp in Unix nanoseconds for when the order will expire,
|
||||
* @description Timestamp for when the order will expire, in nanoseconds,
|
||||
* required field only for `Order.TimeInForce`.TIME_IN_FORCE_GTT`.
|
||||
*/
|
||||
readonly expiresAt?: string;
|
||||
/** @description Parameters used to specify an iceberg order. */
|
||||
readonly icebergOpts?: components['schemas']['v1IcebergOpts'];
|
||||
/** @description Market ID for the order, required field. */
|
||||
readonly marketId?: string;
|
||||
/** @description Used to specify the details for a pegged order. */
|
||||
@@ -764,6 +699,23 @@ export interface components {
|
||||
readonly v1PubKey: {
|
||||
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
|
||||
* network.
|
||||
@@ -780,7 +732,7 @@ export interface components {
|
||||
readonly version?: number;
|
||||
};
|
||||
readonly v1Signer: {
|
||||
/** @description In case of an open oracle - Ethereum address will be submitted. */
|
||||
/** In case of an open oracle - Ethereum address will be submitted */
|
||||
readonly ethAddress?: components['schemas']['v1ETHAddress'];
|
||||
/**
|
||||
* @description List of authorized public keys that signed the data for this
|
||||
@@ -794,55 +746,6 @@ export interface components {
|
||||
/** @description State value proposal details. */
|
||||
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: {
|
||||
/**
|
||||
* @description Optional, if not specified = ALL.
|
||||
@@ -919,7 +822,6 @@ export interface components {
|
||||
* - 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_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
|
||||
* @enum {string}
|
||||
*/
|
||||
@@ -940,8 +842,7 @@ export interface components {
|
||||
| 'ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES'
|
||||
| 'ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES'
|
||||
| 'ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES'
|
||||
| 'ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS'
|
||||
| 'ACCOUNT_TYPE_HOLDING';
|
||||
| 'ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS';
|
||||
/** Vega representation of an external asset */
|
||||
readonly vegaAssetDetails: {
|
||||
/** @description Vega built-in asset. */
|
||||
@@ -997,14 +898,6 @@ export interface components {
|
||||
/** @description Vega network internal asset ID. */
|
||||
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.
|
||||
* DataSourceDefinition can be external or internal, with whatever number of data sources are defined
|
||||
@@ -1019,7 +912,6 @@ export interface components {
|
||||
* It contains one of any of the defined `SourceType` variants.
|
||||
*/
|
||||
readonly vegaDataSourceDefinitionExternal: {
|
||||
readonly ethCall?: components['schemas']['vegaEthCallSpec'];
|
||||
readonly oracle?: components['schemas']['vegaDataSourceSpecConfiguration'];
|
||||
};
|
||||
/**
|
||||
@@ -1255,64 +1147,6 @@ export interface components {
|
||||
/** @description Address into which the bridge will release the funds. */
|
||||
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 */
|
||||
readonly vegaFutureProduct: {
|
||||
/** @description Binding between the data source spec and the settlement data. */
|
||||
@@ -1326,14 +1160,6 @@ export interface components {
|
||||
/** @description Asset ID for the product's settlement asset. */
|
||||
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 */
|
||||
readonly vegaInstrumentConfiguration: {
|
||||
/** @description Instrument code, human-readable shortcode used to describe the instrument. */
|
||||
@@ -1342,8 +1168,6 @@ export interface components {
|
||||
readonly future?: components['schemas']['vegaFutureProduct'];
|
||||
/** @description Instrument name. */
|
||||
readonly name?: string;
|
||||
/** @description Spot. */
|
||||
readonly spot?: components['schemas']['vegaSpotProduct'];
|
||||
};
|
||||
readonly vegaKeyValueBundle: {
|
||||
readonly key?: string;
|
||||
@@ -1434,14 +1258,14 @@ export interface components {
|
||||
/** @description Configuration of the new market. */
|
||||
readonly changes?: components['schemas']['vegaNewMarketConfiguration'];
|
||||
};
|
||||
/** Configuration for a new futures market on Vega */
|
||||
/** Configuration for a new market on Vega */
|
||||
readonly vegaNewMarketConfiguration: {
|
||||
/**
|
||||
* Format: uint64
|
||||
* @description Decimal places used for the new futures market, sets the smallest price increment on the book.
|
||||
* @description Decimal places used for the new market, sets the smallest price increment on the book.
|
||||
*/
|
||||
readonly decimalPlaces?: string;
|
||||
/** @description New futures market instrument configuration. */
|
||||
/** @description New market instrument configuration. */
|
||||
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. */
|
||||
readonly linearSlippageFactor?: string;
|
||||
@@ -1454,11 +1278,11 @@ export interface components {
|
||||
* price levels over which automated liquidity provision orders will be deployed.
|
||||
*/
|
||||
readonly lpPriceRange?: string;
|
||||
/** @description Optional new futures market metadata, tags. */
|
||||
/** @description Optional new market metadata, tags. */
|
||||
readonly metadata?: readonly string[];
|
||||
/**
|
||||
* Format: int64
|
||||
* @description Decimal places for order sizes, sets what size the smallest order / position on the futures market can be.
|
||||
* @description Decimal places for order sizes, sets what size the smallest order / position on the market can be.
|
||||
*/
|
||||
readonly positionDecimalPlaces?: string;
|
||||
/** @description Price monitoring parameters. */
|
||||
@@ -1467,80 +1291,6 @@ export interface components {
|
||||
readonly quadraticSlippageFactor?: string;
|
||||
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
|
||||
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
|
||||
@@ -1619,8 +1369,6 @@ export interface components {
|
||||
};
|
||||
/** Terms for a governance proposal on Vega */
|
||||
readonly vegaProposalTerms: {
|
||||
/** @description Cancel a governance transfer. */
|
||||
readonly cancelTransfer?: components['schemas']['vegaCancelTransfer'];
|
||||
/**
|
||||
* Format: int64
|
||||
* @description Timestamp as Unix time in seconds when voting closes for this proposal,
|
||||
@@ -1640,39 +1388,20 @@ export interface components {
|
||||
* and can be used to gauge community sentiment.
|
||||
*/
|
||||
readonly newFreeform?: components['schemas']['vegaNewFreeform'];
|
||||
/** @description Proposal change for creating new futures market on Vega. */
|
||||
/** @description Proposal change for creating new market on Vega. */
|
||||
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. */
|
||||
readonly updateAsset?: components['schemas']['vegaUpdateAsset'];
|
||||
/** @description Proposal change for modifying an existing futures market on Vega. */
|
||||
/** @description Proposal change for modifying an existing market on Vega. */
|
||||
readonly updateMarket?: components['schemas']['vegaUpdateMarket'];
|
||||
/** @description Proposal change for updating Vega network parameters. */
|
||||
readonly updateNetworkParameter?: components['schemas']['vegaUpdateNetworkParameter'];
|
||||
/** @description Proposal change for modifying an existing spot market on Vega. */
|
||||
readonly updateSpotMarket?: components['schemas']['vegaUpdateSpotMarket'];
|
||||
/**
|
||||
* Format: int64
|
||||
* @description Validation timestamp as Unix time in seconds.
|
||||
*/
|
||||
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 value?: string;
|
||||
};
|
||||
@@ -1713,15 +1442,6 @@ export interface components {
|
||||
*/
|
||||
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: {
|
||||
/** @description Amount deposited as an unsigned base 10 integer scaled to the asset's decimal places. */
|
||||
readonly amount?: string;
|
||||
@@ -1787,13 +1507,6 @@ export interface components {
|
||||
readonly scalarVal?: components['schemas']['vegaScalarValue'];
|
||||
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 */
|
||||
readonly vegaTargetStakeParameters: {
|
||||
/**
|
||||
@@ -1834,14 +1547,14 @@ export interface components {
|
||||
};
|
||||
/** Update an existing market on Vega */
|
||||
readonly vegaUpdateMarket: {
|
||||
/** @description Updated configuration of the futures market. */
|
||||
/** @description Updated configuration of the market. */
|
||||
readonly changes?: components['schemas']['vegaUpdateMarketConfiguration'];
|
||||
/** @description Market ID the update is for. */
|
||||
readonly marketId?: string;
|
||||
};
|
||||
/** Configuration to update a futures market on Vega */
|
||||
/** Configuration to update a market on Vega */
|
||||
readonly vegaUpdateMarketConfiguration: {
|
||||
/** @description Updated futures market instrument configuration. */
|
||||
/** @description Updated market instrument configuration. */
|
||||
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. */
|
||||
readonly linearSlippageFactor?: string;
|
||||
@@ -1854,7 +1567,7 @@ export interface components {
|
||||
* price levels over which automated liquidity provision orders will be deployed.
|
||||
*/
|
||||
readonly lpPriceRange?: string;
|
||||
/** @description Optional futures market metadata, tags. */
|
||||
/** @description Optional market metadata, tags. */
|
||||
readonly metadata?: readonly string[];
|
||||
/** @description Price monitoring parameters. */
|
||||
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
|
||||
@@ -1868,26 +1581,6 @@ export interface components {
|
||||
/** @description The network parameter to update. */
|
||||
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 value?: readonly string[];
|
||||
};
|
||||
@@ -1916,12 +1609,12 @@ export interface components {
|
||||
export type external = Record<string, never>;
|
||||
|
||||
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: {
|
||||
/**
|
||||
* 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: {
|
||||
/** @description A successful response. */
|
||||
200: {
|
||||
@@ -1937,38 +1630,19 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* List transactions
|
||||
* @description List transactions from the Vega blockchain
|
||||
*/
|
||||
BlockExplorer_ListTransactions: {
|
||||
parameters: {
|
||||
query?: {
|
||||
/**
|
||||
* @description Number of transactions to be returned from the blockchain.
|
||||
* This is deprecated, use first and last instead.
|
||||
*/
|
||||
/**
|
||||
* List transactions
|
||||
* @description List transactions from the Vega blockchain
|
||||
*/
|
||||
parameters?: {
|
||||
/** @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;
|
||||
/** @description Optional cursor to paginate the request. */
|
||||
before?: string;
|
||||
/** @description Optional cursor to paginate the request. */
|
||||
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: {
|
||||
@@ -1986,14 +1660,14 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Get transaction
|
||||
* @description Get a transaction from the Vega blockchain
|
||||
*/
|
||||
BlockExplorer_GetTransaction: {
|
||||
/**
|
||||
* Get transaction
|
||||
* @description Get a transaction from the Vega blockchain
|
||||
*/
|
||||
parameters: {
|
||||
path: {
|
||||
/** @description Hash of the transaction */
|
||||
/** @description Hash of the transaction */
|
||||
readonly path: {
|
||||
hash: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { join } = require('path');
|
||||
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
||||
const { createGlobPatternsForDependencies } = require('@nrwl/next/tailwind');
|
||||
const theme = require('../../libs/tailwindcss-config/src/theme');
|
||||
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"types": ["node"]
|
||||
},
|
||||
"files": [
|
||||
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
|
||||
"../../node_modules/@nx/react/typings/image.d.ts"
|
||||
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
||||
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"**/*.spec.ts",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"jest.config.ts"
|
||||
],
|
||||
"files": [
|
||||
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
|
||||
"../../node_modules/@nx/react/typings/image.d.ts"
|
||||
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
||||
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
const { composePlugins, withNx } = require('@nx/webpack');
|
||||
const { withReact } = require('@nx/react');
|
||||
const SentryPlugin = require('@sentry/webpack-plugin');
|
||||
|
||||
module.exports = composePlugins(withNx(), withReact(), (config) => {
|
||||
module.exports = (config, context) => {
|
||||
const additionalPlugins = process.env.SENTRY_AUTH_TOKEN
|
||||
? [
|
||||
new SentryPlugin({
|
||||
@@ -15,6 +13,5 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
|
||||
return {
|
||||
...config,
|
||||
plugins: [...additionalPlugins, ...config.plugins],
|
||||
ignoreWarnings: [/Failed to parse source map/],
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"name": "governance-e2e",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/governance-e2e/src",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"e2e": {
|
||||
"executor": "@nx/cypress:cypress",
|
||||
"executor": "@nrwl/cypress:cypress",
|
||||
"options": {
|
||||
"cypressConfig": "apps/governance-e2e/cypress.config.js",
|
||||
"devServerTarget": "governance:serve"
|
||||
@@ -17,14 +16,14 @@
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/linter:eslint",
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["apps/governance-e2e/**/*.{js,ts}"]
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "nx:run-commands",
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"outputs": [],
|
||||
"options": {
|
||||
"command": "yarn tsc --project ./apps/governance-e2e/"
|
||||
|
||||
@@ -28,17 +28,18 @@ import type { testFreeformProposal } from '../../support/common-interfaces';
|
||||
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
|
||||
|
||||
const proposalVoteProgressForPercentage =
|
||||
'vote-progress-indicator-percentage-for';
|
||||
'[data-testid="vote-progress-indicator-percentage-for"]';
|
||||
const proposalVoteProgressAgainstPercentage =
|
||||
'vote-progress-indicator-percentage-against';
|
||||
const proposalVoteProgressForTokens = 'vote-progress-indicator-tokens-for';
|
||||
'[data-testid="vote-progress-indicator-percentage-against"]';
|
||||
const proposalVoteProgressForTokens =
|
||||
'[data-testid="vote-progress-indicator-tokens-for"]';
|
||||
const proposalVoteProgressAgainstTokens =
|
||||
'vote-progress-indicator-tokens-against';
|
||||
const changeVoteButton = 'change-vote-button';
|
||||
const proposalDetailsTitle = 'proposal-title';
|
||||
const proposalDetailsDescription = 'proposal-description';
|
||||
const openProposals = 'open-proposals';
|
||||
const viewProposalButton = 'view-proposal-btn';
|
||||
'[data-testid="vote-progress-indicator-tokens-against"]';
|
||||
const changeVoteButton = '[data-testid="change-vote-button"]';
|
||||
const proposalDetailsTitle = '[data-testid="proposal-title"]';
|
||||
const proposalDetailsDescription = '[data-testid="proposal-description"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const proposalDescriptionToggle = 'proposal-description-toggle';
|
||||
const voteBreakdownToggle = 'vote-breakdown-toggle';
|
||||
const proposalTermsToggle = 'proposal-json-toggle';
|
||||
@@ -71,18 +72,18 @@ describe(
|
||||
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
cy.get(openProposals).within(() => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() => {
|
||||
cy.getByTestId(viewProposalButton).should('be.visible').click();
|
||||
cy.get(viewProposalButton).should('be.visible').click();
|
||||
});
|
||||
});
|
||||
cy.getByTestId(proposalDetailsTitle).should(
|
||||
cy.get(proposalDetailsTitle).should(
|
||||
'contain.text',
|
||||
rawProposal.rationale.title
|
||||
);
|
||||
cy.getByTestId(proposalDescriptionToggle).click();
|
||||
cy.getByTestId('proposal-description-toggle');
|
||||
cy.getByTestId(proposalDetailsDescription)
|
||||
cy.get(proposalDetailsDescription)
|
||||
.find('p')
|
||||
.should('have.text', proposalDescription);
|
||||
});
|
||||
@@ -116,7 +117,7 @@ describe(
|
||||
});
|
||||
navigateTo(navigation.proposals);
|
||||
getProposalFromTitle(proposalTitle).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
cy.wrap(
|
||||
formatDateWithLocalTimezone(new Date(proposalTimeStamp * 1000))
|
||||
@@ -138,7 +139,7 @@ describe(
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should(
|
||||
@@ -165,7 +166,7 @@ describe(
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
// 3001-VOTE-080
|
||||
@@ -182,16 +183,14 @@ describe(
|
||||
.contains(votedDate)
|
||||
.should('be.visible');
|
||||
});
|
||||
cy.getByTestId(proposalVoteProgressForPercentage) // 3001-VOTE-072
|
||||
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(proposalVoteProgressAgainstPercentage)
|
||||
cy.get(proposalVoteProgressAgainstPercentage)
|
||||
.contains('0.00%')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(proposalVoteProgressForTokens)
|
||||
.contains('1.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(proposalVoteProgressAgainstTokens)
|
||||
cy.get(proposalVoteProgressForTokens).contains('1.00').and('be.visible');
|
||||
cy.get(proposalVoteProgressAgainstTokens)
|
||||
.contains('0.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
@@ -212,15 +211,15 @@ describe(
|
||||
getProposalInformationFromTable('Number of voting parties')
|
||||
.should('have.text', '1')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(changeVoteButton).should('be.visible').click();
|
||||
cy.get(changeVoteButton).should('be.visible').click();
|
||||
voteForProposal('for');
|
||||
// 3001-VOTE-064
|
||||
getProposalInformationFromTable('Tokens for proposal')
|
||||
.should('have.text', (1).toFixed(2))
|
||||
.and('be.visible');
|
||||
cy.getByTestId(changeVoteButton).should('be.visible').click();
|
||||
cy.get(changeVoteButton).should('be.visible').click();
|
||||
voteForProposal('against');
|
||||
cy.getByTestId(proposalVoteProgressAgainstPercentage)
|
||||
cy.get(proposalVoteProgressAgainstPercentage)
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
getProposalInformationFromTable('Tokens against proposal')
|
||||
@@ -237,15 +236,13 @@ describe(
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
voteForProposal('for');
|
||||
// 3001-VOTE-079
|
||||
cy.contains('You voted: For').should('be.visible');
|
||||
cy.getByTestId(proposalVoteProgressForTokens)
|
||||
.contains('1')
|
||||
.and('be.visible');
|
||||
cy.get(proposalVoteProgressForTokens).contains('1').and('be.visible');
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
getProposalInformationFromTable('Total Supply')
|
||||
.invoke('text')
|
||||
@@ -261,22 +258,22 @@ describe(
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
cy.getByTestId(proposalVoteProgressForPercentage)
|
||||
cy.get(proposalVoteProgressForPercentage)
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(proposalVoteProgressAgainstPercentage)
|
||||
cy.get(proposalVoteProgressAgainstPercentage)
|
||||
.contains('0.00%')
|
||||
.and('be.visible');
|
||||
// 3001-VOTE-065
|
||||
cy.getByTestId(changeVoteButton).should('be.visible').click();
|
||||
cy.get(changeVoteButton).should('be.visible').click();
|
||||
voteForProposal('for');
|
||||
cy.getByTestId(proposalVoteProgressForTokens)
|
||||
cy.get(proposalVoteProgressForTokens)
|
||||
.contains(tokensRequiredToAchieveResult)
|
||||
.and('be.visible');
|
||||
cy.getByTestId(proposalVoteProgressAgainstTokens)
|
||||
cy.get(proposalVoteProgressAgainstTokens)
|
||||
.contains('0.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
@@ -313,7 +310,7 @@ describe(
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
voteForProposal('for');
|
||||
cy.contains('You voted: For').should('be.visible');
|
||||
@@ -322,16 +319,13 @@ describe(
|
||||
stakingPageAssociateTokens('2');
|
||||
navigateTo(navigation.proposals);
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
cy.getByTestId('you-voted').should('not.exist');
|
||||
voteForProposal('against');
|
||||
cy.contains('You voted: Against').should('be.visible');
|
||||
switchVegaWalletPubKey();
|
||||
cy.getByTestId(proposalVoteProgressForTokens).should(
|
||||
'contain.text',
|
||||
'1.00'
|
||||
);
|
||||
cy.get(proposalVoteProgressForTokens).should('contain.text', '1.00');
|
||||
// Checking vote status for different public keys is displayed correctly
|
||||
cy.contains('You voted: For').should('be.visible');
|
||||
});
|
||||
|
||||
@@ -19,13 +19,13 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
|
||||
|
||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||
const closedProposals = 'closed-proposals';
|
||||
const proposalStatus = 'proposal-status';
|
||||
const viewProposalButton = 'view-proposal-btn';
|
||||
const votesTable = 'votes-table';
|
||||
const openProposals = 'open-proposals';
|
||||
const closedProposals = '[data-testid="closed-proposals"]';
|
||||
const proposalStatus = '[data-testid="proposal-status"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const votesTable = '[data-testid="votes-table"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const proposalVoteProgressForPercentage =
|
||||
'vote-progress-indicator-percentage-for';
|
||||
'[data-testid="vote-progress-indicator-percentage-for"]';
|
||||
const proposalTimeout = { timeout: 8000 };
|
||||
|
||||
context(
|
||||
@@ -55,18 +55,18 @@ context(
|
||||
cy.createMarket();
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.getByTestId(closedProposals).within(() => {
|
||||
cy.get(closedProposals).within(() => {
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => {
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.getByTestId(viewProposalButton).click();
|
||||
cy.get(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('proposal-type').should('have.text', 'New market');
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.getByTestId(votesTable).within(() => {
|
||||
cy.get(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
});
|
||||
@@ -81,27 +81,27 @@ context(
|
||||
navigateTo(navigation.proposals);
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => cy.getByTestId(viewProposalButton).click());
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
});
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Open');
|
||||
cy.get(proposalStatus).should('have.text', 'Open');
|
||||
voteForProposal('for');
|
||||
cy.getByTestId(proposalStatus, proposalTimeout)
|
||||
cy.get(proposalStatus, proposalTimeout)
|
||||
.should('have.text', 'Passed')
|
||||
.then(() => {
|
||||
cy.getByTestId(proposalStatus, proposalTimeout).should(
|
||||
cy.get(proposalStatus, proposalTimeout).should(
|
||||
'have.text',
|
||||
'Enacted'
|
||||
);
|
||||
});
|
||||
cy.getByTestId(votesTable).within(() => {
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
});
|
||||
cy.getByTestId(proposalVoteProgressForPercentage)
|
||||
cy.get(proposalVoteProgressForPercentage)
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
});
|
||||
@@ -115,18 +115,15 @@ context(
|
||||
navigateTo(navigation.proposals);
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.getByTestId(openProposals, { timeout: 6000 }).within(() => {
|
||||
cy.get(openProposals, { timeout: 6000 }).within(() => {
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => cy.getByTestId(viewProposalButton).click());
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
});
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Open');
|
||||
cy.get(proposalStatus).should('have.text', 'Open');
|
||||
voteForProposal('for');
|
||||
cy.getByTestId(proposalStatus, proposalTimeout).should(
|
||||
'have.text',
|
||||
'Enacted'
|
||||
);
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Enacted');
|
||||
});
|
||||
|
||||
// 3001-VOTE-048 3001-VOTE-049 3001-VOTE-050
|
||||
@@ -137,17 +134,14 @@ context(
|
||||
navigateTo(navigation.proposals);
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => cy.getByTestId(viewProposalButton).click());
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
});
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Open');
|
||||
cy.getByTestId(proposalStatus, proposalTimeout).should(
|
||||
'have.text',
|
||||
'Declined'
|
||||
);
|
||||
cy.get(proposalStatus).should('have.text', 'Open');
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Declined');
|
||||
getProposalInformationFromTable('Rejection reason')
|
||||
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
|
||||
.and('be.visible');
|
||||
|
||||
@@ -36,19 +36,20 @@ import {
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import type { testFreeformProposal } from '../../support/common-interfaces';
|
||||
|
||||
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators';
|
||||
const vegaWalletAssociatedBalance = 'associated-amount';
|
||||
const vegaWalletNameElement = 'wallet-name';
|
||||
const vegaWallet = 'vega-wallet';
|
||||
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
|
||||
const newProposalSubmitButton = 'proposal-submit';
|
||||
const viewProposalButton = 'view-proposal-btn';
|
||||
const rawProposalData = 'proposal-data';
|
||||
const voteButtons = 'vote-buttons';
|
||||
const vegaWalletStakedBalances =
|
||||
'[data-testid="vega-wallet-balance-staked-validators"]';
|
||||
const vegaWalletAssociatedBalance = '[data-testid="associated-amount"]';
|
||||
const vegaWalletNameElement = '[data-testid="wallet-name"]';
|
||||
const vegaWallet = '[data-testid="vega-wallet"]';
|
||||
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const rawProposalData = '[data-testid="proposal-data"]';
|
||||
const voteButtons = '[data-testid="vote-buttons"]';
|
||||
const rejectProposalsLink = '[href="/proposals/rejected"]';
|
||||
const feedbackError = 'Error';
|
||||
const noOpenProposals = 'no-open-proposals';
|
||||
const noClosedProposals = 'no-closed-proposals';
|
||||
const feedbackError = '[data-testid="Error"]';
|
||||
const noOpenProposals = '[data-testid="no-open-proposals"]';
|
||||
const noClosedProposals = '[data-testid="no-closed-proposals"]';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
const proposalTimeout = { timeout: 14000 };
|
||||
@@ -92,10 +93,10 @@ context(
|
||||
// Test can only pass if run before other proposal tests.
|
||||
it.skip('Should be able to see that no proposals exist', function () {
|
||||
// 3001-VOTE-003
|
||||
cy.getByTestId(noOpenProposals)
|
||||
cy.get(noOpenProposals)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'There are no open or yet to enact proposals');
|
||||
cy.getByTestId(noClosedProposals)
|
||||
cy.get(noClosedProposals)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'There are no enacted or rejected proposals');
|
||||
});
|
||||
@@ -125,10 +126,7 @@ context(
|
||||
stakingValidatorPageAddStake('2');
|
||||
closeStakingDialog();
|
||||
|
||||
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
|
||||
'contain',
|
||||
'2'
|
||||
);
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
|
||||
createRawProposal();
|
||||
});
|
||||
|
||||
@@ -170,7 +168,7 @@ context(
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() => {
|
||||
cy.contains('Rejected').should('be.visible');
|
||||
cy.contains('Close time too late').should('be.visible');
|
||||
cy.getByTestId(viewProposalButton).click();
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('proposal-status').should('have.text', 'Rejected');
|
||||
@@ -187,14 +185,14 @@ context(
|
||||
const errorMsg =
|
||||
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)';
|
||||
vegaWalletTeardown();
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||
'0.00',
|
||||
txTimeout
|
||||
);
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.getByTestId(feedbackError).should('have.text', errorMsg);
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
@@ -207,7 +205,7 @@ context(
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.getByTestId(feedbackError).should('have.text', errorMsg);
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
@@ -223,17 +221,17 @@ context(
|
||||
createTenDigitUnixTimeStampForSpecifiedDays(8);
|
||||
freeformProposal.unexpected = `i shouldn't be here`;
|
||||
const proposalPayload = JSON.stringify(freeformProposal);
|
||||
cy.getByTestId(rawProposalData).type(proposalPayload, {
|
||||
cy.get(rawProposalData).type(proposalPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.getByTestId(feedbackError).should('have.text', errorMsg);
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
closeDialog();
|
||||
cy.getByTestId(rawProposalData)
|
||||
cy.get(rawProposalData)
|
||||
.invoke('val')
|
||||
.should('contain', "i shouldn't be here");
|
||||
});
|
||||
@@ -251,15 +249,15 @@ context(
|
||||
rawProposal.terms.unexpectedField = `i shouldn't be here`;
|
||||
const proposalPayload = JSON.stringify(rawProposal);
|
||||
|
||||
cy.getByTestId(rawProposalData).type(proposalPayload, {
|
||||
cy.get(rawProposalData).type(proposalPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.getByTestId(feedbackError).should('have.text', errorMsg);
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
@@ -267,10 +265,10 @@ context(
|
||||
// 3006-PASC-006 3006-PASC-007 3008-PFRO-018 3008-PFRO-019 3003-PMAN-006 3003-PMAN-007
|
||||
it('Unable to submit proposal without valid json', function () {
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
cy.getByTestId(newProposalSubmitButton).click();
|
||||
cy.get(newProposalSubmitButton).click();
|
||||
cy.getByTestId('input-error-text').should('have.text', 'Required');
|
||||
cy.getByTestId(rawProposalData).type('Not a valid json string');
|
||||
cy.getByTestId(newProposalSubmitButton).click();
|
||||
cy.get(rawProposalData).type('Not a valid json string');
|
||||
cy.get(newProposalSubmitButton).click();
|
||||
cy.getByTestId('input-error-text').should(
|
||||
'have.text',
|
||||
'Must be valid JSON'
|
||||
@@ -285,22 +283,22 @@ context(
|
||||
submitUniqueRawProposal({ proposalTitle: proposalTitle });
|
||||
ethereumWalletConnect();
|
||||
stakingPageDisassociateTokens('0.0001');
|
||||
cy.getByTestId(vegaWallet)
|
||||
cy.get(vegaWallet)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'0.9999'
|
||||
);
|
||||
});
|
||||
navigateTo(navigation.proposals);
|
||||
getProposalFromTitle(proposalTitle).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
cy.contains('Vote breakdown').should('be.visible', {
|
||||
timeout: 10000,
|
||||
});
|
||||
cy.getByTestId(voteButtons).should('not.exist');
|
||||
cy.get(voteButtons).should('not.exist');
|
||||
cy.getByTestId('min-proposal-requirements').should(
|
||||
'have.text',
|
||||
`You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal`
|
||||
@@ -313,20 +311,20 @@ context(
|
||||
cy.get('[data-testid="disconnect"]').click();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
// 3001-VOTE-075
|
||||
// 3001-VOTE-076
|
||||
cy.getByTestId(connectToVegaWalletButton)
|
||||
cy.get(connectToVegaWalletButton)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Vega wallet');
|
||||
cy.getByTestId(connectToVegaWalletButton).click();
|
||||
.and('have.text', 'Connect Vega wallet')
|
||||
.click();
|
||||
cy.getByTestId('connector-jsonRpc').click();
|
||||
cy.getByTestId(vegaWalletNameElement).should('be.visible');
|
||||
cy.getByTestId(connectToVegaWalletButton).should('not.exist');
|
||||
cy.get(vegaWalletNameElement).should('be.visible');
|
||||
cy.get(connectToVegaWalletButton).should('not.exist');
|
||||
// 3001-VOTE-100
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||
'1.00',
|
||||
txTimeout
|
||||
);
|
||||
|
||||
@@ -31,25 +31,27 @@ import {
|
||||
} from '../../support/wallet-functions';
|
||||
|
||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||
const openProposals = 'open-proposals';
|
||||
const proposalType = 'proposal-type';
|
||||
const proposalDetails = 'proposal-details';
|
||||
const newProposalSubmitButton = 'proposal-submit';
|
||||
const proposalVoteDeadline = 'proposal-vote-deadline';
|
||||
const proposalParameterSelect = 'proposal-parameter-select';
|
||||
const proposalMarketSelect = 'proposal-market-select';
|
||||
const newProposalTitle = 'proposal-title';
|
||||
const newProposalDescription = 'proposal-description';
|
||||
const newProposalTerms = 'proposal-terms';
|
||||
const newProposedParameterValue = 'selected-proposal-param-new-value';
|
||||
const minVoteDeadline = 'min-vote';
|
||||
const maxVoteDeadline = 'max-vote';
|
||||
const minValidationDeadline = 'min-validation';
|
||||
const minEnactDeadline = 'min-enactment';
|
||||
const maxEnactDeadline = 'max-enactment';
|
||||
const inputError = 'input-error-text';
|
||||
const enactmentDeadlineError = 'enactment-before-voting-deadline';
|
||||
const proposalDownloadBtn = 'proposal-download-json';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const proposalType = '[data-testid="proposal-type"]';
|
||||
const proposalDetails = '[data-testid="proposal-details"]';
|
||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
|
||||
const proposalParameterSelect = '[data-testid="proposal-parameter-select"]';
|
||||
const proposalMarketSelect = '[data-testid="proposal-market-select"]';
|
||||
const newProposalTitle = '[data-testid="proposal-title"]';
|
||||
const newProposalDescription = '[data-testid="proposal-description"]';
|
||||
const newProposalTerms = '[data-testid="proposal-terms"]';
|
||||
const newProposedParameterValue =
|
||||
'[data-testid="selected-proposal-param-new-value"]';
|
||||
const minVoteDeadline = '[data-testid="min-vote"]';
|
||||
const maxVoteDeadline = '[data-testid="max-vote"]';
|
||||
const minValidationDeadline = '[data-testid="min-validation"]';
|
||||
const minEnactDeadline = '[data-testid="min-enactment"]';
|
||||
const maxEnactDeadline = '[data-testid="max-enactment"]';
|
||||
const inputError = '[data-testid="input-error-text"]';
|
||||
const enactmentDeadlineError =
|
||||
'[data-testid="enactment-before-voting-deadline"]';
|
||||
const proposalDownloadBtn = '[data-testid="proposal-download-json"]';
|
||||
const feedbackError = '[data-testid="Error"]';
|
||||
const viewProposalBtn = 'view-proposal-btn';
|
||||
const liquidityVoteStatus = 'liquidity-votes-status';
|
||||
@@ -86,20 +88,18 @@ context(
|
||||
it('Unable to submit network parameter with missing/invalid fields', function () {
|
||||
navigateTo(navigation.proposals);
|
||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||
cy.getByTestId(proposalDownloadBtn).click();
|
||||
cy.getByTestId(inputError).should('have.length', 3);
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
cy.get(proposalDownloadBtn).click();
|
||||
cy.get(inputError).should('have.length', 3);
|
||||
cy.get(newProposalTitle).type(
|
||||
'Invalid update network parameter proposal'
|
||||
);
|
||||
cy.getByTestId(newProposalDescription).type(
|
||||
'E2E invalid test for proposals'
|
||||
);
|
||||
cy.getByTestId(proposalParameterSelect).select(
|
||||
cy.get(newProposalDescription).type('E2E invalid test for proposals');
|
||||
cy.get(proposalParameterSelect).select(
|
||||
'spam_protection_proposal_min_tokens'
|
||||
);
|
||||
cy.getByTestId(newProposedParameterValue).type('0');
|
||||
cy.getByTestId(proposalVoteDeadline).clear().type('0');
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(newProposedParameterValue).type('0');
|
||||
cy.get(proposalVoteDeadline).clear().type('0');
|
||||
cy.get(proposalDownloadBtn)
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.wrap(
|
||||
@@ -109,7 +109,7 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.getByTestId(newProposalSubmitButton).click();
|
||||
cy.get(newProposalSubmitButton).click();
|
||||
validateDialogContentMsg('PROPOSAL_ERROR_CLOSE_TIME_TOO_SOON');
|
||||
});
|
||||
|
||||
@@ -117,33 +117,29 @@ context(
|
||||
it('Able to download and submit network param proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||
// 3007-PNEC-006
|
||||
cy.getByTestId(newProposalTitle)
|
||||
cy.get(newProposalTitle)
|
||||
.siblings()
|
||||
.should('contain.text', '(100 characters or less)');
|
||||
// 3007-PNEC-004 3007-PNEC-005
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
'Test update network parameter proposal'
|
||||
);
|
||||
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
||||
// 3007-PNEC-009
|
||||
cy.getByTestId(newProposalDescription)
|
||||
cy.get(newProposalDescription)
|
||||
.siblings()
|
||||
.should('contain.text', '(20,000 characters or less)');
|
||||
// 3007-PNEC-007 3007-PNEC-008
|
||||
cy.getByTestId(newProposalDescription).type(
|
||||
'E2E test for downloading proposals'
|
||||
);
|
||||
cy.get(newProposalDescription).type('E2E test for downloading proposals');
|
||||
// 3007-PNEC-010
|
||||
cy.getByTestId(proposalParameterSelect).select(
|
||||
cy.get(proposalParameterSelect).select(
|
||||
'governance_proposal_asset_minClose'
|
||||
);
|
||||
// 3007-PNEC-011
|
||||
cy.getByTestId(newProposedParameterValue).type('10s');
|
||||
cy.get(newProposedParameterValue).type('10s');
|
||||
// 3007-PNEC-012
|
||||
cy.getByTestId(proposalVoteDeadline).clear().type('2');
|
||||
cy.get(proposalVoteDeadline).clear().type('2');
|
||||
// 3007-PNEC-013 3007-PNEC-014
|
||||
cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
|
||||
// 3007-PNEC-015
|
||||
cy.getByTestId(maxEnactDeadline).click();
|
||||
cy.get(maxEnactDeadline).click();
|
||||
// 3007-PNEC-016
|
||||
cy.getByTestId('enactment-date').invoke('text').should('not.be.empty');
|
||||
// 3007-PNEC-017
|
||||
@@ -152,7 +148,7 @@ context(
|
||||
).should('be.visible');
|
||||
// 3007-PNE-018
|
||||
cy.log('Download updated proposal file');
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -182,21 +178,19 @@ context(
|
||||
it('Unable to submit network parameter proposal with vote deadline above enactment deadline', function () {
|
||||
navigateTo(navigation.proposals);
|
||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
'Test update network parameter proposal'
|
||||
);
|
||||
cy.getByTestId(newProposalDescription).type('invalid deadlines');
|
||||
cy.getByTestId(proposalParameterSelect).select(
|
||||
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
||||
cy.get(newProposalDescription).type('invalid deadlines');
|
||||
cy.get(proposalParameterSelect).select(
|
||||
'spam_protection_proposal_min_tokens'
|
||||
);
|
||||
cy.getByTestId(newProposedParameterValue).type('0');
|
||||
cy.getByTestId(proposalVoteDeadline).clear().type('0');
|
||||
cy.getByTestId(maxVoteDeadline).click();
|
||||
cy.getByTestId(enactmentDeadlineError).should(
|
||||
cy.get(newProposedParameterValue).type('0');
|
||||
cy.get(proposalVoteDeadline).clear().type('0');
|
||||
cy.get(maxVoteDeadline).click();
|
||||
cy.get(enactmentDeadlineError).should(
|
||||
'have.text',
|
||||
'The proposal will fail if enactment is earlier than the voting deadline'
|
||||
);
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -207,7 +201,7 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.getByTestId(newProposalSubmitButton).click();
|
||||
cy.get(newProposalSubmitButton).click();
|
||||
validateFeedBackMsg(
|
||||
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
|
||||
);
|
||||
@@ -220,16 +214,16 @@ context(
|
||||
function () {
|
||||
const proposalTitle = 'Test new market proposal';
|
||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||
cy.getByTestId(newProposalTitle).type('Test new market proposal');
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(newProposalTitle).type('Test new market proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
||||
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||
cy.getByTestId(newProposalTerms).type(newMarketPayload, {
|
||||
cy.get(newProposalTerms).type(newMarketPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -265,19 +259,19 @@ context(
|
||||
'Invalid params: the transaction does not use a valid Vega command: unknown field "invalid" in vega.NewMarket';
|
||||
|
||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||
cy.getByTestId(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.getByTestId(inputError).should('have.length', 3);
|
||||
cy.getByTestId(newProposalTitle).type('Test new market proposal');
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.get(inputError).should('have.length', 3);
|
||||
cy.get(newProposalTitle).type('Test new market proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
||||
newMarketProposal.invalid = 'I am an invalid field';
|
||||
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||
cy.getByTestId(newProposalTerms).type(newMarketPayload, {
|
||||
cy.get(newProposalTerms).type(newMarketPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -288,30 +282,28 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
validateFeedBackMsg(errorMsg);
|
||||
});
|
||||
|
||||
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
|
||||
// 3002-PROP-022
|
||||
it.skip('Unable to submit update market proposal without equity-like share in the market', function () {
|
||||
it('Unable to submit update market proposal without equity-like share in the market', function () {
|
||||
switchVegaWalletPubKey();
|
||||
stakingPageAssociateTokens('1');
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
'Test update market proposal - rejected'
|
||||
);
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.getByTestId(proposalMarketSelect).select('Test market 1');
|
||||
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(proposalMarketSelect).select('Test market 1');
|
||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -322,7 +314,7 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||
validateDialogContentMsg('PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE');
|
||||
closeDialog();
|
||||
@@ -340,19 +332,17 @@ context(
|
||||
vegaWalletPublicKey
|
||||
);
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
'Test update market proposal - rejected'
|
||||
);
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.getByTestId(proposalMarketSelect).select('Test market 1');
|
||||
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(proposalMarketSelect).select('Test market 1');
|
||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -363,7 +353,7 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
validateFeedBackMsg(
|
||||
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)'
|
||||
@@ -378,9 +368,9 @@ context(
|
||||
vegaWalletPublicKey
|
||||
);
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.getByTestId(newProposalTitle).type('Test update market proposal');
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.getByTestId(proposalMarketSelect).select('Test market 1');
|
||||
cy.get(newProposalTitle).type('Test update market proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(proposalMarketSelect).select('Test market 1');
|
||||
cy.get('[data-testid="update-market-details"]').within(() => {
|
||||
cy.get('dd').eq(0).should('have.text', 'Test market 1');
|
||||
cy.get('dd').eq(1).should('have.text', 'TEST.24h');
|
||||
@@ -395,12 +385,12 @@ context(
|
||||
});
|
||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -447,19 +437,19 @@ context(
|
||||
it('Able to submit new asset proposal using min deadlines', function () {
|
||||
const proposalTitle = 'Test new asset proposal';
|
||||
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||
cy.getByTestId(newProposalTitle).type(proposalTitle);
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(newProposalTitle).type(proposalTitle);
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/new-asset').then((newAssetProposal) => {
|
||||
const newAssetPayload = JSON.stringify(newAssetProposal);
|
||||
cy.getByTestId(newProposalTerms).type(newAssetPayload, {
|
||||
cy.get(newProposalTerms).type(newAssetPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.getByTestId(minVoteDeadline).click();
|
||||
cy.getByTestId(minValidationDeadline).click();
|
||||
cy.getByTestId(minEnactDeadline).click();
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(minVoteDeadline).click();
|
||||
cy.get(minValidationDeadline).click();
|
||||
cy.get(minEnactDeadline).click();
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -470,9 +460,9 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); // 3005-PASN-003
|
||||
});
|
||||
});
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
closeDialog();
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
// cannot submit a proposal with ERC20 address already in use
|
||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||
validateDialogContentMsg('PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE');
|
||||
@@ -493,8 +483,8 @@ context(
|
||||
|
||||
it('Unable to submit new asset proposal with missing/invalid fields', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||
cy.getByTestId(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.getByTestId(inputError).should('have.length', 3);
|
||||
cy.get(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.get(inputError).should('have.length', 3);
|
||||
});
|
||||
|
||||
it('Able to submit update asset proposal using min deadline', function () {
|
||||
@@ -503,9 +493,9 @@ context(
|
||||
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||
enterUpdateAssetProposalDetails();
|
||||
cy.getByTestId(minVoteDeadline).click();
|
||||
cy.getByTestId(minEnactDeadline).click();
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(minVoteDeadline).click();
|
||||
cy.get(minEnactDeadline).click();
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -517,16 +507,13 @@ context(
|
||||
});
|
||||
});
|
||||
navigateTo(navigation.proposals);
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
cy.getByTestId(proposalType)
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.get(proposalType)
|
||||
.contains('Update asset')
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => {
|
||||
cy.getByTestId(proposalDetails).should(
|
||||
'contain.text',
|
||||
assetId.slice(0, 6)
|
||||
); // 3001-VOTE-029
|
||||
cy.get(proposalDetails).should('contain.text', assetId.slice(0, 6)); // 3001-VOTE-029
|
||||
cy.getByTestId(viewProposalBtn).click();
|
||||
});
|
||||
});
|
||||
@@ -546,9 +533,9 @@ context(
|
||||
it('Able to submit update asset proposal using max deadline', function () {
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||
enterUpdateAssetProposalDetails();
|
||||
cy.getByTestId(maxVoteDeadline).click();
|
||||
cy.getByTestId(maxEnactDeadline).click();
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(maxVoteDeadline).click();
|
||||
cy.get(maxEnactDeadline).click();
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -563,36 +550,36 @@ context(
|
||||
|
||||
it('Unable to submit edit asset proposal with missing/invalid fields', function () {
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||
cy.getByTestId(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.getByTestId(inputError).should('have.length', 3);
|
||||
cy.get(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.get(inputError).should('have.length', 3);
|
||||
});
|
||||
|
||||
it('Able to download and submit freeform proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
// 3008-PFRO-006
|
||||
cy.getByTestId(newProposalTitle)
|
||||
cy.get(newProposalTitle)
|
||||
.siblings()
|
||||
.should('contain.text', '(100 characters or less)'); // 3008-PFRO-007
|
||||
// 3008-PFRO-005
|
||||
cy.getByTestId(newProposalTitle).type('Test freeform proposal form');
|
||||
cy.get(newProposalTitle).type('Test freeform proposal form');
|
||||
// 3008-PFRO-009
|
||||
cy.getByTestId(newProposalDescription)
|
||||
cy.get(newProposalDescription)
|
||||
.siblings()
|
||||
.should('contain.text', '(20,000 characters or less)'); // 3008-PFRO-010
|
||||
// 3008-PFRO-008 3002-PROP-012 3002-PROP-016
|
||||
cy.getByTestId(newProposalDescription).type(
|
||||
cy.get(newProposalDescription).type(
|
||||
'E2E test for downloading freeform proposal'
|
||||
);
|
||||
// 3008-PFRO-012
|
||||
cy.getByTestId(minVoteDeadline).should('exist'); // 3002-PROP-008
|
||||
cy.getByTestId(maxVoteDeadline).should('exist');
|
||||
cy.get(minVoteDeadline).should('exist'); // 3002-PROP-008
|
||||
cy.get(maxVoteDeadline).should('exist');
|
||||
// 3008-PFRO-011
|
||||
cy.getByTestId(proposalVoteDeadline).clear().type('2');
|
||||
cy.get(proposalVoteDeadline).clear().type('2');
|
||||
// 3008-PFRO-013 3008-PFRO-014
|
||||
cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
|
||||
// 3008-PFRO-015
|
||||
cy.log('Download updated proposal file');
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -626,11 +613,11 @@ context(
|
||||
}
|
||||
|
||||
function enterUpdateAssetProposalDetails() {
|
||||
cy.getByTestId(newProposalTitle).type('Test update asset proposal');
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(newProposalTitle).type('Test update asset proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/update-asset').then((newAssetProposal) => {
|
||||
const newAssetPayload = JSON.stringify(newAssetProposal);
|
||||
cy.getByTestId(newProposalTerms).type(newAssetPayload, {
|
||||
cy.get(newProposalTerms).type(newAssetPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
|
||||
@@ -24,12 +24,12 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
|
||||
|
||||
const proposalListItem = 'proposals-list-item';
|
||||
const openProposals = 'open-proposals';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const voteStatus = 'vote-status';
|
||||
const proposalType = 'proposal-type';
|
||||
const proposalStatus = 'proposal-status';
|
||||
const proposalClosingDate = 'vote-details';
|
||||
const viewProposalButton = 'view-proposal-btn';
|
||||
const proposalClosingDate = '[data-testid="vote-details"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const voteBreakDownToggle = 'vote-breakdown-toggle';
|
||||
|
||||
describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
@@ -62,13 +62,13 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
}
|
||||
|
||||
navigateTo(navigation.proposals);
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
cy.getByTestId(proposalClosingDate)
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.get(proposalClosingDate)
|
||||
.first()
|
||||
.invoke('text')
|
||||
.should('match', /days|minutes/);
|
||||
cy.getByTestId(proposalClosingDate).should('contain.text', 'months');
|
||||
cy.getByTestId(proposalClosingDate).last().should('contain.text', 'year');
|
||||
cy.get(proposalClosingDate).should('contain.text', 'months');
|
||||
cy.get(proposalClosingDate).last().should('contain.text', 'year');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -77,7 +77,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
const proposalTitle = generateFreeFormProposalTitle();
|
||||
|
||||
submitUniqueRawProposal({ proposalTitle: proposalTitle });
|
||||
cy.get('[data-testid="proposal-filter-toggle"]').click();
|
||||
cy.get('[data-testid="set-proposals-filter-visible"]').click();
|
||||
cy.get('[data-testid="filter-input"]').type(proposerId);
|
||||
// cy.get(`#${proposalId}`).should('contain', proposalId);
|
||||
cy.contains(proposalTitle).should('be.visible');
|
||||
@@ -106,7 +106,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
createRawProposal(this.minProposerBalance);
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() => {
|
||||
cy.getByTestId(viewProposalButton).should('be.visible');
|
||||
cy.get(viewProposalButton).should('be.visible');
|
||||
cy.getByTestId(proposalType).should('have.text', 'Freeform');
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Open');
|
||||
});
|
||||
@@ -124,13 +124,13 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
'have.text',
|
||||
'Participation not reached'
|
||||
);
|
||||
cy.getByTestId(viewProposalButton).click();
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
voteForProposal('for');
|
||||
navigateTo(navigation.proposals);
|
||||
getProposalFromTitle(proposalTitle).within(() => {
|
||||
cy.getByTestId(voteStatus).should('have.text', 'Set to pass');
|
||||
cy.getByTestId(viewProposalButton).click();
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
cy.getByTestId(voteBreakDownToggle).click();
|
||||
getProposalInformationFromTable('Token participation met')
|
||||
|
||||
@@ -17,7 +17,8 @@ import {
|
||||
} from '../../support/wallet-functions';
|
||||
|
||||
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
|
||||
const vegaWalletUnstakedBalance = 'vega-wallet-balance-unstaked';
|
||||
const vegaWalletUnstakedBalance =
|
||||
'[data-testid="vega-wallet-balance-unstaked"]';
|
||||
const rewardsTable = 'epoch-total-rewards-table';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const rewardsTimeOut = { timeout: 60000 };
|
||||
@@ -39,7 +40,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
|
||||
cy.associateTokensToVegaWallet('6000');
|
||||
navigateTo(navigation.validators);
|
||||
cy.VegaWalletTopUpRewardsPool();
|
||||
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'6,000.0',
|
||||
txTimeout
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
verifyStakedBalance,
|
||||
verifyEthWalletTotalAssociatedBalance,
|
||||
verifyEthWalletAssociatedBalance,
|
||||
waitForSpinner,
|
||||
navigateTo,
|
||||
navigation,
|
||||
turnTelemetryOff,
|
||||
@@ -57,7 +58,6 @@ context(
|
||||
before('visit staking tab and connect vega wallet', function () {
|
||||
cy.visit('/');
|
||||
ethereumWalletConnect();
|
||||
cy.connectVegaWallet();
|
||||
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||
});
|
||||
|
||||
@@ -67,9 +67,10 @@ context(
|
||||
function () {
|
||||
cy.clearLocalStorage();
|
||||
turnTelemetryOff();
|
||||
// Go to homepage to allow wallet teardown without epoch timer refreshing page
|
||||
navigateTo(navigation.home);
|
||||
vegaWalletTeardown();
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.connectVegaWallet();
|
||||
ethereumWalletConnect();
|
||||
navigateTo(navigation.validators);
|
||||
}
|
||||
);
|
||||
@@ -127,7 +128,6 @@ context(
|
||||
cy.getByTestId('staked-by-user-tooltip')
|
||||
.first()
|
||||
.should('have.text', 'Staked by me: 2.00');
|
||||
waitForBeginningOfEpoch();
|
||||
cy.getByTestId('total-pending-stake').first().realHover();
|
||||
cy.getByTestId('pending-user-stake-tooltip')
|
||||
.first()
|
||||
@@ -144,7 +144,7 @@ context(
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
cy.getByTestId(viewStakedByMeToggle).click();
|
||||
cy.getByTestId(userStakeBtn, epochTimeout).should('have.length', 2);
|
||||
cy.getByTestId(userStakeBtn).should('have.length', 2);
|
||||
});
|
||||
|
||||
it('Able to stake against a validator - using vega from vesting contract', function () {
|
||||
@@ -398,7 +398,6 @@ context(
|
||||
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||
cy.reload();
|
||||
ethereumWalletConnect();
|
||||
cy.connectVegaWallet();
|
||||
stakingPageAssociateTokens('3');
|
||||
verifyUnstakedBalance(3.0);
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
@@ -504,6 +503,11 @@ context(
|
||||
);
|
||||
});
|
||||
|
||||
afterEach('Teardown Wallet', function () {
|
||||
navigateTo(navigation.home);
|
||||
vegaWalletTeardown();
|
||||
});
|
||||
|
||||
function verifyNextEpochValue(amount: number) {
|
||||
cy.getByTestId('stake-next-epoch', epochTimeout)
|
||||
.contains(amount, epochTimeout)
|
||||
|
||||
@@ -21,24 +21,25 @@ import {
|
||||
vegaWalletTeardown,
|
||||
} from '../../support/wallet-functions';
|
||||
|
||||
const ethWalletContainer = 'ethereum-wallet';
|
||||
const vegaWalletAssociatedBalance = 'currency-value';
|
||||
const vegaWalletUnstakedBalance = 'vega-wallet-balance-unstaked';
|
||||
const ethWalletAssociateButton = '[data-testid="associate-btn"]:visible';
|
||||
const associateWalletRadioButton = 'associate-radio-wallet';
|
||||
const tokenAmountInputBox = 'token-amount-input';
|
||||
const tokenSubmitButton = 'token-input-submit-button';
|
||||
const ethWalletDissociateButton = '[href="/token/disassociate"]:visible';
|
||||
const vestingContractSection = 'vega-in-vesting-contract';
|
||||
const vegaInWalletSection = 'vega-in-wallet';
|
||||
const connectedVegaKey = 'connected-vega-key';
|
||||
const associatedKey = 'associated-key';
|
||||
const associatedAmount = 'associated-amount';
|
||||
const associateCompleteText = 'transaction-complete-body';
|
||||
const disassociationWarning = 'disassociation-warning';
|
||||
const vegaWallet = 'aside [data-testid="vega-wallet"]';
|
||||
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
|
||||
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
|
||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
||||
const vegaWalletUnstakedBalance =
|
||||
'[data-testid="vega-wallet-balance-unstaked"]';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
|
||||
const ethWalletAssociateButton = '[data-testid="associate-btn"]:visible';
|
||||
const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
|
||||
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
|
||||
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
||||
const ethWalletDissociateButton = '[href="/token/disassociate"]:visible';
|
||||
const vestingContractSection = '[data-testid="vega-in-vesting-contract"]';
|
||||
const vegaInWalletSection = '[data-testid="vega-in-wallet"]';
|
||||
const connectedVegaKey = '[data-testid="connected-vega-key"]';
|
||||
const associatedKey = '[data-testid="associated-key"]';
|
||||
const associatedAmount = '[data-testid="associated-amount"]';
|
||||
const associateCompleteText = '[data-testid="transaction-complete-body"]';
|
||||
const disassociationWarning = '[data-testid="disassociation-warning"]';
|
||||
const vegaWallet = 'aside [data-testid="vega-wallet"]';
|
||||
|
||||
context(
|
||||
'Token association flow - with eth and vega wallets connected',
|
||||
@@ -88,15 +89,12 @@ context(
|
||||
verifyEthWalletAssociatedBalance('2.0');
|
||||
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
});
|
||||
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -129,7 +127,7 @@ context(
|
||||
verifyEthWalletAssociatedBalance('1,001.00');
|
||||
verifyEthWalletTotalAssociatedBalance('7,001.00');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'1,001.00'
|
||||
);
|
||||
@@ -139,20 +137,14 @@ context(
|
||||
it('Able to disassociate a partial amount of tokens currently associated', function () {
|
||||
stakingPageAssociateTokens('2');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||
});
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||
stakingPageDisassociateTokens('1');
|
||||
verifyEthWalletAssociatedBalance('1.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
1.0
|
||||
);
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -162,24 +154,21 @@ context(
|
||||
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
|
||||
stakingPageAssociateTokens('2');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||
});
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||
cy.get(ethWalletDissociateButton).click();
|
||||
cy.getByTestId(disassociationWarning).should('contain', warningText);
|
||||
cy.get(disassociationWarning).should('contain', warningText);
|
||||
stakingPageDisassociateAllTokens();
|
||||
cy.getByTestId(ethWalletContainer)
|
||||
cy.get(ethWalletContainer)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
|
||||
'not.exist'
|
||||
);
|
||||
});
|
||||
cy.getByTestId(ethWalletContainer)
|
||||
cy.get(ethWalletContainer)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
|
||||
@@ -187,10 +176,7 @@ context(
|
||||
);
|
||||
});
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
0.0
|
||||
);
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -212,15 +198,9 @@ context(
|
||||
verifyEthWalletAssociatedBalance('2.0');
|
||||
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||
});
|
||||
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
||||
stakingPageDisassociateTokens('1', {
|
||||
type: 'contract',
|
||||
skipConfirmation: true,
|
||||
@@ -241,54 +221,45 @@ context(
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||
stakingPageAssociateTokens('37', { type: 'contract' });
|
||||
cy.getByTestId(vestingContractSection)
|
||||
cy.get(vestingContractSection)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByTestId(associatedKey).should(
|
||||
cy.get(associatedKey).should(
|
||||
'contain',
|
||||
Cypress.env('vegaWalletPublicKeyShort')
|
||||
);
|
||||
cy.getByTestId(associatedAmount, txTimeout).should('contain', 37);
|
||||
cy.get(associatedAmount, txTimeout).should('contain', 37);
|
||||
});
|
||||
cy.getByTestId(vegaInWalletSection)
|
||||
cy.get(vegaInWalletSection)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByTestId(associatedKey).should(
|
||||
cy.get(associatedKey).should(
|
||||
'contain',
|
||||
Cypress.env('vegaWalletPublicKeyShort')
|
||||
);
|
||||
cy.getByTestId(associatedAmount, txTimeout).should('contain', 21);
|
||||
cy.get(associatedAmount, txTimeout).should('contain', 21);
|
||||
});
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
58
|
||||
);
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58);
|
||||
});
|
||||
stakingPageDisassociateTokens('6', { type: 'contract' });
|
||||
cy.getByTestId(vestingContractSection)
|
||||
cy.get(vestingContractSection)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByTestId(associatedAmount, txTimeout).should('contain', 31);
|
||||
cy.get(associatedAmount, txTimeout).should('contain', 31);
|
||||
});
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
52
|
||||
);
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52);
|
||||
});
|
||||
navigateTo(navigation.validators);
|
||||
stakingPageDisassociateTokens('9', { type: 'wallet' });
|
||||
cy.getByTestId(vegaInWalletSection)
|
||||
cy.get(vegaInWalletSection)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByTestId(associatedAmount, txTimeout).should('contain', 12);
|
||||
cy.get(associatedAmount, txTimeout).should('contain', 12);
|
||||
});
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
43
|
||||
);
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -297,10 +268,10 @@ context(
|
||||
// 1004-ASSO-010
|
||||
// No warning visible as described in AC, but the button is disabled
|
||||
cy.get(ethWalletAssociateButton).click();
|
||||
cy.getByTestId(associateWalletRadioButton, { timeout: 30000 }).click();
|
||||
cy.getByTestId(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
|
||||
cy.getByTestId(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
|
||||
cy.getByTestId(tokenSubmitButton, txTimeout).should('be.disabled');
|
||||
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
|
||||
cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
|
||||
cy.get(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
|
||||
cy.get(tokenSubmitButton, txTimeout).should('be.disabled');
|
||||
});
|
||||
|
||||
// 1004-ASSO-004
|
||||
@@ -325,25 +296,22 @@ context(
|
||||
|
||||
it('Able to associate tokens to different public key of connected vega wallet', function () {
|
||||
cy.get(ethWalletAssociateButton).click();
|
||||
cy.getByTestId(associateWalletRadioButton).click();
|
||||
cy.getByTestId(connectedVegaKey).should(
|
||||
cy.get(associateWalletRadioButton).click();
|
||||
cy.get(connectedVegaKey).should(
|
||||
'have.text',
|
||||
Cypress.env('vegaWalletPublicKey')
|
||||
);
|
||||
|
||||
switchVegaWalletPubKey();
|
||||
cy.getByTestId(connectedVegaKey).should(
|
||||
cy.get(connectedVegaKey).should(
|
||||
'have.text',
|
||||
Cypress.env('vegaWalletPublicKey2')
|
||||
);
|
||||
stakingPageAssociateTokens('2');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||
});
|
||||
cy.getByTestId(associateCompleteText).should(
|
||||
cy.get(associateCompleteText).should(
|
||||
'have.text',
|
||||
`Vega key ${Cypress.env(
|
||||
'vegaWalletPublicKey2Short'
|
||||
|
||||
@@ -116,6 +116,7 @@ context(
|
||||
cy.getByTestId(amountInput).click().type('120');
|
||||
cy.getByTestId(submitWithdrawalButton).click();
|
||||
});
|
||||
// assert withdrawal request
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'Funds unlocked')
|
||||
|
||||
@@ -11,7 +11,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
cy.getByTestId('home-proposals').within(() => {
|
||||
cy.get('[href="/proposals"]')
|
||||
.should('exist')
|
||||
.and('have.text', 'See all proposals');
|
||||
.and('have.text', 'Browse, vote, and propose');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -161,7 +161,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
cy.getByTestId('menu-drawer').should('be.visible');
|
||||
});
|
||||
|
||||
it('should have link for proposal page', function () {
|
||||
it.skip('should have link for proposal page', function () {
|
||||
cy.getByTestId('menu-drawer').within(() => {
|
||||
cy.get('[href="/proposals"]')
|
||||
.should('exist')
|
||||
|
||||
@@ -10,13 +10,9 @@ import {
|
||||
} from '../../support/governance.functions';
|
||||
import { mockNetworkUpgradeProposal } from '../../support/proposal.functions';
|
||||
|
||||
const proposalDocsLink = 'proposal-docs-link';
|
||||
const proposalDocumentationLink = 'proposal-documentation-link';
|
||||
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
|
||||
const proposalDocumentationLink = '[data-testid="proposal-documentation-link"]';
|
||||
const governanceDocsUrl = 'https://vega.xyz/governance';
|
||||
const networkUpgradeProposalListItem = 'protocol-upgrade-proposals-list-item';
|
||||
const closedProposals = 'closed-proposals';
|
||||
const closedProposalToggle = 'closed-proposals-toggle-networkUpgrades';
|
||||
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||
|
||||
context(
|
||||
'Governance Page - verify elements on page',
|
||||
@@ -45,7 +41,7 @@ context(
|
||||
|
||||
it('should be able to see a working link for - find out more about Vega governance', function () {
|
||||
// 3001-VOTE-001
|
||||
cy.getByTestId(proposalDocumentationLink)
|
||||
cy.get(proposalDocumentationLink)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Find out more about Vega governance')
|
||||
.and('have.attr', 'href')
|
||||
@@ -68,7 +64,7 @@ context(
|
||||
// 3007-PNE-021
|
||||
it('should have documentation links for network parameter proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/network-parameter-proposal');
|
||||
@@ -77,7 +73,7 @@ context(
|
||||
// 3003-PMAN-002 3003-PMAN-005
|
||||
it('should have documentation links for new market proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/new-market-proposal');
|
||||
@@ -86,7 +82,7 @@ context(
|
||||
// 3004-PMAC-005
|
||||
it('should have documentation links for update market proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/update-market-proposal');
|
||||
@@ -95,7 +91,7 @@ context(
|
||||
// 3005-PASN-002 005-PASN-005
|
||||
it('should have documentation links for new asset proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/new-asset-proposal');
|
||||
@@ -104,7 +100,7 @@ context(
|
||||
// 3006-PASC-002 3006-PASC-005
|
||||
it('should have documentation links for update asset proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/update-asset-proposal');
|
||||
@@ -113,7 +109,7 @@ context(
|
||||
// 3008-PFRO-003 3008-PFRO-017
|
||||
it('should have documentation links for freeform proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/freeform-proposal');
|
||||
@@ -121,7 +117,7 @@ context(
|
||||
|
||||
it('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
cy.getByTestId(connectToVegaWalletButton)
|
||||
cy.get(connectToVegaWalletButton)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Vega wallet');
|
||||
});
|
||||
@@ -130,7 +126,7 @@ context(
|
||||
mockNetworkUpgradeProposal();
|
||||
cy.visit('/');
|
||||
cy.getByTestId('home-proposal-list').within(() => {
|
||||
cy.getByTestId(networkUpgradeProposalListItem).should('exist');
|
||||
cy.getByTestId('protocol-upgrade-proposals-list-item').should('exist');
|
||||
cy.getByTestId('protocol-upgrade-proposal-title').should(
|
||||
'have.text',
|
||||
'Vega release v1'
|
||||
@@ -144,7 +140,11 @@ context(
|
||||
cy.getByTestId('open-proposals').within(() => {
|
||||
cy.get('li')
|
||||
.eq(0)
|
||||
.should('have.attr', 'data-testid', networkUpgradeProposalListItem)
|
||||
.should(
|
||||
'have.attr',
|
||||
'data-testid',
|
||||
'protocol-upgrade-proposals-list-item'
|
||||
)
|
||||
.within(() => {
|
||||
cy.get('h2').should('have.text', 'Vega release v1');
|
||||
cy.getByTestId('protocol-upgrade-proposal-type').should(
|
||||
@@ -161,23 +161,22 @@ context(
|
||||
);
|
||||
cy.getByTestId('protocol-upgrade-proposal-status').should(
|
||||
'have.text',
|
||||
'Approved by validators'
|
||||
'Approved by validators '
|
||||
);
|
||||
});
|
||||
});
|
||||
cy.getByTestId(closedProposals).within(() => {
|
||||
cy.getByTestId(networkUpgradeProposalListItem).should('not.exist');
|
||||
});
|
||||
cy.getByTestId(closedProposalToggle).click();
|
||||
cy.getByTestId(closedProposals).within(() => {
|
||||
cy.getByTestId(networkUpgradeProposalListItem).should('have.length', 1);
|
||||
cy.getByTestId('closed-proposals').within(() => {
|
||||
cy.getByTestId('protocol-upgrade-proposals-list-item').should(
|
||||
'have.length',
|
||||
1
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should see details of network upgrade proposal', function () {
|
||||
mockNetworkUpgradeProposal();
|
||||
navigateTo(navigation.proposals);
|
||||
cy.getByTestId(networkUpgradeProposalListItem)
|
||||
cy.getByTestId('protocol-upgrade-proposals-list-item')
|
||||
.first()
|
||||
.find('[data-testid="view-proposal-btn"]')
|
||||
.click();
|
||||
@@ -214,55 +213,5 @@ 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');
|
||||
});
|
||||
|
||||
it('should display network upgrade banner with estimate', function () {
|
||||
mockNetworkUpgradeProposal();
|
||||
cy.visit('/');
|
||||
cy.getByTestId('banners').within(() => {
|
||||
cy.get('div')
|
||||
.should('contain.text', 'The network will upgrade to v1 in ')
|
||||
.and(
|
||||
'contain.text',
|
||||
'Trading activity will be interrupted, manage your risk appropriately.'
|
||||
);
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/proposals/protocol-upgrade/v1');
|
||||
});
|
||||
|
||||
// estimate does not display possibly due to mocks or Cypress unless the proposal is clicked on several times
|
||||
// By default the application waits for 10 blocks until showing estimate - roughly 10 seconds
|
||||
for (let i = 0; i < 3; i++) {
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(3000);
|
||||
navigateTo(navigation.proposals);
|
||||
cy.getByTestId(networkUpgradeProposalListItem)
|
||||
.first()
|
||||
.find('[data-testid="view-proposal-btn"]')
|
||||
.click();
|
||||
}
|
||||
cy.getByTestId('upgrade-proposal-estimate')
|
||||
.invoke('text')
|
||||
.as('displayedEstimate');
|
||||
cy.get('@displayedEstimate').then((estimateText) => {
|
||||
// Estimated time should automatically update every second
|
||||
cy.getByTestId('protocol-upgrade-time')
|
||||
.invoke('text')
|
||||
.should('not.eq', estimateText);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import {
|
||||
navigateTo,
|
||||
navigation,
|
||||
turnTelemetryOff,
|
||||
waitForSpinner,
|
||||
} from '../../support/common.functions';
|
||||
import {
|
||||
createTenDigitUnixTimeStampForSpecifiedDays,
|
||||
enterRawProposalBody,
|
||||
enterUniqueFreeFormProposalBody,
|
||||
goToMakeNewProposal,
|
||||
governanceProposalType,
|
||||
} from '../../support/governance.functions';
|
||||
@@ -46,11 +47,12 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
|
||||
.and('contain.text', 'USDC (fake)');
|
||||
});
|
||||
|
||||
it('Unable to submit proposal with public key', function () {
|
||||
it.skip('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.`;
|
||||
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||
navigateTo(navigation.proposals);
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
enterUniqueFreeFormProposalBody('50', 'pub key proposal test');
|
||||
cy.getByTestId('dialog-content')
|
||||
.first()
|
||||
.within(() => {
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
} from '../../support/common.functions';
|
||||
import { waitForBeginningOfEpoch } from '../../support/staking.functions';
|
||||
|
||||
const viewToggle = 'epoch-reward-view-toggle-total';
|
||||
const warning = 'callout';
|
||||
const viewToggle = '[data-testid="epoch-reward-view-toggle-total"]';
|
||||
const warning = '[data-testid="callout"]';
|
||||
|
||||
context(
|
||||
'Rewards Page - verify elements on page',
|
||||
@@ -27,7 +27,7 @@ context(
|
||||
});
|
||||
|
||||
it('should have epoch warning', function () {
|
||||
cy.getByTestId(warning)
|
||||
cy.get(warning)
|
||||
.should('be.visible')
|
||||
.and(
|
||||
'have.text',
|
||||
@@ -36,7 +36,7 @@ context(
|
||||
});
|
||||
|
||||
it('should have toggle for seeing total vs individual rewards', function () {
|
||||
cy.getByTestId(viewToggle).should('be.visible');
|
||||
cy.get(viewToggle).should('be.visible');
|
||||
});
|
||||
|
||||
// Skipping due to bug #3471 causing flaky failuress
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { navigateTo, navigation } from '../../support/common.functions';
|
||||
|
||||
const tokenDetailsTable = '.token-details';
|
||||
const address = 'token-address';
|
||||
const contract = 'token-contract';
|
||||
const totalSupply = 'total-supply';
|
||||
const circulatingSupply = 'circulating-supply';
|
||||
const staked = 'staked';
|
||||
const tranchesLink = 'tranches-link';
|
||||
const redeemBtn = 'check-vesting-page-btn';
|
||||
const getVegaWalletLink = 'get-vega-wallet-link';
|
||||
const associateVegaLink = 'associate-vega-tokens-link-on-homepage';
|
||||
const stakingBtn = 'staking-button-on-homepage';
|
||||
const governanceBtn = 'governance-button-on-homepage';
|
||||
const address = '[data-testid="token-address"]';
|
||||
const contract = '[data-testid="token-contract"]';
|
||||
const totalSupply = '[data-testid="total-supply"]';
|
||||
const circulatingSupply = '[data-testid="circulating-supply"]';
|
||||
const staked = '[data-testid="staked"]';
|
||||
const tranchesLink = '[data-testid="tranches-link"]';
|
||||
const redeemBtn = '[data-testid="check-vesting-page-btn"]';
|
||||
const getVegaWalletLink = '[data-testid="get-vega-wallet-link"]';
|
||||
const associateVegaLink =
|
||||
'[data-testid="associate-vega-tokens-link-on-homepage"]';
|
||||
const stakingBtn = '[data-testid="staking-button-on-homepage"]';
|
||||
const governanceBtn = '[data-testid="governance-button-on-homepage"]';
|
||||
|
||||
const vegaTokenAddress = Cypress.env('vegaTokenAddress');
|
||||
const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress');
|
||||
@@ -24,7 +25,7 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
|
||||
describe('THE $VEGA TOKEN table', function () {
|
||||
it('should have TOKEN ADDRESS', function () {
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.getByTestId(address)
|
||||
cy.get(address)
|
||||
.should('be.visible')
|
||||
.invoke('text')
|
||||
.should('be.equal', vegaTokenAddress);
|
||||
@@ -33,7 +34,7 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
|
||||
it('should have VESTING CONTRACT', function () {
|
||||
// 1004-ASSO-001
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.getByTestId(contract)
|
||||
cy.get(contract)
|
||||
.should('be.visible')
|
||||
.invoke('text')
|
||||
.should('be.equal', vegaTokenContractAddress);
|
||||
@@ -41,56 +42,56 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
it('should have TOTAL SUPPLY', function () {
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.getByTestId(totalSupply).should('be.visible');
|
||||
cy.get(totalSupply).should('be.visible');
|
||||
});
|
||||
});
|
||||
it('should have CIRCULATING SUPPLY', function () {
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.getByTestId(circulatingSupply).should('be.visible');
|
||||
cy.get(circulatingSupply).should('be.visible');
|
||||
});
|
||||
});
|
||||
it('should have STAKED $VEGA', function () {
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.getByTestId(staked).should('be.visible');
|
||||
cy.get(staked).should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('links and buttons', function () {
|
||||
it('should have TRANCHES link', function () {
|
||||
cy.getByTestId(tranchesLink)
|
||||
cy.get(tranchesLink)
|
||||
.should('be.visible')
|
||||
.and('have.attr', 'href')
|
||||
.and('equal', '/token/tranches');
|
||||
});
|
||||
it('should have REDEEM button', function () {
|
||||
cy.getByTestId(redeemBtn)
|
||||
cy.get(redeemBtn)
|
||||
.should('be.visible')
|
||||
.parent()
|
||||
.should('have.attr', 'href')
|
||||
.and('equal', '/token/redeem');
|
||||
});
|
||||
it('should have GET VEGA WALLET link', function () {
|
||||
cy.getByTestId(getVegaWalletLink)
|
||||
cy.get(getVegaWalletLink)
|
||||
.should('be.visible')
|
||||
.and('have.attr', 'href')
|
||||
.and('equal', 'https://vega.xyz/wallet');
|
||||
});
|
||||
it('should have ASSOCIATE VEGA TOKENS link', function () {
|
||||
cy.getByTestId(associateVegaLink)
|
||||
cy.get(associateVegaLink)
|
||||
.should('be.visible')
|
||||
.and('have.attr', 'href')
|
||||
.and('equal', '/token/associate');
|
||||
});
|
||||
it('should have STAKING button', function () {
|
||||
cy.getByTestId(stakingBtn)
|
||||
cy.get(stakingBtn)
|
||||
.should('be.visible')
|
||||
.parent()
|
||||
.should('have.attr', 'href')
|
||||
.and('equal', '/validators');
|
||||
});
|
||||
it('should have GOVERNANCE button', function () {
|
||||
cy.getByTestId(governanceBtn)
|
||||
cy.get(governanceBtn)
|
||||
.should('be.visible')
|
||||
.parent()
|
||||
.should('have.attr', 'href')
|
||||
|
||||
@@ -12,26 +12,28 @@ import {
|
||||
} from '../../support/staking.functions';
|
||||
import { previousEpochData } from '../../fixtures/mocks/previous-epoch';
|
||||
|
||||
const guideLink = 'staking-guide-link';
|
||||
const validatorTitle = 'validator-node-title';
|
||||
const validatorId = 'validator-id';
|
||||
const validatorPubKey = 'validator-public-key';
|
||||
const ethAddressLink = 'link';
|
||||
const validatorStatus = 'validator-status';
|
||||
const totalStake = 'total-stake';
|
||||
const pendingStake = 'pending-stake';
|
||||
const stakedByOperator = 'staked-by-operator';
|
||||
const stakedByDelegates = 'staked-by-delegates';
|
||||
const stakeShare = 'stake-percentage';
|
||||
const stakedByOperatorToolTip = 'staked-operator-tooltip';
|
||||
const stakedByDelegatesToolTip = 'staked-delegates-tooltip';
|
||||
const totalStakedToolTip = 'total-staked-tooltip';
|
||||
const unnormalisedVotingPowerToolTip = 'unnormalised-voting-power-tooltip';
|
||||
const normalisedVotingPowerToolTip = 'normalised-voting-power-tooltip';
|
||||
const performancePenaltyToolTip = 'performance-penalty-tooltip';
|
||||
const overstakedPenaltyToolTip = 'overstaked-penalty-tooltip';
|
||||
const multisigPenaltyToolTip = 'multisig-error-tooltip';
|
||||
const epochCountDown = 'epoch-countdown';
|
||||
const guideLink = '[data-testid="staking-guide-link"]';
|
||||
const validatorTitle = '[data-testid="validator-node-title"]';
|
||||
const validatorId = '[data-testid="validator-id"]';
|
||||
const validatorPubKey = '[data-testid="validator-public-key"]';
|
||||
const ethAddressLink = '[data-testid="link"]';
|
||||
const validatorStatus = '[data-testid="validator-status"]';
|
||||
const totalStake = '[data-testid="total-stake"]';
|
||||
const pendingStake = '[data-testid="pending-stake"]';
|
||||
const stakedByOperator = '[data-testid="staked-by-operator"]';
|
||||
const stakedByDelegates = '[data-testid="staked-by-delegates"]';
|
||||
const stakeShare = '[data-testid="stake-percentage"]';
|
||||
const stakedByOperatorToolTip = '[data-testid="staked-operator-tooltip"]';
|
||||
const stakedByDelegatesToolTip = '[data-testid="staked-delegates-tooltip"]';
|
||||
const totalStakedToolTip = '[data-testid="total-staked-tooltip"]';
|
||||
const unnormalisedVotingPowerToolTip =
|
||||
'[data-testid="unnormalised-voting-power-tooltip"]';
|
||||
const normalisedVotingPowerToolTip =
|
||||
'[data-testid="normalised-voting-power-tooltip"]';
|
||||
const performancePenaltyToolTip = '[data-testid="performance-penalty-tooltip"]';
|
||||
const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]';
|
||||
const multisigPenaltyToolTip = '[data-testid="multisig-error-tooltip"]';
|
||||
const epochCountDown = '[data-testid="epoch-countdown"]';
|
||||
const stakeNumberRegex = /^\d{1,3}(,\d{3})*(\.\d+)?$/;
|
||||
|
||||
context('Validators Page - verify elements on page', function () {
|
||||
@@ -50,7 +52,7 @@ context('Validators Page - verify elements on page', function () {
|
||||
|
||||
it('Should have Staking Guide link visible', function () {
|
||||
// 1002-STKE-003
|
||||
cy.getByTestId(guideLink)
|
||||
cy.get(guideLink)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Read more about staking on Vega')
|
||||
.and(
|
||||
@@ -93,13 +95,13 @@ context('Validators Page - verify elements on page', function () {
|
||||
waitForBeginningOfEpoch();
|
||||
cy.getByTestId('total-stake').first().realHover();
|
||||
|
||||
cy.getByTestId(stakedByOperatorToolTip)
|
||||
cy.get(stakedByOperatorToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Staked by operator: 3,000.00');
|
||||
cy.getByTestId(stakedByDelegatesToolTip)
|
||||
cy.get(stakedByDelegatesToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Staked by delegates: 0.00');
|
||||
cy.getByTestId(totalStakedToolTip)
|
||||
cy.get(totalStakedToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Total stake: 3,000.00');
|
||||
});
|
||||
@@ -116,10 +118,10 @@ context('Validators Page - verify elements on page', function () {
|
||||
waitForBeginningOfEpoch();
|
||||
cy.getByTestId('normalised-voting-power').first().realHover();
|
||||
|
||||
cy.getByTestId(unnormalisedVotingPowerToolTip)
|
||||
cy.get(unnormalisedVotingPowerToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Unnormalised voting power: 20.00%');
|
||||
cy.getByTestId(normalisedVotingPowerToolTip)
|
||||
cy.get(normalisedVotingPowerToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Normalised voting power: 50.00%');
|
||||
});
|
||||
@@ -137,10 +139,10 @@ context('Validators Page - verify elements on page', function () {
|
||||
waitForBeginningOfEpoch();
|
||||
cy.getByTestId('total-penalty').realHover();
|
||||
|
||||
cy.getByTestId(performancePenaltyToolTip)
|
||||
cy.get(performancePenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Performance penalty: 0.00%');
|
||||
cy.getByTestId(overstakedPenaltyToolTip)
|
||||
cy.get(overstakedPenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Overstaked penalty: 60.00%'); // value not asserted due to #2886
|
||||
});
|
||||
@@ -159,12 +161,12 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
waitForBeginningOfEpoch();
|
||||
cy.getByTestId('total-penalty').first().realHover();
|
||||
cy.getByTestId(multisigPenaltyToolTip)
|
||||
cy.get(multisigPenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Multisig penalty: 100%');
|
||||
|
||||
cy.getByTestId('total-penalty').eq(1).realHover();
|
||||
cy.getByTestId(multisigPenaltyToolTip)
|
||||
cy.get(multisigPenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Multisig penalty: 100%');
|
||||
});
|
||||
@@ -183,59 +185,53 @@ context('Validators Page - verify elements on page', function () {
|
||||
|
||||
// 1002-STKE-006
|
||||
it('Should be able to see validator name', function () {
|
||||
cy.getByTestId(validatorTitle).should('not.be.empty');
|
||||
cy.get(validatorTitle).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 1002-STKE-007
|
||||
it('Should be able to see validator id', function () {
|
||||
cy.getByTestId(validatorId).should('not.be.empty');
|
||||
cy.get(validatorId).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 1002-STKE-008
|
||||
it('Should be able to see validator public key', function () {
|
||||
cy.getByTestId(validatorPubKey).should('not.be.empty');
|
||||
cy.get(validatorPubKey).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 1002-STKE-010
|
||||
it('Should be able to see Ethereum address', function () {
|
||||
cy.getByTestId(ethAddressLink)
|
||||
.should('not.be.empty')
|
||||
.and('have.attr', 'href');
|
||||
cy.get(ethAddressLink).should('not.be.empty').and('have.attr', 'href');
|
||||
});
|
||||
// TODO validators missing url for more information about them 1002-STKE-09
|
||||
|
||||
it('Should be able to see validator status', function () {
|
||||
cy.getByTestId(validatorStatus).should('have.text', 'Consensus');
|
||||
cy.get(validatorStatus).should('have.text', 'Consensus');
|
||||
});
|
||||
|
||||
// 1002-STKE-012
|
||||
it('Should be able to see total stake', function () {
|
||||
cy.getByTestId(totalStake)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
cy.get(totalStake).invoke('text').should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see pending stake', function () {
|
||||
cy.getByTestId(pendingStake)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
cy.get(pendingStake).invoke('text').should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see staked by operator', function () {
|
||||
cy.getByTestId(stakedByOperator)
|
||||
cy.get(stakedByOperator)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see staked by delegates', function () {
|
||||
cy.getByTestId(stakedByDelegates)
|
||||
cy.get(stakedByDelegates)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
// 1002-STKE-051
|
||||
it('Should be able to see stake share in percentage', function () {
|
||||
cy.getByTestId(stakeShare)
|
||||
cy.get(stakeShare)
|
||||
.invoke('text')
|
||||
.then(($stakePercentage) => {
|
||||
// The pattern must start at a word boundary (\b).
|
||||
@@ -261,7 +257,7 @@ context('Validators Page - verify elements on page', function () {
|
||||
const epochTitle = 'h3';
|
||||
const nextEpochInfo = 'p';
|
||||
|
||||
cy.getByTestId(epochCountDown).within(() => {
|
||||
cy.get(epochCountDown).within(() => {
|
||||
cy.get(epochTitle).should('not.be.empty');
|
||||
cy.get(nextEpochInfo).should('contain.text', 'Next epoch');
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user