Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ace4ff5ca |
@@ -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
|
||||
@@ -46,7 +49,7 @@ jobs:
|
||||
|
||||
lint-pr-title:
|
||||
needs: node-modules
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
||||
name: Verify PR title
|
||||
uses: ./.github/workflows/lint-pr.yml
|
||||
secrets: inherit
|
||||
@@ -107,7 +110,6 @@ jobs:
|
||||
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
||||
echo "Affected: ${affected}"
|
||||
echo "Branch slug: ${branch_slug}"
|
||||
echo "Current ref: ${{ github.ref }}"
|
||||
echo ">>>> eof debug"
|
||||
|
||||
projects_array=()
|
||||
@@ -178,31 +180,6 @@ jobs:
|
||||
fi
|
||||
fi
|
||||
|
||||
# if branch starts with release/ and ends with trading / governance or explorer - overwrite the array of affected projects with fixed single application
|
||||
if [[ "${{ github.ref }}" == *release* ]]; then
|
||||
echo ">> This is a relase branch"
|
||||
case "${{ github.ref }}" in
|
||||
*trading)
|
||||
echo ">> Only trading will be deployed"
|
||||
projects_array=(trading)
|
||||
projects_e2e_array=(trading)
|
||||
;;
|
||||
*governance)
|
||||
echo ">> Only governance will be deployed"
|
||||
projects_array=(governance)
|
||||
projects_e2e_array=(governance)
|
||||
;;
|
||||
*explorer)
|
||||
echo ">> Only explorer will be deployed"
|
||||
projects_array=(explorer)
|
||||
projects_e2e_array=(explorer)
|
||||
;;
|
||||
*)
|
||||
echo ">> All apps will be deployed"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo "Projects: ${projects_array[@]}"
|
||||
echo "Projects E2E: ${projects_e2e_array[@]}"
|
||||
projects_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_array[@]}")
|
||||
@@ -237,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:
|
||||
@@ -248,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' || github.event_name == 'pull_request_target' }}
|
||||
timeout-minutes: 60
|
||||
name: '(CD) comment preview links'
|
||||
steps:
|
||||
@@ -264,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
|
||||
@@ -294,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_RELASE=false >> $GITHUB_ENV
|
||||
|
||||
- name: Is PR
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
echo IS_PR=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is mainnet release
|
||||
if: ${{ contains(github.ref, 'release/mainnnet') && !contains(github.ref, 'mirror') }}
|
||||
run: |
|
||||
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is testnet release
|
||||
if: ${{ contains(github.ref, 'release/testnet') }}
|
||||
run: |
|
||||
echo IS_TESTNET_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is IPFS Release
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( env.IS_MAINNET_RELEASE == 'true' || env.IS_TESTNET_RELEASE == 'true' ) }}
|
||||
run: |
|
||||
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is S3 Release
|
||||
if: ${{ env.IS_IPFS_RELASE == 'false' && github.event_name == 'push' }}
|
||||
run: |
|
||||
echo IS_S3_RELASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Set up QEMU
|
||||
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' || github.event_name == 'pull_request_target' }}
|
||||
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 }}
|
||||
|
||||
@@ -102,8 +70,7 @@ jobs:
|
||||
bucketName=''
|
||||
|
||||
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
||||
# remove prefixing release/ and take the first string limited by - which is supposed to be name of the environment for releasing (format: release/testnet-trading)
|
||||
envName="$(echo ${{ github.ref }} | sed -e "s|refs/heads/release/||" | cut -d '-' -f 1 )"
|
||||
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
|
||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||
envName="stagnet1"
|
||||
if [[ "${{ matrix.app }}" = "multisig-signer" ]]; then
|
||||
@@ -118,7 +85,7 @@ jobs:
|
||||
envName="mainnet"
|
||||
bucketName="ui.vega.rocks"
|
||||
fi
|
||||
elif [[ "${{ github.ref }}" =~ .*mainnet$ ]]; then
|
||||
elif [[ "${{ github.ref }}" =~ .*main$ ]]; then
|
||||
envName="mainnet"
|
||||
fi
|
||||
|
||||
@@ -178,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' || github.event_name == 'pull_request_target' }}
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
|
||||
- name: Sanity check docker image
|
||||
@@ -193,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' || github.event_name == 'pull_request_target' }}
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
@@ -208,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
|
||||
@@ -218,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
|
||||
@@ -245,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_RELASE == '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:
|
||||
@@ -262,11 +229,11 @@ jobs:
|
||||
SOURCE_DIR: 'dist-result'
|
||||
|
||||
- name: Install aws CLI
|
||||
if: ${{ env.IS_S3_RELASE == 'true' }}
|
||||
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
|
||||
uses: unfor19/install-aws-cli-action@master
|
||||
|
||||
- name: Perform cache invalidation
|
||||
if: ${{ env.IS_S3_RELASE == 'true' }}
|
||||
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
@@ -279,16 +246,16 @@ jobs:
|
||||
|
||||
- name: Add preview label
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
if: ${{ env.IS_PR == 'true' }}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
||||
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" \
|
||||
@@ -301,7 +268,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" \
|
||||
@@ -316,7 +283,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'
|
||||
@@ -325,7 +292,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: |
|
||||
@@ -347,11 +314,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
|
||||
|
||||
@@ -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`)
|
||||
|
||||
@@ -27,6 +27,11 @@ context('Home Page', function () {
|
||||
16: 'Chain ID',
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('[data-testid="stats-title"]')
|
||||
.each(($list, index) => {
|
||||
cy.wrap($list).should('contain.text', statTitles[index]);
|
||||
|
||||
@@ -34,6 +34,11 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
||||
const parameterName = network_parameter[0];
|
||||
const parameterValue = network_parameter[1];
|
||||
if (this.networkParameterFormat.json.includes(parameterName)) {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(tableRows)
|
||||
.contains(parameterName)
|
||||
.should('be.visible')
|
||||
@@ -65,6 +70,11 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
||||
if (this.networkParameterFormat.percentage.includes(parameterName)) {
|
||||
const formattedPercentageParameter =
|
||||
(parseFloat(parameterValue) * 100).toFixed(0) + '%';
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(tableRows)
|
||||
.contains(parameterName)
|
||||
.should('be.visible')
|
||||
@@ -148,6 +158,11 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
||||
cy.convert_number_to_max_four_decimal(parameterValue)
|
||||
.add_commas_to_number_if_large_enough()
|
||||
.then((parameterValueFormatted) => {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(tableRows)
|
||||
.contains(parameterName)
|
||||
.should('be.visible')
|
||||
@@ -179,6 +194,11 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
||||
cy.convert_number_to_max_eighteen_decimal(parameterValue)
|
||||
.add_commas_to_number_if_large_enough()
|
||||
.then((parameterValueFormatted) => {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(tableRows)
|
||||
.contains(parameterName)
|
||||
.should('be.visible')
|
||||
|
||||
@@ -169,6 +169,12 @@ context.skip('Parties page', { tags: '@regression' }, function () {
|
||||
const jsonFields = '.hljs';
|
||||
const sideMenuBackground = '.absolute';
|
||||
|
||||
// Engage dark mode if not allready set
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(sideMenuBackground)
|
||||
.should('have.css', 'background-color')
|
||||
.then((background_color) => {
|
||||
|
||||
@@ -60,16 +60,31 @@ context.skip('Transactions page', function () {
|
||||
});
|
||||
cy.get('block').should('not.be.empty');
|
||||
cy.get('encoded-tnx').should('not.be.empty');
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('tx-type')
|
||||
.should('not.be.empty')
|
||||
.invoke('text')
|
||||
.then((txTypeTxt) => {
|
||||
if (txTypeTxt == 'Order Submission') {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('.hljs-attr')
|
||||
.should('have.length.at.least', 8)
|
||||
.each(($propertyName) => {
|
||||
cy.wrap($propertyName).should('not.be.empty');
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('.hljs-string')
|
||||
.should('have.length.at.least', 8)
|
||||
.each(($propertyValue) => {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
"executor": "nx: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"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
+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 =
|
||||
|
||||
@@ -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',
|
||||
@@ -44,27 +44,8 @@ const displayString: StringMap = {
|
||||
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 +117,6 @@ export function getLabelForChainEvent(
|
||||
return t('Signer threshold');
|
||||
}
|
||||
return t('Multisig update');
|
||||
} else if (chainEvent.contractCall) {
|
||||
return t('Contract call');
|
||||
}
|
||||
return t('Chain Event');
|
||||
}
|
||||
|
||||
+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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,6 +15,5 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
|
||||
return {
|
||||
...config,
|
||||
plugins: [...additionalPlugins, ...config.plugins],
|
||||
ignoreWarnings: [/Failed to parse source map/],
|
||||
};
|
||||
});
|
||||
|
||||
@@ -98,6 +98,11 @@ describe(
|
||||
.and('have.length', 64);
|
||||
cy.getByTestId(proposalTermsToggle).click();
|
||||
// 3001-VOTE-052 3001-VOTE-010
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('code.language-json')
|
||||
.should('exist')
|
||||
.within(() => {
|
||||
|
||||
@@ -320,8 +320,8 @@ context(
|
||||
// 3001-VOTE-076
|
||||
cy.getByTestId(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');
|
||||
|
||||
@@ -295,7 +295,7 @@ context(
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -116,6 +116,12 @@ context(
|
||||
cy.getByTestId(amountInput).click().type('120');
|
||||
cy.getByTestId(submitWithdrawalButton).click();
|
||||
});
|
||||
// assert withdrawal request
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'Funds unlocked')
|
||||
@@ -129,6 +135,11 @@ context(
|
||||
cy.getByTestId(toastClose).click();
|
||||
});
|
||||
// withdrawal complete
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'The withdrawal has been approved.')
|
||||
@@ -138,6 +149,11 @@ context(
|
||||
'Withdraw 120.00 tUSDC'
|
||||
);
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(toast)
|
||||
.last(txTimeout)
|
||||
.should('contain.text', 'Transaction confirmed')
|
||||
@@ -145,6 +161,11 @@ context(
|
||||
cy.getByTestId('external-link').should('exist');
|
||||
});
|
||||
// withdrawal history for complete withdrawal displayed
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(tableWithdrawnStatus)
|
||||
.eq(1, txTimeout)
|
||||
.should('have.text', 'Completed')
|
||||
@@ -186,6 +207,11 @@ context(
|
||||
cy.getByTestId(submitWithdrawalButton).click();
|
||||
});
|
||||
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'Funds unlocked')
|
||||
@@ -197,6 +223,11 @@ context(
|
||||
);
|
||||
cy.getByTestId(toastClose).click();
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(tableTxHash)
|
||||
.eq(1)
|
||||
.should('have.text', 'Complete withdrawal')
|
||||
@@ -212,18 +243,33 @@ context(
|
||||
});
|
||||
ethereumWalletConnect();
|
||||
cy.getByTestId(completeWithdrawalButton).first().click();
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(toast)
|
||||
.last(txTimeout)
|
||||
.should('contain.text', 'Awaiting confirmation')
|
||||
.within(() => {
|
||||
cy.getByTestId('external-link').should('exist');
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'The withdrawal has been approved.')
|
||||
.within(() => {
|
||||
cy.getByTestId(toastPanel).should('contain.text', '110.00', 'tUSDC');
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(toast)
|
||||
.last(txTimeout)
|
||||
.should('contain.text', 'Transaction confirmed')
|
||||
@@ -247,6 +293,11 @@ context(
|
||||
cy.getByTestId(amountInput).click().type('50');
|
||||
cy.getByTestId(submitWithdrawalButton).click();
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'Funds unlocked')
|
||||
|
||||
@@ -16,6 +16,11 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
|
||||
it('should display announcement banner', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('app-announcement')
|
||||
.should('contain.text', 'TEST ANNOUNCEMENT!')
|
||||
.within(() => {
|
||||
@@ -35,6 +40,11 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
waitForSpinner();
|
||||
}
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('proposals-list-item')
|
||||
.should('have.length.at.least', 1)
|
||||
.first()
|
||||
@@ -94,6 +104,11 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
|
||||
it('should contain link to specific validators', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('validators')
|
||||
.should('have.length', '2')
|
||||
.each(($validator) => {
|
||||
@@ -120,6 +135,11 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
|
||||
it('should display network data', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('git-network-data')
|
||||
.should('contain.text', 'Reading network data from')
|
||||
.within(() => {
|
||||
@@ -131,6 +151,11 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
|
||||
it('should display eth data', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('git-eth-data')
|
||||
.should('contain.text', 'Reading Ethereum data from')
|
||||
.within(() => {
|
||||
@@ -161,7 +186,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')
|
||||
|
||||
@@ -142,6 +142,11 @@ context(
|
||||
mockNetworkUpgradeProposal();
|
||||
navigateTo(navigation.proposals);
|
||||
cy.getByTestId('open-proposals').within(() => {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('li')
|
||||
.eq(0)
|
||||
.should('have.attr', 'data-testid', networkUpgradeProposalListItem)
|
||||
@@ -200,6 +205,11 @@ context(
|
||||
.should('contain.text', '99.98% approval (% validator voting power)')
|
||||
.and('contain.text', '(67% voting power required)');
|
||||
cy.get('h2').should('contain.text', 'Approvers (4/4 validators)');
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('validator-name')
|
||||
.should('have.length', 4)
|
||||
.each(($validator) => {
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -42,6 +42,11 @@ context(
|
||||
// Skipping due to bug #3471 causing flaky failuress
|
||||
it.skip('should have option to view go to next and previous page', function () {
|
||||
waitForBeginningOfEpoch();
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('page-info')
|
||||
.should('contain.text', 'Page ')
|
||||
.invoke('text')
|
||||
|
||||
@@ -21,6 +21,11 @@ context(
|
||||
// 1005-VEST-001
|
||||
// 1005-VEST-002
|
||||
it('Able to view tranches', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('tranche-item')
|
||||
.should('have.length', 2)
|
||||
.first()
|
||||
@@ -51,6 +56,11 @@ context(
|
||||
cy.get('span').eq(1).should('have.text', 0);
|
||||
});
|
||||
cy.getByTestId('key-value-table').within(() => {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('link')
|
||||
.should('have.length', 8)
|
||||
.each((ethLink) => {
|
||||
@@ -58,6 +68,11 @@ context(
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/address/');
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('redeem-link')
|
||||
.should('have.length', 8)
|
||||
.each((redeemLink) => {
|
||||
@@ -71,6 +86,11 @@ context(
|
||||
it('Able to view tranches with less than 10 vega', function () {
|
||||
navigateTo(navigation.supply);
|
||||
cy.getByTestId('show-all-tranches').click();
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('tranche-item')
|
||||
.should('have.length', 8)
|
||||
.first()
|
||||
|
||||
@@ -74,6 +74,11 @@ context('Validators Page - verify elements on page', function () {
|
||||
function () {
|
||||
// 1002-STKE-050
|
||||
it('Should be able to see validator names', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('[col-id="validator"] > div > span')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($name) => {
|
||||
@@ -82,6 +87,11 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('Should be able to see validator stake', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('total-stake')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($stake) => {
|
||||
@@ -105,6 +115,11 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('Should be able to see validator normalised voting power', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('normalised-voting-power')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($vPower) => {
|
||||
@@ -126,6 +141,11 @@ context('Validators Page - verify elements on page', function () {
|
||||
|
||||
// 2002-SINC-018
|
||||
it('Should be able to see validator total penalties', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('total-penalty')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($penalties) => {
|
||||
@@ -146,6 +166,11 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('Should be able to see validator pending stake', function () {
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('total-pending-stake')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($pendingStake) => {
|
||||
|
||||
@@ -78,7 +78,7 @@ context(
|
||||
cy.getByTestId('connector-jsonRpc')
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Vega wallet');
|
||||
cy.getByTestId('connector-rest')
|
||||
cy.getByTestId('connector-hosted')
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Hosted Fairground wallet');
|
||||
});
|
||||
@@ -94,7 +94,7 @@ context(
|
||||
describe('when rest connector form opened', function () {
|
||||
before('click hosted wallet app button', function () {
|
||||
cy.getByTestId(connectorsList).within(() => {
|
||||
cy.getByTestId('connector-rest').click();
|
||||
cy.getByTestId('connector-hosted').click();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -340,7 +340,7 @@ context(
|
||||
.contains(name)
|
||||
.parent()
|
||||
.siblings()
|
||||
.should((elementAmount) => {
|
||||
.then((elementAmount) => {
|
||||
const displayedAmount = parseFloat(elementAmount.text());
|
||||
expect(displayedAmount).be.gte(expectedAmount);
|
||||
});
|
||||
|
||||
@@ -2,8 +2,13 @@ import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../../contexts/app-state/app-state-context';
|
||||
|
||||
export const ConnectToVega = () => {
|
||||
const { appDispatch } = useAppState();
|
||||
const { t } = useTranslation();
|
||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||
@@ -11,6 +16,10 @@ export const ConnectToVega = () => {
|
||||
return (
|
||||
<Button
|
||||
onClick={() => {
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
||||
isOpen: true,
|
||||
});
|
||||
openVegaWalletDialog();
|
||||
}}
|
||||
data-testid="connect-to-vega-wallet-btn"
|
||||
|
||||
@@ -3,6 +3,11 @@ import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../../contexts/app-state/app-state-context';
|
||||
|
||||
interface VegaWalletContainerProps {
|
||||
children: (key: string) => React.ReactElement;
|
||||
}
|
||||
@@ -10,6 +15,7 @@ interface VegaWalletContainerProps {
|
||||
export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { appDispatch } = useAppState();
|
||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||
}));
|
||||
@@ -19,6 +25,10 @@ export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => {
|
||||
<Button
|
||||
data-testid="connect-to-vega-wallet-btn"
|
||||
onClick={() => {
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
||||
isOpen: true,
|
||||
});
|
||||
openVegaWalletDialog();
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -13,6 +13,12 @@ export const VegaWalletDialogs = () => {
|
||||
<>
|
||||
<VegaConnectDialog
|
||||
connectors={Connectors}
|
||||
onChangeOpen={(open) =>
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
||||
isOpen: open,
|
||||
})
|
||||
}
|
||||
riskMessage={<RiskMessage />}
|
||||
/>
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ export const VegaWallet = () => {
|
||||
|
||||
const VegaWalletNotConnected = () => {
|
||||
const { t } = useTranslation();
|
||||
const { appDispatch } = useAppState();
|
||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||
}));
|
||||
@@ -78,6 +79,10 @@ const VegaWalletNotConnected = () => {
|
||||
<>
|
||||
<Button
|
||||
onClick={() => {
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
||||
isOpen: true,
|
||||
});
|
||||
openVegaWalletDialog();
|
||||
}}
|
||||
fill={true}
|
||||
|
||||
@@ -28,6 +28,9 @@ export interface AppState {
|
||||
/** Total number of VEGA Tokens, both vesting and unlocked, associated for staking */
|
||||
totalAssociated: BigNumber;
|
||||
|
||||
/** Whether or not the connect to VEGA wallet overlay is open */
|
||||
vegaWalletOverlay: boolean;
|
||||
|
||||
/** Whether or not the manage VEGA wallet overlay is open */
|
||||
vegaWalletManageOverlay: boolean;
|
||||
|
||||
@@ -49,7 +52,9 @@ export enum AppStateActionType {
|
||||
SET_TOKEN,
|
||||
SET_ALLOWANCE,
|
||||
REFRESH_BALANCES,
|
||||
SET_VEGA_WALLET_OVERLAY,
|
||||
SET_VEGA_WALLET_MANAGE_OVERLAY,
|
||||
SET_DRAWER,
|
||||
REFRESH_ASSOCIATED_BALANCES,
|
||||
SET_ASSOCIATION_BREAKDOWN,
|
||||
SET_TRANSACTION_OVERLAY,
|
||||
@@ -64,10 +69,18 @@ export type AppStateAction =
|
||||
totalSupply: BigNumber;
|
||||
totalAssociated: BigNumber;
|
||||
}
|
||||
| {
|
||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY;
|
||||
isOpen: boolean;
|
||||
}
|
||||
| {
|
||||
type: AppStateActionType.SET_VEGA_WALLET_MANAGE_OVERLAY;
|
||||
isOpen: boolean;
|
||||
}
|
||||
| {
|
||||
type: AppStateActionType.SET_DRAWER;
|
||||
isOpen: boolean;
|
||||
}
|
||||
| {
|
||||
type: AppStateActionType.SET_TRANSACTION_OVERLAY;
|
||||
isOpen: boolean;
|
||||
|
||||
@@ -14,6 +14,7 @@ const initialAppState: AppState = {
|
||||
totalAssociated: new BigNumber(0),
|
||||
decimals: 0,
|
||||
totalSupply: new BigNumber(0),
|
||||
vegaWalletOverlay: false,
|
||||
vegaWalletManageOverlay: false,
|
||||
transactionOverlay: false,
|
||||
bannerMessage: '',
|
||||
@@ -30,10 +31,23 @@ function appStateReducer(state: AppState, action: AppStateAction): AppState {
|
||||
totalAssociated: action.totalAssociated,
|
||||
};
|
||||
}
|
||||
case AppStateActionType.SET_VEGA_WALLET_OVERLAY: {
|
||||
return {
|
||||
...state,
|
||||
vegaWalletOverlay: action.isOpen,
|
||||
};
|
||||
}
|
||||
case AppStateActionType.SET_VEGA_WALLET_MANAGE_OVERLAY: {
|
||||
return {
|
||||
...state,
|
||||
vegaWalletManageOverlay: action.isOpen,
|
||||
vegaWalletOverlay: action.isOpen ? false : state.vegaWalletOverlay,
|
||||
};
|
||||
}
|
||||
case AppStateActionType.SET_DRAWER: {
|
||||
return {
|
||||
...state,
|
||||
vegaWalletOverlay: false,
|
||||
};
|
||||
}
|
||||
case AppStateActionType.SET_TRANSACTION_OVERLAY: {
|
||||
|
||||
@@ -2,18 +2,15 @@ import {
|
||||
RestConnector,
|
||||
JsonRpcConnector,
|
||||
ViewConnector,
|
||||
InjectedConnector,
|
||||
} from '@vegaprotocol/wallet';
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
export const injected = new InjectedConnector();
|
||||
export const rest = new RestConnector();
|
||||
export const jsonRpc = new JsonRpcConnector();
|
||||
export const view = new ViewConnector(urlParams.get('address'));
|
||||
|
||||
export const Connectors = {
|
||||
injected,
|
||||
rest,
|
||||
jsonRpc,
|
||||
view,
|
||||
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { addDecimal, toBigNum } from '@vegaprotocol/utils';
|
||||
import { ProposalState, VoteValue } from '@vegaprotocol/types';
|
||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../../../../contexts/app-state/app-state-context';
|
||||
import { BigNumber } from '../../../../lib/bignumber';
|
||||
import { DATE_FORMAT_LONG } from '../../../../lib/date-formats';
|
||||
import { VoteState } from './use-user-vote';
|
||||
@@ -70,6 +73,7 @@ export const VoteButtons = ({
|
||||
dialog: Dialog,
|
||||
}: VoteButtonsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { appDispatch } = useAppState();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||
@@ -94,6 +98,10 @@ export const VoteButtons = ({
|
||||
<div data-testid="connect-wallet">
|
||||
<ButtonLink
|
||||
onClick={() => {
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
||||
isOpen: true,
|
||||
});
|
||||
openVegaWalletDialog();
|
||||
}}
|
||||
>
|
||||
@@ -134,6 +142,7 @@ export const VoteButtons = ({
|
||||
minVoterBalance,
|
||||
spamProtectionMinTokens,
|
||||
t,
|
||||
appDispatch,
|
||||
openVegaWalletDialog,
|
||||
]);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ const mockAppState: AppState = {
|
||||
totalAssociated: new BigNumber('50063005'),
|
||||
decimals: 18,
|
||||
totalSupply: mockTotalSupply,
|
||||
vegaWalletOverlay: false,
|
||||
vegaWalletManageOverlay: false,
|
||||
transactionOverlay: false,
|
||||
bannerMessage: '',
|
||||
|
||||
@@ -91,46 +91,46 @@ query Proposal($proposalId: ID!) {
|
||||
}
|
||||
}
|
||||
}
|
||||
# dataSourceSpecForTradingTermination {
|
||||
# sourceType {
|
||||
# ... on DataSourceDefinitionInternal {
|
||||
# sourceType {
|
||||
# ... on DataSourceSpecConfigurationTime {
|
||||
# conditions {
|
||||
# operator
|
||||
# value
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# ... on DataSourceDefinitionExternal {
|
||||
# sourceType {
|
||||
# ... on DataSourceSpecConfiguration {
|
||||
# signers {
|
||||
# signer {
|
||||
# ... on PubKey {
|
||||
# key
|
||||
# }
|
||||
# ... on ETHAddress {
|
||||
# address
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# filters {
|
||||
# key {
|
||||
# name
|
||||
# type
|
||||
# }
|
||||
# conditions {
|
||||
# operator
|
||||
# value
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
dataSourceSpecForTradingTermination {
|
||||
sourceType {
|
||||
... on DataSourceDefinitionInternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfigurationTime {
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on DataSourceDefinitionExternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfiguration {
|
||||
signers {
|
||||
signer {
|
||||
... on PubKey {
|
||||
key
|
||||
}
|
||||
... on ETHAddress {
|
||||
address
|
||||
}
|
||||
}
|
||||
}
|
||||
filters {
|
||||
key {
|
||||
name
|
||||
type
|
||||
}
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dataSourceSpecBinding {
|
||||
settlementDataProperty
|
||||
tradingTerminationProperty
|
||||
@@ -203,46 +203,46 @@ query Proposal($proposalId: ID!) {
|
||||
}
|
||||
}
|
||||
}
|
||||
# dataSourceSpecForTradingTermination {
|
||||
# sourceType {
|
||||
# ... on DataSourceDefinitionInternal {
|
||||
# sourceType {
|
||||
# ... on DataSourceSpecConfigurationTime {
|
||||
# conditions {
|
||||
# operator
|
||||
# value
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# ... on DataSourceDefinitionExternal {
|
||||
# sourceType {
|
||||
# ... on DataSourceSpecConfiguration {
|
||||
# signers {
|
||||
# signer {
|
||||
# ... on PubKey {
|
||||
# key
|
||||
# }
|
||||
# ... on ETHAddress {
|
||||
# address
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# filters {
|
||||
# key {
|
||||
# name
|
||||
# type
|
||||
# }
|
||||
# conditions {
|
||||
# operator
|
||||
# value
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
dataSourceSpecForTradingTermination {
|
||||
sourceType {
|
||||
... on DataSourceDefinitionInternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfigurationTime {
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on DataSourceDefinitionExternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfiguration {
|
||||
signers {
|
||||
signer {
|
||||
... on PubKey {
|
||||
key
|
||||
}
|
||||
... on ETHAddress {
|
||||
address
|
||||
}
|
||||
}
|
||||
}
|
||||
filters {
|
||||
key {
|
||||
name
|
||||
type
|
||||
}
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dataSourceSpecBinding {
|
||||
settlementDataProperty
|
||||
tradingTerminationProperty
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2,9 +2,14 @@ import classNames from 'classnames';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../../contexts/app-state/app-state-context';
|
||||
import { SubHeading } from '../../components/heading';
|
||||
|
||||
export const ConnectToSeeRewards = () => {
|
||||
const { appDispatch } = useAppState();
|
||||
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
|
||||
openVegaWalletDialog: store.openVegaWalletDialog,
|
||||
}));
|
||||
@@ -21,6 +26,10 @@ export const ConnectToSeeRewards = () => {
|
||||
<Button
|
||||
data-testid="connect-to-vega-wallet-btn"
|
||||
onClick={() => {
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY,
|
||||
isOpen: true,
|
||||
});
|
||||
openVegaWalletDialog();
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -14,6 +14,5 @@ module.exports = composePlugins(withNx(), withReact(), (config, context) => {
|
||||
return {
|
||||
...config,
|
||||
plugins: [...additionalPlugins, ...config.plugins],
|
||||
ignoreWarnings: [/Failed to parse source map/],
|
||||
};
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import { removeDecimal } from '@vegaprotocol/cypress';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
OrderStatusMapping,
|
||||
OrderTimeInForceMapping,
|
||||
OrderTypeMapping,
|
||||
Side,
|
||||
} from '@vegaprotocol/types';
|
||||
@@ -16,6 +17,7 @@ const orderStatus = 'status';
|
||||
const orderRemaining = 'remaining';
|
||||
const orderPrice = 'price';
|
||||
const orderTimeInForce = 'timeInForce';
|
||||
const orderCreatedAt = 'createdAt';
|
||||
const orderUpdatedAt = 'updatedAt';
|
||||
const assetSelectField = 'select[name="asset"]';
|
||||
const amountField = 'input[name="amount"]';
|
||||
@@ -90,14 +92,16 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
|
||||
cy.highlight('deposit verification');
|
||||
|
||||
cy.get('[col-id="asset.symbol"]', txTimeout).should(
|
||||
'contain.text',
|
||||
btcSymbol
|
||||
);
|
||||
cy.getByTestId('asset', txTimeout).should('contain.text', btcSymbol);
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.get('.ag-cell-value', txTimeout).should('contain.text', btcSymbol);
|
||||
cy.get('[col-id="status"]').should('not.have.text', 'Open', txTimeout);
|
||||
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('[col-id="txHash"]')
|
||||
.should('have.length.above', 2)
|
||||
.eq(1)
|
||||
@@ -120,7 +124,7 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
cy.getByTestId(collateralTab).click();
|
||||
cy.getByTestId('open-transfer').click();
|
||||
cy.getByTestId('open-transfer-dialog').click();
|
||||
cy.getByTestId('transfer-form').should('be.visible');
|
||||
cy.getByTestId('transfer-form').find('[name="toAddress"]').select(1);
|
||||
cy.get('select option')
|
||||
@@ -145,6 +149,7 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
// 1002-WITH-022
|
||||
// 1002-WITH-023
|
||||
// 0003-WTXN-011
|
||||
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
selectAsset(0);
|
||||
@@ -155,9 +160,18 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
'contain.text',
|
||||
'Funds unlocked'
|
||||
);
|
||||
// cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId('tab-withdrawals').within(() => {
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get('[col-id="status"]').should('contain.text', 'Pending');
|
||||
});
|
||||
});
|
||||
|
||||
cy.highlight('withdrawals verification');
|
||||
cy.getByTestId('toast-complete-withdrawal').last().click();
|
||||
cy.getByTestId('toast-complete-withdrawal').click();
|
||||
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
@@ -187,21 +201,19 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
// 0006-NETW-010
|
||||
const market = this.market;
|
||||
cy.visit(`/#/markets/${market.id}`);
|
||||
cy.getByTestId('node-health-trigger').realHover();
|
||||
cy.getByTestId('node-health')
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Operational')
|
||||
.next()
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).hostname)
|
||||
.next()
|
||||
.then(($el) => {
|
||||
const blockHeight = parseInt($el.text());
|
||||
// block height will increase over the course of the test run so best
|
||||
// we can do here is check that its showing something sensible
|
||||
expect(blockHeight).to.be.greaterThan(0);
|
||||
});
|
||||
cy.getByTestId('node-health')
|
||||
.children()
|
||||
.eq(1)
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).hostname);
|
||||
});
|
||||
|
||||
it('can place and receive an order', function () {
|
||||
@@ -216,12 +228,9 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
};
|
||||
const rawPrice = removeDecimal(order.price, market.decimalPlaces);
|
||||
cy.getByTestId(toastCloseBtn, txTimeout).click();
|
||||
|
||||
cy.getByTestId('Collateral').click();
|
||||
cy.get('[col-id="asset.symbol"]', txTimeout).should(
|
||||
'contain.text',
|
||||
usdcSymbol
|
||||
);
|
||||
cy.getByTestId('asset', txTimeout).should('contain.text', usdcSymbol);
|
||||
|
||||
createOrder(order);
|
||||
|
||||
@@ -260,7 +269,10 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
OrderStatusMapping.STATUS_ACTIVE
|
||||
);
|
||||
|
||||
cy.get(`[col-id='${orderRemaining}']`).should('contain.text', '0.00');
|
||||
cy.get(`[col-id='${orderRemaining}']`).should(
|
||||
'contain.text',
|
||||
`0.00/${order.size}`
|
||||
);
|
||||
|
||||
cy.get(`[col-id='${orderPrice}']`).then(($price) => {
|
||||
expect(parseFloat($price.text())).to.equal(parseFloat(order.price));
|
||||
@@ -268,19 +280,17 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
|
||||
cy.get(`[col-id='${orderTimeInForce}']`).should(
|
||||
'contain.text',
|
||||
'GTC'
|
||||
OrderTimeInForceMapping[order.timeInForce]
|
||||
);
|
||||
|
||||
checkIfDataAndTimeOfCreationAndUpdateIsEqual(orderUpdatedAt);
|
||||
checkIfDataAndTimeOfCreationAndUpdateIsEqual(orderCreatedAt);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('can edit order', function () {
|
||||
const market = this.market;
|
||||
cy.visit(`/#/markets/${market.id}`);
|
||||
cy.getByTestId(toastCloseBtn, txTimeout).click();
|
||||
cy.getByTestId(openOrdersTab).click();
|
||||
cy.getByTestId('edit', txTimeout).should('be.visible');
|
||||
cy.getByTestId('edit').first().should('be.visible').click();
|
||||
cy.getByTestId('dialog-title').should('contain.text', 'Edit order');
|
||||
cy.get('#limitPrice').focus().clear().type(newPrice);
|
||||
@@ -308,7 +318,6 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
it('can cancel order', function () {
|
||||
const market = this.market;
|
||||
cy.visit(`/#/markets/${market.id}`);
|
||||
cy.getByTestId(toastCloseBtn, txTimeout).click();
|
||||
cy.getByTestId(openOrdersTab).click();
|
||||
cy.getByTestId('cancel').first().click();
|
||||
cy.getByTestId(toastContent).should(
|
||||
@@ -345,7 +354,7 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId(toastCloseBtn, txTimeout).click();
|
||||
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
@@ -356,6 +365,14 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
'contain.text',
|
||||
'Funds unlocked'
|
||||
);
|
||||
cy.getByTestId('tab-withdrawals').within(() => {
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get('[col-id="status"]').should('contain.text', 'Pending');
|
||||
});
|
||||
});
|
||||
|
||||
cy.highlight('withdrawals verification');
|
||||
cy.getByTestId('toast-complete-withdrawal').click();
|
||||
@@ -403,6 +420,11 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
.eq(0, txTimeout)
|
||||
.should('contain.text', 'Completed');
|
||||
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('[col-id="txHash"]', txTimeout)
|
||||
.should('have.length.above', 1)
|
||||
.eq(1)
|
||||
@@ -432,7 +454,6 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
// 1001-DEPO-007
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId(toastCloseBtn, txTimeout).click();
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
@@ -453,8 +474,8 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
// 1002-WITH-007
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]', txTimeout).should('exist');
|
||||
cy.getByTestId(toastCloseBtn, txTimeout).click();
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
@@ -476,14 +497,16 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
|
||||
cy.highlight('deposit verification');
|
||||
|
||||
cy.get('[col-id="asset.symbol"]', txTimeout).should(
|
||||
'contain.text',
|
||||
vegaSymbol
|
||||
);
|
||||
cy.getByTestId('asset', txTimeout).should('contain.text', vegaSymbol);
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.get('.ag-cell-value', txTimeout).should('contain.text', vegaSymbol);
|
||||
cy.get('[col-id="status"]').should('not.have.text', 'Open', txTimeout);
|
||||
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('[col-id="txHash"]')
|
||||
.should('have.length.above', 2)
|
||||
.eq(1)
|
||||
@@ -512,16 +535,6 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId(completeWithdrawalBtn).first().should('be.visible').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should('contain.text', 'Delayed');
|
||||
cy.getByTestId('tab-withdrawals').within(() => {
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get('[col-id="status"]').contains(
|
||||
/Delayed \(ready in (\d{1,2}:\d{2}:\d{2}:\d{2})\)/
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId('Deposits').click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('MetaMask');
|
||||
cy.wait('@Assets');
|
||||
connectEthereumWallet('MetaMask');
|
||||
}
|
||||
|
||||
before(() => {
|
||||
@@ -102,6 +102,8 @@ describe('deposit actions', { tags: '@smoke' }, () => {
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/markets/market-1');
|
||||
cy.wait('@MarketsCandles');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
});
|
||||
|
||||
it('Deposit to trade is visble', () => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const dialogContent = 'dialog-content';
|
||||
const nodeHealth = 'node-health';
|
||||
const nodeHealthTrigger = 'node-health-trigger';
|
||||
|
||||
describe('home', { tags: '@regression' }, () => {
|
||||
before(() => {
|
||||
@@ -9,23 +8,22 @@ describe('home', { tags: '@regression' }, () => {
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
describe('node health', () => {
|
||||
describe('footer', () => {
|
||||
it('shows current block height', () => {
|
||||
// 0006-NETW-004
|
||||
// 0006-NETW-008
|
||||
// 0006-NETW-009
|
||||
cy.getByTestId(nodeHealthTrigger).realHover();
|
||||
|
||||
cy.getByTestId(nodeHealth)
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Operational', {
|
||||
timeout: 10000,
|
||||
})
|
||||
.next()
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).hostname)
|
||||
.next()
|
||||
.should('contain.text', '100'); // all mocked queries have x-block-height header set to 100
|
||||
cy.getByTestId(nodeHealth)
|
||||
.children()
|
||||
.eq(1)
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).hostname);
|
||||
});
|
||||
|
||||
it('shows node switcher details', () => {
|
||||
@@ -34,7 +32,7 @@ describe('home', { tags: '@regression' }, () => {
|
||||
// 0006-NETW-014
|
||||
// 0006-NETW-015
|
||||
// 0006-NETW-016
|
||||
cy.getByTestId(nodeHealthTrigger).click();
|
||||
cy.getByTestId(nodeHealth).click();
|
||||
cy.getByTestId(dialogContent).should('contain.text', 'Connected node');
|
||||
cy.getByTestId(dialogContent).should(
|
||||
'contain.text',
|
||||
@@ -58,7 +56,7 @@ describe('home', { tags: '@regression' }, () => {
|
||||
// 0006-NETW-018
|
||||
// 0006-NETW-019
|
||||
// 0006-NETW-020
|
||||
cy.getByTestId(nodeHealthTrigger).click();
|
||||
cy.getByTestId(nodeHealth).click();
|
||||
cy.getByTestId('connect').should('be.disabled');
|
||||
cy.getByTestId('node-url-custom').click();
|
||||
cy.getByTestId('connect').should('be.disabled');
|
||||
|
||||
@@ -153,7 +153,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
||||
cy.get(dropdownContent)
|
||||
.find(dropdownContentItem)
|
||||
.eq(2)
|
||||
.should('have.text', 'View settlement asset details');
|
||||
.should('have.text', 'View asset');
|
||||
cy.getByTestId('market-actions-content').click();
|
||||
});
|
||||
|
||||
|
||||
@@ -68,15 +68,14 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
|
||||
validateMarketDataRow(0, 'Name', 'BTCUSD Monthly (30 Jun 2022)');
|
||||
validateMarketDataRow(1, 'Market ID', 'market-0');
|
||||
validateMarketDataRow(2, 'Parent Market ID', 'market-1');
|
||||
validateMarketDataRow(
|
||||
3,
|
||||
2,
|
||||
'Trading Mode',
|
||||
MarketTradingModeMapping.TRADING_MODE_CONTINUOUS
|
||||
);
|
||||
validateMarketDataRow(4, 'Market Decimal Places', '5');
|
||||
validateMarketDataRow(5, 'Position Decimal Places', '0');
|
||||
validateMarketDataRow(6, 'Settlement Asset Decimal Places', '5');
|
||||
validateMarketDataRow(3, 'Market Decimal Places', '5');
|
||||
validateMarketDataRow(4, 'Position Decimal Places', '0');
|
||||
validateMarketDataRow(5, 'Settlement Asset Decimal Places', '5');
|
||||
});
|
||||
|
||||
it('instrument displayed', () => {
|
||||
|
||||
@@ -132,10 +132,9 @@ describe('liquidity table view', { tags: '@smoke' }, () => {
|
||||
it('can see header title', () => {
|
||||
// 5002-LIQP-004
|
||||
// 5002-LIQP-005
|
||||
cy.getByTestId('header-title').should(
|
||||
'contain.text',
|
||||
'BTCUSD.MF21 liquidity provision'
|
||||
);
|
||||
cy.getByTestId('header-title')
|
||||
.should('contain.text', 'BTCUSD.MF21 liquidity provision')
|
||||
.and('contain.text', 'Go to trading');
|
||||
});
|
||||
|
||||
it('can see target stake', () => {
|
||||
@@ -172,7 +171,7 @@ describe('liquidity table view', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId('liquidity-supplied').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Liquidity supplied');
|
||||
cy.getByTestId('indicator').should('be.visible');
|
||||
cy.getByTestId(itemValue).should('have.text', ' 0.10%').realHover();
|
||||
cy.getByTestId(itemValue).should('have.text', '0.10%').realHover();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,12 +22,15 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
|
||||
cy.wait('@Markets');
|
||||
cy.wait('@MarketsData');
|
||||
cy.wait('@MarketsCandles');
|
||||
});
|
||||
|
||||
// 6001-MARK-066
|
||||
it('can open popover to view markets', () => {
|
||||
it('can toggle the sidebar', () => {
|
||||
cy.getByTestId('market-selector').should('be.visible');
|
||||
cy.getByTestId('sidebar-toggle').click();
|
||||
cy.getByTestId('market-selector').should('not.exist');
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
cy.getByTestId('sidebar-toggle').click();
|
||||
cy.getByTestId('market-selector').should('be.visible');
|
||||
});
|
||||
|
||||
@@ -37,30 +40,29 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
const data = [
|
||||
{
|
||||
code: 'SOLUSD',
|
||||
markPrice: 'XYZalpha84.41',
|
||||
markPrice: '84.41XYZalpha',
|
||||
change: '',
|
||||
vol: '24h vol0.00',
|
||||
vol: '0.0024h vol',
|
||||
},
|
||||
{
|
||||
code: 'ETHBTC.QM21',
|
||||
markPrice: 'tBTC46,126.90058',
|
||||
markPrice: '46,126.90058tBTC',
|
||||
change: '',
|
||||
vol: '24h vol0.00',
|
||||
vol: '0.0024h vol',
|
||||
},
|
||||
{
|
||||
code: 'BTCUSD.MF21',
|
||||
markPrice: 'tDAI46,126.90058',
|
||||
markPrice: '46,126.90058tDAI',
|
||||
change: '',
|
||||
vol: '24h vol0.00',
|
||||
vol: '0.0024h vol',
|
||||
},
|
||||
{
|
||||
code: 'AAPL.MF21',
|
||||
markPrice: 'tUSDC46,126.90058',
|
||||
markPrice: '46,126.90058tUSDC',
|
||||
change: '',
|
||||
vol: '24h vol0.00',
|
||||
vol: '0.0024h vol',
|
||||
},
|
||||
];
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
cy.getByTestId(list)
|
||||
.find('a')
|
||||
.each((item, i) => {
|
||||
@@ -84,9 +86,18 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('can use the filter options', () => {
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
it('can see all markets link', () => {
|
||||
// 6001-MARK-026
|
||||
cy.getByTestId('market-selector').within(() => {
|
||||
cy.getByTestId('all-markets-link')
|
||||
.should('be.visible')
|
||||
.and('have.text', 'All markets')
|
||||
.and('have.attr', 'href')
|
||||
.and('contain', '#/markets/all');
|
||||
});
|
||||
});
|
||||
|
||||
it('can use the filter options', () => {
|
||||
// 6001-MARK-027
|
||||
// product type
|
||||
cy.getByTestId('product-Spot').click();
|
||||
@@ -107,8 +118,6 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('can sort by by top gaining and top losing market', () => {
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
|
||||
// 6001-MARK-030
|
||||
// 6001-MARK-031
|
||||
// 6001-MARK-032
|
||||
@@ -126,8 +135,6 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('can filter by settlement asset', () => {
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
|
||||
// 6001-MARK-028
|
||||
cy.getByTestId('asset-trigger').click();
|
||||
cy.getByTestId('asset-id-asset-3').contains('tBTC').click();
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
describe('market bottom panel', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.clearAllLocalStorage();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@MarketData');
|
||||
});
|
||||
|
||||
it('on xxl screen should be splitted out into two tables', () => {
|
||||
cy.getByTestId('tab-positions').should('have.attr', 'data-state', 'active');
|
||||
cy.getByTestId('tab-open-orders').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'inactive'
|
||||
);
|
||||
cy.getByTestId('tab-closed-orders').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'inactive'
|
||||
);
|
||||
cy.getByTestId('tab-rejected-orders').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'inactive'
|
||||
);
|
||||
cy.getByTestId('tab-orders').should('have.attr', 'data-state', 'inactive');
|
||||
cy.getByTestId('tab-fills').should('have.attr', 'data-state', 'inactive');
|
||||
cy.getByTestId('tab-accounts').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'inactive'
|
||||
);
|
||||
|
||||
cy.viewport(1801, 1000);
|
||||
cy.getByTestId('tab-positions').should('have.attr', 'data-state', 'active');
|
||||
cy.getByTestId('tab-open-orders').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'inactive'
|
||||
);
|
||||
cy.getByTestId('tab-closed-orders').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'inactive'
|
||||
);
|
||||
cy.getByTestId('tab-rejected-orders').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'inactive'
|
||||
);
|
||||
cy.getByTestId('tab-orders').should('have.attr', 'data-state', 'inactive');
|
||||
cy.getByTestId('tab-fills').should('have.attr', 'data-state', 'inactive');
|
||||
cy.getByTestId('tab-accounts').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'inactive'
|
||||
);
|
||||
|
||||
cy.getByTestId('Fills').click();
|
||||
cy.getByTestId('Collateral').click();
|
||||
cy.getByTestId('tab-positions').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'inactive'
|
||||
);
|
||||
cy.getByTestId('tab-orders').should('have.attr', 'data-state', 'inactive');
|
||||
cy.getByTestId('tab-fills').should('have.attr', 'data-state', 'active');
|
||||
cy.getByTestId('tab-accounts').should('have.attr', 'data-state', 'active');
|
||||
});
|
||||
});
|
||||
@@ -137,6 +137,11 @@ describe('Market trading page', () => {
|
||||
.realHover();
|
||||
});
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(expirtyTooltip)
|
||||
.eq(0)
|
||||
.should(
|
||||
@@ -170,6 +175,11 @@ describe('Market trading page', () => {
|
||||
.realHover();
|
||||
});
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(tradingModeTooltip)
|
||||
.should(
|
||||
'contain.text',
|
||||
@@ -196,6 +206,11 @@ describe('Market trading page', () => {
|
||||
cy.getByTestId(itemValue).realHover();
|
||||
});
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId(liquiditySuppliedTooltip)
|
||||
.should('contain.text', 'Supplied stake')
|
||||
.and('contain.text', 'Target stake')
|
||||
|
||||
@@ -99,6 +99,9 @@ describe('Navbar', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId('menu-drawer').should('not.be.visible');
|
||||
cy.getByTestId('button-menu-drawer').click();
|
||||
cy.getByTestId('menu-drawer').should('be.visible');
|
||||
cy.getByTestId('menu-drawer')
|
||||
.find('[data-testid="Settings"]')
|
||||
.should('be.visible');
|
||||
cy.getByTestId('button-menu-drawer').click();
|
||||
cy.getByTestId('menu-drawer').should('not.be.visible');
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const orderbookTab = 'Orderbook';
|
||||
const orderbookTable = 'tab-orderbook';
|
||||
const askPrice = 'price-9894185';
|
||||
const askPrice = 'price-9894585';
|
||||
const bidPrice = 'price-9889001';
|
||||
const askVolume = 'ask-vol-9894185';
|
||||
const askVolume = 'ask-vol-9894585';
|
||||
const bidVolume = 'bid-vol-9889001';
|
||||
const askCumulative = 'cumulative-vol-9894185';
|
||||
const askCumulative = 'cumulative-vol-9894585';
|
||||
const bidCumulative = 'cumulative-vol-9889001';
|
||||
const midPrice = 'middle-mark-price-4612690000';
|
||||
const priceResolution = 'resolution';
|
||||
@@ -33,7 +33,7 @@ describe('order book', { tags: '@smoke' }, () => {
|
||||
|
||||
it('show orders prices', () => {
|
||||
// 6003-ORDB-003
|
||||
cy.getByTestId(askPrice).should('have.text', '98.94185');
|
||||
cy.getByTestId(askPrice).should('have.text', '98.94585');
|
||||
cy.getByTestId(bidPrice).should('have.text', '98.89001');
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('order book', { tags: '@smoke' }, () => {
|
||||
|
||||
it('show prices cumulative volumes', () => {
|
||||
// 6003-ORDB-005
|
||||
cy.getByTestId(askCumulative).should('have.text', '38');
|
||||
cy.getByTestId(askCumulative).should('have.text', '39');
|
||||
cy.getByTestId(bidCumulative).should('have.text', '7');
|
||||
});
|
||||
|
||||
@@ -71,7 +71,7 @@ describe('order book', { tags: '@smoke' }, () => {
|
||||
it('copy price to deal ticket form', () => {
|
||||
// 6003-ORDB-009
|
||||
cy.getByTestId(askPrice).click();
|
||||
cy.getByTestId(dealTicketPrice).should('have.value', '98.94185');
|
||||
cy.getByTestId(dealTicketPrice).should('have.value', '98.94585');
|
||||
});
|
||||
|
||||
it('change price resolution', () => {
|
||||
|
||||
@@ -1,29 +1,42 @@
|
||||
describe('Settings page', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
|
||||
// Only click if not already active otherwise sidebar will close
|
||||
cy.get('[data-testid="sidebar-content"]').then(($sidebarContent) => {
|
||||
if ($sidebarContent.find('h2').text() !== 'Settings') {
|
||||
cy.get('[data-testid="sidebar"] [data-testid="Settings"]').click();
|
||||
}
|
||||
cy.clearLocalStorage().then(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
cy.get('[aria-label="cog icon"]').click();
|
||||
});
|
||||
});
|
||||
|
||||
it('telemetry checkbox should work well', () => {
|
||||
const telemetrySwitch = '#switch-settings-telemetry-switch';
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked');
|
||||
cy.get(telemetrySwitch).click();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'checked');
|
||||
cy.location('hash').should('equal', '#/settings');
|
||||
cy.getByTestId('telemetry-approval').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'unchecked'
|
||||
);
|
||||
cy.get('[for="telemetry-approval"]').click();
|
||||
cy.getByTestId('telemetry-approval').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'checked'
|
||||
);
|
||||
cy.reload();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'checked');
|
||||
cy.get(telemetrySwitch).click();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked');
|
||||
cy.getByTestId('telemetry-approval').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'checked'
|
||||
);
|
||||
cy.get('[for="telemetry-approval"]').click();
|
||||
cy.getByTestId('telemetry-approval').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'unchecked'
|
||||
);
|
||||
cy.reload();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked');
|
||||
cy.getByTestId('telemetry-approval').should(
|
||||
'have.attr',
|
||||
'data-state',
|
||||
'unchecked'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ describe(
|
||||
'account validation',
|
||||
{ tags: '@regression', testIsolation: true },
|
||||
() => {
|
||||
describe.skip('zero balance error', () => {
|
||||
describe('zero balance error', () => {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
@@ -74,8 +74,8 @@ describe(
|
||||
'You may not have enough margin available to open this position. 5.00 tDAI is currently required. You have only 0.01001 tDAI available.'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-deposit-dialog-button').click();
|
||||
cy.getByTestId('sidebar-content')
|
||||
.find('h2')
|
||||
cy.getByTestId('dialog-content')
|
||||
.find('h1')
|
||||
.eq(0)
|
||||
.should('have.text', 'Deposit');
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ const orderStatus = 'status';
|
||||
const orderRemaining = 'remaining';
|
||||
const orderPrice = 'price';
|
||||
const orderTimeInForce = 'timeInForce';
|
||||
const orderUpdatedAt = 'updatedAt';
|
||||
const orderCreatedAt = 'createdAt';
|
||||
const cancelOrderBtn = 'cancel';
|
||||
const cancelAllOrdersBtn = 'cancelAll';
|
||||
const editOrderBtn = 'edit';
|
||||
@@ -46,10 +46,6 @@ describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
|
||||
cy.wrap($symbol).invoke('text').should('not.be.empty');
|
||||
});
|
||||
|
||||
cy.get(`[col-id='${orderRemaining}']`).each(($remaining) => {
|
||||
cy.wrap($remaining).invoke('text').should('not.be.empty');
|
||||
});
|
||||
|
||||
cy.get(`[col-id='${orderSize}']`).each(($size) => {
|
||||
cy.wrap($size).invoke('text').should('not.be.empty');
|
||||
});
|
||||
@@ -62,6 +58,10 @@ describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
|
||||
cy.wrap($status).invoke('text').should('not.be.empty');
|
||||
});
|
||||
|
||||
cy.get(`[col-id='${orderRemaining}']`).each(($remaining) => {
|
||||
cy.wrap($remaining).invoke('text').should('not.be.empty');
|
||||
});
|
||||
|
||||
cy.get(`[col-id='${orderPrice}']`).each(($price) => {
|
||||
cy.wrap($price).invoke('text').should('not.be.empty');
|
||||
});
|
||||
@@ -70,7 +70,7 @@ describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
|
||||
cy.wrap($timeInForce).invoke('text').should('not.be.empty');
|
||||
});
|
||||
|
||||
cy.get(`[col-id='${orderUpdatedAt}']`).each(($dateTime) => {
|
||||
cy.get(`[col-id='${orderCreatedAt}']`).each(($dateTime) => {
|
||||
cy.wrap($dateTime).invoke('text').should('not.be.empty');
|
||||
});
|
||||
});
|
||||
@@ -96,8 +96,7 @@ describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
|
||||
'have.text',
|
||||
'Partially Filled'
|
||||
);
|
||||
cy.get(`[col-id='${orderRemaining}']`).should('have.text', '7');
|
||||
cy.get(`[col-id='${orderSize}']`).should('have.text', '-10');
|
||||
cy.get(`[col-id='${orderRemaining}']`).should('have.text', '7/10');
|
||||
cy.getByTestId(cancelOrderBtn).should('not.exist');
|
||||
cy.getByTestId(editOrderBtn).should('not.exist');
|
||||
});
|
||||
@@ -119,6 +118,11 @@ describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
|
||||
cy.contains('Reset').click();
|
||||
cy.getByTestId('All').click();
|
||||
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.getByTestId('tab-orders')
|
||||
.get(`.ag-center-cols-container [col-id='${orderSymbol}']`)
|
||||
.should('have.length.at.least', expectedOrderList.length)
|
||||
@@ -215,7 +219,7 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId(`order-status-${orderId}`)
|
||||
.parentsUntil(`.ag-row`)
|
||||
.siblings(`[col-id=${orderRemaining}]`)
|
||||
.should('have.text', '4');
|
||||
.should('have.text', '4/5');
|
||||
});
|
||||
|
||||
it('must see a filled order', () => {
|
||||
@@ -263,7 +267,7 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
});
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find(`[col-id="${orderSize}"]`)
|
||||
.find('[col-id="size"]')
|
||||
.should('have.text', '-15');
|
||||
});
|
||||
|
||||
@@ -277,7 +281,7 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
});
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find(`[col-id="${orderSize}"]`)
|
||||
.find('[col-id="size"]')
|
||||
.should('have.text', '+5');
|
||||
});
|
||||
|
||||
@@ -360,7 +364,7 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
|
||||
});
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find(`[col-id='${orderTimeInForce}']`)
|
||||
.should('have.text', 'GTC');
|
||||
.should('have.text', "Good 'til Cancelled (GTC)");
|
||||
});
|
||||
|
||||
it('for Active order when is part of a liquidity or peg shape, must not see an option to amend the individual order ', () => {
|
||||
@@ -431,8 +435,6 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
const orderId = '1234567890';
|
||||
|
||||
// this test is flakey
|
||||
it('must be able to amend the price of an order', () => {
|
||||
// 7003-MORD-007
|
||||
// 7003-MORD-012
|
||||
@@ -444,6 +446,11 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
peggedOrder: null,
|
||||
liquidityProvisionId: null,
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find('[data-testid="edit"]')
|
||||
.should('have.text', 'Edit')
|
||||
@@ -473,6 +480,11 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
peggedOrder: null,
|
||||
liquidityProvisionId: null,
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find(`[data-testid="cancel"]`)
|
||||
.should('have.text', 'Cancel')
|
||||
@@ -495,6 +507,11 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
peggedOrder: null,
|
||||
liquidityProvisionId: null,
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(`[data-testid="cancelAll"]`)
|
||||
.should('have.text', 'Cancel all')
|
||||
.then(($btn) => {
|
||||
@@ -511,6 +528,11 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
peggedOrder: null,
|
||||
liquidityProvisionId: null,
|
||||
});
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find('[data-testid="edit"]')
|
||||
.should('have.text', 'Edit')
|
||||
|
||||
@@ -47,6 +47,11 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
|
||||
cy.get(
|
||||
'[role="columnheader"][col-id="fromAccountType"] .ag-header-cell-menu-button'
|
||||
).click();
|
||||
/**
|
||||
* TODO(@nx/cypress): Nesting Cypress commands in a should assertion now throws.
|
||||
* You should use .then() to chain commands instead.
|
||||
* More Info: https://docs.cypress.io/guides/references/migration-guide#-should
|
||||
**/
|
||||
cy.get('fieldset.ag-simple-filter-body-wrapper')
|
||||
.should('be.visible')
|
||||
.within((fields) => {
|
||||
|
||||
@@ -267,22 +267,22 @@ describe('positions', { tags: '@regression', testIsolation: true }, () => {
|
||||
cy.get('.ag-center-cols-container').within(() => {
|
||||
assertPNLColor(
|
||||
'[col-id="realisedPNL"]',
|
||||
'text-market-green-600',
|
||||
'text-market-red'
|
||||
'text-vega-green',
|
||||
'text-vega-pink'
|
||||
);
|
||||
});
|
||||
cy.get('.ag-center-cols-container').within(() => {
|
||||
assertPNLColor(
|
||||
'[col-id="unrealisedPNL"]',
|
||||
'text-market-green-600',
|
||||
'text-market-red'
|
||||
'text-vega-green',
|
||||
'text-vega-pink'
|
||||
);
|
||||
});
|
||||
cy.get('.ag-center-cols-container').within(() => {
|
||||
assertPNLColor(
|
||||
'[col-id="openVolume"]',
|
||||
'text-market-green-600',
|
||||
'text-market-red'
|
||||
'text-vega-green',
|
||||
'text-vega-pink'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,7 +10,6 @@ describe('trades', { tags: '@smoke' }, () => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
});
|
||||
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
@@ -28,50 +27,37 @@ describe('trades', { tags: '@smoke' }, () => {
|
||||
|
||||
it('show trades prices', () => {
|
||||
// 6005-THIS-003
|
||||
cy.getByTestId(tradesTable)
|
||||
.get(`${colIdPrice} ${colHeader}`)
|
||||
.first()
|
||||
.should('have.text', 'Price');
|
||||
cy.getByTestId(tradesTable)
|
||||
.get(colIdPrice)
|
||||
.each(($tradePrice) => {
|
||||
cy.wrap($tradePrice).invoke('text').should('not.be.empty');
|
||||
});
|
||||
cy.get(`${colIdPrice} ${colHeader}`).first().should('have.text', 'Price');
|
||||
cy.get(colIdPrice).each(($tradePrice) => {
|
||||
cy.wrap($tradePrice).invoke('text').should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('show trades sizes', () => {
|
||||
// 6005-THIS-004
|
||||
cy.getByTestId(tradesTable)
|
||||
.get(`${colIdSize} ${colHeader}`)
|
||||
.first()
|
||||
.should('have.text', 'Size');
|
||||
cy.getByTestId(tradesTable)
|
||||
.get(colIdSize)
|
||||
.each(($tradeSize) => {
|
||||
cy.wrap($tradeSize).invoke('text').should('not.be.empty');
|
||||
});
|
||||
cy.get(`${colIdSize} ${colHeader}`).first().should('have.text', 'Size');
|
||||
cy.get(colIdSize).each(($tradeSize) => {
|
||||
cy.wrap($tradeSize).invoke('text').should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
// This won't pass in CI, but does locally
|
||||
it.skip('show trades date and time', () => {
|
||||
it('show trades date and time', () => {
|
||||
// 6005-THIS-005
|
||||
cy.getByTestId(tradesTable) // order table shares identical col id
|
||||
.find(`${colIdCreatedAt} ${colHeader}`)
|
||||
.should('have.text', 'Created at');
|
||||
cy.get(`${colIdCreatedAt} ${colHeader}`).should('have.text', 'Created at');
|
||||
const dateTimeRegex =
|
||||
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
|
||||
cy.getByTestId(tradesTable)
|
||||
.get(`.ag-center-cols-container ${colIdCreatedAt}`)
|
||||
.each(($tradeDateTime) => {
|
||||
cy.get(colIdCreatedAt).each(($tradeDateTime, index) => {
|
||||
if (index != 0) {
|
||||
//ignore header
|
||||
cy.wrap($tradeDateTime).invoke('text').should('match', dateTimeRegex);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('trades are sorted descending by datetime', () => {
|
||||
// 6005-THIS-006
|
||||
const dateTimes: Date[] = [];
|
||||
cy.getByTestId(tradesTable)
|
||||
.find(colIdCreatedAt)
|
||||
cy.get(colIdCreatedAt)
|
||||
.each(($tradeDateTime, index) => {
|
||||
if (index != 0) {
|
||||
//ignore header
|
||||
@@ -85,15 +71,9 @@ describe('trades', { tags: '@smoke' }, () => {
|
||||
});
|
||||
});
|
||||
|
||||
// this passes locally but doesn't in CI
|
||||
it.skip('copy price to deal ticket form', () => {
|
||||
cy.getByTestId('order-type-TYPE_LIMIT').click(); // make sure on limit
|
||||
it('copy price to deal ticket form', () => {
|
||||
// 6005-THIS-007
|
||||
cy.getByTestId(tradesTable)
|
||||
.find(colIdPrice)
|
||||
.last()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get(colIdPrice).last().should('be.visible').click();
|
||||
cy.getByTestId('order-price').should('have.value', '171.16898');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -63,7 +63,7 @@ describe(
|
||||
cy.contains('Hosted Fairground wallet');
|
||||
|
||||
cy.getByTestId('connectors-list')
|
||||
.find('[data-testid="connector-rest"]')
|
||||
.find('[data-testid="connector-hosted"]')
|
||||
.click();
|
||||
cy.getByTestId(form).find('#wallet').click().type('user');
|
||||
cy.getByTestId(form).find('#passphrase').click().type('pass');
|
||||
@@ -89,7 +89,7 @@ describe(
|
||||
);
|
||||
cy.getByTestId(connectVegaBtn).click();
|
||||
cy.getByTestId('connectors-list')
|
||||
.find('[data-testid="connector-rest"]')
|
||||
.find('[data-testid="connector-hosted"]')
|
||||
.click();
|
||||
cy.getByTestId(form).find('#wallet').click().type('invalid name');
|
||||
cy.getByTestId(form).find('#passphrase').click().type('invalid password');
|
||||
@@ -100,7 +100,7 @@ describe(
|
||||
it('doesnt connect with empty fields', () => {
|
||||
cy.getByTestId(connectVegaBtn).click();
|
||||
cy.getByTestId('connectors-list')
|
||||
.find('[data-testid="connector-rest"]')
|
||||
.find('[data-testid="connector-hosted"]')
|
||||
.click();
|
||||
|
||||
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
|
||||
|
||||
@@ -5,16 +5,20 @@ const amountShortName = 'input[name="amount"] + div + span.text-xs';
|
||||
const assetSelection = 'select-asset';
|
||||
const assetBalance = 'asset-balance';
|
||||
const assetOption = 'rich-select-option';
|
||||
const transferText = 'transfer-intro-text';
|
||||
const closeDialog = 'dialog-close';
|
||||
const dialogTitle = 'dialog-title';
|
||||
const dialogTransferText = 'dialog-transfer-text';
|
||||
const dropdownMenu = 'dropdown-menu';
|
||||
const errorText = 'input-error-text';
|
||||
const formFieldError = 'input-error-text';
|
||||
const includeTransferFeeRadioBtn = 'include-transfer-fee';
|
||||
const keyID = `[data-testid="${transferText}"] > .rounded-md`;
|
||||
const keyID = '[data-testid="dialog-transfer-text"] > .rounded-md';
|
||||
const manageVegaWallet = 'manage-vega-wallet';
|
||||
const openTransferButton = 'open-transfer';
|
||||
const openTransferDialog = 'open-transfer-dialog';
|
||||
const submitTransferBtn = '[type="submit"]';
|
||||
const toAddressField = '[name="toAddress"]';
|
||||
const totalTransferfee = 'total-transfer-fee';
|
||||
const transfer = 'transfer';
|
||||
const transferAmount = 'transfer-amount';
|
||||
const transferForm = 'transfer-form';
|
||||
const transferFee = 'transfer-fee';
|
||||
@@ -35,18 +39,14 @@ describe('transfer fees', { tags: '@regression', testIsolation: true }, () => {
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
|
||||
cy.visit('/');
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId('Trading').first().click();
|
||||
cy.getByTestId(collateralTab).click();
|
||||
cy.getByTestId(dropdownMenu).first().click();
|
||||
cy.getByTestId(transfer).click();
|
||||
|
||||
// Only click if not already active otherwise sidebar will close
|
||||
cy.get('[data-testid="sidebar-content"]').then(($sidebarContent) => {
|
||||
if ($sidebarContent.find('h2').text() !== 'Transfer') {
|
||||
cy.get('[data-testid="sidebar"] [data-testid="Transfer"]').click();
|
||||
}
|
||||
});
|
||||
|
||||
cy.wait('@Assets');
|
||||
cy.wait('@Accounts');
|
||||
|
||||
cy.wait('@Assets');
|
||||
cy.mockVegaWalletTransaction();
|
||||
});
|
||||
|
||||
@@ -72,18 +72,21 @@ describe('transfer fees', { tags: '@regression', testIsolation: true }, () => {
|
||||
cy.get('[data-side="bottom"] div')
|
||||
.should('be.visible')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId(dialogTitle).click();
|
||||
|
||||
//Check Transfer Fee tooltip
|
||||
cy.contains('div', 'Transfer fee').realHover();
|
||||
cy.get('[data-side="bottom"] div')
|
||||
.should('be.visible')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId(dialogTitle).click();
|
||||
|
||||
//Check Amount to be transferred tooltip
|
||||
cy.contains('div', 'Amount to be transferred').realHover();
|
||||
cy.get('[data-side="bottom"] div')
|
||||
.should('be.visible')
|
||||
.should('not.be.empty');
|
||||
cy.getByTestId(dialogTitle).click();
|
||||
|
||||
//Check Total amount (with fee) tooltip
|
||||
cy.contains('div', 'Total amount (with fee)').realHover();
|
||||
@@ -131,7 +134,6 @@ describe('transfer fees', { tags: '@regression', testIsolation: true }, () => {
|
||||
.should('contain.text', '1.00');
|
||||
});
|
||||
});
|
||||
|
||||
describe(
|
||||
'transfer form validation',
|
||||
{ tags: '@regression', testIsolation: true },
|
||||
@@ -152,7 +154,7 @@ describe(
|
||||
|
||||
it('transfer Text', () => {
|
||||
// 1003-TRAN-003
|
||||
cy.getByTestId(transferText)
|
||||
cy.getByTestId(dialogTransferText)
|
||||
.should('exist')
|
||||
.get(keyID)
|
||||
.invoke('text')
|
||||
@@ -202,6 +204,7 @@ describe(
|
||||
'contain.text',
|
||||
'You cannot transfer more than your available collateral'
|
||||
);
|
||||
cy.getByTestId(closeDialog).click();
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -214,7 +217,7 @@ describe('withdraw actions', { tags: '@smoke', testIsolation: true }, () => {
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId(collateralTab).click();
|
||||
cy.getByTestId(openTransferButton).click();
|
||||
cy.getByTestId(openTransferDialog).click();
|
||||
|
||||
cy.wait('@Accounts');
|
||||
cy.wait('@Assets');
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('withdraw form validation', { tags: '@smoke' }, () => {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
|
||||
cy.getByTestId('Withdraw').click(); // sidebar item
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
|
||||
// It also requires connection Ethereum wallet
|
||||
connectEthereumWallet('MetaMask');
|
||||
@@ -87,17 +87,15 @@ describe(
|
||||
cy.setVegaWallet();
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
|
||||
cy.wait('@Accounts');
|
||||
cy.wait('@Assets');
|
||||
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
|
||||
cy.getByTestId('Withdraw').click();
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
|
||||
// It also requires connection Ethereum wallet
|
||||
connectEthereumWallet('MetaMask');
|
||||
|
||||
cy.wait('@Accounts');
|
||||
cy.wait('@Assets');
|
||||
cy.mockVegaWalletTransaction();
|
||||
});
|
||||
|
||||
|
||||
@@ -14,4 +14,4 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||
# TAG name of the current app version - TODO: bump to the latest upon release
|
||||
NX_APP_VERSION=v0.20.21-core-0.71.6
|
||||
NX_APP_VERSION=v0.20.19-core-0.71.6
|
||||
|
||||
@@ -11,7 +11,7 @@ cp .env.[environment] .env.local
|
||||
Starting the app:
|
||||
|
||||
```bash
|
||||
yarn nx serve trading
|
||||
yarn nx serve explorer
|
||||
```
|
||||
|
||||
### Configuration
|
||||
@@ -26,7 +26,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\trading\.env.{env} yarn nx run trading:serve # e.g. stagnet1
|
||||
yarn env-cmd -f .\apps\token\.env.{env} yarn nx run token:serve # e.g. stagnet1
|
||||
```
|
||||
|
||||
There are a few different configuration options offered for this app:
|
||||
|
||||
@@ -14,13 +14,20 @@ import {
|
||||
useNetworkParams,
|
||||
} from '@vegaprotocol/network-parameters';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { Tab, Tabs, Indicator, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
Tab,
|
||||
Tabs,
|
||||
Link as UiToolkitLink,
|
||||
Indicator,
|
||||
ExternalLink,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { memo, useEffect, useState } from 'react';
|
||||
|
||||
import { Header, HeaderStat, HeaderTitle } from '../../components/header';
|
||||
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
|
||||
import { useMarket, useStaticMarketData } from '@vegaprotocol/markets';
|
||||
import { DocsLinks } from '@vegaprotocol/environment';
|
||||
@@ -64,15 +71,19 @@ const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
|
||||
return (
|
||||
<Header
|
||||
title={
|
||||
market?.tradableInstrument.instrument.name &&
|
||||
market?.tradableInstrument.instrument.code &&
|
||||
marketId && (
|
||||
<HeaderTitle>
|
||||
{market.tradableInstrument.instrument.code &&
|
||||
t(
|
||||
'%s liquidity provision',
|
||||
market.tradableInstrument.instrument.code
|
||||
)}
|
||||
</HeaderTitle>
|
||||
<HeaderTitle
|
||||
primaryContent={`${market.tradableInstrument.instrument.code} ${t(
|
||||
'liquidity provision'
|
||||
)}`}
|
||||
secondaryContent={
|
||||
<Link to={Links[Routes.MARKET](marketId)}>
|
||||
<UiToolkitLink>{t('Go to trading')}</UiToolkitLink>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -105,7 +116,9 @@ const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
|
||||
</div>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Liquidity supplied')} testId="liquidity-supplied">
|
||||
<Indicator variant={status} /> {formatNumberPercentage(percentage, 2)}
|
||||
<Indicator variant={status} />
|
||||
|
||||
{formatNumberPercentage(percentage, 2)}
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Market ID')} testId="liquidity-market-id">
|
||||
<div className="break-word">{marketId}</div>
|
||||
@@ -156,34 +169,24 @@ export const LiquidityViewContainer = ({
|
||||
return (
|
||||
<div className="h-full grid grid-rows-[min-content_1fr]">
|
||||
<LiquidityViewHeader marketId={marketId} />
|
||||
<div className="p-1">
|
||||
<div className="h-full border border-default">
|
||||
<Tabs value={tab || LiquidityTabs.Active} onValueChange={setTab}>
|
||||
<Tab
|
||||
id={LiquidityTabs.MyLiquidityProvision}
|
||||
name={t('My liquidity provision')}
|
||||
hidden={!pubKey}
|
||||
>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ partyId: pubKey || undefined }}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Active} name={t('Active')}>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ active: true }}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ active: false }}
|
||||
/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs value={tab || LiquidityTabs.Active} onValueChange={setTab}>
|
||||
<Tab
|
||||
id={LiquidityTabs.MyLiquidityProvision}
|
||||
name={t('My liquidity provision')}
|
||||
hidden={!pubKey}
|
||||
>
|
||||
<LiquidityContainer
|
||||
marketId={marketId}
|
||||
filter={{ partyId: pubKey || undefined }}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Active} name={t('Active')}>
|
||||
<LiquidityContainer marketId={marketId} filter={{ active: true }} />
|
||||
</Tab>
|
||||
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
||||
<LiquidityContainer marketId={marketId} filter={{ active: false }} />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,15 +9,13 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
type Assets = Array<{ id: string; symbol: string }>;
|
||||
|
||||
export const AssetDropdown = ({
|
||||
assets,
|
||||
checkedAssets,
|
||||
onSelect,
|
||||
onReset,
|
||||
}: {
|
||||
assets: Assets | undefined;
|
||||
assets: Array<{ id: string; symbol: string }> | undefined;
|
||||
checkedAssets: string[];
|
||||
onSelect: (id: string, checked: boolean) => void;
|
||||
onReset: () => void;
|
||||
@@ -30,7 +28,7 @@ export const AssetDropdown = ({
|
||||
<DropdownMenu
|
||||
trigger={
|
||||
<DropdownMenuTrigger data-testid="asset-trigger">
|
||||
<TriggerText assets={assets} checkedAssets={checkedAssets} />
|
||||
<span className="px-1">$</span>
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
@@ -58,23 +56,3 @@ export const AssetDropdown = ({
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
|
||||
const TriggerText = ({
|
||||
assets,
|
||||
checkedAssets,
|
||||
}: {
|
||||
assets: Assets;
|
||||
checkedAssets: string[];
|
||||
}) => {
|
||||
let text = t('Asset');
|
||||
|
||||
if (checkedAssets.length === 1) {
|
||||
const assetId = checkedAssets[0];
|
||||
const asset = assets.find((a) => a.id === assetId);
|
||||
text = asset ? asset.symbol : t('Asset (1)');
|
||||
} else if (checkedAssets.length > 1) {
|
||||
text = t(`Asset (${checkedAssets.length})`);
|
||||
}
|
||||
|
||||
return <span className="px-1">{text}</span>;
|
||||
};
|
||||
|
||||
+70
-63
@@ -5,85 +5,92 @@ import { MarketProposalNotification } from '@vegaprotocol/proposals';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import { getExpiryDate, getMarketExpiryDate } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Last24hPriceChange, Last24hVolume } from '@vegaprotocol/markets';
|
||||
import { MarketState as State } from '@vegaprotocol/types';
|
||||
import { HeaderStat } from '../../components/header';
|
||||
import { MarketMarkPrice } from '../../components/market-mark-price';
|
||||
import { HeaderStatMarketTradingMode } from '../../components/market-trading-mode';
|
||||
import { Last24hPriceChange, Last24hVolume } from '@vegaprotocol/markets';
|
||||
import { MarketState } from '../../components/market-state';
|
||||
import { HeaderStatMarketTradingMode } from '../../components/market-trading-mode';
|
||||
import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
|
||||
import { MarketState as State } from '@vegaprotocol/types';
|
||||
|
||||
interface MarketHeaderStatsProps {
|
||||
interface HeaderStatsProps {
|
||||
market: Market | null;
|
||||
}
|
||||
|
||||
export const MarketHeaderStats = ({ market }: MarketHeaderStatsProps) => {
|
||||
export const HeaderStats = ({ market }: HeaderStatsProps) => {
|
||||
const { VEGA_EXPLORER_URL } = useEnvironment();
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
|
||||
const asset = market?.tradableInstrument.instrument.product?.settlementAsset;
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeaderStat
|
||||
heading={t('Expiry')}
|
||||
description={
|
||||
market && (
|
||||
<ExpiryTooltipContent
|
||||
market={market}
|
||||
explorerUrl={VEGA_EXPLORER_URL}
|
||||
/>
|
||||
)
|
||||
}
|
||||
testId="market-expiry"
|
||||
>
|
||||
<ExpiryLabel market={market} />
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Price')} testId="market-price">
|
||||
<MarketMarkPrice
|
||||
marketId={market?.id}
|
||||
decimalPlaces={market?.decimalPlaces}
|
||||
/>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Change (24h)')} testId="market-change">
|
||||
<Last24hPriceChange
|
||||
marketId={market?.id}
|
||||
decimalPlaces={market?.decimalPlaces}
|
||||
/>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Volume (24h)')} testId="market-volume">
|
||||
<Last24hVolume
|
||||
marketId={market?.id}
|
||||
positionDecimalPlaces={market?.positionDecimalPlaces}
|
||||
/>
|
||||
</HeaderStat>
|
||||
<HeaderStatMarketTradingMode
|
||||
marketId={market?.id}
|
||||
initialTradingMode={market?.tradingMode}
|
||||
/>
|
||||
<MarketState market={market} />
|
||||
{asset ? (
|
||||
<HeaderStat
|
||||
heading={t('Settlement asset')}
|
||||
testId="market-settlement-asset"
|
||||
<div className="flex flex-col justify-end lg:pt-4">
|
||||
<div className="xl:flex xl:gap-4 items-end">
|
||||
<div
|
||||
data-testid="header-summary"
|
||||
className="flex flex-nowrap items-end xl:flex-1 w-full overflow-x-auto text-xs"
|
||||
>
|
||||
<div>
|
||||
<ButtonLink
|
||||
onClick={(e) => {
|
||||
openAssetDetailsDialog(asset.id, e.target as HTMLElement);
|
||||
}}
|
||||
<HeaderStat
|
||||
heading={t('Expiry')}
|
||||
description={
|
||||
market && (
|
||||
<ExpiryTooltipContent
|
||||
market={market}
|
||||
explorerUrl={VEGA_EXPLORER_URL}
|
||||
/>
|
||||
)
|
||||
}
|
||||
testId="market-expiry"
|
||||
>
|
||||
<ExpiryLabel market={market} />
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Price')} testId="market-price">
|
||||
<MarketMarkPrice
|
||||
marketId={market?.id}
|
||||
decimalPlaces={market?.decimalPlaces}
|
||||
/>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Change (24h)')} testId="market-change">
|
||||
<Last24hPriceChange
|
||||
marketId={market?.id}
|
||||
decimalPlaces={market?.decimalPlaces}
|
||||
/>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Volume (24h)')} testId="market-volume">
|
||||
<Last24hVolume
|
||||
marketId={market?.id}
|
||||
positionDecimalPlaces={market?.positionDecimalPlaces}
|
||||
/>
|
||||
</HeaderStat>
|
||||
<HeaderStatMarketTradingMode
|
||||
marketId={market?.id}
|
||||
initialTradingMode={market?.tradingMode}
|
||||
/>
|
||||
<MarketState market={market} />
|
||||
{asset ? (
|
||||
<HeaderStat
|
||||
heading={t('Settlement asset')}
|
||||
testId="market-settlement-asset"
|
||||
>
|
||||
{asset.symbol}
|
||||
</ButtonLink>
|
||||
</div>
|
||||
</HeaderStat>
|
||||
) : null}
|
||||
<MarketLiquiditySupplied
|
||||
marketId={market?.id}
|
||||
assetDecimals={asset?.decimals || 0}
|
||||
/>
|
||||
<MarketProposalNotification marketId={market?.id} />
|
||||
</>
|
||||
<div>
|
||||
<ButtonLink
|
||||
onClick={(e) => {
|
||||
openAssetDetailsDialog(asset.id, e.target as HTMLElement);
|
||||
}}
|
||||
>
|
||||
{asset.symbol}
|
||||
</ButtonLink>
|
||||
</div>
|
||||
</HeaderStat>
|
||||
) : null}
|
||||
<MarketLiquiditySupplied
|
||||
marketId={market?.id}
|
||||
assetDecimals={asset?.decimals || 0}
|
||||
/>
|
||||
<MarketProposalNotification marketId={market?.id} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { createMarketFragment } from '@vegaprotocol/mock';
|
||||
import { MarketSelectorItem } from './market-selector-item';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
@@ -90,6 +91,8 @@ describe('MarketSelectorItem', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const mockOnSelect = jest.fn();
|
||||
|
||||
const renderJsx = (mocks: MockedResponse[]) => {
|
||||
return render(
|
||||
<MemoryRouter>
|
||||
@@ -98,6 +101,7 @@ describe('MarketSelectorItem', () => {
|
||||
market={market}
|
||||
currentMarketId={market.id}
|
||||
style={{}}
|
||||
onSelect={mockOnSelect}
|
||||
/>
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
@@ -169,7 +173,7 @@ describe('MarketSelectorItem', () => {
|
||||
// link renders and is styled
|
||||
expect(link).toHaveAttribute('href', '/markets/' + market.id);
|
||||
|
||||
expect(link.parentNode).toHaveClass('bg-vega-light-100');
|
||||
expect(link).toHaveClass('ring-1');
|
||||
|
||||
expect(screen.getByTitle('24h vol')).toHaveTextContent('0.00');
|
||||
expect(screen.getByTitle(symbol)).toHaveTextContent('-');
|
||||
@@ -179,6 +183,13 @@ describe('MarketSelectorItem', () => {
|
||||
expect(screen.getByTitle(symbol)).toHaveTextContent(
|
||||
addDecimalsFormatNumber(marketData.markPrice, market.decimalPlaces)
|
||||
);
|
||||
expect(screen.getByTestId('market-item-change')).toHaveTextContent(
|
||||
'+100.00%'
|
||||
);
|
||||
});
|
||||
|
||||
await userEvent.click(link);
|
||||
|
||||
expect(mockOnSelect).toHaveBeenCalledWith(market.id);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import type { CSSProperties } from 'react';
|
||||
import type { CSSProperties, ReactNode } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
priceChangePercentage,
|
||||
} from '@vegaprotocol/utils';
|
||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/markets';
|
||||
import { calcCandleVolume } from '@vegaprotocol/markets';
|
||||
import { useCandles } from '@vegaprotocol/markets';
|
||||
@@ -17,22 +21,29 @@ export const MarketSelectorItem = ({
|
||||
market,
|
||||
style,
|
||||
currentMarketId,
|
||||
onSelect,
|
||||
}: {
|
||||
market: MarketMaybeWithDataAndCandles;
|
||||
style: CSSProperties;
|
||||
currentMarketId?: string;
|
||||
onSelect?: (marketId: string) => void;
|
||||
}) => {
|
||||
// 'py-1 px-2',
|
||||
const wrapperClasses = classNames(
|
||||
'block bg-vega-light-100 dark:bg-vega-dark-100 rounded-lg p-4',
|
||||
'min-h-[120px]',
|
||||
{
|
||||
'ring-1 ring-vega-light-300 dark:ring-vega-dark-300':
|
||||
currentMarketId === market.id,
|
||||
}
|
||||
);
|
||||
return (
|
||||
<div style={style} role="row">
|
||||
<div style={style} className="my-0.5 px-4">
|
||||
<Link
|
||||
to={`/markets/${market.id}`}
|
||||
className={classNames('h-full flex items-center gap-2 px-4', {
|
||||
'hover:bg-vega-clight-700 dark:hover:bg-vega-cdark-700':
|
||||
market.id !== currentMarketId,
|
||||
'bg-vega-clight-600 dark:bg-vega-cdark-600':
|
||||
market.id === currentMarketId,
|
||||
})}
|
||||
className={wrapperClasses}
|
||||
onClick={() => {
|
||||
onSelect && onSelect(market.id);
|
||||
}}
|
||||
>
|
||||
<MarketData market={market} />
|
||||
</Link>
|
||||
@@ -80,41 +91,86 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-1/4" role="gridcell">
|
||||
<h3 className="text-ellipsis whitespace-nowrap overflow-hidden">
|
||||
<div className="flex items-end gap-1 mb-1">
|
||||
<h3
|
||||
className={classNames(
|
||||
'overflow-hidden text-ellipsis whitespace-nowrap',
|
||||
{
|
||||
'w-1/2': mode, // make space for showing the trading mode
|
||||
}
|
||||
)}
|
||||
>
|
||||
{market.tradableInstrument.instrument.code}
|
||||
</h3>
|
||||
{mode && (
|
||||
<p className="text-xs text-vega-orange-500 dark:text-vega-orange-550 whitespace-nowrap">
|
||||
<p className="w-1/2 text-xs text-right text-vega-orange-500 dark:text-vega-orange-550">
|
||||
{mode}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="w-1/4 text-sm"
|
||||
title={instrument.product.settlementAsset.symbol}
|
||||
data-testid="market-selector-data-row"
|
||||
role="gridcell"
|
||||
>
|
||||
{price} {instrument.product.settlementAsset.symbol}
|
||||
</div>
|
||||
<div
|
||||
className="w-1/4 text-sm text-right"
|
||||
title={t('24h vol')}
|
||||
data-testid="market-selector-data-row"
|
||||
role="gridcell"
|
||||
>
|
||||
{volume}
|
||||
</div>
|
||||
<div className="w-1/4" role="gridcell">
|
||||
<DataRow value={volume} label={t('24h vol')} />
|
||||
<DataRow
|
||||
value={price}
|
||||
label={instrument.product.settlementAsset.symbol}
|
||||
/>
|
||||
<div className="relative text-xs p-1">
|
||||
{oneDayCandles && (
|
||||
<Sparkline
|
||||
width={70}
|
||||
height={15}
|
||||
data={oneDayCandles.map((c) => Number(c.close))}
|
||||
/>
|
||||
<PriceChange candles={oneDayCandles.map((c) => c.close)} />
|
||||
)}
|
||||
|
||||
<div
|
||||
// absolute so height is not larger than price change value
|
||||
className="absolute right-0 bottom-0 w-[120px]"
|
||||
>
|
||||
{oneDayCandles && (
|
||||
<Sparkline
|
||||
width={120}
|
||||
height={20}
|
||||
data={oneDayCandles.map((c) => Number(c.close))}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const DataRow = ({
|
||||
value,
|
||||
label,
|
||||
}: {
|
||||
value: string | ReactNode;
|
||||
label: string;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className="text-ellipsis whitespace-nowrap overflow-hidden leading-tight"
|
||||
data-testid="market-selector-data-row"
|
||||
>
|
||||
<span title={label} className="text-sm mr-1">
|
||||
{value}
|
||||
</span>
|
||||
<span className="text-xs text-vega-light-300 dark:text-vega-light-300">
|
||||
{label}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const PriceChange = ({ candles }: { candles: string[] }) => {
|
||||
const priceChange = candles ? priceChangePercentage(candles) : undefined;
|
||||
const priceChangeClasses = classNames('text-xs', {
|
||||
'text-vega-pink': priceChange && priceChange < 0,
|
||||
'text-vega-green': priceChange && priceChange > 0,
|
||||
});
|
||||
let prefix = '';
|
||||
if (priceChange && priceChange > 0) {
|
||||
prefix = '+';
|
||||
}
|
||||
const formattedChange = formatNumber(Number(priceChange), 2);
|
||||
return (
|
||||
<div className={priceChangeClasses} data-testid="market-item-change">
|
||||
{priceChange ? `${prefix}${formattedChange}%` : '-'}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -143,6 +143,7 @@ describe('MarketSelector', () => {
|
||||
expect(screen.getAllByTestId(/market-\d/)).toHaveLength(
|
||||
activeMarkets.length
|
||||
);
|
||||
expect(screen.getByRole('link')).toHaveTextContent('All markets');
|
||||
});
|
||||
|
||||
it('filters by product type', async () => {
|
||||
|
||||
@@ -9,7 +9,9 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { useCallback, useState, useMemo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import { useMarketSelectorList } from './use-market-selector-list';
|
||||
import type { ProductType } from './product-selector';
|
||||
import { Product, ProductSelector } from './product-selector';
|
||||
@@ -17,7 +19,6 @@ import { AssetDropdown } from './asset-dropdown';
|
||||
import type { SortType } from './sort-dropdown';
|
||||
import { Sort, SortDropdown } from './sort-dropdown';
|
||||
import { MarketSelectorItem } from './market-selector-item';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export type Filter = {
|
||||
searchTerm: string;
|
||||
@@ -47,15 +48,18 @@ export const MarketSelector = ({
|
||||
const { markets, data, loading, error } = useMarketSelectorList(filter);
|
||||
|
||||
return (
|
||||
<div data-testid="market-selector">
|
||||
<div className="pt-2 px-2 mb-2 w-[320px] lg:w-[584px]">
|
||||
<div
|
||||
className="grid grid-rows-[min-content_1fr_min-content] h-full"
|
||||
data-testid="market-selector"
|
||||
>
|
||||
<div className="px-4 pt-2 pb-4">
|
||||
<ProductSelector
|
||||
product={filter.product}
|
||||
onSelect={(product) => {
|
||||
setFilter((curr) => ({ ...curr, product }));
|
||||
}}
|
||||
/>
|
||||
<div className="text-sm grid grid-cols-[2fr_1fr_1fr] gap-1 ">
|
||||
<div className="text-sm flex gap-1 items-stretch">
|
||||
<div className="flex-1">
|
||||
<Input
|
||||
onChange={(e) =>
|
||||
@@ -72,7 +76,7 @@ export const MarketSelector = ({
|
||||
onClick={() =>
|
||||
setFilter((curr) => ({ ...curr, searchTerm: '' }))
|
||||
}
|
||||
className="text-secondary"
|
||||
className="text-vega-light-200 dark:text-vega-dark-200"
|
||||
>
|
||||
<VegaIcon name={VegaIconNames.CROSS} />
|
||||
</button>
|
||||
@@ -145,6 +149,18 @@ export const MarketSelector = ({
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-4 py-2">
|
||||
<span className="inline-block border-b border-black dark:border-white">
|
||||
<Link
|
||||
to={'/markets/all'}
|
||||
data-testid="all-markets-link"
|
||||
className="flex items-center gap-x-2"
|
||||
>
|
||||
{t('All markets')}
|
||||
<VegaIcon name={VegaIconNames.ARROW_RIGHT} />
|
||||
</Link>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -169,34 +185,21 @@ const MarketList = ({
|
||||
return <div>{error.message}</div>;
|
||||
}
|
||||
return (
|
||||
<TinyScroll>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex gap-2',
|
||||
'bg-vega-clight-700 dark:bg-vega-cdark-700',
|
||||
'p-2 mx-2 border-b border-default text-xs text-secondary'
|
||||
)}
|
||||
>
|
||||
<div className="w-1/4" role="columnheader">
|
||||
{t('Name')}
|
||||
</div>
|
||||
<div className="w-1/4" role="columnheader">
|
||||
{t('Price')}
|
||||
</div>
|
||||
<div className="w-1/4 text-right" role="columnheader">
|
||||
{t('24h volume')}
|
||||
</div>
|
||||
<div className="w-1/4" role="columnheader" />
|
||||
</div>
|
||||
<List
|
||||
data={data}
|
||||
loading={loading}
|
||||
height={400}
|
||||
currentMarketId={currentMarketId}
|
||||
onSelect={onSelect}
|
||||
noItems={noItems}
|
||||
/>
|
||||
</TinyScroll>
|
||||
<AutoSizer>
|
||||
{({ width, height }) => (
|
||||
<TinyScroll>
|
||||
<List
|
||||
data={data}
|
||||
loading={loading}
|
||||
width={width}
|
||||
height={height}
|
||||
currentMarketId={currentMarketId}
|
||||
onSelect={onSelect}
|
||||
noItems={noItems}
|
||||
/>
|
||||
</TinyScroll>
|
||||
)}
|
||||
</AutoSizer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -219,18 +222,21 @@ const ListItem = ({
|
||||
market={data.data[index]}
|
||||
currentMarketId={data.currentMarketId}
|
||||
style={style}
|
||||
onSelect={data.onSelect}
|
||||
/>
|
||||
);
|
||||
|
||||
const List = ({
|
||||
data,
|
||||
loading,
|
||||
width,
|
||||
height,
|
||||
onSelect,
|
||||
noItems,
|
||||
currentMarketId,
|
||||
}: ListItemData & {
|
||||
loading: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
noItems: string;
|
||||
}) => {
|
||||
@@ -244,7 +250,7 @@ const List = ({
|
||||
);
|
||||
if (!data || loading) {
|
||||
return (
|
||||
<div style={{ height }}>
|
||||
<div style={{ width, height }}>
|
||||
<Skeleton />
|
||||
<Skeleton />
|
||||
</div>
|
||||
@@ -253,20 +259,24 @@ const List = ({
|
||||
|
||||
if (!data.length) {
|
||||
return (
|
||||
<div style={{ height }} data-testid="no-items">
|
||||
<div className="mx-4 my-2 text-sm">{noItems}</div>
|
||||
<div style={{ width, height }} data-testid="no-items">
|
||||
<div className="mb-2 px-4">
|
||||
<div className="text-sm bg-vega-light-100 dark:bg-vega-dark-100 rounded-lg px-4 py-2">
|
||||
{noItems}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FixedSizeList
|
||||
className="vega-scrollbar"
|
||||
className="virtualized-list"
|
||||
itemCount={data.length}
|
||||
itemData={itemData}
|
||||
itemSize={45}
|
||||
itemSize={130}
|
||||
itemKey={itemKey}
|
||||
width="100%"
|
||||
width={width}
|
||||
height={height}
|
||||
>
|
||||
{ListItem}
|
||||
|
||||
@@ -14,7 +14,6 @@ import { TradePanels } from './trade-panels';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import { ViewType, useSidebar } from '../../components/sidebar';
|
||||
|
||||
const calculatePrice = (markPrice?: string, decimalPlaces?: number) => {
|
||||
return markPrice && decimalPlaces
|
||||
@@ -62,7 +61,7 @@ const TitleUpdater = ({
|
||||
export const MarketPage = () => {
|
||||
const { marketId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { init, view, setView } = useSidebar();
|
||||
|
||||
const { screenSize } = useScreenDimensions();
|
||||
const largeScreen = ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize);
|
||||
const update = useGlobalStore((store) => store.update);
|
||||
@@ -82,13 +81,6 @@ export const MarketPage = () => {
|
||||
}
|
||||
}, [update, lastMarketId, data?.id]);
|
||||
|
||||
// Make sidebar open on deal ticket by default
|
||||
useEffect(() => {
|
||||
if (init && view === null) {
|
||||
setView({ type: ViewType.Order });
|
||||
}
|
||||
}, [init, view, setView]);
|
||||
|
||||
const tradeView = useMemo(() => {
|
||||
if (largeScreen) {
|
||||
return (
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Routes } from '../../pages/client-router';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
// Make sure these match the available __typename properties on product
|
||||
export const Product = {
|
||||
@@ -29,12 +25,12 @@ export const ProductSelector = ({
|
||||
onSelect: (product: ProductType) => void;
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex mb-2">
|
||||
<div className="flex gap-3 mb-3">
|
||||
{Object.keys(Product).map((t) => {
|
||||
const classes = classNames('px-3 py-1.5 rounded', {
|
||||
'bg-vega-clight-500 dark:bg-vega-cdark-500 text-default':
|
||||
t === product,
|
||||
'text-secondary': t !== product,
|
||||
const classes = classNames('py-1 border-b-2', {
|
||||
'border-vega-yellow text-black dark:text-white': t === product,
|
||||
'border-transparent text-vega-light-300 dark:text-vega-dark-300':
|
||||
t !== product,
|
||||
});
|
||||
return (
|
||||
<button
|
||||
@@ -49,10 +45,6 @@ export const ProductSelector = ({
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<Link to={Routes.MARKETS} className="flex items-center gap-2 ml-auto">
|
||||
<span className="underline underline-offset-4">{t('All markets')}</span>
|
||||
<VegaIcon name={VegaIconNames.ARROW_RIGHT} />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuSeparator,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const Sort = {
|
||||
@@ -41,9 +43,7 @@ export const SortDropdown = ({
|
||||
<DropdownMenu
|
||||
trigger={
|
||||
<DropdownMenuTrigger data-testid="sort-trigger">
|
||||
{currentSort === SortTypeMapping.None
|
||||
? t('Sort')
|
||||
: SortTypeMapping[currentSort]}
|
||||
<VegaIcon name={VegaIconNames.TREND_UP} />
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { memo } from 'react';
|
||||
import { memo, useState } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { LayoutPriority } from 'allotment';
|
||||
import classNames from 'classnames';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
@@ -9,7 +10,10 @@ import { OracleBanner } from '@vegaprotocol/markets';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import { Filter } from '@vegaprotocol/orders';
|
||||
import {
|
||||
Popover,
|
||||
usePaneLayout,
|
||||
useScreenDimensions,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
Tab,
|
||||
LocalStoragePersistTabs as Tabs,
|
||||
VegaIcon,
|
||||
@@ -17,22 +21,167 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
||||
import { Header, HeaderTitle } from '../../components/header';
|
||||
import { HeaderTitle } from '../../components/header';
|
||||
import {
|
||||
ResizableGrid,
|
||||
ResizableGridPanel,
|
||||
usePaneLayout,
|
||||
} from '../../components/resizable-grid';
|
||||
import { TradingViews } from './trade-views';
|
||||
import { MarketSuccessorBanner } from '../../components/market-banner';
|
||||
import { MarketSelector } from './market-selector';
|
||||
import { MarketHeaderStats } from './market-header-stats';
|
||||
import { HeaderStats } from './header-stats';
|
||||
|
||||
interface TradeGridProps {
|
||||
market: Market | null;
|
||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
}
|
||||
|
||||
interface BottomPanelProps {
|
||||
marketId: string;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
}
|
||||
|
||||
const MarketBottomPanel = memo(
|
||||
({ marketId, pinnedAsset }: BottomPanelProps) => {
|
||||
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'bottom' });
|
||||
const { screenSize } = useScreenDimensions();
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
|
||||
return 'xxxl' === screenSize ? (
|
||||
<ResizableGrid
|
||||
proportionalLayout
|
||||
minSize={200}
|
||||
onChange={handleOnLayoutChange}
|
||||
>
|
||||
<ResizableGridPanel
|
||||
priority={LayoutPriority.Low}
|
||||
preferredSize={sizes[0] || '50%'}
|
||||
minSize={50}
|
||||
>
|
||||
<TradeGridChild>
|
||||
<Tabs storageKey="console-trade-grid-bottom-left">
|
||||
<Tab id="open-orders" name={t('Open')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component
|
||||
marketId={marketId}
|
||||
filter={Filter.Open}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="closed-orders" name={t('Closed')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component
|
||||
marketId={marketId}
|
||||
filter={Filter.Closed}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="rejected-orders" name={t('Rejected')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component
|
||||
marketId={marketId}
|
||||
filter={Filter.Rejected}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="orders" name={t('All')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component marketId={marketId} />
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="fills" name={t('Fills')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.fills.component onMarketClick={onMarketClick} />
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</TradeGridChild>
|
||||
</ResizableGridPanel>
|
||||
<ResizableGridPanel
|
||||
priority={LayoutPriority.Low}
|
||||
preferredSize={sizes[1] || '50%'}
|
||||
minSize={50}
|
||||
>
|
||||
<TradeGridChild>
|
||||
<Tabs storageKey="console-trade-grid-bottom-right">
|
||||
<Tab id="positions" name={t('Positions')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.positions.component
|
||||
onMarketClick={onMarketClick}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="accounts" name={t('Collateral')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.collateral.component
|
||||
pinnedAsset={pinnedAsset}
|
||||
onMarketClick={onMarketClick}
|
||||
hideButtons
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</TradeGridChild>
|
||||
</ResizableGridPanel>
|
||||
</ResizableGrid>
|
||||
) : (
|
||||
<TradeGridChild>
|
||||
<Tabs storageKey="console-trade-grid-bottom">
|
||||
<Tab id="positions" name={t('Positions')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.positions.component onMarketClick={onMarketClick} />
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="open-orders" name={t('Open')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component
|
||||
marketId={marketId}
|
||||
filter={Filter.Open}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="closed-orders" name={t('Closed')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component
|
||||
marketId={marketId}
|
||||
filter={Filter.Closed}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="rejected-orders" name={t('Rejected')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component
|
||||
marketId={marketId}
|
||||
filter={Filter.Rejected}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="orders" name={t('All')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component marketId={marketId} />
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="fills" name={t('Fills')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.fills.component onMarketClick={onMarketClick} />
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="accounts" name={t('Collateral')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.collateral.component
|
||||
pinnedAsset={pinnedAsset}
|
||||
onMarketClick={onMarketClick}
|
||||
hideButtons
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</TradeGridChild>
|
||||
);
|
||||
}
|
||||
);
|
||||
MarketBottomPanel.displayName = 'MarketBottomPanel';
|
||||
|
||||
const MainGrid = memo(
|
||||
({
|
||||
marketId,
|
||||
@@ -41,6 +190,7 @@ const MainGrid = memo(
|
||||
marketId: string;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'top' });
|
||||
const [sizesMiddle, handleOnMiddleLayoutChange] = usePaneLayout({
|
||||
id: 'middle-1',
|
||||
@@ -55,6 +205,25 @@ const MainGrid = memo(
|
||||
minSize={200}
|
||||
onChange={handleOnMiddleLayoutChange}
|
||||
>
|
||||
<ResizableGridPanel
|
||||
preferredSize={sizesMiddle[0] || 330}
|
||||
minSize={300}
|
||||
>
|
||||
<TradeGridChild>
|
||||
<Tabs storageKey="console-trade-grid-main-center">
|
||||
<Tab id="ticket" name={t('Ticket')}>
|
||||
<TradingViews.ticket.component
|
||||
marketId={marketId}
|
||||
onMarketClick={onMarketClick}
|
||||
onClickCollateral={() => navigate('/portfolio')}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab id="info" name={t('Info')}>
|
||||
<TradingViews.info.component marketId={marketId} />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</TradeGridChild>
|
||||
</ResizableGridPanel>
|
||||
<ResizableGridPanel
|
||||
priority={LayoutPriority.High}
|
||||
minSize={200}
|
||||
@@ -96,63 +265,7 @@ const MainGrid = memo(
|
||||
preferredSize={sizes[1] || '25%'}
|
||||
minSize={50}
|
||||
>
|
||||
<TradeGridChild>
|
||||
<Tabs storageKey="console-trade-grid-bottom">
|
||||
<Tab id="positions" name={t('Positions')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.positions.component
|
||||
onMarketClick={onMarketClick}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="open-orders" name={t('Open')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component
|
||||
marketId={marketId}
|
||||
filter={Filter.Open}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="closed-orders" name={t('Closed')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component
|
||||
marketId={marketId}
|
||||
filter={Filter.Closed}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="rejected-orders" name={t('Rejected')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component
|
||||
marketId={marketId}
|
||||
filter={Filter.Rejected}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="orders" name={t('All')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.orders.component marketId={marketId} />
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="fills" name={t('Fills')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.fills.component
|
||||
marketId={marketId}
|
||||
onMarketClick={onMarketClick}
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="accounts" name={t('Collateral')}>
|
||||
<VegaWalletContainer>
|
||||
<TradingViews.collateral.component
|
||||
pinnedAsset={pinnedAsset}
|
||||
onMarketClick={onMarketClick}
|
||||
hideButtons
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</TradeGridChild>
|
||||
<MarketBottomPanel marketId={marketId} pinnedAsset={pinnedAsset} />
|
||||
</ResizableGridPanel>
|
||||
</ResizableGrid>
|
||||
);
|
||||
@@ -161,34 +274,61 @@ const MainGrid = memo(
|
||||
MainGrid.displayName = 'MainGrid';
|
||||
|
||||
export const TradeGrid = ({ market, pinnedAsset }: TradeGridProps) => {
|
||||
const [sidebarOpen, setSidebarOpen] = useState(true);
|
||||
const wrapperClasses = classNames(
|
||||
'h-full grid',
|
||||
'grid-rows-[min-content_min-content_1fr]'
|
||||
'grid-rows-[min-content_min-content_1fr]',
|
||||
'grid-cols-[320px_1fr]'
|
||||
);
|
||||
const paneWrapperClasses = classNames('min-h-0', {
|
||||
'col-span-2 col-start-1': !sidebarOpen,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
<Header
|
||||
title={
|
||||
<Popover
|
||||
trigger={
|
||||
<HeaderTitle>
|
||||
{market?.tradableInstrument.instrument.code}
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={14} />
|
||||
</HeaderTitle>
|
||||
}
|
||||
<div className="border-b border-r border-default">
|
||||
<div className="h-full flex gap-2 justify-between items-end px-4 pt-1 pb-3">
|
||||
<HeaderTitle
|
||||
primaryContent={market?.tradableInstrument.instrument.code}
|
||||
secondaryContent={market?.tradableInstrument.instrument.name}
|
||||
/>
|
||||
<button
|
||||
onClick={() => setSidebarOpen((x) => !x)}
|
||||
className="flex flex-col items-center text-xs w-12"
|
||||
data-testid="sidebar-toggle"
|
||||
>
|
||||
<MarketSelector currentMarketId={market?.id} />
|
||||
</Popover>
|
||||
}
|
||||
>
|
||||
<MarketHeaderStats market={market} />
|
||||
</Header>
|
||||
<div className="bg-vega-green">
|
||||
<MarketSuccessorBanner market={market} />
|
||||
{sidebarOpen ? (
|
||||
<>
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_UP} />
|
||||
<span className="text-vega-light-300 dark:text-vega-dark-300">
|
||||
{t('Close')}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} />
|
||||
<span className="text-vega-light-300 dark:text-vega-dark-300">
|
||||
{t('Markets')}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-b border-default min-w-0">
|
||||
<HeaderStats market={market} />
|
||||
</div>
|
||||
<div className="col-span-2 bg-vega-green">
|
||||
<OracleBanner marketId={market?.id || ''} />
|
||||
</div>
|
||||
<div className="min-h-0 py-0.5">
|
||||
{sidebarOpen && (
|
||||
<div className="border-r border-default min-h-0">
|
||||
<div className="h-full pb-8">
|
||||
<MarketSelector currentMarketId={market?.id} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={paneWrapperClasses}>
|
||||
<MainGrid marketId={market?.id || ''} pinnedAsset={pinnedAsset} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -201,16 +341,9 @@ interface TradeGridChildProps {
|
||||
|
||||
const TradeGridChild = ({ children }: TradeGridChildProps) => {
|
||||
return (
|
||||
<section className="h-full p-1">
|
||||
<section className="h-full">
|
||||
<AutoSizer>
|
||||
{({ width, height }) => (
|
||||
<div
|
||||
style={{ width, height }}
|
||||
className="border border-default rounded-sm"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
{({ width, height }) => <div style={{ width, height }}>{children}</div>}
|
||||
</AutoSizer>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { TradingView } from './trade-views';
|
||||
import { TradingViews } from './trade-views';
|
||||
import { memo, useState } from 'react';
|
||||
import {
|
||||
Popover,
|
||||
Icon,
|
||||
Splash,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
@@ -17,10 +17,10 @@ import {
|
||||
import { NO_MARKET } from './constants';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import classNames from 'classnames';
|
||||
import { Header, HeaderTitle } from '../../components/header';
|
||||
import { HeaderStats } from './header-stats';
|
||||
import * as DialogPrimitives from '@radix-ui/react-dialog';
|
||||
import { HeaderTitle } from '../../components/header';
|
||||
import { MarketSelector } from './market-selector';
|
||||
import { MarketSuccessorBanner } from '../../components/market-banner';
|
||||
import { MarketHeaderStats } from './market-header-stats';
|
||||
|
||||
interface TradePanelsProps {
|
||||
market: Market | null;
|
||||
@@ -37,6 +37,7 @@ export const TradePanels = ({
|
||||
onClickCollateral,
|
||||
pinnedAsset,
|
||||
}: TradePanelsProps) => {
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const onOrderTypeClick = useMarketLiquidityClickHandler();
|
||||
|
||||
@@ -71,24 +72,26 @@ export const TradePanels = ({
|
||||
|
||||
return (
|
||||
<div className="h-full grid grid-rows-[min-content_min-content_1fr_min-content]">
|
||||
<Header
|
||||
title={
|
||||
<Popover
|
||||
trigger={
|
||||
<HeaderTitle>
|
||||
{market?.tradableInstrument.instrument.code}
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} />
|
||||
</HeaderTitle>
|
||||
}
|
||||
>
|
||||
<MarketSelector currentMarketId={market?.id} />
|
||||
</Popover>
|
||||
}
|
||||
>
|
||||
<MarketHeaderStats market={market} />
|
||||
</Header>
|
||||
<div className="border-b border-default min-w-0">
|
||||
<div className="flex gap-4 items-center px-4 py-2">
|
||||
<HeaderTitle
|
||||
primaryContent={market?.tradableInstrument.instrument.code}
|
||||
secondaryContent={market?.tradableInstrument.instrument.name}
|
||||
/>
|
||||
<button onClick={() => setDrawerOpen((x) => !x)} className="p-2">
|
||||
<span
|
||||
className={classNames('block', {
|
||||
'rotate-90 translate-x-1': !drawerOpen,
|
||||
'-rotate-90 -translate-x-1': drawerOpen,
|
||||
})}
|
||||
>
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_UP} />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<HeaderStats market={market} />
|
||||
</div>
|
||||
<div>
|
||||
<MarketSuccessorBanner market={market} />
|
||||
<OracleBanner marketId={market?.id || ''} />
|
||||
</div>
|
||||
<div className="h-full">
|
||||
@@ -104,7 +107,8 @@ export const TradePanels = ({
|
||||
{Object.keys(TradingViews).map((key) => {
|
||||
const isActive = view === key;
|
||||
const className = classNames('p-4 min-w-[100px] capitalize', {
|
||||
'bg-vega-clight-500 dark:bg-vega-cdark-500': isActive,
|
||||
'text-black dark:text-vega-yellow': isActive,
|
||||
'bg-neutral-200 dark:bg-neutral-800': isActive,
|
||||
});
|
||||
return (
|
||||
<button
|
||||
@@ -118,6 +122,25 @@ export const TradePanels = ({
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<DialogPrimitives.Root open={drawerOpen} onOpenChange={setDrawerOpen}>
|
||||
<DialogPrimitives.Portal>
|
||||
<DialogPrimitives.Overlay />
|
||||
<DialogPrimitives.Content
|
||||
className={classNames(
|
||||
'fixed h-full max-w-[500px] w-[90vw] z-10 top-0 left-0 transition-transform',
|
||||
'bg-white dark:bg-black',
|
||||
'border-r border-default'
|
||||
)}
|
||||
>
|
||||
<DialogPrimitives.Close className="absolute top-0 right-0 p-2">
|
||||
<Icon name="cross" />
|
||||
</DialogPrimitives.Close>
|
||||
{drawerOpen && (
|
||||
<MarketSelector onSelect={() => setDrawerOpen(false)} />
|
||||
)}
|
||||
</DialogPrimitives.Content>
|
||||
</DialogPrimitives.Portal>
|
||||
</DialogPrimitives.Root>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { ComponentProps } from 'react';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { DealTicketContainer } from '@vegaprotocol/deal-ticket';
|
||||
import { MarketInfoAccordionContainer } from '@vegaprotocol/markets';
|
||||
import { TradesContainer } from '@vegaprotocol/trades';
|
||||
import { DepthChartContainer } from '@vegaprotocol/market-depth';
|
||||
import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
|
||||
@@ -16,6 +18,8 @@ import { OrdersContainer } from '../../components/orders-container';
|
||||
type MarketDependantView =
|
||||
| typeof CandlesChartContainer
|
||||
| typeof DepthChartContainer
|
||||
| typeof DealTicketContainer
|
||||
| typeof MarketInfoAccordionContainer
|
||||
| typeof OrderbookContainer
|
||||
| typeof TradesContainer;
|
||||
|
||||
@@ -43,6 +47,14 @@ export const TradingViews = {
|
||||
label: 'Liquidity',
|
||||
component: requiresMarket(LiquidityContainer),
|
||||
},
|
||||
ticket: {
|
||||
label: 'Ticket',
|
||||
component: requiresMarket(DealTicketContainer),
|
||||
},
|
||||
info: {
|
||||
label: 'Info',
|
||||
component: requiresMarket(MarketInfoAccordionContainer),
|
||||
},
|
||||
orderbook: {
|
||||
label: 'Orderbook',
|
||||
component: requiresMarket(OrderbookContainer),
|
||||
|
||||
@@ -18,7 +18,7 @@ import type {
|
||||
MarketMaybeWithData,
|
||||
} from '@vegaprotocol/markets';
|
||||
import {
|
||||
MarketActionsDropdown,
|
||||
MarketTableActions,
|
||||
closedMarketsWithDataProvider,
|
||||
} from '@vegaprotocol/markets';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
@@ -291,7 +291,7 @@ const ClosedMarketsDataGrid = ({
|
||||
cellRenderer: ({ data }: VegaICellRendererParams<Row>) => {
|
||||
if (!data) return null;
|
||||
return (
|
||||
<MarketActionsDropdown
|
||||
<MarketTableActions
|
||||
marketId={data.id}
|
||||
assetId={data.settlementAsset.id}
|
||||
/>
|
||||
|
||||
@@ -15,20 +15,16 @@ export const MarketsPage = () => {
|
||||
updateTitle(titlefy(['Markets']));
|
||||
}, [updateTitle]);
|
||||
return (
|
||||
<div className="h-full pt-0.5 pb-3 px-1">
|
||||
<div className="h-full my-1 border border-default rounded-sm">
|
||||
<Tabs storageKey="console-markets">
|
||||
<Tab id="all-markets" name={t('All markets')}>
|
||||
<Markets />
|
||||
</Tab>
|
||||
<Tab id="proposed-markets" name={t('Proposed markets')}>
|
||||
<Proposed />
|
||||
</Tab>
|
||||
<Tab id="closed-markets" name={t('Closed markets')}>
|
||||
<Closed />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs storageKey="console-markets">
|
||||
<Tab id="all-markets" name={t('All markets')}>
|
||||
<Markets />
|
||||
</Tab>
|
||||
<Tab id="proposed-markets" name={t('Proposed markets')}>
|
||||
<Proposed />
|
||||
</Tab>
|
||||
<Tab id="closed-markets" name={t('Closed markets')}>
|
||||
<Closed />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -24,10 +24,7 @@ import { PriceChart } from 'pennant';
|
||||
import 'pennant/dist/style.css';
|
||||
import type { Account } from '@vegaprotocol/accounts';
|
||||
import { accountsDataProvider } from '@vegaprotocol/accounts';
|
||||
import {
|
||||
useLocalStorageSnapshot,
|
||||
useThemeSwitcher,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
|
||||
@@ -71,7 +68,7 @@ export const AccountHistoryContainer = () => {
|
||||
const { data: assets } = useAssetsDataProvider();
|
||||
|
||||
if (!pubKey) {
|
||||
return <Splash>{t('Connect wallet')}</Splash>;
|
||||
return <Splash>Connect wallet</Splash>;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -117,15 +114,7 @@ const AccountHistoryManager = ({
|
||||
.sort((a, b) => a.name.localeCompare(b.name)),
|
||||
[assetData, assetIds]
|
||||
);
|
||||
const [assetId, setAssetId] = useLocalStorageSnapshot(
|
||||
'account-history-active-asset-id'
|
||||
);
|
||||
|
||||
const asset = useMemo(
|
||||
() => assets.find((a) => a.id === assetId) || assets[0],
|
||||
[assetId, assets]
|
||||
);
|
||||
|
||||
const [asset, setAsset] = useState<AssetFieldsFragment>(assets[0]);
|
||||
const [range, setRange] = useState<typeof DateRange[keyof typeof DateRange]>(
|
||||
DateRange.RANGE_1M
|
||||
);
|
||||
@@ -157,10 +146,10 @@ const AccountHistoryManager = ({
|
||||
m.tradableInstrument.instrument.product.settlementAsset.id;
|
||||
const newAsset = assets.find((item) => item.id === newAssetId);
|
||||
if ((!asset || (assets && newAssetId !== asset.id)) && newAsset) {
|
||||
setAssetId(newAsset.id);
|
||||
setAsset(newAsset);
|
||||
}
|
||||
},
|
||||
[asset, assets, setAssetId]
|
||||
[asset, assets]
|
||||
);
|
||||
|
||||
const variables = useMemo(
|
||||
@@ -222,14 +211,14 @@ const AccountHistoryManager = ({
|
||||
>
|
||||
<DropdownMenuContent>
|
||||
{assets.map((a) => (
|
||||
<DropdownMenuItem key={a.id} onClick={() => setAssetId(a.id)}>
|
||||
<DropdownMenuItem key={a.id} onClick={() => setAsset(a)}>
|
||||
{a.symbol}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}, [asset, assets, setAssetId]);
|
||||
}, [assets, asset]);
|
||||
const marketsMenu = useMemo(() => {
|
||||
return accountType === Schema.AccountType.ACCOUNT_TYPE_MARGIN &&
|
||||
markets?.length ? (
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { DepositsTable } from '@vegaprotocol/deposits';
|
||||
import { useDepositDialog, DepositsTable } from '@vegaprotocol/deposits';
|
||||
import { depositsProvider } from '@vegaprotocol/deposits';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useRef } from 'react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { useSidebar, ViewType } from '../../components/sidebar';
|
||||
|
||||
export const DepositsContainer = () => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
@@ -16,7 +15,7 @@ export const DepositsContainer = () => {
|
||||
variables: { partyId: pubKey || '' },
|
||||
skip: !pubKey,
|
||||
});
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
const openDepositDialog = useDepositDialog((state) => state.open);
|
||||
return (
|
||||
<div className="h-full">
|
||||
<DepositsTable
|
||||
@@ -25,11 +24,11 @@ export const DepositsContainer = () => {
|
||||
overlayNoRowsTemplate={error ? error.message : t('No deposits')}
|
||||
/>
|
||||
{!isReadOnly && (
|
||||
<div className="h-auto flex justify-end p-2 bottom-0 right-0 absolute dark:bg-black/75 bg-white/75 rounded">
|
||||
<div className="h-auto flex justify-end px-[11px] py-2 bottom-0 right-3 absolute dark:bg-black/75 bg-white/75 rounded">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={() => setView({ type: ViewType.Deposit })}
|
||||
onClick={() => openDepositDialog()}
|
||||
data-testid="deposit-button"
|
||||
>
|
||||
{t('Deposit')}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { LayoutPriority } from 'allotment';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useIncompleteWithdrawals } from '@vegaprotocol/withdraws';
|
||||
import { usePaneLayout } from '@vegaprotocol/react-helpers';
|
||||
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
@@ -19,9 +20,7 @@ import { AccountHistoryContainer } from './account-history-container';
|
||||
import {
|
||||
ResizableGrid,
|
||||
ResizableGridPanel,
|
||||
usePaneLayout,
|
||||
} from '../../components/resizable-grid';
|
||||
import { ViewType, useSidebar } from '../../components/sidebar';
|
||||
|
||||
const WithdrawalsIndicator = () => {
|
||||
const { ready } = useIncompleteWithdrawals();
|
||||
@@ -29,14 +28,13 @@ const WithdrawalsIndicator = () => {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<span className="bg-vega-clight-500 dark:bg-vega-cdark-500 text-default rounded p-1 leading-none">
|
||||
<span className="bg-vega-blue-450 text-white text-[10px] rounded p-[3px] pb-[2px] leading-none">
|
||||
{ready.length}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export const Portfolio = () => {
|
||||
const { init, view, setView } = useSidebar();
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
@@ -45,16 +43,9 @@ export const Portfolio = () => {
|
||||
updateTitle(titlefy([t('Portfolio')]));
|
||||
}, [updateTitle]);
|
||||
|
||||
// Make transfer sidebar open by default
|
||||
useEffect(() => {
|
||||
if (init && view === null) {
|
||||
setView({ type: ViewType.Transfer });
|
||||
}
|
||||
}, [init, view, setView]);
|
||||
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' });
|
||||
const wrapperClasses = 'py-0.5 h-full max-h-full flex flex-col';
|
||||
const wrapperClasses = 'h-full max-h-full flex flex-col';
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
<ResizableGrid vertical onChange={handleOnLayoutChange}>
|
||||
@@ -127,8 +118,8 @@ interface PortfolioGridChildProps {
|
||||
|
||||
const PortfolioGridChild = ({ children }: PortfolioGridChildProps) => {
|
||||
return (
|
||||
<section className="h-full p-1">
|
||||
<div className="border border-default h-full rounded-sm">{children}</div>
|
||||
<section className="bg-white dark:bg-black w-full h-full">
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
withdrawalProvider,
|
||||
useWithdrawalDialog,
|
||||
WithdrawalsTable,
|
||||
useIncompleteWithdrawals,
|
||||
} from '@vegaprotocol/withdraws';
|
||||
@@ -8,7 +9,6 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
||||
import { ViewType, useSidebar } from '../../components/sidebar';
|
||||
|
||||
export const WithdrawalsContainer = () => {
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
@@ -17,7 +17,7 @@ export const WithdrawalsContainer = () => {
|
||||
variables: { partyId: pubKey || '' },
|
||||
skip: !pubKey,
|
||||
});
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
const openWithdrawDialog = useWithdrawalDialog((state) => state.open);
|
||||
const { ready, delayed } = useIncompleteWithdrawals();
|
||||
|
||||
return (
|
||||
@@ -32,11 +32,11 @@ export const WithdrawalsContainer = () => {
|
||||
/>
|
||||
</div>
|
||||
{!isReadOnly && (
|
||||
<div className="h-auto flex justify-end p-2 bottom-0 right-0 absolute dark:bg-black/75 bg-white/75 rounded">
|
||||
<div className="h-auto flex justify-end px-[11px] py-2 bottom-0 right-3 absolute dark:bg-black/75 bg-white/75 rounded">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={() => setView({ type: ViewType.Withdraw })}
|
||||
onClick={() => openWithdrawDialog()}
|
||||
data-testid="withdraw-dialog-button"
|
||||
>
|
||||
{t('Make withdrawal')}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export { Settings as default } from './settings';
|
||||
export { SettingsButton } from './settings-button';
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Icon, NavigationLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
|
||||
export const SettingsButton = ({ withMobile }: { withMobile?: boolean }) => {
|
||||
return (
|
||||
<NavigationLink data-testid="Settings" to={Links[Routes.SETTINGS]()}>
|
||||
{withMobile ? (
|
||||
t('Settings')
|
||||
) : (
|
||||
<Icon name={IconNames.COG} className="!align-middle" />
|
||||
)}
|
||||
</NavigationLink>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TelemetryApproval } from '../../components/welcome-dialog/telemetry-approval';
|
||||
import {
|
||||
Divider,
|
||||
RoundedWrapper,
|
||||
Switch,
|
||||
ThemeSwitcher,
|
||||
ToastPositionSetter,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const Settings = () => {
|
||||
const { theme, setTheme } = useThemeSwitcher();
|
||||
const text = t(theme === 'dark' ? 'Light mode' : 'Dark mode');
|
||||
return (
|
||||
<div className="py-16 px-8 flex w-full justify-center">
|
||||
<div className="lg:min-w-[700px] min-w-[300px]">
|
||||
<h1 className="text-4xl xl:text-5xl uppercase font-alpha calt">
|
||||
{t('Settings')}
|
||||
</h1>
|
||||
<div className="mt-8 text-base text-neutral-500 dark:text-neutral-400">
|
||||
{t('Changes are applied automatically.')}
|
||||
</div>
|
||||
<div className="mt-10 w-full">
|
||||
<RoundedWrapper paddingBottom>
|
||||
<div className="flex justify-between py-3">
|
||||
<div className="flex shrink">
|
||||
<ThemeSwitcher />
|
||||
<label htmlFor="theme-switcher" className="self-center text-lg">
|
||||
{text}
|
||||
</label>
|
||||
</div>
|
||||
<Switch
|
||||
name="settings-theme-switch"
|
||||
onCheckedChange={() => setTheme()}
|
||||
checked={theme === 'dark'}
|
||||
/>
|
||||
</div>
|
||||
<Divider />
|
||||
<TelemetryApproval
|
||||
helpText={t(
|
||||
'Help identify bugs and improve the service by sharing anonymous usage data.'
|
||||
)}
|
||||
/>
|
||||
<Divider />
|
||||
<ToastPositionSetter />
|
||||
</RoundedWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,17 +1,18 @@
|
||||
import { useCallback } from 'react';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useWithdrawalDialog } from '@vegaprotocol/withdraws';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
||||
import { AccountManager } from '@vegaprotocol/accounts';
|
||||
import { AccountManager, useTransferDialog } from '@vegaprotocol/accounts';
|
||||
import { useDepositDialog } from '@vegaprotocol/deposits';
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
|
||||
export const AccountsContainer = ({
|
||||
pinnedAsset,
|
||||
@@ -24,7 +25,9 @@ export const AccountsContainer = ({
|
||||
}) => {
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
const openWithdrawalDialog = useWithdrawalDialog((store) => store.open);
|
||||
const openDepositDialog = useDepositDialog((store) => store.open);
|
||||
const openTransferDialog = useTransferDialog((store) => store.open);
|
||||
|
||||
const gridStore = useAccountStore((store) => store.gridStore);
|
||||
const updateGridStore = useAccountStore((store) => store.updateGridStore);
|
||||
@@ -52,34 +55,27 @@ export const AccountsContainer = ({
|
||||
<AccountManager
|
||||
partyId={pubKey}
|
||||
onClickAsset={onClickAsset}
|
||||
onClickWithdraw={(assetId) => {
|
||||
setView({ type: ViewType.Withdraw, assetId });
|
||||
}}
|
||||
onClickDeposit={(assetId) => {
|
||||
setView({ type: ViewType.Deposit, assetId });
|
||||
}}
|
||||
onClickTransfer={(assetId) => {
|
||||
setView({ type: ViewType.Transfer, assetId });
|
||||
}}
|
||||
onClickWithdraw={openWithdrawalDialog}
|
||||
onClickDeposit={openDepositDialog}
|
||||
onMarketClick={onMarketClick}
|
||||
isReadOnly={isReadOnly}
|
||||
pinnedAsset={pinnedAsset}
|
||||
gridProps={gridStoreCallbacks}
|
||||
/>
|
||||
{!isReadOnly && !hideButtons && (
|
||||
<div className="flex gap-2 justify-end p-2 absolute bottom-0 right-0 dark:bg-black/75 bg-white/75 rounded">
|
||||
<div className="flex gap-2 justify-end p-2 px-[11px] absolute lg:fixed bottom-0 right-3 dark:bg-black/75 bg-white/75 rounded">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
data-testid="open-transfer"
|
||||
onClick={() => setView({ type: ViewType.Transfer })}
|
||||
data-testid="open-transfer-dialog"
|
||||
onClick={() => openTransferDialog()}
|
||||
>
|
||||
{t('Transfer')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={() => setView({ type: ViewType.Deposit })}
|
||||
onClick={() => openDepositDialog()}
|
||||
>
|
||||
{t('Deposit')}
|
||||
</Button>
|
||||
|
||||
@@ -6,7 +6,7 @@ export const AnnouncementBanner = () => {
|
||||
// Return an empty div so that the grid layout in _app.page.ts
|
||||
// renders correctly
|
||||
if (!ANNOUNCEMENTS_CONFIG_URL) {
|
||||
return null;
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return <Banner app="console" configUrl={ANNOUNCEMENTS_CONFIG_URL} />;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { NodeHealth, NodeUrl, HealthIndicator } from './footer';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
const mockSetNodeSwitcher = jest.fn();
|
||||
|
||||
jest.mock('@vegaprotocol/environment', () => ({
|
||||
...jest.requireActual('@vegaprotocol/environment'),
|
||||
useEnvironment: jest.fn().mockImplementation(() => ({
|
||||
VEGA_URL: 'https://vega-url.wtf',
|
||||
VEGA_INCIDENT_URL: 'https://blog.vega.community',
|
||||
})),
|
||||
useNodeSwitcherStore: jest.fn(() => mockSetNodeSwitcher),
|
||||
}));
|
||||
|
||||
describe('NodeHealth', () => {
|
||||
it('controls the node switcher dialog', async () => {
|
||||
render(<NodeHealth />, { wrapper: MockedProvider });
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
expect(mockSetNodeSwitcher).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('External link to blog should be present', () => {
|
||||
render(<NodeHealth />, { wrapper: MockedProvider });
|
||||
expect(
|
||||
screen.getByRole('link', { name: /^Mainnet status & incidents/ })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('NodeUrl', () => {
|
||||
it('renders correct part of node url', () => {
|
||||
const node = 'https://api.n99.somenetwork.vega.xyz';
|
||||
|
||||
render(<NodeUrl url={node} />);
|
||||
|
||||
expect(
|
||||
screen.getByText('api.n99.somenetwork.vega.xyz')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('HealthIndicator', () => {
|
||||
const cases = [
|
||||
{
|
||||
intent: Intent.Success,
|
||||
text: 'Operational',
|
||||
classname: 'bg-vega-green-550',
|
||||
},
|
||||
{
|
||||
intent: Intent.Warning,
|
||||
text: '5 Blocks behind',
|
||||
classname: 'bg-warning',
|
||||
},
|
||||
{ intent: Intent.Danger, text: 'Non operational', classname: 'bg-danger' },
|
||||
];
|
||||
it.each(cases)(
|
||||
'renders correct text and indicator color for $diff block difference',
|
||||
(elem) => {
|
||||
render(<HealthIndicator text={elem.text} intent={elem.intent} />);
|
||||
expect(screen.getByTestId('indicator')).toHaveClass(elem.classname);
|
||||
expect(screen.getByText(elem.text)).toBeInTheDocument();
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,119 @@
|
||||
import { useCallback } from 'react';
|
||||
import {
|
||||
useEnvironment,
|
||||
useNodeHealth,
|
||||
useNodeSwitcherStore,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { Indicator, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
||||
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<footer className="px-4 py-1 text-xs border-t border-default text-vega-light-300 dark:text-vega-dark-300 lg:fixed bottom-0 left-0 border-r bg-white dark:bg-black">
|
||||
{/* Pull left to align with top nav, due to button padding */}
|
||||
<div className="-ml-2">
|
||||
<NodeHealth />
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export const NodeHealth = () => {
|
||||
const { VEGA_URL, VEGA_INCIDENT_URL } = useEnvironment();
|
||||
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
|
||||
const { datanodeBlockHeight, text, intent } = useNodeHealth();
|
||||
const onClick = useCallback(() => {
|
||||
setNodeSwitcher(true);
|
||||
}, [setNodeSwitcher]);
|
||||
const incidentsLink = VEGA_INCIDENT_URL && (
|
||||
<ExternalLink className="ml-1" href={VEGA_INCIDENT_URL}>
|
||||
{t('Mainnet status & incidents')}
|
||||
</ExternalLink>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
{VEGA_URL && (
|
||||
<FooterButton onClick={onClick} data-testid="node-health">
|
||||
<FooterButtonPart>
|
||||
<HealthIndicator text={text} intent={intent} />
|
||||
</FooterButtonPart>
|
||||
<FooterButtonPart>
|
||||
<NodeUrl url={VEGA_URL} />
|
||||
</FooterButtonPart>
|
||||
{/* create a monospace effect - avoiding jumps of width */}
|
||||
<FooterButtonPart
|
||||
width={`${
|
||||
datanodeBlockHeight
|
||||
? String(datanodeBlockHeight).length + 'ch'
|
||||
: 'auto'
|
||||
}`}
|
||||
>
|
||||
<span title={t('Block height')}>{datanodeBlockHeight}</span>
|
||||
</FooterButtonPart>
|
||||
</FooterButton>
|
||||
)}
|
||||
{incidentsLink}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface NodeUrlProps {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export const NodeUrl = ({ url }: NodeUrlProps) => {
|
||||
const urlObj = new URL(url);
|
||||
const nodeUrl = urlObj.hostname;
|
||||
return <span title={t('Connected node')}>{nodeUrl}</span>;
|
||||
};
|
||||
|
||||
interface HealthIndicatorProps {
|
||||
text: string;
|
||||
intent: Intent;
|
||||
}
|
||||
|
||||
export const HealthIndicator = ({ text, intent }: HealthIndicatorProps) => {
|
||||
return (
|
||||
<span title={t('Node health')}>
|
||||
<Indicator variant={intent} />
|
||||
{text}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
type FooterButtonProps = ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
const FooterButton = (props: FooterButtonProps) => {
|
||||
const buttonClasses = classNames(
|
||||
'px-2 py-0.5 rounded-md',
|
||||
'enabled:hover:bg-vega-light-150',
|
||||
'dark:enabled:hover:bg-vega-dark-150'
|
||||
);
|
||||
return <button {...props} className={buttonClasses} />;
|
||||
};
|
||||
|
||||
const FooterButtonPart = ({
|
||||
width = 'auto',
|
||||
children,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
width?: string;
|
||||
}) => {
|
||||
return (
|
||||
<span
|
||||
style={{ width }}
|
||||
className={classNames(
|
||||
'relative inline-block mr-2 last:mr-0 pr-2 last:pr-0',
|
||||
'last:after:hidden',
|
||||
'after:content after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2',
|
||||
'after:h-3 after:w-1 after:border-r',
|
||||
'after:border-vega-light-300 dark:after:border-vega-dark-300'
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './footer';
|
||||
@@ -1,30 +1,28 @@
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ReactElement, ReactNode } from 'react';
|
||||
import { Children } from 'react';
|
||||
import { cloneElement } from 'react';
|
||||
|
||||
interface TradeMarketHeaderProps {
|
||||
title: ReactNode;
|
||||
children: ReactNode;
|
||||
children: Array<ReactElement | null>;
|
||||
}
|
||||
|
||||
export const Header = ({ title, children }: TradeMarketHeaderProps) => {
|
||||
const headerClasses = classNames(
|
||||
'grid',
|
||||
'grid-rows-[min-content_min-content]',
|
||||
'xl:grid-cols-[min-content_1fr]',
|
||||
'lg:border-x border-b border-default',
|
||||
'bg-vega-clight-800 dark:bg-vega-cdark-800'
|
||||
);
|
||||
return (
|
||||
<header className="lg:px-1">
|
||||
<div className={headerClasses}>
|
||||
<div className="flex flex-col justify-center items-start pl-3 lg:pl-4 pt-2 xl:pb-2 pb-0">
|
||||
{title}
|
||||
</div>
|
||||
<div data-testid="header-summary" className="min-w-0">
|
||||
<div className="px-3 lg:px-4 py-2 flex flex-nowrap gap-4 items-center text-xs overflow-x-auto">
|
||||
{children}
|
||||
</div>
|
||||
<header className="w-screen xl:px-4 pt-2 border-b border-default">
|
||||
<div className="xl:flex xl:gap-4 items-end">
|
||||
<div className="px-4 xl:px-0 pb-2 xl:pb-3">{title}</div>
|
||||
<div
|
||||
data-testid="header-summary"
|
||||
className="flex flex-nowrap items-end xl:flex-1 w-full overflow-x-auto text-xs"
|
||||
>
|
||||
{Children.map(children, (child, index) => {
|
||||
if (!child) return null;
|
||||
return cloneElement(child, {
|
||||
id: `header-stat-${index}`,
|
||||
});
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
@@ -44,11 +42,9 @@ export const HeaderStat = ({
|
||||
description?: string | ReactNode;
|
||||
testId?: string;
|
||||
}) => {
|
||||
const itemClass = classNames(
|
||||
'text-muted',
|
||||
'min-w-min last:pr-0 whitespace-nowrap'
|
||||
);
|
||||
const itemValueClasses = 'text-default';
|
||||
const itemClass =
|
||||
'min-w-min w-[120px] whitespace-nowrap pb-3 px-4 border-l border-default first:border-none text-neutral-500 dark:text-neutral-400';
|
||||
const itemHeading = 'text-black dark:text-white';
|
||||
|
||||
return (
|
||||
<div data-testid={testId} className={itemClass}>
|
||||
@@ -59,7 +55,7 @@ export const HeaderStat = ({
|
||||
<div
|
||||
data-testid="item-value"
|
||||
aria-labelledby={id}
|
||||
className={itemValueClasses}
|
||||
className={itemHeading}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
@@ -68,13 +64,21 @@ export const HeaderStat = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const HeaderTitle = ({ children }: { children: ReactNode }) => {
|
||||
export const HeaderTitle = ({
|
||||
primaryContent,
|
||||
secondaryContent,
|
||||
}: {
|
||||
primaryContent: ReactNode;
|
||||
secondaryContent: ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<h1
|
||||
data-testid="header-title"
|
||||
className="flex gap-4 items-center text-lg whitespace-nowrap xl:pr-4 xl:border-r border-default"
|
||||
>
|
||||
{children}
|
||||
</h1>
|
||||
<div className="text-left" data-testid="header-title">
|
||||
<div className="text-sm md:text-md lg:text-lg whitespace-nowrap !leading-[1]">
|
||||
{primaryContent}
|
||||
</div>
|
||||
<div className="text-xs whitespace-nowrap text-vega-light-300 dark:text-vega-dark-300">
|
||||
{secondaryContent}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './layout-with-sidebar';
|
||||
@@ -1,38 +0,0 @@
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import { Sidebar, SidebarContent, useSidebar } from '../sidebar';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export const LayoutWithSidebar = () => {
|
||||
const sidebarView = useSidebar((store) => store.view);
|
||||
const sidebarOpen = sidebarView !== null;
|
||||
|
||||
const gridClasses = classNames(
|
||||
'h-full relative z-0 grid',
|
||||
'grid-cols-[1fr_45px]',
|
||||
'lg:grid-cols-[1fr_350px_45px]'
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={gridClasses}>
|
||||
<section
|
||||
className={classNames('col-start-1 col-end-1', {
|
||||
'lg:col-end-3': !sidebarOpen,
|
||||
'hidden lg:block lg:col-end-2': sidebarOpen,
|
||||
})}
|
||||
>
|
||||
<Outlet />
|
||||
</section>
|
||||
<div
|
||||
// min-h-0 is needed as this element is part of a grid, we want the content to be scrollable, without it it will push the grid element taller
|
||||
className={classNames('col-start-1 lg:col-start-2 min-h-0', {
|
||||
hidden: !sidebarOpen,
|
||||
})}
|
||||
>
|
||||
<SidebarContent />
|
||||
</div>
|
||||
<div className="col-start-2 lg:col-start-3 bg-vega-clight-800 dark:bg-vega-cdark-800 border-l border-default">
|
||||
<Sidebar />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -156,7 +156,8 @@ export const MarketLiquiditySupplied = ({
|
||||
description={description}
|
||||
testId="liquidity-supplied"
|
||||
>
|
||||
<Indicator variant={status} /> {supplied} (
|
||||
<Indicator variant={status} />
|
||||
{supplied} (
|
||||
{percentage.gt(100) ? '>100%' : formatNumberPercentage(percentage, 2)})
|
||||
</HeaderStat>
|
||||
) : (
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './market-successor-banner';
|
||||
@@ -1,188 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/react-testing';
|
||||
import * as dataProviders from '@vegaprotocol/data-provider';
|
||||
import { MarketSuccessorBanner } from './market-successor-banner';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import * as allUtils from '@vegaprotocol/utils';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
const market = {
|
||||
id: 'marketId',
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
metadata: {
|
||||
tags: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
marketTimestamps: {
|
||||
close: null,
|
||||
},
|
||||
successorMarketID: 'successorMarketID',
|
||||
} as unknown as Market;
|
||||
|
||||
let mockDataSuccessorMarket: PartialDeep<Market> | null = null;
|
||||
jest.mock('@vegaprotocol/data-provider', () => ({
|
||||
...jest.requireActual('@vegaprotocol/data-provider'),
|
||||
useDataProvider: jest.fn().mockImplementation((args) => {
|
||||
if (args.skip) {
|
||||
return {
|
||||
data: null,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
return {
|
||||
data: mockDataSuccessorMarket,
|
||||
error: null,
|
||||
};
|
||||
}),
|
||||
}));
|
||||
jest.mock('@vegaprotocol/utils', () => ({
|
||||
...jest.requireActual('@vegaprotocol/utils'),
|
||||
getMarketExpiryDate: jest.fn(),
|
||||
}));
|
||||
let mockCandles = {};
|
||||
jest.mock('@vegaprotocol/markets', () => ({
|
||||
...jest.requireActual('@vegaprotocol/markets'),
|
||||
useCandles: () => mockCandles,
|
||||
}));
|
||||
|
||||
describe('MarketSuccessorBanner', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockDataSuccessorMarket = {
|
||||
id: 'successorMarketID',
|
||||
state: Types.MarketState.STATE_ACTIVE,
|
||||
tradingMode: Types.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
name: 'Successor Market Name',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
describe('should be hidden', () => {
|
||||
it('when no market', () => {
|
||||
const { container } = render(<MarketSuccessorBanner market={null} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('when no successorMarketID', () => {
|
||||
const amendedMarket = {
|
||||
...market,
|
||||
successorMarketID: null,
|
||||
};
|
||||
const { container } = render(
|
||||
<MarketSuccessorBanner market={amendedMarket} />,
|
||||
{
|
||||
wrapper: MockedProvider,
|
||||
}
|
||||
);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
expect(dataProviders.useDataProvider).lastCalledWith(
|
||||
expect.objectContaining({ skip: true })
|
||||
);
|
||||
});
|
||||
|
||||
it('no successor market data', () => {
|
||||
mockDataSuccessorMarket = null;
|
||||
const { container } = render(<MarketSuccessorBanner market={market} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
expect(dataProviders.useDataProvider).lastCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: { marketId: 'successorMarketID' },
|
||||
skip: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('successor market not in continuous mode', () => {
|
||||
mockDataSuccessorMarket = {
|
||||
...mockDataSuccessorMarket,
|
||||
tradingMode: Types.MarketTradingMode.TRADING_MODE_NO_TRADING,
|
||||
};
|
||||
const { container } = render(<MarketSuccessorBanner market={market} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
expect(dataProviders.useDataProvider).lastCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: { marketId: 'successorMarketID' },
|
||||
skip: false,
|
||||
})
|
||||
);
|
||||
expect(allUtils.getMarketExpiryDate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('successor market is not active', () => {
|
||||
mockDataSuccessorMarket = {
|
||||
...mockDataSuccessorMarket,
|
||||
state: Types.MarketState.STATE_PENDING,
|
||||
};
|
||||
const { container } = render(<MarketSuccessorBanner market={market} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
expect(dataProviders.useDataProvider).lastCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: { marketId: 'successorMarketID' },
|
||||
skip: false,
|
||||
})
|
||||
);
|
||||
expect(allUtils.getMarketExpiryDate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('should be displayed', () => {
|
||||
it('should be rendered', () => {
|
||||
render(<MarketSuccessorBanner market={market} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(
|
||||
screen.getByText('This market has been succeeded')
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('link', { name: 'Successor Market Name' })
|
||||
).toHaveAttribute('href', '/#/markets/successorMarketID');
|
||||
});
|
||||
|
||||
it('should display optionally successor volume', () => {
|
||||
mockDataSuccessorMarket = {
|
||||
...mockDataSuccessorMarket,
|
||||
positionDecimalPlaces: 3,
|
||||
};
|
||||
mockCandles = {
|
||||
oneDayCandles: [
|
||||
{ volume: 123 },
|
||||
{ volume: 456 },
|
||||
{ volume: 789 },
|
||||
{ volume: 99999 },
|
||||
],
|
||||
};
|
||||
|
||||
render(<MarketSuccessorBanner market={market} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(screen.getByText('has 101.367 24h vol.')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display optionally duration', () => {
|
||||
jest
|
||||
.spyOn(allUtils, 'getMarketExpiryDate')
|
||||
.mockReturnValue(
|
||||
new Date(Date.now() + 24 * 60 * 60 * 1000 + 60 * 1000)
|
||||
);
|
||||
render(<MarketSuccessorBanner market={market} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(
|
||||
screen.getByText(/^This market expires in 1 day/)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,115 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import { isBefore, formatDuration, intervalToDuration } from 'date-fns';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import {
|
||||
calcCandleVolume,
|
||||
marketProvider,
|
||||
useCandles,
|
||||
} from '@vegaprotocol/markets';
|
||||
import {
|
||||
ExternalLink,
|
||||
Intent,
|
||||
NotificationBanner,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
getMarketExpiryDate,
|
||||
isNumeric,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
const getExpiryDate = (tags: string[], close?: string): Date | null => {
|
||||
const expiryDate = getMarketExpiryDate(tags);
|
||||
return expiryDate || (close && new Date(close)) || null;
|
||||
};
|
||||
|
||||
export const MarketSuccessorBanner = ({
|
||||
market,
|
||||
}: {
|
||||
market: Market | null;
|
||||
}) => {
|
||||
const { data: successorData } = useDataProvider({
|
||||
dataProvider: marketProvider,
|
||||
variables: {
|
||||
marketId: market?.successorMarketID || '',
|
||||
},
|
||||
skip: !market?.successorMarketID,
|
||||
});
|
||||
const [visible, setVisible] = useState(true);
|
||||
|
||||
const expiry = market
|
||||
? getExpiryDate(
|
||||
market.tradableInstrument.instrument.metadata.tags || [],
|
||||
market.marketTimestamps.close
|
||||
)
|
||||
: null;
|
||||
|
||||
const duration =
|
||||
expiry && isBefore(new Date(), expiry)
|
||||
? intervalToDuration({ start: new Date(), end: expiry })
|
||||
: null;
|
||||
|
||||
const isInContinuesMode =
|
||||
successorData?.state === Types.MarketState.STATE_ACTIVE &&
|
||||
successorData?.tradingMode ===
|
||||
Types.MarketTradingMode.TRADING_MODE_CONTINUOUS;
|
||||
|
||||
const { oneDayCandles } = useCandles({
|
||||
marketId: successorData?.id,
|
||||
});
|
||||
|
||||
const candleVolume = oneDayCandles?.length
|
||||
? calcCandleVolume(oneDayCandles)
|
||||
: null;
|
||||
|
||||
const successorVolume =
|
||||
candleVolume && isNumeric(successorData?.positionDecimalPlaces)
|
||||
? addDecimalsFormatNumber(
|
||||
candleVolume,
|
||||
successorData?.positionDecimalPlaces as number
|
||||
)
|
||||
: null;
|
||||
|
||||
if (isInContinuesMode && visible) {
|
||||
return (
|
||||
<NotificationBanner
|
||||
intent={Intent.Primary}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="uppercase mb-1">
|
||||
{t('This market has been succeeded')}
|
||||
</div>
|
||||
<div>
|
||||
{duration && (
|
||||
<span>
|
||||
{t('This market expires in %s.', [
|
||||
formatDuration(duration, {
|
||||
format: [
|
||||
'years',
|
||||
'months',
|
||||
'weeks',
|
||||
'days',
|
||||
'hours',
|
||||
'minutes',
|
||||
],
|
||||
}),
|
||||
])}
|
||||
</span>
|
||||
)}{' '}
|
||||
{t('The successor market')}{' '}
|
||||
<ExternalLink href={`/#/markets/${successorData?.id}`}>
|
||||
{successorData?.tradableInstrument.instrument.name}
|
||||
</ExternalLink>
|
||||
{successorVolume && (
|
||||
<span> {t('has %s 24h vol.', [successorVolume])}</span>
|
||||
)}
|
||||
</div>
|
||||
</NotificationBanner>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { SettingsButton } from '../../client-pages/settings';
|
||||
import {
|
||||
ProtocolUpgradeCountdown,
|
||||
ProtocolUpgradeCountdownMode,
|
||||
@@ -44,13 +45,14 @@ export const Navbar = ({
|
||||
|
||||
return (
|
||||
<Navigation
|
||||
appName="console"
|
||||
appName="Console"
|
||||
theme={theme}
|
||||
actions={
|
||||
<>
|
||||
<ProtocolUpgradeCountdown
|
||||
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
|
||||
/>
|
||||
<SettingsButton />
|
||||
<VegaWalletConnectButton />
|
||||
</>
|
||||
}
|
||||
@@ -118,6 +120,18 @@ export const Navbar = ({
|
||||
</NavigationItem>
|
||||
)}
|
||||
</NavigationList>
|
||||
<NavigationList
|
||||
className="[.drawer-content_&]:border-t [.drawer-content_&]:border-t-vega-light-200 dark:[.drawer-content_&]:border-t-vega-dark-200 [.drawer-content_&]:pt-4 [.drawer-content_&]:mt-4"
|
||||
hide={[
|
||||
NavigationBreakpoint.Small,
|
||||
NavigationBreakpoint.Narrow,
|
||||
NavigationBreakpoint.Full,
|
||||
]}
|
||||
>
|
||||
<NavigationItem className="[.drawer-content_&]:w-full">
|
||||
<SettingsButton withMobile />
|
||||
</NavigationItem>
|
||||
</NavigationList>
|
||||
</Navigation>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './node-health';
|
||||
@@ -1,62 +0,0 @@
|
||||
import { render, screen, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { NodeHealthContainer, NodeUrl } from './node-health';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
const mockSetNodeSwitcher = jest.fn();
|
||||
|
||||
jest.mock('@vegaprotocol/environment', () => ({
|
||||
...jest.requireActual('@vegaprotocol/environment'),
|
||||
useEnvironment: jest.fn().mockImplementation(() => ({
|
||||
VEGA_URL: 'https://vega-url.wtf',
|
||||
VEGA_INCIDENT_URL: 'https://blog.vega.community',
|
||||
})),
|
||||
useNodeSwitcherStore: jest.fn(() => mockSetNodeSwitcher),
|
||||
}));
|
||||
|
||||
describe('NodeHealthContainer', () => {
|
||||
it('controls the node switcher dialog', async () => {
|
||||
render(<NodeHealthContainer />, { wrapper: MockedProvider });
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
expect(mockSetNodeSwitcher).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Shows node health data on hover', async () => {
|
||||
render(<NodeHealthContainer />, { wrapper: MockedProvider });
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
await userEvent.hover(screen.getByRole('button'));
|
||||
await waitFor(() => {
|
||||
const portal = within(
|
||||
document.querySelector(
|
||||
'[data-radix-popper-content-wrapper]'
|
||||
) as HTMLElement
|
||||
);
|
||||
// two tooltips get rendered, I believe for animation purposes
|
||||
const tooltip = within(portal.getAllByTestId('tooltip-content')[0]);
|
||||
expect(
|
||||
tooltip.getByRole('link', { name: /^Mainnet status & incidents/ })
|
||||
).toBeInTheDocument();
|
||||
expect(tooltip.getByText('Non operational')).toBeInTheDocument();
|
||||
expect(tooltip.getByTitle('Connected node')).toHaveTextContent(
|
||||
'vega-url.wtf'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('NodeUrl', () => {
|
||||
it('renders correct part of node url', () => {
|
||||
const node = 'https://api.n99.somenetwork.vega.xyz';
|
||||
|
||||
render(<NodeUrl url={node} />);
|
||||
|
||||
expect(
|
||||
screen.getByText('api.n99.somenetwork.vega.xyz')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user