Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a213632794 |
+2
-5
@@ -51,8 +51,7 @@
|
|||||||
"ul": ["list"],
|
"ul": ["list"],
|
||||||
"ol": ["list"]
|
"ol": ["list"]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"no-console": ["error", { "allow": ["warn", "error"] }]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -73,11 +72,9 @@
|
|||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"prefer": "type-imports",
|
"prefer": "type-imports",
|
||||||
"disallowTypeAnnotations": true,
|
"disallowTypeAnnotations": true
|
||||||
"fixStyle": "inline-type-imports"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"@typescript-eslint/no-useless-constructor": 0,
|
|
||||||
"curly": ["error", "multi-line"]
|
"curly": ["error", "multi-line"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
* text eol=lf
|
* text eol=lf
|
||||||
*.png binary
|
*.png binary
|
||||||
*.ico binary
|
*.ico binary
|
||||||
*.woff2 binary
|
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature Epic
|
|
||||||
about: A template to capture and scope user requirements, high level process, and basic mockups for an upcoming feature as part of the initial core spec review process.
|
|
||||||
title: 'FEATURE EPIC: '
|
|
||||||
labels: feature-epic
|
|
||||||
---
|
|
||||||
|
|
||||||
## Core Feature
|
|
||||||
|
|
||||||
<Name>
|
|
||||||
|
|
||||||
## Tasks
|
|
||||||
|
|
||||||
- [ ] Define high level requirements
|
|
||||||
- [ ] Create basic mockups
|
|
||||||
- [ ] Update "API Requirements" in core spec
|
|
||||||
- [ ] Update "User-Interface Spec" in relevant front end repo
|
|
||||||
- [ ] Create detailed user stories using normal template
|
|
||||||
|
|
||||||
## High Level Requirements
|
|
||||||
|
|
||||||
## Basic Mockups
|
|
||||||
|
|
||||||
## Link to API Requirements in Core spec
|
|
||||||
|
|
||||||
## Link to User Interface Specs
|
|
||||||
|
|
||||||
## Linked User Stories
|
|
||||||
@@ -7,7 +7,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
after-release:
|
after-release:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
timeout-minutes: 45
|
timeout-minutes: 30
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -30,20 +30,18 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Wait for publish to complete
|
|
||||||
uses: lewagon/wait-on-check-action@v1.3.1
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.release.tag_name }}
|
|
||||||
check-name: '(CD) publish dist / trading'
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
wait-interval: 10
|
|
||||||
|
|
||||||
- name: resolve ipfs hashes for release
|
- name: resolve ipfs hashes for release
|
||||||
run: |
|
run: |
|
||||||
echo "Name: ${{ github.event.release.name }}"
|
echo "Name: ${{ github.event.release.name }}"
|
||||||
echo "Description: ${{ github.event.release.body }}"
|
echo "Description: ${{ github.event.release.body }}"
|
||||||
echo "Tag: ${{ github.event.release.tag_name }}"
|
echo "Tag: ${{ github.event.release.tag_name }}"
|
||||||
docker run --rm vegaprotocol/trading:mainnet cat /ipfs-hash > ipfs-hash
|
commit="$(git rev-list -n 1 ${{ github.event.release.tag_name }})"
|
||||||
|
echo "Commit: $commit"
|
||||||
|
until docker pull vegaprotocol/trading:$commit; do
|
||||||
|
echo "Image not pushed yet, waiting 60 seconds"
|
||||||
|
sleep 60
|
||||||
|
done
|
||||||
|
docker run --rm vegaprotocol/trading:$commit cat /ipfs-hash > ipfs-hash
|
||||||
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
|
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
|
||||||
tar -xzf kubo.tgz
|
tar -xzf kubo.tgz
|
||||||
export PATH="$PATH:$PWD/kubo"
|
export PATH="$PATH:$PWD/kubo"
|
||||||
@@ -82,38 +80,3 @@ jobs:
|
|||||||
https://${{ env.IPFS_V1 }}.ipfs.dweb.link/
|
https://${{ env.IPFS_V1 }}.ipfs.dweb.link/
|
||||||
https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/
|
https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/
|
||||||
ipfs://${{ env.IPFS_V0 }}/
|
ipfs://${{ env.IPFS_V0 }}/
|
||||||
|
|
||||||
- name: Ensure 'Released' label exists
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
REPO="${{ github.repository }}"
|
|
||||||
LABEL_EXIST=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
"https://api.github.com/repos/$REPO/labels/Released")
|
|
||||||
if [[ "$LABEL_EXIST" == *"Not Found"* ]]; then
|
|
||||||
curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
-X POST "https://api.github.com/repos/$REPO/labels" \
|
|
||||||
-d '{"name": "Released", "color": "FFFFFF"}'
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Extract issues from release notes
|
|
||||||
id: extract-issues
|
|
||||||
run: |
|
|
||||||
ISSUES=$(echo "${{ github.event.release.body }}" | grep -o -E '#[0-9]+' | tr -d '#' | jq -R . | jq -cs .)
|
|
||||||
echo "Issues to label: $ISSUES"
|
|
||||||
echo "::set-output name=issue_numbers::$ISSUES"
|
|
||||||
|
|
||||||
- name: Add 'Released' label to issues
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
ISSUE_NUMBERS="${{ steps.extract-issues.outputs.issue_numbers }}"
|
|
||||||
REPO="${{ github.repository }}"
|
|
||||||
for ISSUE in $(echo "$ISSUE_NUMBERS" | jq -r '.[]'); do
|
|
||||||
curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
-X POST "https://api.github.com/repos/$REPO/issues/$ISSUE/labels" \
|
|
||||||
-d '{"labels": ["Released"]}'
|
|
||||||
done
|
|
||||||
|
|||||||
+154
-132
@@ -5,17 +5,15 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- release/*
|
- release/*
|
||||||
- develop
|
- develop
|
||||||
- main
|
|
||||||
pull_request:
|
pull_request:
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
- ready_for_review
|
- ready_for_review
|
||||||
- reopened
|
- reopened
|
||||||
|
- edited
|
||||||
- synchronize
|
- synchronize
|
||||||
jobs:
|
jobs:
|
||||||
node-modules:
|
node-modules:
|
||||||
# All jobs depend on node_modules, so none should run if the PR is in draft
|
|
||||||
if: github.event.pull_request.draft == false
|
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
name: 'Cache yarn modules'
|
name: 'Cache yarn modules'
|
||||||
steps:
|
steps:
|
||||||
@@ -23,6 +21,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: Cache node modules
|
||||||
id: cache
|
id: cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -34,21 +33,29 @@ jobs:
|
|||||||
${{ runner.os }}-cache-node-modules-
|
${{ runner.os }}-cache-node-modules-
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|
||||||
- name: yarn install
|
- name: yarn install
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
run: yarn install --pure-lockfile
|
run: yarn install --pure-lockfile
|
||||||
|
|
||||||
lint-format:
|
lint-pr-title:
|
||||||
timeout-minutes: 20
|
needs: node-modules
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
name: Verify PR title
|
||||||
|
uses: ./.github/workflows/lint-pr.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
lint-test-build:
|
||||||
|
timeout-minutes: 60
|
||||||
needs: node-modules
|
needs: node-modules
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
name: '(CI) lint + format check'
|
name: '(CI) lint + unit test + build'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -57,7 +64,7 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
@@ -83,85 +90,132 @@ jobs:
|
|||||||
- name: Build affected spec
|
- name: Build affected spec
|
||||||
run: yarn nx affected --target=build-spec
|
run: yarn nx affected --target=build-spec
|
||||||
|
|
||||||
test-affected:
|
|
||||||
timeout-minutes: 30
|
|
||||||
needs: build-sources
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: 'run unit test of affected apps'
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: node_modules
|
|
||||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
|
||||||
|
|
||||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
|
||||||
uses: nrwl/nx-set-shas@v3
|
|
||||||
with:
|
|
||||||
main-branch-name: develop
|
|
||||||
|
|
||||||
- name: Test affected
|
- name: Test affected
|
||||||
run: yarn nx affected:test
|
run: yarn nx affected:test
|
||||||
|
|
||||||
build-sources:
|
- name: Build affected
|
||||||
timeout-minutes: 30
|
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
||||||
needs: lint-format
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: 'Build sources of affected apps'
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: node_modules
|
|
||||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
|
||||||
|
|
||||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
|
||||||
uses: nrwl/nx-set-shas@v3
|
|
||||||
with:
|
|
||||||
main-branch-name: develop
|
|
||||||
|
|
||||||
# See affected apps
|
# See affected apps
|
||||||
- name: See affected apps
|
- name: See affected apps
|
||||||
run: |
|
run: |
|
||||||
|
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
|
||||||
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
|
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
|
||||||
python3 tools/ci/check-affected.py --github-ref="${{ github.ref }}" --branch-slug="$branch_slug" --event-name="${{ github.event_name }}"
|
|
||||||
|
|
||||||
- name: Verify script result
|
echo ">>>> debug"
|
||||||
run: |
|
echo "NX_BASE: ${{ env.NX_BASE }}"
|
||||||
echo "Check outputs from script"
|
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
||||||
echo "projects: ${{ env.PROJECTS }}"
|
echo "Affected: ${affected}"
|
||||||
echo "projects-e2e: ${{ env.PROJECTS_E2E }}"
|
echo "Branch slug: ${branch_slug}"
|
||||||
echo "preview_governance: ${{ env.PREVIEW_GOVERNANCE }}"
|
echo "Current ref: ${{ github.ref }}"
|
||||||
echo "preview_trading: ${{ env.PREVIEW_TRADING }}"
|
echo ">>>> eof debug"
|
||||||
echo "preview_explorer: ${{ env.PREVIEW_EXPLORER }}"
|
|
||||||
echo "preview_tools: ${{ env.PREVIEW_TOOLS }}"
|
projects_array=()
|
||||||
|
|
||||||
|
preview_governance="not deployed"
|
||||||
|
preview_trading="not deployed"
|
||||||
|
preview_explorer="not deployed"
|
||||||
|
preview_tools="not deployed"
|
||||||
|
|
||||||
|
# parse if affected is any of three main applications, if none - use all of them
|
||||||
|
if echo "$affected" | grep -q governance; then
|
||||||
|
echo "Governance is affected"
|
||||||
|
projects_array+=("governance")
|
||||||
|
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
||||||
|
fi
|
||||||
|
if echo "$affected" | grep -q trading; then
|
||||||
|
echo "Trading is affected"
|
||||||
|
projects_array+=("trading")
|
||||||
|
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
||||||
|
fi
|
||||||
|
if echo "$affected" | grep -q explorer; then
|
||||||
|
echo "Explorer is affected"
|
||||||
|
projects_array+=("explorer")
|
||||||
|
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
||||||
|
fi
|
||||||
|
if [[ ${#projects_array[@]} -eq 0 ]]; then
|
||||||
|
projects_array=("governance" "trading" "explorer")
|
||||||
|
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
||||||
|
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
||||||
|
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# applications parsed before this loop are applicable for running e2e-tests
|
||||||
|
projects_e2e_array=()
|
||||||
|
for project in "${projects_array[@]}"; do
|
||||||
|
projects_e2e_array+=("${project}-e2e")
|
||||||
|
done
|
||||||
|
# all applications below this loop are not applicable for running e2e-test
|
||||||
|
|
||||||
|
# check if pull request event to deploy tools
|
||||||
|
if [[ "${{ github.event_name }}" = "pull_request" ]]; then
|
||||||
|
if echo "$affected" | grep -q multisig-signer; then
|
||||||
|
echo "Tools are affected"
|
||||||
|
echo "Deploying tools on preview"
|
||||||
|
preview_tools=$(printf "https://%s.%s.vega.rocks" "tools" "$branch_slug")
|
||||||
|
|
||||||
|
projects_array+=("multisig-signer")
|
||||||
|
fi
|
||||||
|
# those apps deploy only from develop to mainnet
|
||||||
|
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||||
|
if echo "$affected" | grep -q multisig-signer; then
|
||||||
|
echo "Tools are affected"
|
||||||
|
echo "Deploying tools on s3"
|
||||||
|
|
||||||
|
projects_array+=("multisig-signer")
|
||||||
|
fi
|
||||||
|
if echo "$affected" | grep -q static; then
|
||||||
|
echo "static is affected"
|
||||||
|
echo "Deploying static on s3"
|
||||||
|
|
||||||
|
projects_array+=("static")
|
||||||
|
fi
|
||||||
|
if echo "$affected" | grep -q ui-toolkit; then
|
||||||
|
echo "ui-toolkit is affected"
|
||||||
|
echo "Deploying ui-toolkit on s3"
|
||||||
|
|
||||||
|
projects_array+=("ui-toolkit")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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[@]}")
|
||||||
|
projects_e2e_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_e2e_array[@]}")
|
||||||
|
|
||||||
|
echo PROJECTS_E2E=$projects_e2e_json >> $GITHUB_ENV
|
||||||
|
echo PROJECTS=$projects_json >> $GITHUB_ENV
|
||||||
|
|
||||||
|
echo PREVIEW_GOVERNANCE=$preview_governance >> $GITHUB_ENV
|
||||||
|
echo PREVIEW_TRADING=$preview_trading >> $GITHUB_ENV
|
||||||
|
echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
|
||||||
|
echo PREVIEW_TOOLS=$preview_tools >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Build affected
|
|
||||||
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
|
||||||
outputs:
|
outputs:
|
||||||
projects: ${{ env.PROJECTS }}
|
projects: ${{ env.PROJECTS }}
|
||||||
projects-e2e: ${{ env.PROJECTS_E2E }}
|
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||||
@@ -170,62 +224,30 @@ jobs:
|
|||||||
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
||||||
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
||||||
|
|
||||||
check-e2e-needed:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-sources
|
|
||||||
name: '(CI) check if e2e needed'
|
|
||||||
outputs:
|
|
||||||
run-tests: ${{ steps.check-test.outputs.e2e-needed }}
|
|
||||||
steps:
|
|
||||||
- name: Check branch
|
|
||||||
id: check-test
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.base_ref }}" == "develop" ]]; then
|
|
||||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.base_ref }}" == "main" ]]; then
|
|
||||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/"* ]]; then
|
|
||||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "e2e-needed=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
- name: Print result
|
|
||||||
run: |
|
|
||||||
echo "e2e-needed: ${{ steps.check-test.outputs.e2e-needed }}"
|
|
||||||
|
|
||||||
cypress:
|
cypress:
|
||||||
needs: [build-sources, check-e2e-needed]
|
needs: lint-test-build
|
||||||
name: '(CI) cypress'
|
name: '(CI) cypress'
|
||||||
if: ${{ needs.check-e2e-needed.outputs.run-tests == 'true' }}
|
# if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
|
||||||
uses: ./.github/workflows/cypress-run.yml
|
uses: ./.github/workflows/cypress-run.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
projects: ${{ needs.build-sources.outputs.projects-e2e }}
|
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
|
||||||
tags: '@smoke'
|
tags: '@smoke @regression'
|
||||||
|
|
||||||
console-e2e:
|
|
||||||
needs: [build-sources, check-e2e-needed]
|
|
||||||
name: '(CI) trading e2e python'
|
|
||||||
uses: ./.github/workflows/console-test-run.yml
|
|
||||||
secrets: inherit
|
|
||||||
if: needs.check-e2e-needed.outputs.run-tests == 'true' && contains(needs.build-sources.outputs.projects, 'trading')
|
|
||||||
with:
|
|
||||||
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
publish-dist:
|
publish-dist:
|
||||||
needs: build-sources
|
needs: lint-test-build
|
||||||
name: '(CD) publish dist'
|
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: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
|
||||||
uses: ./.github/workflows/publish-dist.yml
|
uses: ./.github/workflows/publish-dist.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
projects: ${{ needs.build-sources.outputs.projects }}
|
projects: ${{ needs.lint-test-build.outputs.projects }}
|
||||||
|
|
||||||
dist-check:
|
dist-check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
- publish-dist
|
- publish-dist
|
||||||
- build-sources
|
- 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.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
name: '(CD) comment preview links'
|
name: '(CD) comment preview links'
|
||||||
@@ -241,27 +263,27 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
||||||
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
||||||
if [[ "${{ needs.build-sources.outputs.preview_governance }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_governance }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
|
||||||
echo "waiting for governance preview: ${{ needs.build-sources.outputs.preview_governance }}"
|
echo "waiting for governance preview: ${{ needs.lint-test-build.outputs.preview_governance }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.build-sources.outputs.preview_explorer }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_explorer }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
|
||||||
echo "waiting for explorer preview: ${{ needs.build-sources.outputs.preview_explorer }}"
|
echo "waiting for explorer preview: ${{ needs.lint-test-build.outputs.preview_explorer }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.build-sources.outputs.preview_trading }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_trading }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
|
||||||
echo "waiting for trading preview: ${{ needs.build-sources.outputs.preview_trading }}"
|
echo "waiting for trading preview: ${{ needs.lint-test-build.outputs.preview_trading }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.build-sources.outputs.preview_tools }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_tools }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
|
||||||
echo "waiting for tools preview: ${{ needs.build-sources.outputs.preview_tools }}"
|
echo "waiting for tools preview: ${{ needs.lint-test-build.outputs.preview_tools }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
@@ -273,10 +295,10 @@ jobs:
|
|||||||
issue-number: ${{ github.event.pull_request.number }}
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
body: |
|
body: |
|
||||||
Previews
|
Previews
|
||||||
* governance: ${{ needs.build-sources.outputs.preview_governance }}
|
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
||||||
* explorer: ${{ needs.build-sources.outputs.preview_explorer }}
|
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
||||||
* trading: ${{ needs.build-sources.outputs.preview_trading }}
|
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
||||||
* tools: ${{ needs.build-sources.outputs.preview_tools }}
|
* tools: ${{ needs.lint-test-build.outputs.preview_tools }}
|
||||||
|
|
||||||
# Report single result at the end, to avoid mess with required checks in PR
|
# Report single result at the end, to avoid mess with required checks in PR
|
||||||
cypress-check:
|
cypress-check:
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#managing-caches
|
|
||||||
name: cleanup caches by a branch
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- closed
|
|
||||||
jobs:
|
|
||||||
cleanup:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Cleanup
|
|
||||||
run: |
|
|
||||||
gh extension install actions/gh-actions-cache
|
|
||||||
|
|
||||||
echo "Fetching list of cache key"
|
|
||||||
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
|
|
||||||
|
|
||||||
## Setting this to not fail the workflow while deleting cache keys.
|
|
||||||
set +e
|
|
||||||
echo "Deleting caches..."
|
|
||||||
for cacheKey in $cacheKeysForPR
|
|
||||||
do
|
|
||||||
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
|
|
||||||
done
|
|
||||||
echo "Done"
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
REPO: ${{ github.repository }}
|
|
||||||
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
|
|
||||||
@@ -1,272 +1,59 @@
|
|||||||
name: (CI) Console tests
|
name: console-test-run
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
github-sha:
|
github-sha:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
console-test-branch:
|
|
||||||
type: choice
|
|
||||||
description: 'main: v0.73.5, develop: v0.73.5'
|
|
||||||
options:
|
|
||||||
- main
|
|
||||||
- develop
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
create-docker-image:
|
console-test:
|
||||||
name: Create docker image for console-test
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
timeout-minutes: 45
|
|
||||||
steps:
|
|
||||||
#----------------------------------------------
|
|
||||||
# check-out frontend-monorepo
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Checkout frontend-monorepo
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: ${{ inputs.github-sha || github.sha }}
|
|
||||||
#----------------------------------------------
|
|
||||||
# cache node modules
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: setup node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Cache node modules
|
|
||||||
id: cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: node_modules
|
|
||||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
|
||||||
# comment out "restore-keys" if you need to rebuild yarn from 0
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-cache-node-modules-
|
|
||||||
#----------------------------------------------
|
|
||||||
# install deps if cache missing
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: yarn install
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
run: yarn install --pure-lockfile
|
|
||||||
#----------------------------------------------
|
|
||||||
# build trading
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Build trading app
|
|
||||||
run: |
|
|
||||||
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
|
|
||||||
DIST_LOCATION=dist/apps/trading/exported
|
|
||||||
mv $DIST_LOCATION dist-result
|
|
||||||
tree dist-result
|
|
||||||
|
|
||||||
#----------------------------------------------
|
|
||||||
# export trading app docker image
|
|
||||||
#----------------------------------------------
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Build and export to local Docker
|
|
||||||
id: docker_build
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/node-outside-docker.Dockerfile
|
|
||||||
load: true
|
|
||||||
build-args: |
|
|
||||||
APP=trading
|
|
||||||
ENV_NAME=stagnet1
|
|
||||||
tags: ci/trading:local
|
|
||||||
outputs: type=docker,dest=/tmp/console-image.tar
|
|
||||||
|
|
||||||
- name: Verify docker image created
|
|
||||||
run: |
|
|
||||||
echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
echo ${{ steps.docker_build.outputs.imageid }}
|
|
||||||
|
|
||||||
- name: Upload docker image for console-test usage
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: console-image
|
|
||||||
path: /tmp/console-image.tar
|
|
||||||
|
|
||||||
console-test-branch:
|
|
||||||
name: Choose console-test branch to run on
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
outputs:
|
runs-on: self-hosted-runner
|
||||||
console-branch: ${{ steps.output-step.outputs.branch }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Workflow dispatch input
|
- name: Checkout console test repo
|
||||||
id: dispatch-step
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
run: echo "branch=${{ inputs.console-test-branch }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Print Workflow dispatch input
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
run: echo ${{ steps.dispatch-step.outputs.branch }}
|
|
||||||
|
|
||||||
- name: Workflow_call input
|
|
||||||
id: workflow_call-step
|
|
||||||
if: github.event_name != 'workflow_dispatch'
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
|
||||||
echo "branch=main" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
|
|
||||||
echo "branch=main" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
|
|
||||||
echo "branch=main" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "branch=develop" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Print Workflow_call input
|
|
||||||
if: github.event_name != 'workflow_dispatch'
|
|
||||||
run: echo ${{ steps.workflow_call-step.outputs.branch }}
|
|
||||||
|
|
||||||
- name: Set output
|
|
||||||
id: output-step
|
|
||||||
run: echo "branch=${{ steps.dispatch-step.outputs.branch || steps.workflow_call-step.outputs.branch }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Print final output
|
|
||||||
run: echo ${{ steps.output-step.outputs.branch }}
|
|
||||||
|
|
||||||
run-tests:
|
|
||||||
name: run-tests
|
|
||||||
runs-on: 8-cores
|
|
||||||
needs: [create-docker-image, console-test-branch]
|
|
||||||
timeout-minutes: 45
|
|
||||||
steps:
|
|
||||||
#----------------------------------------------
|
|
||||||
# load docker image
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Download docker image from previous job
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: console-image
|
|
||||||
path: /tmp
|
|
||||||
|
|
||||||
- name: Load Docker image
|
|
||||||
run: |
|
|
||||||
docker load --input /tmp/console-image.tar
|
|
||||||
docker image ls -a
|
|
||||||
#----------------------------------------------
|
|
||||||
# check-out frontend-monorepo
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Checkout frontend-monorepo
|
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.github-sha || github.sha }}
|
repository: vegaprotocol/console-test
|
||||||
#----------------------------------------------
|
path: './console-test'
|
||||||
# get vega version
|
|
||||||
#----------------------------------------------
|
- name: Set up Python
|
||||||
- name: Set VEGA_VERSION from .env
|
|
||||||
id: set_vega_version
|
|
||||||
run: echo "VEGA_VERSION=$(grep VEGA_VERSION apps/trading/e2e/.env | cut -d '=' -f2)" >> $GITHUB_ENV
|
|
||||||
#----------------------------------------------
|
|
||||||
# ----- Setup python -----
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10.11'
|
||||||
#----------------------------------------------
|
|
||||||
# ----- install & configure poetry -----
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Install Poetry
|
- name: Install Poetry
|
||||||
uses: snok/install-poetry@v1
|
uses: snok/install-poetry@v1
|
||||||
with:
|
|
||||||
virtualenvs-create: true
|
|
||||||
virtualenvs-in-project: true
|
|
||||||
virtualenvs-path: .venv
|
|
||||||
|
|
||||||
#----------------------------------------------
|
|
||||||
# install python dependencies
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: poetry install --no-interaction --no-root
|
run: |
|
||||||
working-directory: apps/trading/e2e
|
poetry install --no-root
|
||||||
#----------------------------------------------
|
working-directory: ./console-test
|
||||||
# install vega binaries
|
|
||||||
#----------------------------------------------
|
- name: load Binaries
|
||||||
- name: Install vega binaries
|
run: |
|
||||||
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
|
poetry run python -m vega_sim.tools.load_binaries
|
||||||
working-directory: apps/trading/e2e
|
working-directory: ./console-test
|
||||||
#----------------------------------------------
|
|
||||||
# install playwrightworking-directory: apps/trading/e2e
|
- 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
|
- name: install playwright
|
||||||
run: poetry run playwright install --with-deps chromium
|
run: poetry run playwright install
|
||||||
working-directory: apps/trading/e2e
|
working-directory: ./console-test
|
||||||
#----------------------------------------------
|
|
||||||
# run tests
|
- name: run tests
|
||||||
#----------------------------------------------
|
run: poetry run pytest --numprocesses auto
|
||||||
- name: Run tests
|
working-directory: ./console-test
|
||||||
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 1 --dist loadfile --durations=45
|
|
||||||
working-directory: apps/trading/e2e
|
|
||||||
#----------------------------------------------
|
|
||||||
# upload traces
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Upload Playwright Trace
|
- name: Upload Playwright Trace
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: playwright-trace
|
name: playwright-trace
|
||||||
path: apps/trading/e2e/traces/
|
path: ./traces/
|
||||||
retention-days: 15
|
|
||||||
#----------------------------------------------
|
|
||||||
# ----- upload logs -----
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Upload worker logs
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: worker-logs
|
|
||||||
path: ./logs/
|
|
||||||
retention-days: 15
|
|
||||||
#----------------------------------------------
|
|
||||||
# ----- upload market-sim logs -----
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Prepare and Zip market-sim-logs
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
parent_dir="/tmp/market-sim-logs"
|
|
||||||
echo "Creating parent directory at $parent_dir"
|
|
||||||
mkdir -p "$parent_dir"
|
|
||||||
|
|
||||||
echo "Waiting for vega-sim-* folders to be created..."
|
|
||||||
sleep 10 # Waits 10 seconds to ensure all folders are created
|
|
||||||
|
|
||||||
echo "Before searching for vega-sim-* folders in /tmp..."
|
|
||||||
folders=$(find /tmp -mindepth 1 -type d -name 'vega-sim-*' -print) || echo "Find command failed with exit code $?"
|
|
||||||
|
|
||||||
echo "After searching for vega-sim-* folders in /tmp..."
|
|
||||||
|
|
||||||
if [ -z "$folders" ]; then
|
|
||||||
echo "No vega-sim-* folders found."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Moving vega-sim-* folders to $parent_dir"
|
|
||||||
echo "$folders" | xargs -I {} mv {} "$parent_dir/"
|
|
||||||
|
|
||||||
echo "Checking if $parent_dir is not empty..."
|
|
||||||
if [ "$(ls -A $parent_dir)" ]; then
|
|
||||||
echo "Zipping the parent directory..."
|
|
||||||
zip -r market-sim-logs.zip "$parent_dir" && echo "Zip file created successfully."
|
|
||||||
else
|
|
||||||
echo "$parent_dir is empty. No zip file created."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
shell: /usr/bin/bash -e {0}
|
|
||||||
|
|
||||||
- name: Upload market-sim-logs
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: market-sim-logs
|
|
||||||
path: market-sim-logs.zip
|
|
||||||
retention-days: 15
|
retention-days: 15
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Use Node.js 20
|
- name: Use Node.js 16
|
||||||
id: Node
|
id: Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version: 16.15.1
|
||||||
|
|
||||||
- name: Run Cypress tests
|
- name: Run Cypress tests
|
||||||
uses: cypress-io/github-action@v4
|
uses: cypress-io/github-action@v4
|
||||||
|
|||||||
@@ -13,36 +13,14 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
runner-choice:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
runner: ${{ steps.step.outputs.runner }}
|
|
||||||
steps:
|
|
||||||
- name: Check branch
|
|
||||||
id: step
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
|
||||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
|
|
||||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
|
|
||||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "runner=self-hosted-runner" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Print runner
|
|
||||||
run: echo ${{ steps.step.outputs.runner }}
|
|
||||||
|
|
||||||
e2e:
|
e2e:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
project: ${{ fromJSON(inputs.projects) }}
|
project: ${{ fromJSON(inputs.projects) }}
|
||||||
name: ${{ matrix.project }}
|
name: ${{ matrix.project }}
|
||||||
needs: runner-choice
|
runs-on: self-hosted-runner
|
||||||
runs-on: ${{ needs.runner-choice.outputs.runner }}
|
timeout-minutes: 100
|
||||||
timeout-minutes: 120
|
|
||||||
steps:
|
steps:
|
||||||
# Checks if skip cache was requested
|
# Checks if skip cache was requested
|
||||||
- name: Set skip-nx-cache flag
|
- name: Set skip-nx-cache flag
|
||||||
@@ -57,17 +35,8 @@ jobs:
|
|||||||
path: './frontend-monorepo'
|
path: './frontend-monorepo'
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: './frontend-monorepo/.nvmrc'
|
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
|
||||||
cache: yarn
|
|
||||||
cache-dependency-path: './frontend-monorepo/yarn.lock'
|
|
||||||
|
|
||||||
# Restore node_modules from cache if possible
|
# Restore node_modules from cache if possible
|
||||||
- name: Restore node_modules from cache
|
- name: Restore node_modules from cache
|
||||||
id: cache-node-modules
|
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@@ -77,7 +46,6 @@ jobs:
|
|||||||
|
|
||||||
# Install frontend dependencies
|
# Install frontend dependencies
|
||||||
- name: Install root dependencies
|
- name: Install root dependencies
|
||||||
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn install --frozen-lockfile
|
||||||
working-directory: frontend-monorepo
|
working-directory: frontend-monorepo
|
||||||
|
|
||||||
@@ -93,14 +61,13 @@ jobs:
|
|||||||
- name: Run Vegacapsule network and Vega wallet
|
- name: Run Vegacapsule network and Vega wallet
|
||||||
id: setup-vega
|
id: setup-vega
|
||||||
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
||||||
timeout-minutes: 10
|
|
||||||
|
|
||||||
######
|
######
|
||||||
## Run some tests
|
## Run some tests
|
||||||
######
|
######
|
||||||
|
|
||||||
- name: Run Cypress tests
|
- name: Run Cypress tests
|
||||||
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --browser chrome --env.grepTags="${{ inputs.tags }}"
|
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --browser chrome --env.grepTags="${{ inputs.tags }}"
|
||||||
working-directory: frontend-monorepo
|
working-directory: frontend-monorepo
|
||||||
env:
|
env:
|
||||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
|||||||
@@ -2,12 +2,7 @@
|
|||||||
name: Verify PR title
|
name: Verify PR title
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
workflow_call:
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- edited
|
|
||||||
- reopened
|
|
||||||
- synchronize
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint_pr:
|
lint_pr:
|
||||||
@@ -16,16 +11,21 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Cache node modules
|
||||||
run: |
|
uses: actions/cache@v3
|
||||||
rm package.json
|
with:
|
||||||
npm install --no-save @commitlint/cli @commitlint/config-conventional @commitlint/config-nx-scopes nx
|
path: node_modules
|
||||||
|
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
||||||
|
|
||||||
- name: Check PR title
|
- name: Check PR title
|
||||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
||||||
|
|||||||
@@ -28,19 +28,6 @@ jobs:
|
|||||||
echo IS_MAINNET_RELEASE=false >> $GITHUB_ENV
|
echo IS_MAINNET_RELEASE=false >> $GITHUB_ENV
|
||||||
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
||||||
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
||||||
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
|
||||||
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
|
|
||||||
echo IS_MAIN_IMAGE=false >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Is dev image
|
|
||||||
if: ${{ github.ref_name == 'develop' && github.event_name == 'push' && matrix.app == 'trading' }}
|
|
||||||
run: |
|
|
||||||
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Is main image
|
|
||||||
if: ${{ github.ref_name == 'main' && github.event_name == 'push' && matrix.app == 'trading' }}
|
|
||||||
run: |
|
|
||||||
echo IS_MAIN_IMAGE=true >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Is PR
|
- name: Is PR
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
@@ -48,7 +35,7 @@ jobs:
|
|||||||
echo IS_PR=true >> $GITHUB_ENV
|
echo IS_PR=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Is mainnet release
|
- name: Is mainnet release
|
||||||
if: ${{ contains(github.ref, 'release/mainnet') && !contains(github.ref, 'mirror') }}
|
if: ${{ contains(github.ref, 'release/mainnnet') && !contains(github.ref, 'mirror') }}
|
||||||
run: |
|
run: |
|
||||||
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
|
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -62,11 +49,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Is S3 Release
|
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' && github.ref_name != 'main'}}
|
|
||||||
run: |
|
|
||||||
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
id: quemu
|
id: quemu
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
@@ -87,13 +69,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
- name: Log in to the Container registry (docker hub)
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
@@ -109,13 +91,52 @@ jobs:
|
|||||||
- name: Define dist variables
|
- name: Define dist variables
|
||||||
if: ${{ github.event_name == 'push' }}
|
if: ${{ github.event_name == 'push' }}
|
||||||
run: |
|
run: |
|
||||||
python3 tools/ci/define-dist-variables.py --github-ref="${{ github.ref }}" --app="${{ matrix.app }}"
|
envName=''
|
||||||
|
domain="vega.rocks"
|
||||||
|
bucketName=''
|
||||||
|
|
||||||
- name: Verify script result
|
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
||||||
if: ${{ github.event_name == 'push' }}
|
# 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)
|
||||||
run: |
|
envName="$(echo ${{ github.ref }} | sed -e "s|refs/heads/release/||" | cut -d '-' -f 1 )"
|
||||||
echo "BUCKET_NAME=${{ env.BUCKET_NAME }}"
|
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||||
echo "ENV_NAME=${{ env.ENV_NAME }}"
|
envName="stagnet1"
|
||||||
|
if [[ "${{ matrix.app }}" = "multisig-signer" ]]; then
|
||||||
|
envName="mainnet"
|
||||||
|
bucketName="tools.vega.xyz"
|
||||||
|
fi
|
||||||
|
if [[ "${{ matrix.app }}" = "static" ]]; then
|
||||||
|
envName="mainnet"
|
||||||
|
bucketName="static.vega.xyz"
|
||||||
|
fi
|
||||||
|
if [[ "${{ matrix.app }}" = "ui-toolkit" ]]; then
|
||||||
|
envName="mainnet"
|
||||||
|
bucketName="ui.vega.rocks"
|
||||||
|
fi
|
||||||
|
elif [[ "${{ github.ref }}" =~ .*mainnet$ ]]; then
|
||||||
|
envName="mainnet"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${envName}" = "mainnet" ]]; then
|
||||||
|
domain="vega.xyz"
|
||||||
|
if [[ -z "${bucketName}" ]]; then
|
||||||
|
bucketName="${{ matrix.app }}.${domain}"
|
||||||
|
fi
|
||||||
|
elif [[ "${envName}" = "testnet" ]]; then
|
||||||
|
domain="fairground.wtf"
|
||||||
|
if [[ -z "${bucketName}" ]]; then
|
||||||
|
bucketName="${{ matrix.app }}.${domain}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${bucketName}" ]]; then
|
||||||
|
bucketName="${{ matrix.app }}.${envName}.${domain}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "bucket name: ${bucketName}"
|
||||||
|
echo "env name: ${envName}"
|
||||||
|
|
||||||
|
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
|
||||||
|
echo ENV_NAME=${envName} >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Build local dist
|
- name: Build local dist
|
||||||
run: |
|
run: |
|
||||||
@@ -130,12 +151,8 @@ jobs:
|
|||||||
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
||||||
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
||||||
DIST_LOCATION=dist/storybook/ui-toolkit
|
DIST_LOCATION=dist/storybook/ui-toolkit
|
||||||
elif [ "${{ matrix.app }}" = "static" ]; then
|
|
||||||
yarn nx build static || (yarn install && yarn nx build static)
|
|
||||||
else
|
else
|
||||||
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
|
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
|
||||||
fi
|
|
||||||
if [[ -z "$DIST_LOCATION" ]]; then
|
|
||||||
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
||||||
fi
|
fi
|
||||||
mv $DIST_LOCATION dist-result
|
mv $DIST_LOCATION dist-result
|
||||||
@@ -161,10 +178,10 @@ jobs:
|
|||||||
- name: Sanity check docker image
|
- name: Sanity check docker image
|
||||||
run: |
|
run: |
|
||||||
echo "Check ipfs-hash"
|
echo "Check ipfs-hash"
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash'
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash > ${{ matrix.app }}-ipfs-hash
|
||||||
echo "List html directory"
|
echo "List html directory"
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'apk add --update tree; tree /usr/share/nginx/html'
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree /usr/share/nginx/html'
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr)
|
- name: Publish dist as docker image (ghcr)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
@@ -185,7 +202,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
id: dockerhub-push
|
id: dockerhub-push
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -195,7 +212,7 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr - retry)
|
- name: Publish dist as docker image (ghcr - retry)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
@@ -222,13 +239,13 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
||||||
|
|
||||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
||||||
- name: Publish dist to s3
|
- name: Publish dist to s3
|
||||||
uses: jakejarvis/s3-sync-action@master
|
uses: jakejarvis/s3-sync-action@master
|
||||||
# s3 releases are not happening for trading on mainnet - it's IPFS
|
# s3 releases are not happening for trading on mainnet - it's IPFS
|
||||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'false' }}
|
||||||
with:
|
with:
|
||||||
args: --acl private --follow-symlinks --delete
|
args: --acl private --follow-symlinks --delete
|
||||||
env:
|
env:
|
||||||
@@ -239,11 +256,11 @@ jobs:
|
|||||||
SOURCE_DIR: 'dist-result'
|
SOURCE_DIR: 'dist-result'
|
||||||
|
|
||||||
- name: Install aws CLI
|
- name: Install aws CLI
|
||||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'false' }}
|
||||||
uses: unfor19/install-aws-cli-action@master
|
uses: unfor19/install-aws-cli-action@master
|
||||||
|
|
||||||
- name: Perform cache invalidation
|
- name: Perform cache invalidation
|
||||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'false' }}
|
||||||
env:
|
env:
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
@@ -335,9 +352,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# create commit
|
# create commit
|
||||||
if ! git diff --cached --exit-code; then
|
commit_msg="Automated hash update from ${{ github.ref }}"
|
||||||
commit_msg="Automated hash update from ${{ github.ref }}"
|
git commit -m "$commit_msg"
|
||||||
git commit -m "$commit_msg"
|
git push -u origin "main"
|
||||||
git push -u origin "main"
|
|
||||||
fi
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ on:
|
|||||||
- types
|
- types
|
||||||
- utils
|
- utils
|
||||||
- i18n
|
- i18n
|
||||||
- wallet
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
@@ -29,7 +28,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
|||||||
+1
-9
@@ -48,15 +48,7 @@ cypress.env.json
|
|||||||
# Next.js
|
# Next.js
|
||||||
.next
|
.next
|
||||||
|
|
||||||
# cypress
|
#cypress
|
||||||
/apps/**/cypress/reports/
|
/apps/**/cypress/reports/
|
||||||
/apps/**/cypress/downloads/
|
/apps/**/cypress/downloads/
|
||||||
/apps/**/fixtures/wallet/node**
|
/apps/**/fixtures/wallet/node**
|
||||||
|
|
||||||
# apps/trading/e2e
|
|
||||||
__pycache__/
|
|
||||||
apps/trading/e2e/logs/
|
|
||||||
apps/trading/e2e/.pytest_cache/
|
|
||||||
apps/trading/e2e/traces/
|
|
||||||
|
|
||||||
.nx/
|
|
||||||
|
|||||||
@@ -3,3 +3,6 @@
|
|||||||
|
|
||||||
# Lint commit messages to ensure they follow conventional commit standards
|
# Lint commit messages to ensure they follow conventional commit standards
|
||||||
yarn commitlint --edit "${1}"
|
yarn commitlint --edit "${1}"
|
||||||
|
|
||||||
|
# Lint all staged files
|
||||||
|
yarn lint-staged
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
# Auto-format all files
|
|
||||||
yarn nx format:write
|
|
||||||
|
|
||||||
# Lint all staged files
|
|
||||||
yarn lint-staged
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
# Lint all staged files - this brings more value as pre-commit
|
|
||||||
# yarn nx format:check
|
|
||||||
|
|
||||||
# Test all projects with changes
|
|
||||||
# yarn nx affected -t test --exclude trading
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
# Add files here to ignore them from prettier formatting
|
# Add files here to ignore them from prettier formatting
|
||||||
|
|
||||||
/dist
|
/dist
|
||||||
/dist-result
|
|
||||||
/coverage
|
/coverage
|
||||||
__generated__
|
__generated__
|
||||||
__generated___
|
__generated___
|
||||||
@@ -9,15 +8,3 @@ __generated___
|
|||||||
apps/static/src/assets/devnet-tranches.json
|
apps/static/src/assets/devnet-tranches.json
|
||||||
apps/static/src/assets/mainnet-tranches.json
|
apps/static/src/assets/mainnet-tranches.json
|
||||||
apps/static/src/assets/testnet-tranches.json
|
apps/static/src/assets/testnet-tranches.json
|
||||||
|
|
||||||
/apps/**/cypress/reports/
|
|
||||||
/apps/**/cypress/downloads/
|
|
||||||
|
|
||||||
/.nx/cache
|
|
||||||
|
|
||||||
# apps/trading/e2e
|
|
||||||
__pycache__/
|
|
||||||
apps/trading/e2e/logs/
|
|
||||||
apps/trading/e2e/.pytest_cache/
|
|
||||||
apps/trading/e2e/traces/
|
|
||||||
.pytest_cache/
|
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
* @vegaprotocol/frontend
|
* @vegaprotocol/frontend
|
||||||
apps/ @vegaprotocol/frontend-qa
|
|
||||||
libs/ @vegaprotocol/frontend-qa
|
|
||||||
*.graphql @vegaprotocol/core
|
*.graphql @vegaprotocol/core
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ recalculate-ipfs:
|
|||||||
echo "ipfs hash inside the image"
|
echo "ipfs hash inside the image"
|
||||||
docker run --rm ${TAG} cat /ipfs-hash
|
docker run --rm ${TAG} cat /ipfs-hash
|
||||||
echo "recalculating ipfs hash"
|
echo "recalculating ipfs hash"
|
||||||
docker run --rm ${TAG} ipfs add -rQ /usr/share/nginx/html
|
docker run --rm ${TAG} ipfs add -r /usr/share/nginx/html
|
||||||
|
|
||||||
.PHONY: eject-ipfs-hash
|
.PHONY: eject-ipfs-hash
|
||||||
unpack:
|
unpack:
|
||||||
|
|||||||
@@ -113,47 +113,13 @@ In order to run a container on port 3000:
|
|||||||
docker run -p 3000:80 [TAG]
|
docker run -p 3000:80 [TAG]
|
||||||
```
|
```
|
||||||
|
|
||||||
On top of that there are two possible scenarios for running docker image - using nginx server (default) of ipfs daemon.
|
|
||||||
|
|
||||||
to run ipfs on port 3000:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -p 3000:80 [TAG] /run-ipfs.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
to run nginx on port 3000:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -p 3000:80 [TAG]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build instructions
|
## Build instructions
|
||||||
|
|
||||||
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of Console either for the web, or ready for pinning on IPFS.
|
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of console either for the web, or ready for pinning on IPFS
|
||||||
|
|
||||||
### nx build inside the docker
|
|
||||||
|
|
||||||
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build). The multistage builds ensures consistent CPU architecture and build toolchains are used so that the result will be identical.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=20.9.1 --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
|
|
||||||
```
|
|
||||||
|
|
||||||
### Computing ipfs-hash of the build
|
|
||||||
|
|
||||||
At the moment this feature is important only for Console releases.
|
|
||||||
|
|
||||||
Each docker build finishes with hash calculation for ` dist`` directory. Resulting hash is added to file named as `/ipfs-hash`. Once docker image is produced you can run following commad to display ipfs-hash:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make recalculate-ipfs TAG=vegaprotocol/trading:{YOUR_VERSION}
|
|
||||||
```
|
|
||||||
|
|
||||||
**updating hash:** recompiling dist directory (even if there are no changed to source code) results in different hash computed by ipfs command.
|
|
||||||
|
|
||||||
### nx build outside the docker
|
### nx build outside the docker
|
||||||
|
|
||||||
This Docker image packages a pre-built `dist` folder into an [`nginx`](https://hub.docker.com/_/nginx)([server configuration](./nginx/nginx.conf)) docker image. In this case, the application on docker host machine from source.
|
Packaging prepared dist into [`nginx`](https://hub.docker.com/_/nginx)([server configuration](./nginx/nginx.conf)) docker image involves building the application on docker host machine from source.
|
||||||
|
|
||||||
As a prerequisite you need to perform build of `dist` directory and move its content for specific application to `dist-result` directory. Use following script to do it with a single command:
|
As a prerequisite you need to perform build of `dist` directory and move its content for specific application to `dist-result` directory. Use following script to do it with a single command:
|
||||||
|
|
||||||
@@ -164,21 +130,41 @@ As a prerequisite you need to perform build of `dist` directory and move its con
|
|||||||
You can build any of the containers locally with the following command:
|
You can build any of the containers locally with the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build -f docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
docker build --dockerfile docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### nx build inside the docker
|
||||||
|
|
||||||
|
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build) example.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=$(cat .nvmrc) --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Computing ipfs-hash of the build
|
||||||
|
|
||||||
|
At the moment this feature is important only for `trading` (console) releases.
|
||||||
|
|
||||||
|
Each docker build finishes with hash calculation for dist directory. Resulting hash is added to file named as `/ipfs-hash`. Once docker image is produced you can run following commad to display ipfs-hash:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make recalculate-ipfs TAG=vegaprotocol/trading:{YOUR_VERSION}
|
||||||
|
```
|
||||||
|
|
||||||
|
**updating hash:** recompiling dist directory (even if there are no changed to source code) results in different hash computed by ipfs command.
|
||||||
|
|
||||||
### Verifying ipfs-hash of existing current application version
|
### Verifying ipfs-hash of existing current application version
|
||||||
|
|
||||||
An IPFS CID will be attached to every [release](https://github.com/vegaprotocol/frontend-monorepo/releases). If you are intending to pin an application on IPFS, you can check that your build matches by running the following steps:
|
An IPFS CID will be attached to every [release](https://github.com/vegaprotocol/frontend-monorepo/releases). If you are intending to pin an application on IPFS, you can check that your build matches by running the following steps:
|
||||||
|
|
||||||
1. Show latest release by running: `make latest-release`. You need to configure [`gh`](https://cli.github.com/) for this step to work, otherwise please provide release manually from [github](https://github.com/vegaprotocol/frontend-monorepo/releases) or [dockerhub](https://hub.docker.com/r/vegaprotocol/trading)
|
1. Show latest release by runnning: `make latest-release`. You need to configure [`gh`](https://cli.github.com/) for this step to work, otherwise please provide release manually from [github](https://github.com/vegaprotocol/frontend-monorepo/releases) or [dockerhub](https://hub.docker.com/r/vegaprotocol/trading)
|
||||||
2. Set RELEASE environment variable to value that you want to validate: `export RELEASE=$(make latest-release)` or `export RELEASE=vXX.XX.XX`
|
2. Set RELEASE environment variable to value that you want to validate: `export RELEASE=$(make latest-release)` or `export RELEASE=vXX.XX.XX`
|
||||||
3. Set TAG environment variable to image that you want to validate: `export TAG=vegaprotocol/trading:$RELEASE`
|
3. Set TAG environment variable to image that you want to validate: `export TAG=vegaprotocol/trading:$RELEASE`
|
||||||
4. Download docker image with the desired release `docker pull $TAG`.
|
4. Download docker image with the desired release `docker pull $TAG`.
|
||||||
5. Recalculate hash: `make recalculate-ipfs`
|
5. Recalculate hash: `make recalculate-ipfs`
|
||||||
6. You should see exactly same hash produced by ipfs command as one placed with the release notes: `make show-latest-release`
|
6. You should see exactly same hash produced by ipfs command as one placed with the release notes: `make show-latest-release`
|
||||||
7. If you want to extract dist from docker image to your local filesystem you can run following command: `make unpack`
|
7. If you want to extract dist from docker image to your local filesystem you can run following command: `make unpack`
|
||||||
8. Now `dist` directory contains valid application build
|
8. Now `dist` directory contains valid application build. **it is not possible to calculate same ipfs hash on files that are result of copy operation**
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,5 @@ NX_EXPLORER_NETWORK_PARAMETERS=1
|
|||||||
NX_EXPLORER_PARTIES=1
|
NX_EXPLORER_PARTIES=1
|
||||||
NX_EXPLORER_VALIDATORS=1
|
NX_EXPLORER_VALIDATORS=1
|
||||||
|
|
||||||
CYPRESS_VEGA_URL=http://localhost:3008/graphql
|
|
||||||
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
|
||||||
CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545
|
|
||||||
CYPRESS_FAUCET_URL=http://localhost:1790/api/v1/mint
|
|
||||||
CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65
|
|
||||||
CYPRESS_VEGA_WALLET_URL=http://localhost:1789
|
|
||||||
CYPRESS_VEGA_WALLET_API_TOKEN=
|
CYPRESS_VEGA_WALLET_API_TOKEN=
|
||||||
|
CYPRESS_VEGA_URL=http://localhost:3008/graphql
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
|||||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||||
NX_VEGA_ENV=DEVNET
|
NX_VEGA_ENV=DEVNET
|
||||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocke
|
|||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
NX_VEGA_ENV=MAINNET
|
NX_VEGA_ENV=MAINNET
|
||||||
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
|
|||||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
NX_VEGA_ENV=TESTNET
|
NX_VEGA_ENV=TESTNET
|
||||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,9 +4,7 @@
|
|||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
"rules": {
|
"rules": {}
|
||||||
"cypress/unsafe-to-chain-command": 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ module.exports = defineConfig({
|
|||||||
viewportWidth: 1440,
|
viewportWidth: 1440,
|
||||||
viewportHeight: 900,
|
viewportHeight: 900,
|
||||||
testIsolation: false,
|
testIsolation: false,
|
||||||
experimentalMemoryManagement: true,
|
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
environment: 'CUSTOM',
|
environment: 'CUSTOM',
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nx/eslint:lint",
|
"executor": "@nx/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"proposalSubmission": {
|
|
||||||
"rationale": {
|
|
||||||
"title": "Test new asset proposal",
|
|
||||||
"description": "E2E test for proposals"
|
|
||||||
},
|
|
||||||
"terms": {
|
|
||||||
"newAsset": {
|
|
||||||
"changes": {
|
|
||||||
"name": "USDT Coin",
|
|
||||||
"symbol": "USDT",
|
|
||||||
"decimals": "18",
|
|
||||||
"quantum": "1",
|
|
||||||
"erc20": {
|
|
||||||
"contractAddress": "0xb404c51bbc10dcbe948077f18a4b8e553d160084",
|
|
||||||
"withdrawThreshold": "10",
|
|
||||||
"lifetimeLimit": "10"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"closingTimestamp": 1724339572,
|
|
||||||
"enactmentTimestamp": 1724339572,
|
|
||||||
"validationTimestamp": 1692799617
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,168 +1,19 @@
|
|||||||
import { createSuccessorMarketProposal } from '../support/governance.functions';
|
//Tests set to skip until market bug for capsule checkpoint is fixed
|
||||||
|
context.skip('Market page', { tags: '@regression' }, function () {
|
||||||
context('Market page', { tags: '@regression' }, function () {
|
|
||||||
describe('Verify elements on page', function () {
|
describe('Verify elements on page', function () {
|
||||||
const marketHeaders = 'markets-heading';
|
const marketHeaders = '[data-testid="markets-header"]';
|
||||||
|
const marketNavigation = 'a[href="/markets"]';
|
||||||
|
|
||||||
before('Create market', function () {
|
it('Markets page is displayed', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.createMarket();
|
cy.get(marketNavigation).click();
|
||||||
|
cy.common_validate_blocks_data_displayed(marketHeaders);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach('Get market id', function () {
|
it('Markets page displayed on mobile', function () {
|
||||||
cy.navigate_to('markets');
|
|
||||||
cy.get('[col-id="id"]').last().invoke('text').as('createdMarketId');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Market displayed on market page', function () {
|
|
||||||
cy.navigate_to('markets');
|
|
||||||
cy.getByTestId(marketHeaders).should('be.visible');
|
|
||||||
cy.get(`[row-id="${this.createdMarketId}"]`)
|
|
||||||
.should('be.visible')
|
|
||||||
.within(() => {
|
|
||||||
cy.get_element_by_col_id('code').should('have.text', 'TEST.24h');
|
|
||||||
cy.get_element_by_col_id('name').should('have.text', 'Test market 1');
|
|
||||||
cy.get_element_by_col_id('state').should('have.text', 'Pending');
|
|
||||||
cy.get_element_by_col_id('asset').should('have.text', 'fUSDC');
|
|
||||||
cy.get_element_by_col_id('id').should(
|
|
||||||
'have.text',
|
|
||||||
this.createdMarketId
|
|
||||||
);
|
|
||||||
cy.get_element_by_col_id('actions')
|
|
||||||
.find('a')
|
|
||||||
.should('have.attr', 'href', `/markets/${this.createdMarketId}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Able to go to market details page', function () {
|
|
||||||
cy.navigate_to('markets');
|
|
||||||
cy.contains('Test market 1').click();
|
|
||||||
cy.getByTestId(marketHeaders).should('have.text', 'Test market 1');
|
|
||||||
cy.validate_element_from_table('Name', 'Test market 1');
|
|
||||||
cy.validate_element_from_table('Trading Mode', 'Opening auction');
|
|
||||||
cy.validate_element_from_table('Market Decimal Places', '5');
|
|
||||||
cy.validate_element_from_table('Position Decimal Places', '5');
|
|
||||||
cy.validate_element_from_table('Settlement Asset Decimal Places', '5');
|
|
||||||
// Instrument
|
|
||||||
cy.validate_element_from_table('Market Name', 'Test market 1');
|
|
||||||
cy.validate_element_from_table('Code', 'TEST.24h');
|
|
||||||
cy.validate_element_from_table('Product Type', 'Future');
|
|
||||||
cy.validate_element_from_table('Quote Name', 'fUSDC');
|
|
||||||
// Settlement Asset
|
|
||||||
cy.validate_element_from_table('Quote Name', 'fUSDC');
|
|
||||||
cy.validate_element_from_table('Symbol', 'fUSDC');
|
|
||||||
cy.validate_element_from_table('Decimals', '5');
|
|
||||||
cy.validate_element_from_table('Quantum', '0.00');
|
|
||||||
cy.validate_element_from_table('Status', 'Enabled');
|
|
||||||
cy.validate_element_from_table('Max faucet amount', '10,000,000.00');
|
|
||||||
cy.validate_element_from_table(
|
|
||||||
'Infrastructure fee account balance',
|
|
||||||
'0.00'
|
|
||||||
);
|
|
||||||
cy.validate_element_from_table(
|
|
||||||
'Global reward pool account balance',
|
|
||||||
'0.00'
|
|
||||||
);
|
|
||||||
// Metadata
|
|
||||||
cy.validate_element_from_table('Sector', 'tech');
|
|
||||||
cy.validate_element_from_table('Source', 'docs.vega.xyz');
|
|
||||||
// Risk model
|
|
||||||
cy.validate_element_from_table('Tau', '0.0001140771161');
|
|
||||||
cy.validate_element_from_table('Risk Aversion Parameter', '0.01');
|
|
||||||
// Risk parameters
|
|
||||||
// cy.validate_element_from_table('R', '0.016')
|
|
||||||
cy.validate_element_from_table('Sigma', '0.5');
|
|
||||||
// Risk factors
|
|
||||||
cy.validate_element_from_table('Short', '0.0143218738374871');
|
|
||||||
cy.validate_element_from_table('Long', '0.0141450471498822');
|
|
||||||
// Price monitoring settings 1
|
|
||||||
cy.validate_element_from_table('Horizon Secs', '43,200');
|
|
||||||
cy.validate_element_from_table('Probability', '1');
|
|
||||||
cy.validate_element_from_table('Auction Extension Secs', '600');
|
|
||||||
// Liquidity Monitoring
|
|
||||||
cy.validate_element_from_table('Triggering Ratio', '0.7');
|
|
||||||
cy.validate_element_from_table('Time Window', '3,600');
|
|
||||||
cy.validate_element_from_table('Scaling Factor', '10');
|
|
||||||
// Liquidity
|
|
||||||
cy.validate_element_from_table('Target Stake', '0.00 fUSDC');
|
|
||||||
cy.validate_element_from_table('Supplied Stake', '0.00 fUSDC');
|
|
||||||
// Liquidity price range
|
|
||||||
cy.validate_element_from_table(
|
|
||||||
'Liquidity Price Range',
|
|
||||||
'95.00% of mid price'
|
|
||||||
);
|
|
||||||
cy.validate_element_from_table('Lowest Price', '0.00 fUSDC');
|
|
||||||
cy.validate_element_from_table('Highest Price', '0.00 fUSDC');
|
|
||||||
cy.getByTestId('oracle-spec-links')
|
|
||||||
.should('have.attr', 'href')
|
|
||||||
.and(
|
|
||||||
'contain',
|
|
||||||
'/oracles/bf242aa5c9f64fcbb77808aa8582e73711519f4b35264eb797a80f1803590a24'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Able to view Json
|
|
||||||
cy.contains('View JSON').click();
|
|
||||||
cy.get('.language-json').should('exist');
|
|
||||||
cy.getByTestId('icon-cross').click();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Skipping due to resize observer loop limit error
|
|
||||||
it.skip('Markets page displayed on mobile', function () {
|
|
||||||
cy.common_switch_to_mobile_and_click_toggle();
|
cy.common_switch_to_mobile_and_click_toggle();
|
||||||
cy.navigate_to('markets', true);
|
cy.get(marketNavigation).click();
|
||||||
cy.getByTestId(marketHeaders).should('be.visible');
|
cy.common_validate_blocks_data_displayed(marketHeaders);
|
||||||
cy.get(`[row-id="${this.createdMarketId}"]`)
|
|
||||||
.should('be.visible')
|
|
||||||
.within(() => {
|
|
||||||
cy.get_element_by_col_id('code').should('have.text', 'TEST.24h');
|
|
||||||
cy.get_element_by_col_id('name').should('have.text', 'Test market 1');
|
|
||||||
cy.get_element_by_col_id('state').should('have.text', 'Pending');
|
|
||||||
cy.get_element_by_col_id('asset').should('have.text', 'fUSDC');
|
|
||||||
cy.get_element_by_col_id('id').should(
|
|
||||||
'have.text',
|
|
||||||
this.createdMarketId
|
|
||||||
);
|
|
||||||
cy.get_element_by_col_id('actions')
|
|
||||||
.find('a')
|
|
||||||
.should('have.attr', 'href', `/markets/${this.createdMarketId}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Able to go to market details page for successor market', function () {
|
|
||||||
const successionLineItem = 'succession-line-item';
|
|
||||||
const successionLineMarketId = 'succession-line-item-market-id';
|
|
||||||
|
|
||||||
createSuccessorMarketProposal(this.createdMarketId);
|
|
||||||
cy.navigate_to('markets');
|
|
||||||
cy.reload();
|
|
||||||
cy.contains('Token test market', { timeout: 8000 }).should('be.visible');
|
|
||||||
cy.get('[row-index="0"]')
|
|
||||||
.invoke('attr', 'row-id')
|
|
||||||
.as('successorMarketId');
|
|
||||||
cy.contains('Token test market').click();
|
|
||||||
cy.getByTestId(marketHeaders).should('have.text', 'Token test market');
|
|
||||||
cy.validate_element_from_table('Triggering Ratio', '0.7');
|
|
||||||
cy.validate_element_from_table('Time Window', '3,600');
|
|
||||||
cy.validate_element_from_table('Scaling Factor', '10');
|
|
||||||
|
|
||||||
cy.getByTestId(successionLineItem)
|
|
||||||
.first()
|
|
||||||
.within(() => {
|
|
||||||
cy.contains('Test market 1');
|
|
||||||
cy.getByTestId(successionLineMarketId).should(
|
|
||||||
'have.text',
|
|
||||||
this.createdMarketId
|
|
||||||
);
|
|
||||||
});
|
|
||||||
cy.getByTestId(successionLineItem)
|
|
||||||
.eq(1)
|
|
||||||
.within(() => {
|
|
||||||
cy.contains('Token test market');
|
|
||||||
cy.getByTestId(successionLineMarketId).should(
|
|
||||||
'have.text',
|
|
||||||
this.successorMarketId
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
context('Network parameters page', { tags: '@smoke' }, function () {
|
context('Network parameters page', { tags: '@smoke' }, function () {
|
||||||
before('navigate to network parameter page', function () {
|
before('navigate to network parameter page', function () {
|
||||||
cy.fixture('net_parameter_format_lookup').as('networkParameterFormat');
|
cy.fixture('net_parameter_format_lookup').as('networkParameterFormat');
|
||||||
cy.visit('/network-parameters');
|
|
||||||
});
|
});
|
||||||
describe('Verify elements on page', function () {
|
describe('Verify elements on page', function () {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/network-parameters');
|
||||||
|
});
|
||||||
|
|
||||||
const networkParametersHeader = '[data-testid="network-param-header"]';
|
const networkParametersHeader = '[data-testid="network-param-header"]';
|
||||||
const tableRows = '[data-testid="key-value-table-row"]';
|
const tableRows = '[data-testid="key-value-table-row"]';
|
||||||
|
|
||||||
@@ -13,7 +16,6 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
|||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 0006-NETW-021
|
|
||||||
it('should list each of the network parameters available', function () {
|
it('should list each of the network parameters available', function () {
|
||||||
cy.get_network_parameters().then((network_parameters) => {
|
cy.get_network_parameters().then((network_parameters) => {
|
||||||
const numberOfNetworkParametersInSystem =
|
const numberOfNetworkParametersInSystem =
|
||||||
@@ -196,19 +198,6 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 0006-NETW-022 0006-NETW-023
|
|
||||||
it('governance assets should be correctly grouped', function () {
|
|
||||||
cy.getByTestId('governance')
|
|
||||||
.should('exist')
|
|
||||||
.parent()
|
|
||||||
.should('have.attr', 'href', '/network-parameters#governance');
|
|
||||||
cy.get('[id="governance-proposal-asset"]')
|
|
||||||
.parent()
|
|
||||||
.within(() => {
|
|
||||||
cy.getByTestId('key-value-table-row').should('have.length', 8);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to see network parameters - on mobile', function () {
|
it('should be able to see network parameters - on mobile', function () {
|
||||||
cy.switchToMobile();
|
cy.switchToMobile();
|
||||||
cy.get_network_parameters().then((network_parameters) => {
|
cy.get_network_parameters().then((network_parameters) => {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ context.skip('Node switcher', { tags: '@regression' }, function () {
|
|||||||
const errorTypeTxt = 'Error: invalid url';
|
const errorTypeTxt = 'Error: invalid url';
|
||||||
const nodeErrorTxt = 'fakeUrl is not a valid url.';
|
const nodeErrorTxt = 'fakeUrl is not a valid url.';
|
||||||
|
|
||||||
cy.getByTestId('node-url-custom').click({ force: true });
|
cy.getByTestId('node-url-custom').click();
|
||||||
|
|
||||||
cy.getByTestId(customNodeBtn).within(() => {
|
cy.getByTestId(customNodeBtn).within(() => {
|
||||||
cy.get('input').clear().type('fakeUrl');
|
cy.get('input').clear().type('fakeUrl');
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
import { getNewAssetTxBody } from '../support/governance.functions';
|
|
||||||
|
|
||||||
context('Proposal page', { tags: '@smoke' }, function () {
|
|
||||||
describe('Verify elements on page', function () {
|
|
||||||
const proposalHeading = 'proposals-heading';
|
|
||||||
const dateTimeRegex =
|
|
||||||
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
|
|
||||||
|
|
||||||
before('Create market proposal', function () {
|
|
||||||
cy.visit('/');
|
|
||||||
cy.createMarket();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Able to view proposal', function () {
|
|
||||||
const proposalTitle = 'Add Lorem Ipsum market';
|
|
||||||
|
|
||||||
cy.navigate_to('governanceProposals');
|
|
||||||
cy.getByTestId(proposalHeading).should('be.visible');
|
|
||||||
cy.contains(proposalTitle)
|
|
||||||
.parent()
|
|
||||||
.parent()
|
|
||||||
.parent()
|
|
||||||
.within(() => {
|
|
||||||
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
|
||||||
cy.get_element_by_col_id('type').should('have.text', 'NewMarket');
|
|
||||||
cy.get_element_by_col_id('state').should('have.text', 'Enacted');
|
|
||||||
cy.getByTestId('vote-progress').should('be.visible');
|
|
||||||
cy.getByTestId('vote-progress-bar-for')
|
|
||||||
.invoke('attr', 'style')
|
|
||||||
.should('eq', 'width: 100%;');
|
|
||||||
cy.get('[col-id="cDate"]')
|
|
||||||
.invoke('text')
|
|
||||||
.should('match', dateTimeRegex);
|
|
||||||
cy.get('[col-id="eDate"]')
|
|
||||||
.invoke('text')
|
|
||||||
.should('match', dateTimeRegex);
|
|
||||||
cy.getByTestId('external-link')
|
|
||||||
.should('have.attr', 'href')
|
|
||||||
.and('contains', 'https://governance.fairground.wtf/proposals/');
|
|
||||||
cy.contains('View terms').should('exist').click();
|
|
||||||
});
|
|
||||||
cy.getByTestId('dialog-title').should('have.text', proposalTitle);
|
|
||||||
cy.get('.language-json').should('exist');
|
|
||||||
cy.getByTestId('icon-cross').click();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Proposal page displayed on mobile', function () {
|
|
||||||
const proposalTitle = 'Add Lorem Ipsum market';
|
|
||||||
|
|
||||||
cy.common_switch_to_mobile_and_click_toggle();
|
|
||||||
cy.navigate_to('governanceProposals', true);
|
|
||||||
cy.getByTestId(proposalHeading).should('be.visible');
|
|
||||||
cy.get('[row-index="0"]').within(() => {
|
|
||||||
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it.skip('Able to view new asset proposal', function () {
|
|
||||||
const proposalTitle = 'Test new asset proposal';
|
|
||||||
const newAssetProposalBody = getNewAssetTxBody();
|
|
||||||
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
|
||||||
|
|
||||||
cy.visit('/');
|
|
||||||
cy.navigate_to('governanceProposals');
|
|
||||||
cy.contains(proposalTitle)
|
|
||||||
.parent()
|
|
||||||
.parent()
|
|
||||||
.parent()
|
|
||||||
.within(() => {
|
|
||||||
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
|
||||||
cy.get_element_by_col_id('type').should('have.text', 'NewAsset');
|
|
||||||
cy.get_element_by_col_id('state').should(
|
|
||||||
'have.text',
|
|
||||||
'Waiting for Node Vote'
|
|
||||||
);
|
|
||||||
cy.getByTestId('vote-progress').should('be.visible');
|
|
||||||
cy.getByTestId('vote-progress-bar-against')
|
|
||||||
.invoke('attr', 'style')
|
|
||||||
.should('eq', 'width: 100%;');
|
|
||||||
cy.get('[col-id="cDate"]')
|
|
||||||
.invoke('text')
|
|
||||||
.should('match', dateTimeRegex);
|
|
||||||
cy.get('[col-id="eDate"]')
|
|
||||||
.invoke('text')
|
|
||||||
.should('match', dateTimeRegex);
|
|
||||||
cy.getByTestId('external-link')
|
|
||||||
.should('have.attr', 'href')
|
|
||||||
.and('contains', 'https://governance.fairground.wtf/proposals/');
|
|
||||||
cy.contains('View terms').should('exist').click();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -40,7 +40,7 @@ context.skip('Transactions page', function () {
|
|||||||
.first()
|
.first()
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
} else {
|
} else {
|
||||||
cy.log('Unable to find any transactions on page');
|
cy.slack('Unable to find any transactions on page');
|
||||||
cy.screenshot();
|
cy.screenshot();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -78,7 +78,7 @@ context.skip('Transactions page', function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
cy.log('Unable to find any transactions on page');
|
cy.slack('Unable to find any transactions on page');
|
||||||
cy.screenshot();
|
cy.screenshot();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,11 +7,7 @@ context('Validator page', { tags: '@smoke' }, function () {
|
|||||||
it('should be able to see validator tiles', function () {
|
it('should be able to see validator tiles', function () {
|
||||||
cy.getNodes().then((nodes) => {
|
cy.getNodes().then((nodes) => {
|
||||||
nodes.forEach((node) => {
|
nodes.forEach((node) => {
|
||||||
if (node.rankingScore.performanceScore > 0) {
|
cy.get(`[validator-id="${node.id}"]`).should('be.visible');
|
||||||
cy.get(`[validator-id="${node.id}"]`).should('be.visible');
|
|
||||||
} else {
|
|
||||||
cy.get(`[validator-id="${node.id}"]`).should('not.exist');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ Cypress.Commands.add('switchToMobile', () => {
|
|||||||
Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () {
|
Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () {
|
||||||
cy.viewport('iphone-x');
|
cy.viewport('iphone-x');
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.get('[data-testid="button-menu-drawer"]').click();
|
cy.get('[data-testid="open-menu"]').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('monitor_clipboard', () => {
|
Cypress.Commands.add('monitor_clipboard', () => {
|
||||||
@@ -88,49 +88,3 @@ Cypress.Commands.add('convert_number_to_max_four_decimal', (number) => {
|
|||||||
maximumFractionDigits: 4,
|
maximumFractionDigits: 4,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('navigate_to', (page, mobileView = false) => {
|
|
||||||
const navigation = {
|
|
||||||
transactions: '/txs',
|
|
||||||
blocks: '/blocks',
|
|
||||||
oracles: '/oracles',
|
|
||||||
validators: '/validators',
|
|
||||||
parties: '/parties',
|
|
||||||
assets: '/assets',
|
|
||||||
markets: '/markets',
|
|
||||||
governanceProposals: '/governance',
|
|
||||||
networkParameters: '/network-parameters',
|
|
||||||
genesisParameters: '/genesis',
|
|
||||||
};
|
|
||||||
|
|
||||||
const topLevelRoutes = ['transactions', 'blocks', 'oracles', 'validators'];
|
|
||||||
|
|
||||||
cy.getByTestId('navigation').within(() => {
|
|
||||||
if (!topLevelRoutes.includes(page) && mobileView === false) {
|
|
||||||
cy.getByTestId('other').first().click();
|
|
||||||
}
|
|
||||||
cy.get(`[href="${navigation[page]}"]`).first().click();
|
|
||||||
});
|
|
||||||
cy.url().should('include', navigation[page]);
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('get_element_by_col_id', (elementName) => {
|
|
||||||
cy.get(`[col-id="${elementName}"]`);
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'validate_element_from_table',
|
|
||||||
(tableRowName, tableRowValue) => {
|
|
||||||
cy.contains(tableRowName)
|
|
||||||
.parentsUntil("[data-testid='key-value-table-row']")
|
|
||||||
.siblings()
|
|
||||||
.should('have.text', tableRowValue);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'validate_proposal_change_type',
|
|
||||||
(tableRowName, changeType) => {
|
|
||||||
cy.contains(tableRowName).siblings().should('have.text', changeType);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -1,186 +0,0 @@
|
|||||||
import { addSeconds, millisecondsToSeconds } from 'date-fns';
|
|
||||||
|
|
||||||
export function createSuccessorMarketProposal(parentMarketId) {
|
|
||||||
cy.VegaWalletSubmitProposal(getSuccessorTxBody(parentMarketId));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSuccessorTxBody(parentMarketId) {
|
|
||||||
const MIN_CLOSE_SEC = 500;
|
|
||||||
const MIN_ENACT_SEC = 700;
|
|
||||||
|
|
||||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
|
||||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
|
||||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
|
||||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
|
||||||
|
|
||||||
return {
|
|
||||||
proposalSubmission: {
|
|
||||||
rationale: {
|
|
||||||
title: 'Test successor market proposal details',
|
|
||||||
description: 'E2E test for successor market',
|
|
||||||
},
|
|
||||||
terms: {
|
|
||||||
newMarket: {
|
|
||||||
changes: {
|
|
||||||
decimalPlaces: '5',
|
|
||||||
positionDecimalPlaces: '5',
|
|
||||||
linearSlippageFactor: '0.001',
|
|
||||||
quadraticSlippageFactor: '0',
|
|
||||||
instrument: {
|
|
||||||
name: 'Token test market',
|
|
||||||
code: 'TEST.24h',
|
|
||||||
future: {
|
|
||||||
settlementAsset:
|
|
||||||
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc',
|
|
||||||
quoteName: 'fUSDC',
|
|
||||||
dataSourceSpecForSettlementData: {
|
|
||||||
external: {
|
|
||||||
oracle: {
|
|
||||||
signers: [
|
|
||||||
{
|
|
||||||
pubKey: {
|
|
||||||
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
name: 'prices.BTC.value',
|
|
||||||
type: 'TYPE_INTEGER',
|
|
||||||
numberDecimalPlaces: '0',
|
|
||||||
},
|
|
||||||
conditions: [
|
|
||||||
{
|
|
||||||
operator: 'OPERATOR_GREATER_THAN',
|
|
||||||
value: '0',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dataSourceSpecForTradingTermination: {
|
|
||||||
external: {
|
|
||||||
oracle: {
|
|
||||||
signers: [
|
|
||||||
{
|
|
||||||
pubKey: {
|
|
||||||
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
name: 'trading.terminated.ETH5',
|
|
||||||
type: 'TYPE_BOOLEAN',
|
|
||||||
},
|
|
||||||
conditions: [
|
|
||||||
{
|
|
||||||
operator: 'OPERATOR_EQUALS',
|
|
||||||
value: 'true',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dataSourceSpecBinding: {
|
|
||||||
settlementDataProperty: 'prices.BTC.value',
|
|
||||||
tradingTerminationProperty: 'trading.terminated.ETH5',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
metadata: [
|
|
||||||
'sector:food',
|
|
||||||
'sector:materials',
|
|
||||||
'source:docs.vega.xyz',
|
|
||||||
],
|
|
||||||
priceMonitoringParameters: {
|
|
||||||
triggers: [
|
|
||||||
{
|
|
||||||
horizon: '43200',
|
|
||||||
probability: '0.9999999',
|
|
||||||
auctionExtension: '600',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
liquidityMonitoringParameters: {
|
|
||||||
targetStakeParameters: {
|
|
||||||
timeWindow: '3600',
|
|
||||||
scalingFactor: 10,
|
|
||||||
},
|
|
||||||
triggeringRatio: '0.7',
|
|
||||||
auctionExtension: '1',
|
|
||||||
},
|
|
||||||
logNormal: {
|
|
||||||
tau: 0.0001140771161,
|
|
||||||
riskAversionParameter: 0.01,
|
|
||||||
params: {
|
|
||||||
mu: 0,
|
|
||||||
r: 0.016,
|
|
||||||
sigma: 0.5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
successor: {
|
|
||||||
parentMarketId: parentMarketId,
|
|
||||||
insurancePoolFraction: '0.75',
|
|
||||||
},
|
|
||||||
liquiditySlaParameters: {
|
|
||||||
priceRange: '0.95',
|
|
||||||
commitmentMinTimeFraction: '0.5',
|
|
||||||
performanceHysteresisEpochs: 2,
|
|
||||||
slaCompetitionFactor: '0.75',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
closingTimestamp,
|
|
||||||
enactmentTimestamp,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getNewAssetTxBody() {
|
|
||||||
const MIN_CLOSE_SEC = 500;
|
|
||||||
const MIN_ENACT_SEC = 700;
|
|
||||||
const MIN_VALID_SEC = 60;
|
|
||||||
|
|
||||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
|
||||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
|
||||||
const validationDate = addSeconds(new Date(), MIN_VALID_SEC);
|
|
||||||
|
|
||||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
|
||||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
|
||||||
const validationTimestamp = millisecondsToSeconds(validationDate.getTime());
|
|
||||||
|
|
||||||
return {
|
|
||||||
proposalSubmission: {
|
|
||||||
rationale: {
|
|
||||||
title: 'Test new asset proposal',
|
|
||||||
description: 'E2E test for proposals',
|
|
||||||
},
|
|
||||||
terms: {
|
|
||||||
newAsset: {
|
|
||||||
changes: {
|
|
||||||
name: 'USDT Coin',
|
|
||||||
symbol: 'USDT',
|
|
||||||
decimals: '18',
|
|
||||||
quantum: '1',
|
|
||||||
erc20: {
|
|
||||||
contractAddress: '0xb404c51bbc10dcbe948077f18a4b8e553d160084',
|
|
||||||
withdrawThreshold: '10',
|
|
||||||
lifetimeLimit: '10',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
closingTimestamp,
|
|
||||||
enactmentTimestamp,
|
|
||||||
validationTimestamp,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
|
NX_TENDERMINT_URL=http://localhost:26617
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_TXS_LIST=0
|
NX_EXPLORER_TXS_LIST=0
|
||||||
|
|
||||||
NX_TENDERMINT_URL=http://localhost:26617
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
|
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
NX_VEGA_ENV=DEVNET
|
NX_VEGA_ENV=DEVNET
|
||||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||||
@@ -8,7 +10,3 @@ NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
|||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
|
NX_TENDERMINT_URL=https://be.vega.community
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||||
NX_SENTRY_DSN=https://b3a56b03eda842faad731f3ea9dfd1bc@o286262.ingest.sentry.io/6242427
|
NX_SENTRY_DSN=https://b3a56b03eda842faad731f3ea9dfd1bc@o286262.ingest.sentry.io/6242427
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
@@ -9,7 +11,3 @@ NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
||||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://be.vega.community
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
|
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
||||||
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
||||||
NX_VEGA_ENV=MAINNET_MIRROR
|
NX_VEGA_ENV=MAINNET-MIRROR
|
||||||
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
|
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
||||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
# .env is stagnet1, so there are no overrides required
|
# .env is stagnet1, so there are no overrides required
|
||||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
|
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
|
||||||
NX_VEGA_ENV=TESTNET
|
NX_VEGA_ENV=TESTNET
|
||||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
@@ -9,7 +11,3 @@ NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||||
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
|
||||||
|
|||||||
@@ -7,11 +7,9 @@ NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9
|
|||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
|
|
||||||
|
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
||||||
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
|
||||||
|
|||||||
@@ -5,5 +5,4 @@ NX_VEGA_ENV=CUSTOM
|
|||||||
NX_BLOCK_EXPLORER=
|
NX_BLOCK_EXPLORER=
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[[redirects]]
|
||||||
|
from = "/*"
|
||||||
|
to = "/index.html"
|
||||||
|
status = 200
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nx/eslint:lint",
|
"executor": "@nx/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
||||||
@@ -63,14 +63,30 @@
|
|||||||
"executor": "@nx/jest:jest",
|
"executor": "@nx/jest:jest",
|
||||||
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
||||||
"options": {
|
"options": {
|
||||||
"jestConfig": "apps/explorer/jest.config.ts"
|
"jestConfig": "apps/explorer/jest.config.ts",
|
||||||
|
"passWithNoTests": true
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"ci": {
|
||||||
|
"ci": true,
|
||||||
|
"codeCoverage": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generate-types": {
|
"generate-types": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.73.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/spec-update-v0.72.0-preview.2/specs/v0.72.0-preview.2/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"build-netlify": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"commands": [
|
||||||
|
"cp apps/explorer/netlify.toml netlify.toml",
|
||||||
|
"nx build explorer"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import '../i18n';
|
|
||||||
import {
|
import {
|
||||||
|
AppFailure,
|
||||||
NetworkLoader,
|
NetworkLoader,
|
||||||
NodeFailure,
|
|
||||||
NodeGuard,
|
NodeGuard,
|
||||||
NodeSwitcherDialog,
|
NodeSwitcherDialog,
|
||||||
useEnvironment,
|
useEnvironment,
|
||||||
@@ -12,8 +11,7 @@ import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-web
|
|||||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { useRouterConfig } from './routes/router-config';
|
import { router } from './routes/router-config';
|
||||||
import { createBrowserRouter } from 'react-router-dom';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
@@ -30,27 +28,20 @@ function App() {
|
|||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<TendermintWebsocketProvider>
|
<TendermintWebsocketProvider>
|
||||||
<Suspense fallback={splashLoading}>
|
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
||||||
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
<NodeGuard
|
||||||
<NodeGuard
|
skeleton={<div>{t('Loading')}</div>}
|
||||||
skeleton={<div>{t('Loading')}</div>}
|
failure={<AppFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />}
|
||||||
failure={
|
>
|
||||||
<NodeFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />
|
<Suspense fallback={splashLoading}>
|
||||||
}
|
<RouterProvider router={router} fallbackElement={splashLoading} />
|
||||||
>
|
</Suspense>
|
||||||
<Suspense fallback={splashLoading}>
|
</NodeGuard>
|
||||||
<RouterProvider
|
<NodeSwitcherDialog
|
||||||
router={createBrowserRouter(useRouterConfig())}
|
open={nodeSwitcherOpen}
|
||||||
fallbackElement={splashLoading}
|
setOpen={setNodeSwitcherOpen}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</NetworkLoader>
|
||||||
</NodeGuard>
|
|
||||||
<NodeSwitcherDialog
|
|
||||||
open={nodeSwitcherOpen}
|
|
||||||
setOpen={setNodeSwitcherOpen}
|
|
||||||
/>
|
|
||||||
</NetworkLoader>
|
|
||||||
</Suspense>
|
|
||||||
</TendermintWebsocketProvider>
|
</TendermintWebsocketProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useAssetDataProvider } from '@vegaprotocol/assets';
|
import { useAssetDataProvider } from '@vegaprotocol/assets';
|
||||||
import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
import { AssetLink } from '../links';
|
import { AssetLink } from '../links';
|
||||||
|
|
||||||
export type AssetBalanceProps = {
|
export type AssetBalanceProps = {
|
||||||
@@ -23,12 +23,12 @@ const AssetBalance = ({
|
|||||||
|
|
||||||
const label =
|
const label =
|
||||||
!loading && asset && asset.decimals
|
!loading && asset && asset.decimals
|
||||||
? addDecimalsFixedFormatNumber(price, asset.decimals)
|
? addDecimalsFormatNumber(price, asset.decimals)
|
||||||
: price;
|
: price;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inline-block">
|
<div className="inline-block">
|
||||||
<span className="font-mono">{label}</span>{' '}
|
<span>{label}</span>{' '}
|
||||||
{showAssetLink && asset?.id ? (
|
{showAssetLink && asset?.id ? (
|
||||||
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
|
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -1,30 +1,24 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import {
|
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||||
useAssetTypeMapping,
|
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
||||||
useAssetStatusMapping,
|
|
||||||
type AssetFieldsFragment,
|
|
||||||
} from '@vegaprotocol/assets';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { type AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import { type VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
||||||
import { useRef, useLayoutEffect } from 'react';
|
import { useRef, useLayoutEffect } from 'react';
|
||||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { type ColDef } from 'ag-grid-community';
|
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
||||||
import type { RowClickedEvent } from 'ag-grid-community';
|
|
||||||
|
|
||||||
type AssetsTableProps = {
|
type AssetsTableProps = {
|
||||||
data: AssetFieldsFragment[] | null;
|
data: AssetFieldsFragment[] | null;
|
||||||
};
|
};
|
||||||
export const AssetsTable = ({ data }: AssetsTableProps) => {
|
export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||||
const assetTypeMapping = useAssetTypeMapping();
|
|
||||||
const assetStatusMapping = useAssetStatusMapping();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const ref = useRef<AgGridReact>(null);
|
const ref = useRef<AgGridReact>(null);
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
ref.current?.api.setColumnsVisible(
|
ref.current?.columnApi.setColumnsVisible(
|
||||||
['id', 'type', 'status'],
|
['id', 'type', 'status'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
@@ -53,14 +47,14 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
field: 'source.__typename',
|
field: 'source.__typename',
|
||||||
hide: window.innerWidth < BREAKPOINT_MD,
|
hide: window.innerWidth < BREAKPOINT_MD,
|
||||||
valueFormatter: ({ value }: { value?: string }) =>
|
valueFormatter: ({ value }: { value?: string }) =>
|
||||||
value ? assetTypeMapping[value].value : '',
|
value ? AssetTypeMapping[value].value : '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: t('Status'),
|
headerName: t('Status'),
|
||||||
field: 'status',
|
field: 'status',
|
||||||
hide: window.innerWidth < BREAKPOINT_MD,
|
hide: window.innerWidth < BREAKPOINT_MD,
|
||||||
valueFormatter: ({ value }: { value?: string }) =>
|
valueFormatter: ({ value }: { value?: string }) =>
|
||||||
value ? assetStatusMapping[value].value : '',
|
value ? AssetStatusMapping[value].value : '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colId: 'actions',
|
colId: 'actions',
|
||||||
@@ -75,7 +69,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
||||||
value ? (
|
value ? (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
onClick={() => {
|
onClick={(e) => {
|
||||||
navigate(value);
|
navigate(value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -86,7 +80,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[navigate, assetStatusMapping, assetTypeMapping]
|
[navigate]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const Footer = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="grid grid-cols-[1fr_auto] items-center text-xs md:text-md lg:flex md:col-span-2 px-4 pt-2 pb-3 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200">
|
<footer className="grid grid-rows-2 lg:grid-cols-[1fr_auto] text-xs md:text-md lg:flex md:col-span-2 px-4 py-2 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200">
|
||||||
<div className="flex justify-between gap-2 align-middle">
|
<div className="flex justify-between gap-2 align-middle">
|
||||||
{GIT_COMMIT_HASH && (
|
{GIT_COMMIT_HASH && (
|
||||||
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
||||||
@@ -43,12 +43,9 @@ export const Footer = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="content-center flex pr-4 md:border-r border-neutral-700 dark:border-neutral-300">
|
<div className="content-center flex pl-2 md:border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
||||||
<span className="pr-2">{VEGA_URL && <NodeUrl url={VEGA_URL} />}</span>
|
{VEGA_URL && <NodeUrl url={VEGA_URL} />}
|
||||||
<Link
|
<Link className="ml-2" onClick={() => setNodeSwitcherOpen(true)}>
|
||||||
className="ml-2 underline-offset-4"
|
|
||||||
onClick={() => setNodeSwitcherOpen(true)}
|
|
||||||
>
|
|
||||||
{t('Change')}
|
{t('Change')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,10 +59,7 @@ export const Footer = () => {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="pl-2 align-center lg:align-right lg:flex lg:justify-end gap-2 align-middle lg:max-w-xs lg:ml-auto">
|
<div className="pl-2 align-center lg:align-right lg:flex lg:justify-end gap-2 align-middle lg:max-w-xs lg:ml-auto">
|
||||||
<RouteLink
|
<RouteLink to={`/${Routes.DISCLAIMER}`} className="underline">
|
||||||
to={`/${Routes.DISCLAIMER}`}
|
|
||||||
className="underline underline-offset-4"
|
|
||||||
>
|
|
||||||
Disclaimer
|
Disclaimer
|
||||||
</RouteLink>
|
</RouteLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { Routes } from '../../routes/route-names';
|
|||||||
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
||||||
import type { Navigable } from '../../routes/router-config';
|
import type { Navigable } from '../../routes/router-config';
|
||||||
import { isNavigable } from '../../routes/router-config';
|
import { isNavigable } from '../../routes/router-config';
|
||||||
import { useRouterConfig } from '../../routes/router-config';
|
import { routerConfig } from '../../routes/router-config';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import { Search } from '../search';
|
import { Search } from '../search';
|
||||||
@@ -26,7 +26,6 @@ const routeToNavigationItem = (r: Navigable) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const routerConfig = useRouterConfig();
|
|
||||||
const isHome = Boolean(useMatch(Routes.HOME));
|
const isHome = Boolean(useMatch(Routes.HOME));
|
||||||
const pages = routerConfig[0].children || [];
|
const pages = routerConfig[0].children || [];
|
||||||
const mainItems = compact(
|
const mainItems = compact(
|
||||||
@@ -96,10 +95,7 @@ export const Header = () => {
|
|||||||
{mainItems.map(routeToNavigationItem)}
|
{mainItems.map(routeToNavigationItem)}
|
||||||
{groupedItems && groupedItems.length > 0 && (
|
{groupedItems && groupedItems.length > 0 && (
|
||||||
<NavigationItem>
|
<NavigationItem>
|
||||||
<NavigationTrigger
|
<NavigationTrigger isActive={Boolean(isOnOther)}>
|
||||||
isActive={Boolean(isOnOther)}
|
|
||||||
data-testid="other"
|
|
||||||
>
|
|
||||||
{t('Other')}
|
{t('Other')}
|
||||||
</NavigationTrigger>
|
</NavigationTrigger>
|
||||||
<NavigationContent>
|
<NavigationContent>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export type HashProps = {
|
export type HashProps = {
|
||||||
text: string;
|
text: string;
|
||||||
truncate?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -8,16 +7,10 @@ export type HashProps = {
|
|||||||
* are broken when they need to wrap. This will remove the need
|
* are broken when they need to wrap. This will remove the need
|
||||||
* for a lot of the overflow scrolling that currently exists.
|
* for a lot of the overflow scrolling that currently exists.
|
||||||
*/
|
*/
|
||||||
const Hash = ({ text, truncate = false }: HashProps) => {
|
const Hash = ({ text }: HashProps) => {
|
||||||
const h = truncate ? text.slice(0, 6) : text;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<code
|
<code className="break-all font-mono" style={{ wordWrap: 'break-word' }}>
|
||||||
title={text}
|
{text}
|
||||||
className="break-all font-mono"
|
|
||||||
style={{ wordWrap: 'break-word' }}
|
|
||||||
>
|
|
||||||
{h}
|
|
||||||
</code>
|
</code>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ query ExplorerMarket($id: ID!) {
|
|||||||
id
|
id
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
positionDecimalPlaces
|
positionDecimalPlaces
|
||||||
state
|
|
||||||
tradableInstrument {
|
tradableInstrument {
|
||||||
instrument {
|
instrument {
|
||||||
name
|
name
|
||||||
@@ -14,14 +13,9 @@ query ExplorerMarket($id: ID!) {
|
|||||||
decimals
|
decimals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
... on Perpetual {
|
|
||||||
quoteName
|
|
||||||
settlementAsset {
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-8
@@ -8,7 +8,7 @@ export type ExplorerMarketQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Perpetual', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Spot' } } } } | null };
|
export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } } } } | null };
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerMarketDocument = gql`
|
export const ExplorerMarketDocument = gql`
|
||||||
@@ -17,7 +17,6 @@ export const ExplorerMarketDocument = gql`
|
|||||||
id
|
id
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
positionDecimalPlaces
|
positionDecimalPlaces
|
||||||
state
|
|
||||||
tradableInstrument {
|
tradableInstrument {
|
||||||
instrument {
|
instrument {
|
||||||
name
|
name
|
||||||
@@ -28,15 +27,10 @@ export const ExplorerMarketDocument = gql`
|
|||||||
decimals
|
decimals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
... on Perpetual {
|
|
||||||
quoteName
|
|
||||||
settlementAsset {
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -61,11 +61,7 @@ describe('Market link component', () => {
|
|||||||
instrument: {
|
instrument: {
|
||||||
name: 'test-label',
|
name: 'test-label',
|
||||||
product: {
|
product: {
|
||||||
__typename: 'Future',
|
|
||||||
quoteName: 'dai',
|
quoteName: 'dai',
|
||||||
settlementAsset: {
|
|
||||||
decimals: 8,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -91,6 +87,6 @@ describe('Market link component', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const res = render(renderComponent('123', [mock]));
|
const res = render(renderComponent('123', [mock]));
|
||||||
expect(await res.findByTitle('123')).toBeInTheDocument();
|
expect(await res.findByText('123')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ const MarketLink = ({
|
|||||||
}: MarketLinkProps) => {
|
}: MarketLinkProps) => {
|
||||||
const { data, error, loading } = useExplorerMarketQuery({
|
const { data, error, loading } = useExplorerMarketQuery({
|
||||||
variables: { id },
|
variables: { id },
|
||||||
fetchPolicy: 'cache-first',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let label = <span>{id}</span>;
|
let label = <span>{id}</span>;
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
import OracleLink, { getStatusString } from './oracle-link';
|
|
||||||
import { render, screen } from '@testing-library/react';
|
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
|
||||||
|
|
||||||
describe('getStatusString', () => {
|
|
||||||
it("returns 'Unknown' for undefined status", () => {
|
|
||||||
expect(getStatusString(undefined)).toBe('Unknown');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the correct string for a known status', () => {
|
|
||||||
expect(getStatusString('STATUS_ACTIVE')).toBe('Active');
|
|
||||||
expect(getStatusString('STATUS_DEACTIVATED')).toBe('Deactivated');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('OracleLink', () => {
|
|
||||||
it('renders the truncated Oracle ID', () => {
|
|
||||||
const id = '123456789';
|
|
||||||
render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<OracleLink id={id} />
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
const idElement = screen.getByText(id.slice(0, 6));
|
|
||||||
expect(idElement).toBeInTheDocument();
|
|
||||||
expect(idElement).toHaveAttribute('title', id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders the Oracle status', () => {
|
|
||||||
const id = '123';
|
|
||||||
const status = 'STATUS_ACTIVE';
|
|
||||||
render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<OracleLink id={id} status={status} data-testid="link" />
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(screen.getByTestId('link')).toHaveAttribute('data-status', 'Active');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders the Oracle data indicator', () => {
|
|
||||||
const id = '123';
|
|
||||||
const hasSeenOracleReports = true;
|
|
||||||
render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<OracleLink id={id} hasSeenOracleReports={hasSeenOracleReports} />
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(screen.getByTestId('oracle-data-indicator')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -3,93 +3,20 @@ import { Link } from 'react-router-dom';
|
|||||||
|
|
||||||
import type { ComponentProps } from 'react';
|
import type { ComponentProps } from 'react';
|
||||||
import Hash from '../hash';
|
import Hash from '../hash';
|
||||||
import { Tooltip, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import {
|
|
||||||
DataSourceSpecStatus,
|
|
||||||
DataSourceSpecStatusMapping,
|
|
||||||
} from '@vegaprotocol/types';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a human-readable string for the given status, or a meaningful
|
|
||||||
* default if the status is unrecognised
|
|
||||||
* @param status string status
|
|
||||||
*/
|
|
||||||
export function getStatusString(status: string | undefined): string {
|
|
||||||
if (status && status in DataSourceSpecStatus) {
|
|
||||||
return DataSourceSpecStatusMapping[status as DataSourceSpecStatus];
|
|
||||||
}
|
|
||||||
|
|
||||||
return t('Unknown');
|
|
||||||
}
|
|
||||||
|
|
||||||
export type OracleLinkProps = Partial<ComponentProps<typeof Link>> & {
|
export type OracleLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||||
// The Oracle ID
|
|
||||||
id: string;
|
id: string;
|
||||||
// If available, the oracle status
|
|
||||||
status?: string;
|
|
||||||
// If the oracle has corresponding data in the OracleDataConnection
|
|
||||||
hasSeenOracleReports?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const OracleLink = ({ id, ...props }: OracleLinkProps) => {
|
||||||
* Given an Oracle ID, renders a data-dense link to the Oracle page. Data density is achieved by:
|
|
||||||
* - Colour coding the link based on the Oracle's status
|
|
||||||
* - Showing a small indicator if the Oracle has matched data
|
|
||||||
* - Showing a tooltip with the Oracle's status and whether it has matched data
|
|
||||||
*
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const OracleLink = ({
|
|
||||||
id,
|
|
||||||
status,
|
|
||||||
hasSeenOracleReports = false,
|
|
||||||
...props
|
|
||||||
}: OracleLinkProps) => {
|
|
||||||
const bgColour =
|
|
||||||
status === 'STATUS_ACTIVE'
|
|
||||||
? 'bg-yellow-100 hover:bg-yellow-200 border-yellow-200 dark:bg-yellow-200 dark:border-yellow-200 dark:text-gray-900 dark:border-yellow-300'
|
|
||||||
: 'bg-gray-100 hover:bg-gray-200 border-gray-200';
|
|
||||||
const indicatorColour =
|
|
||||||
status === 'STATUS_ACTIVE'
|
|
||||||
? 'bg-yellow-300 hover:bg-yellow-500 dark:bg-yellow-500'
|
|
||||||
: 'bg-gray-300 hover:bg-gray-500';
|
|
||||||
|
|
||||||
const description = (
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<strong>{`Status: `}</strong>
|
|
||||||
{getStatusString(status)}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>{`Matched data: `}</strong>
|
|
||||||
{hasSeenOracleReports ? (
|
|
||||||
<VegaIcon name={VegaIconNames.TICK} />
|
|
||||||
) : (
|
|
||||||
<VegaIcon name={VegaIconNames.CROSS} />
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip description={description}>
|
<Link
|
||||||
<Link
|
className="underline font-mono"
|
||||||
className={`pl-2 pr-2 font-mono dark:text-black ${bgColour} rounded-sm border-solid border-2 relative`}
|
{...props}
|
||||||
{...props}
|
to={`/${Routes.ORACLES}/${id}`}
|
||||||
to={`/${Routes.ORACLES}/${id}`}
|
>
|
||||||
data-status={getStatusString(status)}
|
<Hash text={id} />
|
||||||
>
|
</Link>
|
||||||
<Hash text={id} truncate={true} />
|
|
||||||
{hasSeenOracleReports ? (
|
|
||||||
<strong
|
|
||||||
data-testid="oracle-data-indicator"
|
|
||||||
className={`absolute top-0 right-0 w-1 h-full font-thin ${indicatorColour}`}
|
|
||||||
title="Oracle has matched data"
|
|
||||||
></strong>
|
|
||||||
) : null}
|
|
||||||
</Link>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span className="whitespace-nowrap">
|
||||||
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
||||||
<Link
|
<Link
|
||||||
className="underline font-mono"
|
className="underline font-mono"
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
query ExplorerProposal($id: ID!) {
|
query ExplorerProposal($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
... on Proposal {
|
id
|
||||||
id
|
rationale {
|
||||||
rationale {
|
title
|
||||||
title
|
description
|
||||||
description
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -8,18 +8,16 @@ export type ExplorerProposalQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerProposalQuery = { __typename?: 'Query', proposal?: { __typename?: 'BatchProposal' } | { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null };
|
export type ExplorerProposalQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null };
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerProposalDocument = gql`
|
export const ExplorerProposalDocument = gql`
|
||||||
query ExplorerProposal($id: ID!) {
|
query ExplorerProposal($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
... on Proposal {
|
id
|
||||||
id
|
rationale {
|
||||||
rationale {
|
title
|
||||||
title
|
description
|
||||||
description
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,7 @@ import { MockedProvider } from '@apollo/client/testing';
|
|||||||
import type { MockedResponse } from '@apollo/client/testing';
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import ProposalLink from './proposal-link';
|
import ProposalLink from './proposal-link';
|
||||||
import {
|
import { ExplorerProposalDocument } from './__generated__/Proposal';
|
||||||
ExplorerProposalDocument,
|
|
||||||
type ExplorerProposalQuery,
|
|
||||||
type ExplorerProposalQueryVariables,
|
|
||||||
} from './__generated__/Proposal';
|
|
||||||
import { GraphQLError } from 'graphql';
|
import { GraphQLError } from 'graphql';
|
||||||
|
|
||||||
function renderComponent(id: string, mocks: MockedResponse[]) {
|
function renderComponent(id: string, mocks: MockedResponse[]) {
|
||||||
@@ -27,10 +23,7 @@ describe('Proposal link component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Renders the ID on error', async () => {
|
it('Renders the ID on error', async () => {
|
||||||
const mock: MockedResponse<
|
const mock = {
|
||||||
ExplorerProposalQuery,
|
|
||||||
ExplorerProposalQueryVariables
|
|
||||||
> = {
|
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerProposalDocument,
|
query: ExplorerProposalDocument,
|
||||||
variables: {
|
variables: {
|
||||||
@@ -47,22 +40,17 @@ describe('Proposal link component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Renders the proposal title when the query returns a result', async () => {
|
it('Renders the proposal title when the query returns a result', async () => {
|
||||||
const proposalId = '123';
|
const mock = {
|
||||||
const mock: MockedResponse<
|
|
||||||
ExplorerProposalQuery,
|
|
||||||
ExplorerProposalQueryVariables
|
|
||||||
> = {
|
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerProposalDocument,
|
query: ExplorerProposalDocument,
|
||||||
variables: {
|
variables: {
|
||||||
id: proposalId,
|
id: '123',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
data: {
|
data: {
|
||||||
proposal: {
|
proposal: {
|
||||||
__typename: 'Proposal',
|
id: '123',
|
||||||
id: proposalId,
|
|
||||||
rationale: {
|
rationale: {
|
||||||
title: 'test-title',
|
title: 'test-title',
|
||||||
description: 'test description',
|
description: 'test description',
|
||||||
@@ -72,16 +60,13 @@ describe('Proposal link component', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = render(renderComponent(proposalId, [mock]));
|
const res = render(renderComponent('123', [mock]));
|
||||||
expect(res.getByText(proposalId)).toBeInTheDocument();
|
expect(res.getByText('123')).toBeInTheDocument();
|
||||||
expect(await res.findByText('test-title')).toBeInTheDocument();
|
expect(await res.findByText('test-title')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Leaves the proposal id when the market is not found', async () => {
|
it('Leaves the proposal id when the market is not found', async () => {
|
||||||
const mock: MockedResponse<
|
const mock = {
|
||||||
ExplorerProposalQuery,
|
|
||||||
ExplorerProposalQueryVariables
|
|
||||||
> = {
|
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerProposalDocument,
|
query: ExplorerProposalDocument,
|
||||||
variables: {
|
variables: {
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
import {
|
import { useExplorerProposalQuery } from './__generated__/Proposal';
|
||||||
useExplorerProposalQuery,
|
|
||||||
type ExplorerProposalQuery,
|
|
||||||
} from './__generated__/Proposal';
|
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { ENV } from '../../../config/env';
|
import { ENV } from '../../../config/env';
|
||||||
import Hash from '../hash';
|
import Hash from '../hash';
|
||||||
|
|
||||||
export type ProposalLinkProps = {
|
export type ProposalLinkProps = {
|
||||||
id: string;
|
id: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
@@ -20,13 +16,8 @@ const ProposalLink = ({ id, text }: ProposalLinkProps) => {
|
|||||||
variables: { id },
|
variables: { id },
|
||||||
});
|
});
|
||||||
|
|
||||||
const proposal = data?.proposal as Extract<
|
|
||||||
ExplorerProposalQuery['proposal'],
|
|
||||||
{ __typename?: 'Proposal' }
|
|
||||||
>;
|
|
||||||
|
|
||||||
const base = ENV.dataSources.governanceUrl;
|
const base = ENV.dataSources.governanceUrl;
|
||||||
const label = proposal?.rationale.title || id;
|
const label = data?.proposal?.rationale.title || id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ExternalLink href={`${base}/proposals/${id}`}>
|
<ExternalLink href={`${base}/proposals/${id}`}>
|
||||||
|
|||||||
@@ -1,41 +1,34 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
import {
|
import { PriceMonitoringBoundsInfoPanel } from '@vegaprotocol/markets';
|
||||||
LiquidityPriceRangeInfoPanel,
|
|
||||||
LiquiditySLAParametersInfoPanel,
|
|
||||||
MarginScalingFactorsPanel,
|
|
||||||
PriceMonitoringBoundsInfoPanel,
|
|
||||||
SuccessionLineInfoPanel,
|
|
||||||
getDataSourceSpecForSettlementData,
|
|
||||||
getDataSourceSpecForTradingTermination,
|
|
||||||
} from '@vegaprotocol/markets';
|
|
||||||
import {
|
import {
|
||||||
LiquidityInfoPanel,
|
LiquidityInfoPanel,
|
||||||
LiquidityMonitoringParametersInfoPanel,
|
LiquidityMonitoringParametersInfoPanel,
|
||||||
InstrumentInfoPanel,
|
InstrumentInfoPanel,
|
||||||
KeyDetailsInfoPanel,
|
KeyDetailsInfoPanel,
|
||||||
|
LiquidityPriceRangeInfoPanel,
|
||||||
MetadataInfoPanel,
|
MetadataInfoPanel,
|
||||||
OracleInfoPanel,
|
OracleInfoPanel,
|
||||||
RiskFactorsInfoPanel,
|
RiskFactorsInfoPanel,
|
||||||
RiskModelInfoPanel,
|
RiskModelInfoPanel,
|
||||||
|
RiskParametersInfoPanel,
|
||||||
SettlementAssetInfoPanel,
|
SettlementAssetInfoPanel,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import { MarketInfoTable } from '@vegaprotocol/markets';
|
import { MarketInfoTable } from '@vegaprotocol/markets';
|
||||||
import type { DataSourceFragment } from '@vegaprotocol/markets';
|
import type { DataSourceDefinition } from '@vegaprotocol/types';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
|
||||||
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||||
if (!market) return null;
|
if (!market) return null;
|
||||||
const { product } = market.tradableInstrument.instrument;
|
|
||||||
const settlementDataSource = getDataSourceSpecForSettlementData(product);
|
|
||||||
const terminationDataSource = getDataSourceSpecForTradingTermination(product);
|
|
||||||
|
|
||||||
const getSigners = ({ data }: DataSourceFragment) => {
|
const settlementData = market.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
||||||
|
const terminationData = market.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
||||||
|
|
||||||
|
const getSigners = (data: DataSourceDefinition) => {
|
||||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||||
const signers =
|
const signers = data.sourceType.sourceType.signers || [];
|
||||||
('signers' in data.sourceType.sourceType &&
|
|
||||||
data.sourceType.sourceType.signers) ||
|
|
||||||
[];
|
|
||||||
|
|
||||||
return signers.map(({ signer }, i) => {
|
return signers.map(({ signer }, i) => {
|
||||||
return (
|
return (
|
||||||
@@ -47,13 +40,10 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const showTwoOracles =
|
const showTwoOracles = isEqual(
|
||||||
settlementDataSource &&
|
getSigners(settlementData),
|
||||||
terminationDataSource &&
|
getSigners(terminationData)
|
||||||
isEqual(
|
);
|
||||||
getSigners(settlementDataSource),
|
|
||||||
getSigners(terminationDataSource)
|
|
||||||
);
|
|
||||||
|
|
||||||
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
|
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
|
||||||
|
|
||||||
@@ -69,8 +59,8 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
<MetadataInfoPanel market={market} />
|
<MetadataInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Risk model')}</h2>
|
<h2 className={headerClassName}>{t('Risk model')}</h2>
|
||||||
<RiskModelInfoPanel market={market} />
|
<RiskModelInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Margin scaling factors')}</h2>
|
<h2 className={headerClassName}>{t('Risk parameters')}</h2>
|
||||||
<MarginScalingFactorsPanel market={market} />
|
<RiskParametersInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
||||||
<RiskFactorsInfoPanel market={market} />
|
<RiskFactorsInfoPanel market={market} />
|
||||||
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
||||||
@@ -96,12 +86,10 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
)}
|
)}
|
||||||
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
||||||
<LiquidityMonitoringParametersInfoPanel market={market} />
|
<LiquidityMonitoringParametersInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
|
||||||
<LiquidityPriceRangeInfoPanel market={market} />
|
|
||||||
<h2 className={headerClassName}>{t('Liquidity SLA protocol')}</h2>
|
|
||||||
<LiquiditySLAParametersInfoPanel market={market} />
|
|
||||||
<h2 className={headerClassName}>{t('Liquidity')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity')}</h2>
|
||||||
<LiquidityInfoPanel market={market} />
|
<LiquidityInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
||||||
|
<LiquidityPriceRangeInfoPanel market={market} />
|
||||||
{showTwoOracles ? (
|
{showTwoOracles ? (
|
||||||
<>
|
<>
|
||||||
<h2 className={headerClassName}>{t('Settlement oracle')}</h2>
|
<h2 className={headerClassName}>{t('Settlement oracle')}</h2>
|
||||||
@@ -115,8 +103,6 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
<OracleInfoPanel market={market} type="settlementData" />
|
<OracleInfoPanel market={market} type="settlementData" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<h2 className={`${headerClassName} mb-4`}>{t('Succession line')}</h2>
|
|
||||||
<SuccessionLineInfoPanel market={market} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { getAsset, type MarketFieldsFragment } from '@vegaprotocol/markets';
|
import type { MarketFieldsFragment } from '@vegaprotocol/markets';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { type AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { type ColDef } from 'ag-grid-community';
|
import type { ColDef } from 'ag-grid-community';
|
||||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import {
|
import type {
|
||||||
type VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
type VegaValueGetterParams,
|
VegaValueGetterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { useRef, useLayoutEffect } from 'react';
|
import { useRef, useLayoutEffect } from 'react';
|
||||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||||
import { MarketStateMapping } from '@vegaprotocol/types';
|
import { MarketStateMapping } from '@vegaprotocol/types';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import { type RowClickedEvent } from 'ag-grid-community';
|
import type { RowClickedEvent } from 'ag-grid-community';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
type MarketsTableProps = {
|
type MarketsTableProps = {
|
||||||
@@ -29,7 +29,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
const gridRef = useRef<AgGridReact>(null);
|
const gridRef = useRef<AgGridReact>(null);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
gridRef.current?.api.setColumnsVisible(
|
gridRef.current?.columnApi.setColumnsVisible(
|
||||||
['id', 'state', 'asset'],
|
['id', 'state', 'asset'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
@@ -73,7 +73,8 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
MarketFieldsFragment,
|
MarketFieldsFragment,
|
||||||
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
||||||
>) => {
|
>) => {
|
||||||
const value = data && getAsset(data);
|
const value =
|
||||||
|
data?.tradableInstrument.instrument.product.settlementAsset;
|
||||||
return value ? (
|
return value ? (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { render, waitFor } from '@testing-library/react';
|
import { render, waitFor } from '@testing-library/react';
|
||||||
import { NestedDataList, sortNestedDataByChildren } from './nested-data-list';
|
import {
|
||||||
|
BORDER_COLOURS,
|
||||||
|
NestedDataList,
|
||||||
|
sortNestedDataByChildren,
|
||||||
|
} from './nested-data-list';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
const mockData = {
|
const mockData = {
|
||||||
@@ -57,6 +61,38 @@ describe('NestedDataList', () => {
|
|||||||
expect(parent[0].querySelector('li')).toHaveClass('pl-4 border-l-4 pt-2');
|
expect(parent[0].querySelector('li')).toHaveClass('pl-4 border-l-4 pt-2');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should repeat the border colours in the correct order', () => {
|
||||||
|
const colourMockData = {
|
||||||
|
t0: {
|
||||||
|
t1: {
|
||||||
|
t2: {
|
||||||
|
t3: {
|
||||||
|
t4: {
|
||||||
|
t5: {
|
||||||
|
t6: {
|
||||||
|
t7: {
|
||||||
|
t8: {
|
||||||
|
hello: 'world',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const tree = render(<NestedDataList data={colourMockData} />);
|
||||||
|
const { getByTestId } = tree;
|
||||||
|
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const item = getByTestId(`T${i}`);
|
||||||
|
const expected = BORDER_COLOURS.light[i % 5];
|
||||||
|
expect(item.style.borderColor.toUpperCase()).toBe(expected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should sort the data by values with children', () => {
|
it('should sort the data by values with children', () => {
|
||||||
const mockData = {
|
const mockData = {
|
||||||
nonce: '5980890939790185837',
|
nonce: '5980890939790185837',
|
||||||
|
|||||||
@@ -31,9 +31,6 @@ fragment ExplorerDeterministicOrderFields on Order {
|
|||||||
... on Future {
|
... on Future {
|
||||||
quoteName
|
quoteName
|
||||||
}
|
}
|
||||||
... on Perpetual {
|
|
||||||
quoteName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
fragment ExplorerStopOrderFields on StopOrder {
|
|
||||||
id
|
|
||||||
status
|
|
||||||
createdAt
|
|
||||||
trigger {
|
|
||||||
... on StopOrderPrice {
|
|
||||||
price
|
|
||||||
}
|
|
||||||
... on StopOrderTrailingPercentOffset {
|
|
||||||
trailingPercentOffset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createdAt
|
|
||||||
ocoLinkId
|
|
||||||
triggerDirection
|
|
||||||
order {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query ExplorerStopOrder($stopOrderId: ID!) {
|
|
||||||
stopOrder(id: $stopOrderId) {
|
|
||||||
...ExplorerStopOrderFields
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } };
|
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } };
|
||||||
|
|
||||||
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
||||||
orderId: Types.Scalars['ID'];
|
orderId: Types.Scalars['ID'];
|
||||||
@@ -11,7 +11,7 @@ export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } } };
|
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } } };
|
||||||
|
|
||||||
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
||||||
fragment ExplorerDeterministicOrderFields on Order {
|
fragment ExplorerDeterministicOrderFields on Order {
|
||||||
@@ -47,9 +47,6 @@ export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
|||||||
... on Future {
|
... on Future {
|
||||||
quoteName
|
quoteName
|
||||||
}
|
}
|
||||||
... on Perpetual {
|
|
||||||
quoteName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
import * as Types from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client';
|
|
||||||
import * as Apollo from '@apollo/client';
|
|
||||||
const defaultOptions = {} as const;
|
|
||||||
export type ExplorerStopOrderFieldsFragment = { __typename?: 'StopOrder', id: string, status: Types.StopOrderStatus, createdAt: any, ocoLinkId?: string | null, triggerDirection: Types.StopOrderTriggerDirection, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, order?: { __typename?: 'Order', id: string } | null };
|
|
||||||
|
|
||||||
export type ExplorerStopOrderQueryVariables = Types.Exact<{
|
|
||||||
stopOrderId: Types.Scalars['ID'];
|
|
||||||
}>;
|
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerStopOrderQuery = { __typename?: 'Query', stopOrder?: { __typename?: 'StopOrder', id: string, status: Types.StopOrderStatus, createdAt: any, ocoLinkId?: string | null, triggerDirection: Types.StopOrderTriggerDirection, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, order?: { __typename?: 'Order', id: string } | null } | null };
|
|
||||||
|
|
||||||
export const ExplorerStopOrderFieldsFragmentDoc = gql`
|
|
||||||
fragment ExplorerStopOrderFields on StopOrder {
|
|
||||||
id
|
|
||||||
status
|
|
||||||
createdAt
|
|
||||||
trigger {
|
|
||||||
... on StopOrderPrice {
|
|
||||||
price
|
|
||||||
}
|
|
||||||
... on StopOrderTrailingPercentOffset {
|
|
||||||
trailingPercentOffset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createdAt
|
|
||||||
ocoLinkId
|
|
||||||
triggerDirection
|
|
||||||
order {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
export const ExplorerStopOrderDocument = gql`
|
|
||||||
query ExplorerStopOrder($stopOrderId: ID!) {
|
|
||||||
stopOrder(id: $stopOrderId) {
|
|
||||||
...ExplorerStopOrderFields
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${ExplorerStopOrderFieldsFragmentDoc}`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __useExplorerStopOrderQuery__
|
|
||||||
*
|
|
||||||
* To run a query within a React component, call `useExplorerStopOrderQuery` and pass it any options that fit your needs.
|
|
||||||
* When your component renders, `useExplorerStopOrderQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
|
||||||
* you can use to render your UI.
|
|
||||||
*
|
|
||||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const { data, loading, error } = useExplorerStopOrderQuery({
|
|
||||||
* variables: {
|
|
||||||
* stopOrderId: // value for 'stopOrderId'
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function useExplorerStopOrderQuery(baseOptions: Apollo.QueryHookOptions<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>) {
|
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
|
||||||
return Apollo.useQuery<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>(ExplorerStopOrderDocument, options);
|
|
||||||
}
|
|
||||||
export function useExplorerStopOrderLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>) {
|
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
|
||||||
return Apollo.useLazyQuery<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>(ExplorerStopOrderDocument, options);
|
|
||||||
}
|
|
||||||
export type ExplorerStopOrderQueryHookResult = ReturnType<typeof useExplorerStopOrderQuery>;
|
|
||||||
export type ExplorerStopOrderLazyQueryHookResult = ReturnType<typeof useExplorerStopOrderLazyQuery>;
|
|
||||||
export type ExplorerStopOrderQueryResult = Apollo.QueryResult<ExplorerStopOrderQuery, ExplorerStopOrderQueryVariables>;
|
|
||||||
@@ -17,7 +17,7 @@ function renderAmendOrderDetails(
|
|||||||
mocks: MockedResponse[]
|
mocks: MockedResponse[]
|
||||||
) {
|
) {
|
||||||
return render(
|
return render(
|
||||||
<MockedProvider mocks={mocks}>
|
<MockedProvider mocks={mocks} addTypename={false}>
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<AmendOrderDetails version={version} id={id} amend={amend} />
|
<AmendOrderDetails version={version} id={id} amend={amend} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
@@ -44,18 +44,18 @@ function renderExistingAmend(
|
|||||||
orderByID: {
|
orderByID: {
|
||||||
__typename: 'Order',
|
__typename: 'Order',
|
||||||
id: '123',
|
id: '123',
|
||||||
type: Schema.OrderType.TYPE_LIMIT,
|
type: 'GTT',
|
||||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||||
version: version ? version.toString() : '',
|
version: version,
|
||||||
createdAt: '123',
|
createdAt: '123',
|
||||||
updatedAt: '456',
|
updatedAt: '456',
|
||||||
expiresAt: '789',
|
expiresAt: '789',
|
||||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||||
price: '200',
|
price: '200',
|
||||||
side: Schema.Side.SIDE_BUY,
|
side: 'BUY',
|
||||||
peggedOrder: null,
|
peggedOrder: null,
|
||||||
remaining: '99',
|
remaining: '99',
|
||||||
rejectionReason: Schema.OrderRejectionReason.ORDER_ERROR_NOT_FOUND,
|
rejectionReason: 'rejection',
|
||||||
reference: '123',
|
reference: '123',
|
||||||
size: '100',
|
size: '100',
|
||||||
party: {
|
party: {
|
||||||
@@ -65,9 +65,9 @@ function renderExistingAmend(
|
|||||||
market: {
|
market: {
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
id: '789',
|
id: '789',
|
||||||
state: Schema.MarketState.STATE_ACTIVE,
|
state: 'STATUS_ACTIVE',
|
||||||
positionDecimalPlaces: 2,
|
positionDecimalPlaces: 2,
|
||||||
decimalPlaces: 0,
|
decimalPlaces: '5',
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
@@ -94,18 +94,18 @@ function renderExistingAmend(
|
|||||||
orderByID: {
|
orderByID: {
|
||||||
__typename: 'Order',
|
__typename: 'Order',
|
||||||
id: '123',
|
id: '123',
|
||||||
type: Schema.OrderType.TYPE_LIMIT,
|
type: 'GTT',
|
||||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||||
version: '100',
|
version: 100,
|
||||||
createdAt: '123',
|
createdAt: '123',
|
||||||
updatedAt: '456',
|
updatedAt: '456',
|
||||||
expiresAt: '789',
|
expiresAt: '789',
|
||||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||||
peggedOrder: null,
|
peggedOrder: null,
|
||||||
price: '200',
|
price: '200',
|
||||||
side: Schema.Side.SIDE_BUY,
|
side: 'BUY',
|
||||||
remaining: '99',
|
remaining: '99',
|
||||||
rejectionReason: Schema.OrderRejectionReason.ORDER_ERROR_NOT_FOUND,
|
rejectionReason: 'rejection',
|
||||||
reference: '123',
|
reference: '123',
|
||||||
size: '200',
|
size: '200',
|
||||||
party: {
|
party: {
|
||||||
@@ -114,10 +114,10 @@ function renderExistingAmend(
|
|||||||
},
|
},
|
||||||
market: {
|
market: {
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
id: '8888',
|
id: 'amend-to-order-latest-version',
|
||||||
state: Schema.MarketState.STATE_ACTIVE,
|
state: 'STATUS_ACTIVE',
|
||||||
positionDecimalPlaces: 2,
|
positionDecimalPlaces: 2,
|
||||||
decimalPlaces: 0,
|
decimalPlaces: '5',
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
name: 'amend-to-order-latest-version-test',
|
name: 'amend-to-order-latest-version-test',
|
||||||
@@ -136,13 +136,13 @@ function renderExistingAmend(
|
|||||||
request: {
|
request: {
|
||||||
query: ExplorerMarketDocument,
|
query: ExplorerMarketDocument,
|
||||||
variables: {
|
variables: {
|
||||||
id: '8888',
|
id: '789',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
data: {
|
data: {
|
||||||
market: {
|
market: {
|
||||||
id: '8888',
|
id: '789',
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
positionDecimalPlaces: 2,
|
positionDecimalPlaces: 2,
|
||||||
state: 'irrelevant-test-data',
|
state: 'irrelevant-test-data',
|
||||||
@@ -150,11 +150,7 @@ function renderExistingAmend(
|
|||||||
instrument: {
|
instrument: {
|
||||||
name: 'test-label',
|
name: 'test-label',
|
||||||
product: {
|
product: {
|
||||||
__typename: 'Future',
|
|
||||||
quoteName: 'dai',
|
quoteName: 'dai',
|
||||||
settlementAsset: {
|
|
||||||
decimals: 8,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -219,10 +215,12 @@ describe('Amend order details', () => {
|
|||||||
|
|
||||||
it('Fetches latest version when version is not specified', async () => {
|
it('Fetches latest version when version is not specified', async () => {
|
||||||
const amend: Amend = {
|
const amend: Amend = {
|
||||||
price: '123',
|
price: '-7879',
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = renderExistingAmend('123', undefined, amend);
|
const res = renderExistingAmend('123', undefined, amend);
|
||||||
expect(await res.findByText('test-label')).toBeInTheDocument();
|
expect(
|
||||||
|
await res.findByText('amend-to-order-latest-version')
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-12 lg:mb-0">
|
<div className="mb-12 lg:mb-0">
|
||||||
<div className="relative block rounded-lg px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block rounded-lg px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="display-5 mb-4 text-3xl font-bold">
|
<h2 className="text-3xl font-bold mb-4 display-5">
|
||||||
{t('Order not found')}
|
{t('Order not found')}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mb-12 text-gray-500">
|
<p className="text-gray-500 mb-12">
|
||||||
{t('No order created from this transaction')}
|
{t('No order created from this transaction')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,24 +68,24 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-12 lg:mb-0">
|
<div className="mb-12 lg:mb-0">
|
||||||
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="display-5 mb-4 text-3xl font-bold">
|
<h2 className="text-3xl font-bold mb-4 display-5">
|
||||||
{t('Edits to ')}
|
{t('Edits to ')}
|
||||||
{sideText[o.side]}
|
{sideText[o.side]}
|
||||||
{t(' order')}
|
{t(' order')}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="mb-4 text-gray-500">
|
<p className="text-gray-500 mb-4">
|
||||||
In <MarketLink id={o.market.id} />, updated at{' '}
|
In <MarketLink id={o.market.id} />, updated at{' '}
|
||||||
<Time date={o.updatedAt} />.
|
<Time date={o.updatedAt} />.
|
||||||
</div>
|
</p>
|
||||||
|
|
||||||
<div className="grid gap-x-6 md:grid-cols-4">
|
<div className="grid md:grid-cols-4 gap-x-6">
|
||||||
{amend.sizeDelta && amend.sizeDelta !== '0' ? (
|
{amend.sizeDelta && amend.sizeDelta !== '0' ? (
|
||||||
<div className="mb-12 md:mb-0">
|
<div className="mb-12 md:mb-0">
|
||||||
<h2 className="text-dark mb-4 text-2xl font-bold">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('New size')}
|
{t('New size')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5
|
<h5
|
||||||
className={`mb-0 text-lg font-medium capitalize text-gray-500 ${getSideDeltaColour(
|
className={`text-lg font-medium text-gray-500 mb-0 capitalize ${getSideDeltaColour(
|
||||||
amend.sizeDelta
|
amend.sizeDelta
|
||||||
)}`}
|
)}`}
|
||||||
>
|
>
|
||||||
@@ -96,10 +96,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
|
|
||||||
{amend.price && amend.price !== '0' ? (
|
{amend.price && amend.price !== '0' ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-dark mb-4 text-2xl font-bold">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('New price')}
|
{t('New price')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="mb-0 text-lg font-medium text-gray-500">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
<PriceInMarket price={amend.price} marketId={o.market.id} />
|
<PriceInMarket price={amend.price} marketId={o.market.id} />
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
@@ -108,10 +108,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
{amend.peggedReference &&
|
{amend.peggedReference &&
|
||||||
amend.peggedReference !== 'PEGGED_REFERENCE_UNSPECIFIED' ? (
|
amend.peggedReference !== 'PEGGED_REFERENCE_UNSPECIFIED' ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-dark mb-4 text-2xl font-bold">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('New reference')}
|
{t('New reference')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="mb-0 text-lg font-medium text-gray-500">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
{peggedReference[amend.peggedReference]}
|
{peggedReference[amend.peggedReference]}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
@@ -119,10 +119,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
|
|
||||||
{amend.peggedOffset ? (
|
{amend.peggedOffset ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-dark mb-4 text-2xl font-bold">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('New offset')}
|
{t('New offset')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="mb-0 text-lg font-medium text-gray-500">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
{amend.peggedOffset}
|
{amend.peggedOffset}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { Time } from '../time';
|
|||||||
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
||||||
import SizeInMarket from '../size-in-market/size-in-market';
|
import SizeInMarket from '../size-in-market/size-in-market';
|
||||||
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
||||||
import { OrderTypeMapping } from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
export interface DeterministicOrderDetailsProps {
|
export interface DeterministicOrderDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -60,7 +59,7 @@ const DeterministicOrderDetails = ({
|
|||||||
const o = data.orderByID;
|
const o = data.orderByID;
|
||||||
return (
|
return (
|
||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-0">
|
<div className="mb-12 lg:mb-0">
|
||||||
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="text-3xl font-bold mb-4 display-5">
|
<h2 className="text-3xl font-bold mb-4 display-5">
|
||||||
<abbr title={tifFull[o.timeInForce]} className="bb-dotted mr-2">
|
<abbr title={tifFull[o.timeInForce]} className="bb-dotted mr-2">
|
||||||
@@ -70,7 +69,7 @@ const DeterministicOrderDetails = ({
|
|||||||
<span className="mx-5 text-base">@</span>
|
<span className="mx-5 text-base">@</span>
|
||||||
<PriceInMarket price={o.price} marketId={o.market.id} />
|
<PriceInMarket price={o.price} marketId={o.market.id} />
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-400 dark:text-gray-600">
|
<p className="text-gray-200">
|
||||||
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
||||||
</p>
|
</p>
|
||||||
{o.peggedOrder ? (
|
{o.peggedOrder ? (
|
||||||
@@ -84,14 +83,15 @@ const DeterministicOrderDetails = ({
|
|||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{o.reference ? (
|
{o.reference ? (
|
||||||
<p className="text-gray-500 mt-4">
|
<p className="text-gray-500 mt-4">
|
||||||
<span>{t('Reference')}</span>: {o.reference}
|
<span>{t('Reference')}</span>: {o.reference}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-x-6 mt-4">
|
<div className="grid md:grid-cols-4 gap-x-6 mt-4">
|
||||||
<div className="mb-6 md:mb-0">
|
<div className="mb-12 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('Status')}
|
{t('Status')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
||||||
@@ -99,33 +99,21 @@ const DeterministicOrderDetails = ({
|
|||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-6 md:mb-0">
|
<div className="mb-12 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-4">{t('Size')}</h2>
|
||||||
{t('Size')}
|
|
||||||
</h2>
|
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
<SizeInMarket size={o.size} marketId={o.market.id} />
|
<SizeInMarket size={o.size} marketId={o.market.id} />
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-6 md:mb-0">
|
<div className="">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('Version')}
|
{t('Version')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
{o.version}
|
{o.version}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
{o.type ? (
|
|
||||||
<div className="mb-6 md:mb-0">
|
|
||||||
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
|
||||||
{t('Type')}
|
|
||||||
</h2>
|
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
|
||||||
{OrderTypeMapping[o.type]}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ describe('Order TX Summary component', () => {
|
|||||||
expect(res.queryByTestId('order-summary')).not.toBeInTheDocument();
|
expect(res.queryByTestId('order-summary')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Renders "Market Price" if the order passed lacks a price', () => {
|
it('Renders nothing if the order passed lacks a price', () => {
|
||||||
const o: Order = {
|
const o: Order = {
|
||||||
marketId: '123',
|
marketId: '123',
|
||||||
side: 'SIDE_BUY',
|
side: 'SIDE_BUY',
|
||||||
@@ -41,7 +41,7 @@ describe('Order TX Summary component', () => {
|
|||||||
size: '10',
|
size: '10',
|
||||||
};
|
};
|
||||||
const res = renderComponent(o);
|
const res = renderComponent(o);
|
||||||
expect(res.queryByText('Market Price')).toBeInTheDocument();
|
expect(res.queryByTestId('order-summary')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Renders nothing if the order has an unspecified side', () => {
|
it('Renders nothing if the order has an unspecified side', () => {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import type { components } from '../../../types/explorer';
|
|||||||
import PriceInMarket from '../price-in-market/price-in-market';
|
import PriceInMarket from '../price-in-market/price-in-market';
|
||||||
import { sideText } from '../order-details/lib/order-labels';
|
import { sideText } from '../order-details/lib/order-labels';
|
||||||
import SizeInMarket from '../size-in-market/size-in-market';
|
import SizeInMarket from '../size-in-market/size-in-market';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
|
|
||||||
export type OrderSummaryProps = {
|
export type OrderSummaryProps = {
|
||||||
order: components['schemas']['v1OrderSubmission'];
|
order: components['schemas']['v1OrderSubmission'];
|
||||||
@@ -21,6 +20,7 @@ const OrderTxSummary = ({ order }: OrderSummaryProps) => {
|
|||||||
if (
|
if (
|
||||||
!order ||
|
!order ||
|
||||||
!order.marketId ||
|
!order.marketId ||
|
||||||
|
!order.price ||
|
||||||
!order.side ||
|
!order.side ||
|
||||||
order.side === 'SIDE_UNSPECIFIED'
|
order.side === 'SIDE_UNSPECIFIED'
|
||||||
) {
|
) {
|
||||||
@@ -36,14 +36,10 @@ const OrderTxSummary = ({ order }: OrderSummaryProps) => {
|
|||||||
'-'
|
'-'
|
||||||
)}
|
)}
|
||||||
<i className="text-xs">@</i>
|
<i className="text-xs">@</i>
|
||||||
{order.price ? (
|
<PriceInMarket
|
||||||
<PriceInMarket
|
marketId={order.marketId}
|
||||||
marketId={order.marketId}
|
price={order.price}
|
||||||
price={order.price}
|
></PriceInMarket>
|
||||||
></PriceInMarket>
|
|
||||||
) : (
|
|
||||||
t('Market Price')
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ const PriceInMarket = ({
|
|||||||
label = addDecimalsFormatNumber(price, data.market.decimalPlaces);
|
label = addDecimalsFormatNumber(price, data.market.decimalPlaces);
|
||||||
} else if (
|
} else if (
|
||||||
decimalSource === 'SETTLEMENT_ASSET' &&
|
decimalSource === 'SETTLEMENT_ASSET' &&
|
||||||
data.market &&
|
|
||||||
'settlementAsset' in data.market.tradableInstrument.instrument.product &&
|
|
||||||
data.market?.tradableInstrument.instrument.product.settlementAsset
|
data.market?.tradableInstrument.instrument.product.settlementAsset
|
||||||
) {
|
) {
|
||||||
label = addDecimalsFormatNumber(
|
label = addDecimalsFormatNumber(
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { type ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
||||||
import { VoteProgress } from '@vegaprotocol/proposals';
|
import { VoteProgress } from '@vegaprotocol/proposals';
|
||||||
import { type AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import {
|
import type {
|
||||||
type VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
type VegaValueFormatterParams,
|
VegaValueFormatterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { type ColDef } from 'ag-grid-community';
|
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
||||||
import type { RowClickedEvent } from 'ag-grid-community';
|
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import {
|
import {
|
||||||
@@ -34,7 +33,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
const { params } = useNetworkParams([
|
const { params } = useNetworkParams([
|
||||||
NetworkParams.governance_proposal_market_requiredMajority,
|
NetworkParams.governance_proposal_market_requiredMajority,
|
||||||
]);
|
]);
|
||||||
const tokenLink = useLinks(DApp.Governance);
|
const tokenLink = useLinks(DApp.Token);
|
||||||
const requiredMajorityPercentage = useMemo(() => {
|
const requiredMajorityPercentage = useMemo(() => {
|
||||||
const requiredMajority =
|
const requiredMajority =
|
||||||
params?.governance_proposal_market_requiredMajority ?? 1;
|
params?.governance_proposal_market_requiredMajority ?? 1;
|
||||||
@@ -44,11 +43,11 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
const gridRef = useRef<AgGridReact>(null);
|
const gridRef = useRef<AgGridReact>(null);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
gridRef.current?.api.setColumnsVisible(
|
gridRef.current?.columnApi.setColumnsVisible(
|
||||||
['voting', 'cDate', 'eDate', 'type'],
|
['voting', 'cDate', 'eDate', 'type'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
gridRef.current?.api.setColumnWidth(
|
gridRef.current?.columnApi.setColumnWidth(
|
||||||
'actions',
|
'actions',
|
||||||
window.innerWidth > BREAKPOINT_MD ? 221 : 80
|
window.innerWidth > BREAKPOINT_MD ? 221 : 80
|
||||||
);
|
);
|
||||||
@@ -106,7 +105,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
? new BigNumber(0)
|
? new BigNumber(0)
|
||||||
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full items-center justify-center pt-2 uppercase">
|
<div className="uppercase flex h-full items-center justify-center pt-2">
|
||||||
<VoteProgress
|
<VoteProgress
|
||||||
threshold={requiredMajorityPercentage}
|
threshold={requiredMajorityPercentage}
|
||||||
progress={yesPercentage}
|
progress={yesPercentage}
|
||||||
@@ -138,7 +137,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
hide: window.innerWidth <= BREAKPOINT_MD,
|
||||||
headerName: t('Enactment date'),
|
headerName: t('Enactment date'),
|
||||||
field: 'terms.enactmentDatetime',
|
field: 'terms.enactmentDatetime',
|
||||||
valueFormatter: ({
|
valueFormatte: ({
|
||||||
value,
|
value,
|
||||||
}: VegaValueFormatterParams<
|
}: VegaValueFormatterParams<
|
||||||
ProposalListFieldsFragment,
|
ProposalListFieldsFragment,
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
|
||||||
import {
|
|
||||||
CopyWithTooltip,
|
|
||||||
VegaIcon,
|
|
||||||
VegaIconNames,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
|
|
||||||
interface SignatureProps {
|
|
||||||
signature: BlockExplorerTransactionResult['signature'];
|
|
||||||
}
|
|
||||||
|
|
||||||
const valueClass =
|
|
||||||
'font-mono px-2.5 py-0.5 text-xs max-w-[200px] cursor-pointer';
|
|
||||||
const valueClassClosed = 'text-ellipsis overflow-hidden';
|
|
||||||
const valueClassOpen = 'break-words text-left';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Viewer component for a vega signature. Featuers copy and pasting, truncation
|
|
||||||
*
|
|
||||||
* @param signature
|
|
||||||
*/
|
|
||||||
export const Signature = ({ signature }: SignatureProps) => {
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
if (!signature || !signature.value || !signature.version || !signature.algo) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="inline-flex border rounded signature-component relative pr-[20px]">
|
|
||||||
<div
|
|
||||||
className="bg-gray-100 px-2.5 py-0.5 text-xs text-gray-500 select-none cursor-default"
|
|
||||||
title={`${signature.algo}`}
|
|
||||||
>
|
|
||||||
<span>v{signature.version}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
isOpen
|
|
||||||
? `${valueClass} ${valueClassOpen}`
|
|
||||||
: `${valueClass} ${valueClassClosed}`
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<CopyWithTooltip text={signature.value}>
|
|
||||||
<span title={signature.value}>{signature.value}</span>
|
|
||||||
</CopyWithTooltip>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={() => setIsOpen(!isOpen)}
|
|
||||||
className="absolute top-[-3px] right-0 pr-2"
|
|
||||||
title={t('Show full signature')}
|
|
||||||
>
|
|
||||||
<VegaIcon name={isOpen ? VegaIconNames.EYE_OFF : VegaIconNames.EYE} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -22,9 +22,5 @@ export const TimeAgo = ({ date, ...props }: TimeAgoProps) => {
|
|||||||
return <>{t('Date unknown')}</>;
|
return <>{t('Date unknown')}</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <span {...props}>{t(`${distanceToNow} ago`)}</span>;
|
||||||
<span {...props} title={date} className="underline decoration-dotted">
|
|
||||||
{t(`${distanceToNow} ago`)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import isUndefined from 'lodash/isUndefined';
|
|||||||
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
||||||
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
|
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
|
||||||
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
|
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
|
||||||
import { TxDetailsContractCall } from './tx-contract-call';
|
|
||||||
|
|
||||||
interface ChainEventProps {
|
interface ChainEventProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -39,7 +38,7 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { builtin, erc20, erc20Multisig, stakingEvent, contractCall } =
|
const { builtin, erc20, erc20Multisig, stakingEvent } =
|
||||||
txData.command.chainEvent;
|
txData.command.chainEvent;
|
||||||
|
|
||||||
// Builtin Asset events
|
// Builtin Asset events
|
||||||
@@ -141,10 +140,6 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contractCall) {
|
|
||||||
return <TxDetailsContractCall contractCall={contractCall} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we hit this return, tx-shared-details should give a basic overview
|
// If we hit this return, tx-shared-details should give a basic overview
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { decodeEthCallResult } from './tx-contract-call';
|
|
||||||
import { base64 } from 'ethers/lib/utils';
|
|
||||||
import { defaultAbiCoder } from '@ethersproject/abi';
|
|
||||||
import { BigNumber } from '@ethersproject/bignumber';
|
|
||||||
|
|
||||||
describe('decodeEthCallResult', () => {
|
|
||||||
it('should decode contractData correctly (mocked)', () => {
|
|
||||||
const mockContractData = base64.encode(
|
|
||||||
defaultAbiCoder.encode(['int256'], [BigNumber.from(123)])
|
|
||||||
);
|
|
||||||
const result = decodeEthCallResult(mockContractData);
|
|
||||||
expect(result).toBe('123');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should decode contractData correctly (known data)', () => {
|
|
||||||
const mockContractData = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADH8cueyY=';
|
|
||||||
const result = decodeEthCallResult(mockContractData);
|
|
||||||
expect(result).toBe('3435020581670');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "-" when an error occurs', () => {
|
|
||||||
const mockContractData = 'invalid_data';
|
|
||||||
const result = decodeEthCallResult(mockContractData);
|
|
||||||
expect(result).toBe('-');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
import { TableCell, TableRow } from '../../../table';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import {
|
|
||||||
EthExplorerLink,
|
|
||||||
EthExplorerLinkTypes,
|
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
|
||||||
import { BigNumber } from 'ethers';
|
|
||||||
import OracleLink from '../../../links/oracle-link/oracle-link';
|
|
||||||
import { useExplorerOracleSpecByIdQuery } from '../../../../routes/oracles/__generated__/Oracles';
|
|
||||||
import { OracleEthSource } from '../../../../routes/oracles/components/oracle-eth-source';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes the b64/ABIcoded result from an eth cal
|
|
||||||
* @param data
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function decodeEthCallResult(contractData: string): string {
|
|
||||||
try {
|
|
||||||
const rawResult = defaultAbiCoder.decode(
|
|
||||||
['int256'],
|
|
||||||
base64.decode(contractData)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Finally, convert the resulting BigNumber in to a string
|
|
||||||
const res = BigNumber.from(rawResult[0]).toString();
|
|
||||||
return res;
|
|
||||||
} catch (e) {
|
|
||||||
return '-';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TxDetailsContractCallProps {
|
|
||||||
contractCall: components['schemas']['vegaEthContractCallEvent'];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TxDetailsContractCall = ({
|
|
||||||
contractCall,
|
|
||||||
}: TxDetailsContractCallProps) => {
|
|
||||||
const { data } = useExplorerOracleSpecByIdQuery({
|
|
||||||
variables: {
|
|
||||||
id: contractCall.specId || '1',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!contractCall || !contractCall.result) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{contractCall.specId && (
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('Oracle')}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<OracleLink
|
|
||||||
id={contractCall.specId}
|
|
||||||
hasSeenOracleReports={true}
|
|
||||||
status={data?.oracleSpec?.dataSourceSpec.spec.status || '-'}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
{contractCall.blockHeight && (
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('ETH block')}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<EthExplorerLink
|
|
||||||
id={contractCall.blockHeight}
|
|
||||||
type={EthExplorerLinkTypes.block}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
{data?.oracleSpec?.dataSourceSpec && (
|
|
||||||
<OracleEthSource
|
|
||||||
sourceType={data.oracleSpec.dataSourceSpec.spec.data.sourceType}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('Result')}</TableCell>
|
|
||||||
<TableCell>{decodeEthCallResult(contractCall.result)}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
query ExplorerSettlementAssetForMarket($id: ID!) {
|
||||||
|
market(id: $id) {
|
||||||
|
id
|
||||||
|
decimalPlaces
|
||||||
|
}
|
||||||
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type ExplorerSettlementAssetForMarketQueryVariables = Types.Exact<{
|
||||||
|
id: Types.Scalars['ID'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ExplorerSettlementAssetForMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number } | null };
|
||||||
|
|
||||||
|
|
||||||
|
export const ExplorerSettlementAssetForMarketDocument = gql`
|
||||||
|
query ExplorerSettlementAssetForMarket($id: ID!) {
|
||||||
|
market(id: $id) {
|
||||||
|
id
|
||||||
|
decimalPlaces
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useExplorerSettlementAssetForMarketQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useExplorerSettlementAssetForMarketQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useExplorerSettlementAssetForMarketQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useExplorerSettlementAssetForMarketQuery({
|
||||||
|
* variables: {
|
||||||
|
* id: // value for 'id'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useExplorerSettlementAssetForMarketQuery(baseOptions: Apollo.QueryHookOptions<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>(ExplorerSettlementAssetForMarketDocument, options);
|
||||||
|
}
|
||||||
|
export function useExplorerSettlementAssetForMarketLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>(ExplorerSettlementAssetForMarketDocument, options);
|
||||||
|
}
|
||||||
|
export type ExplorerSettlementAssetForMarketQueryHookResult = ReturnType<typeof useExplorerSettlementAssetForMarketQuery>;
|
||||||
|
export type ExplorerSettlementAssetForMarketLazyQueryHookResult = ReturnType<typeof useExplorerSettlementAssetForMarketLazyQuery>;
|
||||||
|
export type ExplorerSettlementAssetForMarketQueryResult = Apollo.QueryResult<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>;
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { Side } from '@vegaprotocol/types';
|
||||||
|
import type { LiquidityOrder } from '@vegaprotocol/types';
|
||||||
|
import { PeggedReference } from '@vegaprotocol/types';
|
||||||
|
import { LiquidityProvisionDetailsRow } from './liquidity-provision-details-row';
|
||||||
|
import type { VegaSide } from './liquidity-provision-details-row';
|
||||||
|
|
||||||
|
describe('LiquidityProvisionDetails component', () => {
|
||||||
|
function renderComponent(
|
||||||
|
order: LiquidityOrder,
|
||||||
|
side: VegaSide,
|
||||||
|
normaliseProportionsTo: number,
|
||||||
|
marketId: string
|
||||||
|
) {
|
||||||
|
return render(
|
||||||
|
<MockedProvider>
|
||||||
|
<table>
|
||||||
|
<tbody data-testid="container">
|
||||||
|
<LiquidityProvisionDetailsRow
|
||||||
|
order={order}
|
||||||
|
marketId={marketId}
|
||||||
|
normaliseProportionsTo={normaliseProportionsTo}
|
||||||
|
side={side}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('renders null for an order with no proportion', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
offset: '1',
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_BUY,
|
||||||
|
100,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
expect(res.getByTestId('container')).toBeEmptyDOMElement();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders null for a null order', () => {
|
||||||
|
const res = renderComponent(
|
||||||
|
null as unknown as LiquidityOrder,
|
||||||
|
Side.SIDE_BUY,
|
||||||
|
100,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
expect(res.getByTestId('container')).toBeEmptyDOMElement();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders a row when the order is as expected', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
offset: '1',
|
||||||
|
proportion: 20,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_BUY,
|
||||||
|
100,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
// Row test ids and keys are based on the side, reference and proportion
|
||||||
|
expect(res.getByTestId('SIDE_BUY-20-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('+1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Mid')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('20%')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('normalises offsets when normaliseToProportion is not 100', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
offset: '1',
|
||||||
|
proportion: 20,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_BEST_BID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_SELL,
|
||||||
|
50,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
// Row test ids and keys are based on the side, reference and proportion - and that proportion is scaled
|
||||||
|
expect(res.getByTestId('SIDE_SELL-40-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Best Bid')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('40%')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles a missing offset gracefully (should not happen)', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
proportion: 20,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_BEST_BID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_SELL,
|
||||||
|
50,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
// Row test ids and keys are based on the side, reference and proportion - and that proportion is scaled
|
||||||
|
expect(res.getByTestId('SIDE_SELL-40-')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('-')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles a missing reference gracefully (should not happen)', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
offset: '1',
|
||||||
|
proportion: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_SELL,
|
||||||
|
50,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
// Row test ids and keys are based on the side, reference and proportion - and that proportion is scaled
|
||||||
|
expect(res.getByTestId('SIDE_SELL-40-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('40%')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('-')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import type { components } from '../../../../../../types/explorer';
|
||||||
|
import { TableRow } from '../../../../table';
|
||||||
|
import { LiquidityProvisionOffset } from './liquidity-provision-offset';
|
||||||
|
|
||||||
|
export type VegaPeggedReference = components['schemas']['vegaPeggedReference'];
|
||||||
|
export type VegaSide = components['schemas']['vegaSide'];
|
||||||
|
|
||||||
|
export type LiquidityProvisionOrder =
|
||||||
|
components['schemas']['vegaLiquidityOrder'];
|
||||||
|
|
||||||
|
export const LiquidityReferenceLabel: Record<VegaPeggedReference, string> = {
|
||||||
|
PEGGED_REFERENCE_BEST_ASK: t('Best Ask'),
|
||||||
|
PEGGED_REFERENCE_BEST_BID: t('Best Bid'),
|
||||||
|
PEGGED_REFERENCE_MID: t('Mid'),
|
||||||
|
PEGGED_REFERENCE_UNSPECIFIED: '-',
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LiquidityProvisionDetailsRowProps = {
|
||||||
|
order?: LiquidityProvisionOrder;
|
||||||
|
marketId?: string;
|
||||||
|
side: VegaSide;
|
||||||
|
// If this is
|
||||||
|
normaliseProportionsTo: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Note: offset is formatted by settlement asset on the market, assuming that is available
|
||||||
|
* Note: Due to the mix of references (MID vs BEST_X), it's not possible to correctly order
|
||||||
|
* the orders by their actual distance from a midpoint. This would require us knowing
|
||||||
|
* the best bid (now or at placement) and the mid. Getting the data for *now* would be
|
||||||
|
* misleading for LP submissions in the past. There is no API for getting <mid />
|
||||||
|
* at the time of a transaction.
|
||||||
|
*/
|
||||||
|
export function LiquidityProvisionDetailsRow({
|
||||||
|
normaliseProportionsTo,
|
||||||
|
order,
|
||||||
|
side,
|
||||||
|
marketId,
|
||||||
|
}: LiquidityProvisionDetailsRowProps) {
|
||||||
|
if (!order || !order.proportion) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const proportion =
|
||||||
|
normaliseProportionsTo === 100
|
||||||
|
? order.proportion
|
||||||
|
: Math.round((order.proportion / normaliseProportionsTo) * 100);
|
||||||
|
|
||||||
|
const key = `${side}-${proportion}-${order.offset ? order.offset : ''}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow modifier="bordered" key={key} data-testid={key}>
|
||||||
|
<td className="text-right px-2">
|
||||||
|
{order.offset && marketId ? (
|
||||||
|
<LiquidityProvisionOffset
|
||||||
|
offset={order.offset}
|
||||||
|
side={side}
|
||||||
|
marketId={marketId}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
'-'
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="text-center">
|
||||||
|
{order.reference ? LiquidityReferenceLabel[order.reference] : '-'}
|
||||||
|
</td>
|
||||||
|
<td className="text-center">{proportion}%</td>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { LiquidityProvisionMid } from './liquidity-provision-mid';
|
||||||
|
|
||||||
|
describe('LiquidityProvisionMid component', () => {
|
||||||
|
function renderComponent() {
|
||||||
|
return render(
|
||||||
|
<table>
|
||||||
|
<tbody data-testid="container">
|
||||||
|
<LiquidityProvisionMid />
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('renders a basic row that spans the whole table', () => {
|
||||||
|
const res = renderComponent();
|
||||||
|
const display = res.getByTestId('mid-display');
|
||||||
|
expect(res.getByTestId('mid')).toBeInTheDocument();
|
||||||
|
expect(display).toBeInTheDocument();
|
||||||
|
expect(display).toHaveAttribute('colspan', '3');
|
||||||
|
});
|
||||||
|
});
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
import { TableRow } from '../../../../table';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In a LiquidityProvision table, this row is the midpoint. Above our LP orders on the
|
||||||
|
* buy side, below are LP orders on the sell side. This component simply divides them.
|
||||||
|
*
|
||||||
|
* There is no API that can give us the mid price when the order was created, and even
|
||||||
|
* if there was it isn't clear that would be appropriate for this centre row. So instead
|
||||||
|
* it's a simple divider.
|
||||||
|
*/
|
||||||
|
export function LiquidityProvisionMid() {
|
||||||
|
return (
|
||||||
|
<TableRow modifier="bordered" data-testid="mid">
|
||||||
|
<td data-testid="mid-display" colSpan={3} className="bg-white"></td>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { ExplorerSettlementAssetForMarketDocument } from '../__generated__/Explorer-settlement-asset';
|
||||||
|
import type { ExplorerSettlementAssetForMarketQuery } from '../__generated__/Explorer-settlement-asset';
|
||||||
|
import type { VegaSide } from './liquidity-provision-details-row';
|
||||||
|
import {
|
||||||
|
getFormattedOffset,
|
||||||
|
LiquidityProvisionOffset,
|
||||||
|
} from './liquidity-provision-offset';
|
||||||
|
const decimalsMock: ExplorerSettlementAssetForMarketQuery = {
|
||||||
|
market: {
|
||||||
|
id: '123',
|
||||||
|
__typename: 'Market',
|
||||||
|
decimalPlaces: 5,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('LiquidityProvisionOffset component', () => {
|
||||||
|
function renderComponent(
|
||||||
|
offset: string,
|
||||||
|
side: VegaSide,
|
||||||
|
marketId: string,
|
||||||
|
mocks: MockedResponse[]
|
||||||
|
) {
|
||||||
|
return render(
|
||||||
|
<MockedProvider mocks={mocks}>
|
||||||
|
<LiquidityProvisionOffset
|
||||||
|
offset={offset}
|
||||||
|
side={side}
|
||||||
|
marketId={marketId}
|
||||||
|
/>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('renders a simple row before market data comes in', () => {
|
||||||
|
const res = renderComponent('1', 'SIDE_BUY', '123', []);
|
||||||
|
expect(res.getByText('+1')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('replaces unformatted with formatted if the market data comes in', () => {
|
||||||
|
const mock = {
|
||||||
|
request: {
|
||||||
|
query: ExplorerSettlementAssetForMarketDocument,
|
||||||
|
variables: {
|
||||||
|
id: '123',
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: decimalsMock,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const res = renderComponent('1', 'SIDE_BUY', '123', [mock]);
|
||||||
|
expect(res.getByText('+1')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getFormattedOffset returns the unformatted offset if there is not enough data', () => {
|
||||||
|
const res = getFormattedOffset('1', {});
|
||||||
|
expect(res).toEqual('1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getFormattedOffset decimal formats a number if it comes in with market data', () => {
|
||||||
|
const res = getFormattedOffset('1', decimalsMock);
|
||||||
|
expect(res).toEqual('0.00001');
|
||||||
|
});
|
||||||
|
});
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
import { useExplorerSettlementAssetForMarketQuery } from '../__generated__/Explorer-settlement-asset';
|
||||||
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
import type { ExplorerSettlementAssetForMarketQuery } from '../__generated__/Explorer-settlement-asset';
|
||||||
|
import type { VegaSide } from './liquidity-provision-details-row';
|
||||||
|
|
||||||
|
export type LiquidityProvisionOffsetProps = {
|
||||||
|
side: VegaSide;
|
||||||
|
offset: string;
|
||||||
|
marketId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correctly formats an LP's offset according to the market settlement decimal places.
|
||||||
|
* Initially this will appear unformatted, then when the query loads in the proper formatted
|
||||||
|
* value will be displayed
|
||||||
|
*
|
||||||
|
* @see getFormattedOffset
|
||||||
|
*/
|
||||||
|
export function LiquidityProvisionOffset({
|
||||||
|
side,
|
||||||
|
offset,
|
||||||
|
marketId,
|
||||||
|
}: LiquidityProvisionOffsetProps) {
|
||||||
|
const { data } = useExplorerSettlementAssetForMarketQuery({
|
||||||
|
variables: {
|
||||||
|
id: marketId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// getFormattedOffset handles missing results/loading states
|
||||||
|
const formattedOffset = getFormattedOffset(offset, data);
|
||||||
|
|
||||||
|
const label = side === 'SIDE_BUY' ? '+' : '-';
|
||||||
|
const className = side === 'SIDE_BUY' ? 'text-vega-green' : 'text-vega-pink';
|
||||||
|
return <span className={className}>{`${label}${formattedOffset}`}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the work of formatting the number now we have the market decimal places.
|
||||||
|
* If no market data is assigned (i.e. during loading, or if the market doesn't exist)
|
||||||
|
* this function will return the unformatted number
|
||||||
|
*
|
||||||
|
* @see LiquidityProvisionOffset
|
||||||
|
* @param data the result of a ExplorerSettlementAssetForMarketQuery
|
||||||
|
* @param offset the unformatted offset
|
||||||
|
* @returns string the offset of this lp order formatted with the settlement decimal places
|
||||||
|
*/
|
||||||
|
export function getFormattedOffset(
|
||||||
|
offset: string,
|
||||||
|
data?: ExplorerSettlementAssetForMarketQuery
|
||||||
|
) {
|
||||||
|
const decimals = data?.market?.decimalPlaces;
|
||||||
|
|
||||||
|
if (!decimals) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addDecimalsFormatNumber(offset, decimals);
|
||||||
|
}
|
||||||
+209
@@ -0,0 +1,209 @@
|
|||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import type { LiquidityOrder } from '@vegaprotocol/types';
|
||||||
|
import { PeggedReference } from '@vegaprotocol/types';
|
||||||
|
import type { LiquiditySubmission } from '../tx-liquidity-submission';
|
||||||
|
import {
|
||||||
|
LiquidityProvisionDetails,
|
||||||
|
sumProportions,
|
||||||
|
} from './liquidity-provision-details';
|
||||||
|
|
||||||
|
function mockProportion(proportion: number): LiquidityOrder {
|
||||||
|
return {
|
||||||
|
proportion,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
offset: '1',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
describe('sumProportions function', () => {
|
||||||
|
it('returns 0 if the side is undefined', () => {
|
||||||
|
const side: LiquidityOrder[] = undefined as unknown as LiquidityOrder[];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 0 if the side is empty', () => {
|
||||||
|
const side: LiquidityOrder[] = [];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sums 1 item correctly (under 100%)', () => {
|
||||||
|
const side: LiquidityOrder[] = [mockProportion(10)];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sums 2 item correctly (exactly 100%)', () => {
|
||||||
|
const side: LiquidityOrder[] = [mockProportion(50), mockProportion(50)];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sums 3 item correctly to over 100%', () => {
|
||||||
|
const side: LiquidityOrder[] = [
|
||||||
|
mockProportion(20),
|
||||||
|
mockProportion(40),
|
||||||
|
mockProportion(50),
|
||||||
|
];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(110);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('LiquidityProvisionDetails component', () => {
|
||||||
|
function renderComponent(provision: LiquiditySubmission) {
|
||||||
|
return render(
|
||||||
|
<MockedProvider>
|
||||||
|
<LiquidityProvisionDetails provision={provision} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
it('handles an LP with no buys or sells by returning empty (should never happen)', () => {
|
||||||
|
const mock: LiquiditySubmission = {};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.container).toBeEmptyDOMElement();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles an LP with no sells by just rendering buys', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
buys: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('Price offset')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Price reference')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Proportion')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles an LP with no buys by just rendering sells', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
sells: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('Price offset')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Price reference')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Proportion')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_SELL-50-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_SELL-50-2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles an LP with sells by just rendering buys', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
buys: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('Price offset')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Price reference')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Proportion')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles an LP with both sides', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
buys: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sells: [
|
||||||
|
{
|
||||||
|
offset: '4',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('Price offset')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Price reference')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Proportion')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-2')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_SELL-50-4')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_SELL-50-2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('normalises proportions when they do not total 100%', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
buys: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 25,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 30,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('45%')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('55%')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import type { LiquiditySubmission } from '../tx-liquidity-submission';
|
||||||
|
import { TableRow } from '../../../table';
|
||||||
|
import { LiquidityProvisionMid } from './components/liquidity-provision-mid';
|
||||||
|
import { LiquidityProvisionDetailsRow } from './components/liquidity-provision-details-row';
|
||||||
|
import { Side } from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
export type VegaPeggedReference = components['schemas']['vegaPeggedReference'];
|
||||||
|
|
||||||
|
export type LiquidityProvisionOrder =
|
||||||
|
components['schemas']['vegaLiquidityOrder'];
|
||||||
|
|
||||||
|
export const LiquidityReferenceLabel: Record<VegaPeggedReference, string> = {
|
||||||
|
PEGGED_REFERENCE_BEST_ASK: t('Best Ask'),
|
||||||
|
PEGGED_REFERENCE_BEST_BID: t('Best Bid'),
|
||||||
|
PEGGED_REFERENCE_MID: t('Mid'),
|
||||||
|
PEGGED_REFERENCE_UNSPECIFIED: '-',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a side of a liquidity provision order, returns the total
|
||||||
|
* It should be 100%, but it isn't always and if it isn't the proportion
|
||||||
|
* reported for each order should be scaled
|
||||||
|
*
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
export function sumProportions(
|
||||||
|
side: LiquiditySubmission['buys'] | LiquiditySubmission['sells']
|
||||||
|
): number {
|
||||||
|
if (!side || side.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return side.reduce((total, o) => total + (o.proportion || 0), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LiquidityProvisionDetailsProps = {
|
||||||
|
provision: LiquiditySubmission;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a table displaying all buys and sells in this LP. It is valid for there
|
||||||
|
* to be no buys or sells.
|
||||||
|
*
|
||||||
|
* It might seem logical to turn proportions in to values based on the total commitment
|
||||||
|
* but based on the current API structure it is awkward, and given that non-LP orders
|
||||||
|
* will change the amount that is actually deployed vs assigned to a level, we decided
|
||||||
|
* not to bother going down that route.
|
||||||
|
*/
|
||||||
|
export function LiquidityProvisionDetails({
|
||||||
|
provision,
|
||||||
|
}: LiquidityProvisionDetailsProps) {
|
||||||
|
if (!provision.buys?.length && !provision.sells?.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// We need to do some additional calcs if these aren't both 100
|
||||||
|
const buyTotal = sumProportions(provision.buys);
|
||||||
|
const sellTotal = sumProportions(provision.sells);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<th className="px-2 pb-1">{t('Price offset')}</th>
|
||||||
|
<th className="px-2 pb-1">{t('Price reference')}</th>
|
||||||
|
<th className="px-2 pb-1">{t('Proportion')}</th>
|
||||||
|
</TableRow>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{provision.buys?.map((b, i) => (
|
||||||
|
<LiquidityProvisionDetailsRow
|
||||||
|
order={b}
|
||||||
|
marketId={provision.marketId}
|
||||||
|
side={Side.SIDE_BUY}
|
||||||
|
key={`SIDE_BUY-${i}`}
|
||||||
|
normaliseProportionsTo={buyTotal}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<LiquidityProvisionMid />
|
||||||
|
{provision.sells?.map((s, i) => (
|
||||||
|
<LiquidityProvisionDetailsRow
|
||||||
|
order={s}
|
||||||
|
marketId={provision.marketId}
|
||||||
|
side={Side.SIDE_SELL}
|
||||||
|
key={`SIDE_SELL-${i}`}
|
||||||
|
normaliseProportionsTo={sellTotal}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import { formatNumberPercentage } from '@vegaprotocol/utils';
|
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
import PriceInMarket from '../../../price-in-market/price-in-market';
|
|
||||||
import StopOrderTriggerSummary from './stop-order-trigger';
|
|
||||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import fromUnixTime from 'date-fns/fromUnixTime';
|
|
||||||
|
|
||||||
const wrapperClasses =
|
|
||||||
'flex-1 max-w-xs items-center border border-vega-light-200 dark:border-vega-dark-150 rounded-md pv-2 ph-5 mb-5';
|
|
||||||
|
|
||||||
export type StopOrderType = 'RisesAbove' | 'FallsBelow' | 'OCO';
|
|
||||||
type V1OrderSetup = components['schemas']['v1StopOrderSetup'];
|
|
||||||
|
|
||||||
interface StopOrderSetupProps extends V1OrderSetup {
|
|
||||||
type: StopOrderType;
|
|
||||||
deterministicId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getExpiryTypeLabel(
|
|
||||||
expiryStrategy: V1OrderSetup['expiryStrategy']
|
|
||||||
): string {
|
|
||||||
switch (expiryStrategy) {
|
|
||||||
case 'EXPIRY_STRATEGY_CANCELS':
|
|
||||||
return t('Cancels');
|
|
||||||
case 'EXPIRY_STRATEGY_SUBMIT':
|
|
||||||
return t('Submit');
|
|
||||||
}
|
|
||||||
|
|
||||||
return expiryStrategy || t('Unknown');
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExpiryTriggerProps {
|
|
||||||
trailingPercentOffset?: string;
|
|
||||||
price?: string;
|
|
||||||
marketId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ExpiryTrigger({
|
|
||||||
trailingPercentOffset,
|
|
||||||
price,
|
|
||||||
marketId,
|
|
||||||
}: ExpiryTriggerProps) {
|
|
||||||
if (price && marketId) {
|
|
||||||
return <PriceInMarket price={price} marketId={marketId} />;
|
|
||||||
}
|
|
||||||
if (trailingPercentOffset) {
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
{formatNumberPercentage(new BigNumber(trailingPercentOffset))}{' '}
|
|
||||||
(trailing)
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMovePrefix(
|
|
||||||
type: StopOrderType,
|
|
||||||
trailingPercentOffset?: string
|
|
||||||
): string {
|
|
||||||
if (type === 'RisesAbove') {
|
|
||||||
if (trailingPercentOffset) {
|
|
||||||
return '+';
|
|
||||||
} else {
|
|
||||||
return '>';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (trailingPercentOffset) {
|
|
||||||
return '-';
|
|
||||||
} else {
|
|
||||||
return '<';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TypeLabel = {
|
|
||||||
RisesAbove: t('Rises above ↗'),
|
|
||||||
FallsBelow: t('Falls below ↘'),
|
|
||||||
OCO: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export const StopOrderSetup = ({
|
|
||||||
type,
|
|
||||||
price,
|
|
||||||
orderSubmission,
|
|
||||||
expiresAt,
|
|
||||||
expiryStrategy,
|
|
||||||
trailingPercentOffset,
|
|
||||||
deterministicId,
|
|
||||||
}: StopOrderSetupProps) => {
|
|
||||||
let d = 'Unknown';
|
|
||||||
try {
|
|
||||||
d = expiresAt
|
|
||||||
? fromUnixTime(parseInt(expiresAt) / 1000000000).toLocaleString()
|
|
||||||
: t('Unknown');
|
|
||||||
} catch (e) {
|
|
||||||
d = t('Unknown');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={wrapperClasses}>
|
|
||||||
<div className="mb-12 lg:mb-0">
|
|
||||||
<div className="bg-slate-100 text-slate-900 px-6 py-2 md:px-6 flex">
|
|
||||||
<div className="flex-1">
|
|
||||||
<strong className="font-bold mb-1">{TypeLabel[type]} </strong>
|
|
||||||
<p className=" font-xs mb-0">
|
|
||||||
{getMovePrefix(type, trailingPercentOffset)}
|
|
||||||
<ExpiryTrigger
|
|
||||||
trailingPercentOffset={trailingPercentOffset}
|
|
||||||
price={price}
|
|
||||||
marketId={orderSubmission?.marketId}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{expiresAt && expiryStrategy ? (
|
|
||||||
<div className="flex-1">
|
|
||||||
<strong className="font-bold mb-1">{t('Expiry Type')}</strong>
|
|
||||||
<p className=" font-xs mb-0">
|
|
||||||
<Tooltip description={<span>{d}</span>}>
|
|
||||||
<span>{getExpiryTypeLabel(expiryStrategy)}</span>
|
|
||||||
</Tooltip>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
<StopOrderTriggerSummary
|
|
||||||
id={deterministicId}
|
|
||||||
orderSubmission={orderSubmission}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
import { StopOrderStatus } from '@vegaprotocol/types';
|
|
||||||
import { useExplorerStopOrderQuery } from '../../../order-details/__generated__/StopOrder';
|
|
||||||
import type { ExplorerStopOrderQuery } from '../../../order-details/__generated__/StopOrder';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import { Icon } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import type { IconName } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import OrderTxSummary from '../../../order-summary/order-tx-summary';
|
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import type { ApolloError } from '@apollo/client';
|
|
||||||
|
|
||||||
export const StatusLabel: Record<StopOrderStatus, string> = {
|
|
||||||
[StopOrderStatus.STATUS_CANCELLED]: t('Cancelled'),
|
|
||||||
[StopOrderStatus.STATUS_EXPIRED]: t('Expired'),
|
|
||||||
[StopOrderStatus.STATUS_PENDING]: t('Pending'),
|
|
||||||
[StopOrderStatus.STATUS_REJECTED]: t('Rejected'),
|
|
||||||
[StopOrderStatus.STATUS_STOPPED]: t('Stopped'),
|
|
||||||
[StopOrderStatus.STATUS_TRIGGERED]: t('Triggered'),
|
|
||||||
[StopOrderStatus.STATUS_UNSPECIFIED]: t('Status unknown'),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const StatusIcon: Record<StopOrderStatus, IconName> = {
|
|
||||||
[StopOrderStatus.STATUS_CANCELLED]: 'disable',
|
|
||||||
[StopOrderStatus.STATUS_EXPIRED]: 'outdated',
|
|
||||||
[StopOrderStatus.STATUS_PENDING]: 'circle',
|
|
||||||
[StopOrderStatus.STATUS_REJECTED]: 'cross',
|
|
||||||
[StopOrderStatus.STATUS_STOPPED]: 'stop',
|
|
||||||
[StopOrderStatus.STATUS_TRIGGERED]: 'tick',
|
|
||||||
[StopOrderStatus.STATUS_UNSPECIFIED]: 'help',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const StatusMidColor: Record<StopOrderStatus, string> = {
|
|
||||||
[StopOrderStatus.STATUS_CANCELLED]: 'bg-red-100 text-red-900',
|
|
||||||
[StopOrderStatus.STATUS_EXPIRED]: 'bg-red-100 text-red-900',
|
|
||||||
[StopOrderStatus.STATUS_PENDING]: 'bg-yellow-100 text-yellow-900',
|
|
||||||
[StopOrderStatus.STATUS_REJECTED]: 'bg-red-100 text-red-900',
|
|
||||||
[StopOrderStatus.STATUS_STOPPED]: 'bg-red-100 text-red-900',
|
|
||||||
[StopOrderStatus.STATUS_TRIGGERED]: 'bg-green-100 text-green-900',
|
|
||||||
[StopOrderStatus.STATUS_UNSPECIFIED]: 'bg-yellow-100 text-yellow-900',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const StatusBottomColor: Record<StopOrderStatus, string> = {
|
|
||||||
[StopOrderStatus.STATUS_CANCELLED]: 'bg-red-50 text-red-900 line-through',
|
|
||||||
[StopOrderStatus.STATUS_EXPIRED]: 'bg-red-50 text-red-900 line-through',
|
|
||||||
[StopOrderStatus.STATUS_PENDING]: 'bg-yellow-50 text-yellow-900',
|
|
||||||
[StopOrderStatus.STATUS_REJECTED]: 'bg-red-50 text-red-900 line-through',
|
|
||||||
[StopOrderStatus.STATUS_STOPPED]: 'bg-red-50 text-red-900 line-through',
|
|
||||||
[StopOrderStatus.STATUS_TRIGGERED]: 'bg-green-50 text-green-900',
|
|
||||||
[StopOrderStatus.STATUS_UNSPECIFIED]:
|
|
||||||
'bg-yellow-50 text-yellow-900 line-through',
|
|
||||||
};
|
|
||||||
|
|
||||||
export function getStopOrderTriggerStatus(
|
|
||||||
data?: ExplorerStopOrderQuery,
|
|
||||||
error?: ApolloError
|
|
||||||
) {
|
|
||||||
if (data && data.stopOrder) {
|
|
||||||
return data.stopOrder.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
return StopOrderStatus.STATUS_UNSPECIFIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StopOrderTriggerSummaryProps {
|
|
||||||
id: string;
|
|
||||||
orderSubmission?: components['schemas']['v1OrderSubmission'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
const StopOrderTriggerSummary = ({
|
|
||||||
id,
|
|
||||||
orderSubmission,
|
|
||||||
}: StopOrderTriggerSummaryProps) => {
|
|
||||||
const { data, error } = useExplorerStopOrderQuery({
|
|
||||||
variables: { stopOrderId: id },
|
|
||||||
});
|
|
||||||
|
|
||||||
const status = getStopOrderTriggerStatus(data, error);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div
|
|
||||||
className={`${StatusMidColor[status]} px-3 py-2 md:px-6 flex space-x-4`}
|
|
||||||
>
|
|
||||||
<p className="m-0 p-0 align-top">
|
|
||||||
<Icon
|
|
||||||
size={6}
|
|
||||||
name={StatusIcon[status]}
|
|
||||||
className="inline-block mr-2"
|
|
||||||
/>
|
|
||||||
<span className="align-top">{StatusLabel[status]}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className={`${StatusBottomColor[status]} px-3 py-2 md:px-6 flex space-x-4`}
|
|
||||||
>
|
|
||||||
{orderSubmission && (
|
|
||||||
<p className="text-vega-grey-400 strike">
|
|
||||||
<OrderTxSummary order={orderSubmission} />
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default StopOrderTriggerSummary;
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import SizeInMarket from '../../../size-in-market/size-in-market';
|
|
||||||
|
|
||||||
export interface TxDetailsOrderIcebergDetailsProps {
|
|
||||||
iceberg: components['schemas']['v1IcebergOpts'];
|
|
||||||
size: components['schemas']['v1OrderSubmission']['size'];
|
|
||||||
marketId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
.iceberg .sub {
|
|
||||||
vertical-align: bottom;
|
|
||||||
color: #954F01;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iceberg .sup {
|
|
||||||
vertical-align: top;
|
|
||||||
color: #515E1E;
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visualises the iceberg details of an order, showing the minimum visible size,
|
|
||||||
* the full size and the peak size.
|
|
||||||
*/
|
|
||||||
export const TxOrderIcebergDetails = ({
|
|
||||||
iceberg,
|
|
||||||
size,
|
|
||||||
marketId,
|
|
||||||
}: TxDetailsOrderIcebergDetailsProps) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="inline-block iceberg bg-vega-blue-300 border-vega-blue-350 border-[1px] text-[70%] font-mono py-[2px] pl-2 pr-3 height-[1em] leading-[1em] cursor-pointer"
|
|
||||||
style={{ clipPath: 'polygon(10% 0%, 100% 0%, 90% 100%, 0% 100%)' }}
|
|
||||||
>
|
|
||||||
<Tooltip description={t('Iceberg: Minimum visible size')}>
|
|
||||||
<span className="align-bottom text-vega-orange-650">
|
|
||||||
{marketId ? (
|
|
||||||
<SizeInMarket
|
|
||||||
size={iceberg.minimumVisibleSize}
|
|
||||||
marketId={marketId}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
iceberg.minimumVisibleSize
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip description={t('Iceberg: Total size')}>
|
|
||||||
<span className="text-sm text-vega-blue-600 mx-3">
|
|
||||||
{marketId ? <SizeInMarket size={size} marketId={marketId} /> : size}
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip description={t('Iceberg: Visible peak')}>
|
|
||||||
<span className="align-top text-vega-yellow-600">
|
|
||||||
{marketId ? (
|
|
||||||
<SizeInMarket size={iceberg.peakSize} marketId={marketId} />
|
|
||||||
) : (
|
|
||||||
iceberg.peakSize
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,20 +1,11 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import { TableCell, TableRow } from '../../../table';
|
import { TableCell, TableRow } from '../../../table';
|
||||||
|
import type { VegaPeggedReference } from '../liquidity-provision/liquidity-provision-details';
|
||||||
import { Side, PeggedReferenceMapping } from '@vegaprotocol/types';
|
import { Side, PeggedReferenceMapping } from '@vegaprotocol/types';
|
||||||
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
||||||
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
||||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
export type VegaPeggedReference = components['schemas']['vegaPeggedReference'];
|
|
||||||
|
|
||||||
export const LiquidityReferenceLabel: Record<VegaPeggedReference, string> = {
|
|
||||||
PEGGED_REFERENCE_BEST_ASK: t('Best Ask'),
|
|
||||||
PEGGED_REFERENCE_BEST_BID: t('Best Bid'),
|
|
||||||
PEGGED_REFERENCE_MID: t('Mid'),
|
|
||||||
PEGGED_REFERENCE_UNSPECIFIED: '-',
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface TxDetailsOrderProps {
|
export interface TxDetailsOrderProps {
|
||||||
offset: string;
|
offset: string;
|
||||||
reference: VegaPeggedReference;
|
reference: VegaPeggedReference;
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
query ExplorerProposalStatus($id: ID!) {
|
query ExplorerProposalStatus($id: ID!) {
|
||||||
proposal(id: $id) {
|
proposal(id: $id) {
|
||||||
... on Proposal {
|
id
|
||||||
id
|
state
|
||||||
state
|
rejectionReason
|
||||||
rejectionReason
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user