Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
456635a297 | ||
|
|
489e250b68 |
@@ -1 +0,0 @@
|
|||||||
node_modules
|
|
||||||
+6
-11
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"ignorePatterns": ["**/*"],
|
"ignorePatterns": ["**/*"],
|
||||||
"plugins": ["@nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
|
"plugins": ["@nrwl/nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
|
||||||
"settings": {
|
"settings": {
|
||||||
"jsx-a11y": {
|
"jsx-a11y": {
|
||||||
"components": {
|
"components": {
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
"extends": ["plugin:jsx-a11y/strict"],
|
"extends": ["plugin:jsx-a11y/strict"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"@nx/enforce-module-boundaries": [
|
"@nrwl/nx/enforce-module-boundaries": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"enforceBuildableLibDependency": true,
|
"enforceBuildableLibDependency": true,
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx"],
|
"files": ["*.ts", "*.tsx"],
|
||||||
"extends": ["plugin:@nx/typescript"],
|
"extends": ["plugin:@nrwl/nx/typescript"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/ban-ts-comment": [
|
"@typescript-eslint/ban-ts-comment": [
|
||||||
"error",
|
"error",
|
||||||
@@ -80,19 +80,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": ["*.spec.ts", "*.spec.tsx"],
|
"files": ["*.spec.ts", "*.spec.tsx"],
|
||||||
"extends": ["plugin:@nx/typescript", "plugin:jest/recommended"],
|
"extends": ["plugin:@nrwl/nx/typescript", "plugin:jest/recommended"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"jest/consistent-test-it": [
|
"jest/consistent-test-it": ["error", { "fn": "it" }]
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"fn": "it"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": ["*.js", "*.jsx"],
|
"files": ["*.js", "*.jsx"],
|
||||||
"extends": ["plugin:@nx/javascript"],
|
"extends": ["plugin:@nrwl/nx/javascript"],
|
||||||
"rules": {}
|
"rules": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ What we need to achieve and who for
|
|||||||
|
|
||||||
## Tasks
|
## Tasks
|
||||||
|
|
||||||
- [ ]
|
- [ ] What do we need to do first
|
||||||
- [ ]
|
- [ ] and then what?
|
||||||
|
- [ ] Etc.
|
||||||
|
|
||||||
## Additional details / background info
|
## Additional details / background info
|
||||||
|
|||||||
@@ -22,14 +22,11 @@ So that
|
|||||||
|
|
||||||
## Tasks
|
## Tasks
|
||||||
|
|
||||||
- [ ] UX (if needed)
|
- [ ] Explore and sketch
|
||||||
- [ ] Design (if needed)
|
|
||||||
- [ ] Team and stakeholder review
|
- [ ] Team and stakeholder review
|
||||||
- [ ] Specs reviewed and created or adjusted
|
- [ ] Visual Design
|
||||||
- [ ] Implementation
|
- [ ] Team review
|
||||||
- [ ] Testing (unit and/or e2e)
|
- [ ] Etc.
|
||||||
- [ ] Code review
|
|
||||||
- [ ] QA review
|
|
||||||
|
|
||||||
## Sketch
|
## Sketch
|
||||||
|
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
name: After Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
after-release:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
timeout-minutes: 30
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
|
|
||||||
- name: Log in to the Container registry (ghcr)
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: resolve ipfs hashes for release
|
|
||||||
run: |
|
|
||||||
echo "Name: ${{ github.event.release.name }}"
|
|
||||||
echo "Description: ${{ github.event.release.body }}"
|
|
||||||
echo "Tag: ${{ github.event.release.tag_name }}"
|
|
||||||
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
|
|
||||||
tar -xzf kubo.tgz
|
|
||||||
export PATH="$PATH:$PWD/kubo"
|
|
||||||
which ipfs
|
|
||||||
echo IPFS_V0=$(cat ipfs-hash) >> $GITHUB_ENV
|
|
||||||
echo IPFS_V1=$(ipfs cid format -v 1 -b base32 $(cat ipfs-hash)) >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Edit Release
|
|
||||||
uses: irongut/EditRelease@v1.2.0
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
id: ${{ github.event.release.id }}
|
|
||||||
body: |
|
|
||||||
|
|
||||||
___
|
|
||||||
|
|
||||||
# Deployments
|
|
||||||
* https://explorer.vega.xyz
|
|
||||||
* https://governance.vega.xyz
|
|
||||||
|
|
||||||
# IPFS releases
|
|
||||||
The IPFS hash of this release of the Trading app is:
|
|
||||||
|
|
||||||
CIDv0: ${{ env.IPFS_V0 }}
|
|
||||||
CIDv1: ${{ env.IPFS_V1 }}
|
|
||||||
|
|
||||||
You can always access the latest IPFS release by visiting [console.vega.xyz](https://console.vega.xyz).
|
|
||||||
|
|
||||||
You can also access Trading directly from an IPFS gateway.
|
|
||||||
BEWARE: The Trading interface uses [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to remember your settings, such as which tokens you have imported. You should always use an IPFS gateway that enforces [origin separation](https://ipfs.github.io/public-gateway-checker/).
|
|
||||||
|
|
||||||
Your settings are not remembered across different URLs.
|
|
||||||
|
|
||||||
IPFS gateways:
|
|
||||||
|
|
||||||
https://${{ env.IPFS_V1 }}.ipfs.dweb.link/
|
|
||||||
https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/
|
|
||||||
ipfs://${{ env.IPFS_V0 }}/
|
|
||||||
@@ -6,14 +6,14 @@ name: 'Add Issues To Project Board'
|
|||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.PROJECT_MANAGE_ACTION }}
|
GH_TOKEN: ${{ secrets.GH_NEW_CARD_TO_PROJECT }}
|
||||||
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
|
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
|
||||||
ISSUE_ID: ${{ github.event.issue.node_id }}
|
ISSUE_ID: ${{ github.event.issue.node_id }}
|
||||||
USER: ${{ github.actor }}
|
USER: ${{ github.actor }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
add_issue:
|
add_issue:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: 'Add issue to project board'
|
- name: 'Add issue to project board'
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
name: 'Check if branch is shorter than 52 chars'
|
|
||||||
on: pull_request
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
branch-naming-rules:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
# echo "branches that are longer than 51 chars can't be parsed by kubernetes to create previews. Each app has prefix of it's name like: 'governance-' (12 chars), what leaves 51 max branch length"
|
|
||||||
# current parsable length: $( git rev-parse --abbrev-ref HEAD | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | wc -c)
|
|
||||||
- uses: deepakputhraya/action-branch-name@master
|
|
||||||
with:
|
|
||||||
# regex: '([a-z])+\/([a-z])+' # Regex the branch should match. This example enforces grouping
|
|
||||||
# allowed_prefixes: 'feature,stable,fix' # All branches should start with the given prefix
|
|
||||||
# ignore: master,develop # Ignore exactly matching branch names from convention
|
|
||||||
min_length: 1 # Min length of the branch name
|
|
||||||
max_length: 51 # Max length of the branch name
|
|
||||||
@@ -1,316 +0,0 @@
|
|||||||
name: CI/CD
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- release/*
|
|
||||||
- develop
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- ready_for_review
|
|
||||||
- reopened
|
|
||||||
- edited
|
|
||||||
- synchronize
|
|
||||||
jobs:
|
|
||||||
node-modules:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: 'Cache yarn modules'
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- 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-
|
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: yarn install
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
run: yarn install --pure-lockfile
|
|
||||||
|
|
||||||
lint-pr-title:
|
|
||||||
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
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: '(CI) lint + unit test + build'
|
|
||||||
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@v3
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
|
||||||
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: Check formatting
|
|
||||||
run: yarn nx format:check
|
|
||||||
|
|
||||||
- name: Lint affected
|
|
||||||
run: yarn nx affected:lint --max-warnings=0
|
|
||||||
|
|
||||||
- name: Build affected spec
|
|
||||||
run: yarn nx affected --target=build-spec
|
|
||||||
|
|
||||||
- name: Test affected
|
|
||||||
run: yarn nx affected:test
|
|
||||||
|
|
||||||
- name: Build affected
|
|
||||||
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
|
||||||
|
|
||||||
# See affected apps
|
|
||||||
- name: See affected apps
|
|
||||||
run: |
|
|
||||||
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
|
|
||||||
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
|
|
||||||
|
|
||||||
echo ">>>> debug"
|
|
||||||
echo "NX_BASE: ${{ env.NX_BASE }}"
|
|
||||||
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
|
||||||
echo "Affected: ${affected}"
|
|
||||||
echo "Branch slug: ${branch_slug}"
|
|
||||||
echo "Current ref: ${{ github.ref }}"
|
|
||||||
echo ">>>> eof debug"
|
|
||||||
|
|
||||||
projects_array=()
|
|
||||||
|
|
||||||
preview_governance="not deployed"
|
|
||||||
preview_trading="not deployed"
|
|
||||||
preview_explorer="not deployed"
|
|
||||||
preview_tools="not deployed"
|
|
||||||
|
|
||||||
# parse if affected is any of three main applications, if none - use all of them
|
|
||||||
if echo "$affected" | grep -q governance; then
|
|
||||||
echo "Governance is affected"
|
|
||||||
projects_array+=("governance")
|
|
||||||
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
|
||||||
fi
|
|
||||||
if echo "$affected" | grep -q trading; then
|
|
||||||
echo "Trading is affected"
|
|
||||||
projects_array+=("trading")
|
|
||||||
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
|
||||||
fi
|
|
||||||
if echo "$affected" | grep -q explorer; then
|
|
||||||
echo "Explorer is affected"
|
|
||||||
projects_array+=("explorer")
|
|
||||||
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
|
||||||
fi
|
|
||||||
if [[ ${#projects_array[@]} -eq 0 ]]; then
|
|
||||||
projects_array=("governance" "trading" "explorer")
|
|
||||||
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
|
|
||||||
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
|
|
||||||
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
|
|
||||||
fi
|
|
||||||
|
|
||||||
# applications parsed before this loop are applicable for running e2e-tests
|
|
||||||
projects_e2e_array=()
|
|
||||||
for project in "${projects_array[@]}"; do
|
|
||||||
projects_e2e_array+=("${project}-e2e")
|
|
||||||
done
|
|
||||||
# all applications below this loop are not applicable for running e2e-test
|
|
||||||
|
|
||||||
# check if pull request event to deploy tools
|
|
||||||
if [[ "${{ github.event_name }}" = "pull_request" ]]; then
|
|
||||||
if echo "$affected" | grep -q multisig-signer; then
|
|
||||||
echo "Tools are affected"
|
|
||||||
echo "Deploying tools on preview"
|
|
||||||
preview_tools=$(printf "https://%s.%s.vega.rocks" "tools" "$branch_slug")
|
|
||||||
|
|
||||||
projects_array+=("multisig-signer")
|
|
||||||
fi
|
|
||||||
# those apps deploy only from develop to mainnet
|
|
||||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
|
||||||
if echo "$affected" | grep -q multisig-signer; then
|
|
||||||
echo "Tools are affected"
|
|
||||||
echo "Deploying tools on s3"
|
|
||||||
|
|
||||||
projects_array+=("multisig-signer")
|
|
||||||
fi
|
|
||||||
if echo "$affected" | grep -q static; then
|
|
||||||
echo "static is affected"
|
|
||||||
echo "Deploying static on s3"
|
|
||||||
|
|
||||||
projects_array+=("static")
|
|
||||||
fi
|
|
||||||
if echo "$affected" | grep -q ui-toolkit; then
|
|
||||||
echo "ui-toolkit is affected"
|
|
||||||
echo "Deploying ui-toolkit on s3"
|
|
||||||
|
|
||||||
projects_array+=("ui-toolkit")
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
projects: ${{ env.PROJECTS }}
|
|
||||||
projects-e2e: ${{ env.PROJECTS_E2E }}
|
|
||||||
preview_governance: ${{ env.PREVIEW_GOVERNANCE }}
|
|
||||||
preview_trading: ${{ env.PREVIEW_TRADING }}
|
|
||||||
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
|
||||||
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
|
||||||
|
|
||||||
cypress:
|
|
||||||
needs: lint-test-build
|
|
||||||
name: '(CI) cypress'
|
|
||||||
# if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
|
|
||||||
uses: ./.github/workflows/cypress-run.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
|
|
||||||
tags: '@smoke @regression'
|
|
||||||
|
|
||||||
publish-dist:
|
|
||||||
needs: lint-test-build
|
|
||||||
name: '(CD) publish dist'
|
|
||||||
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
|
|
||||||
uses: ./.github/workflows/publish-dist.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
projects: ${{ needs.lint-test-build.outputs.projects }}
|
|
||||||
|
|
||||||
dist-check:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- publish-dist
|
|
||||||
- lint-test-build
|
|
||||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
|
||||||
timeout-minutes: 60
|
|
||||||
name: '(CD) comment preview links'
|
|
||||||
steps:
|
|
||||||
- name: Find Comment
|
|
||||||
uses: peter-evans/find-comment@v2
|
|
||||||
id: fc
|
|
||||||
with:
|
|
||||||
issue-number: ${{ github.event.pull_request.number }}
|
|
||||||
body-includes: Previews
|
|
||||||
|
|
||||||
- name: Wait for deployments
|
|
||||||
run: |
|
|
||||||
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
|
||||||
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then
|
|
||||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
|
|
||||||
echo "waiting for governance preview: ${{ needs.lint-test-build.outputs.preview_governance }}"
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then
|
|
||||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
|
|
||||||
echo "waiting for explorer preview: ${{ needs.lint-test-build.outputs.preview_explorer }}"
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then
|
|
||||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
|
|
||||||
echo "waiting for trading preview: ${{ needs.lint-test-build.outputs.preview_trading }}"
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then
|
|
||||||
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
|
|
||||||
echo "waiting for tools preview: ${{ needs.lint-test-build.outputs.preview_tools }}"
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create comment
|
|
||||||
uses: peter-evans/create-or-update-comment@v3
|
|
||||||
if: ${{ steps.fc.outputs.comment-id == 0 }}
|
|
||||||
with:
|
|
||||||
issue-number: ${{ github.event.pull_request.number }}
|
|
||||||
body: |
|
|
||||||
Previews
|
|
||||||
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
|
||||||
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
|
||||||
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
|
||||||
* tools: ${{ needs.lint-test-build.outputs.preview_tools }}
|
|
||||||
|
|
||||||
# Report single result at the end, to avoid mess with required checks in PR
|
|
||||||
cypress-check:
|
|
||||||
name: '(CI) cypress - check'
|
|
||||||
if: ${{ always() }}
|
|
||||||
needs: cypress
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- run: |
|
|
||||||
result="${{ needs.cypress.result }}"
|
|
||||||
if [[ $result == "success" || $result == "skipped" ]]; then
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
name: console-test-run
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
github-sha:
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
jobs:
|
|
||||||
console-test:
|
|
||||||
timeout-minutes: 5
|
|
||||||
runs-on: self-hosted-runner
|
|
||||||
steps:
|
|
||||||
- name: Checkout console test repo
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
repository: vegaprotocol/console-test
|
|
||||||
path: './console-test'
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.10.11'
|
|
||||||
|
|
||||||
- name: Install Poetry
|
|
||||||
uses: snok/install-poetry@v1
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
poetry install --no-root
|
|
||||||
working-directory: ./console-test
|
|
||||||
|
|
||||||
- name: load Binaries
|
|
||||||
run: |
|
|
||||||
poetry run python -m vega_sim.tools.load_binaries
|
|
||||||
working-directory: ./console-test
|
|
||||||
|
|
||||||
- name: pull console
|
|
||||||
run: |
|
|
||||||
poetry run docker pull ghcr.io/vegaprotocol/frontend/trading:${{ inputs.github-sha }}
|
|
||||||
|
|
||||||
- name: Update container_name in config.py
|
|
||||||
run: |
|
|
||||||
sed -i "s/container_name = \".*\"/container_name = \"vegaprotocol\/frontend\/trading:${{ inputs.github-sha }}\"/g" config.py
|
|
||||||
|
|
||||||
- name: install playwright
|
|
||||||
run: poetry run playwright install
|
|
||||||
working-directory: ./console-test
|
|
||||||
|
|
||||||
- name: run tests
|
|
||||||
run: poetry run pytest --numprocesses auto
|
|
||||||
working-directory: ./console-test
|
|
||||||
|
|
||||||
- name: Upload Playwright Trace
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: playwright-trace
|
|
||||||
path: ./traces/
|
|
||||||
retention-days: 15
|
|
||||||
@@ -13,7 +13,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
cypress-run:
|
cypress-run:
|
||||||
name: Run Cypress Trading tests -- live environment
|
name: Run Cypress Trading tests -- live environment
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -33,4 +33,5 @@ jobs:
|
|||||||
config: baseUrl=${{ github.event.inputs.url }}
|
config: baseUrl=${{ github.event.inputs.url }}
|
||||||
env: grepTags=@live
|
env: grepTags=@live
|
||||||
env:
|
env:
|
||||||
|
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
name: (CI) Cypress Run
|
name: Cypress Run
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
project: ${{ fromJSON(inputs.projects) }}
|
project: ${{ fromJSON(inputs.projects) }}
|
||||||
name: ${{ matrix.project }}
|
name: ${{ matrix.project }}
|
||||||
runs-on: self-hosted-runner
|
runs-on: self-hosted-runner
|
||||||
timeout-minutes: 100
|
timeout-minutes: 30
|
||||||
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
|
||||||
@@ -33,7 +33,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
path: './frontend-monorepo'
|
path: './frontend-monorepo'
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
# 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
|
||||||
@@ -67,7 +66,7 @@ jobs:
|
|||||||
######
|
######
|
||||||
|
|
||||||
- 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 }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --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 }}
|
||||||
@@ -94,9 +93,3 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: logs-${{ matrix.project }}
|
name: logs-${{ matrix.project }}
|
||||||
path: /home/runner/.vegacapsule/testnet/logs
|
path: /home/runner/.vegacapsule/testnet/logs
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
if: ${{ failure() }}
|
|
||||||
with:
|
|
||||||
name: test-report-${{ matrix.project }}
|
|
||||||
path: frontend-monorepo/apps/${{ matrix.project }}/cypress/reports
|
|
||||||
|
|||||||
@@ -8,25 +8,22 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
master:
|
master:
|
||||||
name: Generate Queries
|
name: Generate Queries
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
fetch-depth: 0
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
- name: Use Node.js 16
|
||||||
cache: yarn
|
id: Node
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 16.15.1
|
||||||
- name: Install root dependencies
|
- name: Install root dependencies
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn install
|
||||||
|
|
||||||
- name: Generate queries
|
- name: Generate queries
|
||||||
run: node ./scripts/get-queries.js
|
run: node ./scripts/get-queries.js
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: queries
|
name: queries
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
---
|
|
||||||
name: Verify PR title
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint_pr:
|
|
||||||
timeout-minutes: 10
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: node_modules
|
|
||||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
|
||||||
|
|
||||||
- name: Check PR title
|
|
||||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
name: Verify PR title
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, ready_for_review, reopened, edited, synchronize]
|
||||||
|
jobs:
|
||||||
|
lint_pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Use Node.js 16
|
||||||
|
id: Node
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 16.15.1
|
||||||
|
- name: Install root dependencies
|
||||||
|
run: yarn install
|
||||||
|
- name: Check PR title
|
||||||
|
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
name: PR Validations
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
- synchronize
|
||||||
|
- ready_for_review
|
||||||
|
jobs:
|
||||||
|
pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check node version
|
||||||
|
id: node-version
|
||||||
|
run: |
|
||||||
|
npmVersion=$(cat .nvmrc | head -n 1)
|
||||||
|
echo ::set-output name=npmVersion::${npmVersion}
|
||||||
|
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ steps.node-version.outputs.npmVersion }}
|
||||||
|
|
||||||
|
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||||
|
uses: nrwl/nx-set-shas@v3
|
||||||
|
with:
|
||||||
|
main-branch-name: develop
|
||||||
|
|
||||||
|
- name: Restore node_modules from cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: '**/node_modules'
|
||||||
|
key: node_modules-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
|
||||||
|
- name: Install root dependencies
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: See affected apps
|
||||||
|
run: |
|
||||||
|
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=HEAD --select=projects)"
|
||||||
|
echo -n "Affected projects: $affected"
|
||||||
|
|
||||||
|
projects_e2e=""
|
||||||
|
if [[ $affected == *"governance"* ]]; then projects_e2e+='"governance-e2e" '; fi
|
||||||
|
if [[ $affected == *"trading"* ]]; then projects_e2e+='"trading-e2e" '; fi
|
||||||
|
if [[ $affected == *"explorer"* ]]; then projects_e2e+='"explorer-e2e" '; fi
|
||||||
|
if [[ -z "$projects_e2e" ]]; then projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '; fi
|
||||||
|
projects_e2e=${projects_e2e%?}
|
||||||
|
projects_e2e=[${projects_e2e// /,}]
|
||||||
|
echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
|
||||||
|
echo PROJECTS=$(echo $projects_e2e | sed 's|-e2e||g') >> $GITHUB_ENV
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
projects: ${{ env.PROJECTS }}
|
||||||
|
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||||
|
|
||||||
|
run-cypress:
|
||||||
|
needs: pr
|
||||||
|
if: ${{ needs.pr.outputs.projects != '[]' }}
|
||||||
|
uses: ./.github/workflows/cypress-run.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
projects: ${{ needs.pr.outputs.projects-e2e }}
|
||||||
|
tags: '@smoke @regression'
|
||||||
|
|
||||||
|
run-docker-build:
|
||||||
|
needs: pr
|
||||||
|
if: ${{ needs.pr.outputs.projects != '[]' }}
|
||||||
|
uses: ./.github/workflows/publish-docker-containers.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
projects: ${{ needs.pr.outputs.projects }}
|
||||||
|
|
||||||
|
# Report single result at the end, to avoid mess with required checks in PR
|
||||||
|
result:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: run-cypress
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Cypress result
|
||||||
|
steps:
|
||||||
|
- run: |
|
||||||
|
result="${{ needs.run-cypress.result }}"
|
||||||
|
if [[ $result == "success" || $result == "skipped" ]]; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
name: Generate tranches
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 */6 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
master:
|
||||||
|
name: Generate Queries
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Use Node.js 16
|
||||||
|
id: Node
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 16.15.1
|
||||||
|
- name: Install root dependencies
|
||||||
|
run: yarn install
|
||||||
|
- name: Generate queries
|
||||||
|
run: node ./scripts/get-tranches.js
|
||||||
|
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
|
with:
|
||||||
|
commit_message: 'chore: update tranches'
|
||||||
|
commit_options: '--no-verify --signoff'
|
||||||
|
skip_fetch: true
|
||||||
|
skip_checkout: true
|
||||||
@@ -1,358 +0,0 @@
|
|||||||
name: (CD) Publish docker + s3
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
projects:
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish-dist:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
app: ${{ fromJSON(inputs.projects) }}
|
|
||||||
name: ${{ matrix.app }}
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
timeout-minutes: 25
|
|
||||||
steps:
|
|
||||||
- name: Check out code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Init variables
|
|
||||||
run: |
|
|
||||||
echo IS_PR=false >> $GITHUB_ENV
|
|
||||||
echo IS_MAINNET_RELEASE=false >> $GITHUB_ENV
|
|
||||||
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
|
|
||||||
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Is PR
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
run: |
|
|
||||||
echo IS_PR=true >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Is mainnet release
|
|
||||||
if: ${{ contains(github.ref, 'release/mainnnet') && !contains(github.ref, 'mirror') }}
|
|
||||||
run: |
|
|
||||||
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Is testnet release
|
|
||||||
if: ${{ contains(github.ref, 'release/testnet') }}
|
|
||||||
run: |
|
|
||||||
echo IS_TESTNET_RELEASE=true >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Is IPFS Release
|
|
||||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( env.IS_MAINNET_RELEASE == 'true' || env.IS_TESTNET_RELEASE == 'true' ) }}
|
|
||||||
run: |
|
|
||||||
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
id: quemu
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
|
|
||||||
- name: Available platforms
|
|
||||||
run: echo ${{ steps.qemu.outputs.platforms }}
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
|
|
||||||
- name: Log in to the Container registry (ghcr)
|
|
||||||
if: ${{ env.IS_PR == 'true' }}
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: node_modules
|
|
||||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
|
||||||
|
|
||||||
# https://docs.github.com/en/actions/learn-github-actions/contexts
|
|
||||||
- name: Define dist variables
|
|
||||||
if: ${{ github.event_name == 'push' }}
|
|
||||||
run: |
|
|
||||||
envName=''
|
|
||||||
domain="vega.rocks"
|
|
||||||
bucketName=''
|
|
||||||
|
|
||||||
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
|
||||||
# remove prefixing release/ and take the first string limited by - which is supposed to be name of the environment for releasing (format: release/testnet-trading)
|
|
||||||
envName="$(echo ${{ github.ref }} | sed -e "s|refs/heads/release/||" | cut -d '-' -f 1 )"
|
|
||||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
|
||||||
envName="stagnet1"
|
|
||||||
if [[ "${{ matrix.app }}" = "multisig-signer" ]]; then
|
|
||||||
envName="mainnet"
|
|
||||||
bucketName="tools.vega.xyz"
|
|
||||||
fi
|
|
||||||
if [[ "${{ matrix.app }}" = "static" ]]; then
|
|
||||||
envName="mainnet"
|
|
||||||
bucketName="static.vega.xyz"
|
|
||||||
fi
|
|
||||||
if [[ "${{ matrix.app }}" = "ui-toolkit" ]]; then
|
|
||||||
envName="mainnet"
|
|
||||||
bucketName="ui.vega.rocks"
|
|
||||||
fi
|
|
||||||
elif [[ "${{ github.ref }}" =~ .*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
|
|
||||||
run: |
|
|
||||||
envCmd=""
|
|
||||||
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
|
|
||||||
envCmd="yarn env-cmd -f ./apps/${{ matrix.app }}/.env.${{ env.ENV_NAME }}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${{ matrix.app }}" = "trading" ]; then
|
|
||||||
$envCmd yarn nx export trading || (yarn install && $envCmd yarn nx export trading)
|
|
||||||
DIST_LOCATION=dist/apps/trading/exported
|
|
||||||
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
|
||||||
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
|
||||||
DIST_LOCATION=dist/storybook/ui-toolkit
|
|
||||||
else
|
|
||||||
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
|
|
||||||
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
|
||||||
fi
|
|
||||||
mv $DIST_LOCATION dist-result
|
|
||||||
tree dist-result
|
|
||||||
|
|
||||||
- name: Build and export to local Docker
|
|
||||||
id: docker_build
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/node-outside-docker.Dockerfile
|
|
||||||
load: true
|
|
||||||
build-args: |
|
|
||||||
APP=${{ matrix.app }}
|
|
||||||
ENV_NAME=${{ env.ENV_NAME }}
|
|
||||||
tags: |
|
|
||||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
|
||||||
|
|
||||||
- name: Image digest
|
|
||||||
if: ${{ env.IS_PR == 'true' }}
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
|
|
||||||
- name: Sanity check docker image
|
|
||||||
run: |
|
|
||||||
echo "Check 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 cat /ipfs-hash > ${{ matrix.app }}-ipfs-hash
|
|
||||||
echo "List html directory"
|
|
||||||
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)
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
continue-on-error: true
|
|
||||||
id: ghcr-push
|
|
||||||
if: ${{ env.IS_PR == 'true' }}
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/node-outside-docker.Dockerfile
|
|
||||||
push: true
|
|
||||||
build-args: |
|
|
||||||
APP=${{ matrix.app }}
|
|
||||||
ENV_NAME=${{ env.ENV_NAME }}
|
|
||||||
tags: |
|
|
||||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Publish dist as docker image (docker hub)
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
continue-on-error: true
|
|
||||||
id: dockerhub-push
|
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/node-outside-docker.Dockerfile
|
|
||||||
push: true
|
|
||||||
build-args: |
|
|
||||||
APP=${{ matrix.app }}
|
|
||||||
ENV_NAME=${{ env.ENV_NAME }}
|
|
||||||
tags: |
|
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
|
||||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr - retry)
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
if: ${{ steps.ghcr-push.outcome == 'failure' }}
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/node-outside-docker.Dockerfile
|
|
||||||
push: true
|
|
||||||
build-args: |
|
|
||||||
APP=${{ matrix.app }}
|
|
||||||
ENV_NAME=${{ env.ENV_NAME }}
|
|
||||||
tags: |
|
|
||||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Publish dist as docker image (docker hub - retry)
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
if: ${{ steps.dockerhub-push.outcome == 'failure' }}
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/node-outside-docker.Dockerfile
|
|
||||||
push: true
|
|
||||||
build-args: |
|
|
||||||
APP=${{ matrix.app }}
|
|
||||||
ENV_NAME=${{ env.ENV_NAME }}
|
|
||||||
tags: |
|
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
|
||||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
|
||||||
|
|
||||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
|
||||||
- name: Publish dist to s3
|
|
||||||
uses: jakejarvis/s3-sync-action@master
|
|
||||||
# s3 releases are not happening for trading on mainnet - it's IPFS
|
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'false' }}
|
|
||||||
with:
|
|
||||||
args: --acl private --follow-symlinks --delete
|
|
||||||
env:
|
|
||||||
AWS_S3_BUCKET: ${{ env.BUCKET_NAME }}
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
AWS_REGION: 'eu-west-1'
|
|
||||||
SOURCE_DIR: 'dist-result'
|
|
||||||
|
|
||||||
- name: Install aws CLI
|
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'false' }}
|
|
||||||
uses: unfor19/install-aws-cli-action@master
|
|
||||||
|
|
||||||
- name: Perform cache invalidation
|
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'false' }}
|
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
AWS_REGION: 'eu-west-1'
|
|
||||||
run: |
|
|
||||||
echo "Looking for distribution for bucket: ${{ env.BUCKET_NAME }}"
|
|
||||||
id=$(aws cloudfront list-distributions | jq -Mrc '.DistributionList.Items | .[] | select(.DefaultCacheBehavior.TargetOriginId == "${{ env.BUCKET_NAME }}") | .Id')
|
|
||||||
echo "Found id is: ${id}"
|
|
||||||
aws cloudfront create-invalidation --distribution-id $id --paths "/*"
|
|
||||||
|
|
||||||
- name: Add preview label
|
|
||||||
uses: actions-ecosystem/action-add-labels@v1
|
|
||||||
if: ${{ env.IS_PR == 'true' }}
|
|
||||||
with:
|
|
||||||
labels: ${{ matrix.app }}-preview
|
|
||||||
number: ${{ github.event.number }}
|
|
||||||
|
|
||||||
- name: Trigger fleek deployment
|
|
||||||
# release to ipfs happens only on mainnet (represented by main branch) for trading
|
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
|
||||||
run: |
|
|
||||||
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
|
|
||||||
# display info about app
|
|
||||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"query": "query{getSiteById(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id latestDeploy{id status}}}"}' \
|
|
||||||
https://api.fleek.co/graphql
|
|
||||||
|
|
||||||
# trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
|
|
||||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
|
||||||
https://api.fleek.co/graphql
|
|
||||||
|
|
||||||
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
|
|
||||||
# display info about app
|
|
||||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"query": "query{getSiteById(siteId:\"79baaeca-1952-4ae7-a256-f668cfc1d68e\"){id latestDeploy{id status}}}"}' \
|
|
||||||
https://api.fleek.co/graphql
|
|
||||||
|
|
||||||
# trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
|
|
||||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"query": "mutation{triggerDeploy(siteId:\"79baaeca-1952-4ae7-a256-f668cfc1d68e\"){id status}}"}' \
|
|
||||||
https://api.fleek.co/graphql
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Check out ipfs-redirect
|
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
repository: 'vegaprotocol/ipfs-redirect'
|
|
||||||
path: 'ipfs-redirect'
|
|
||||||
fetch-depth: '0'
|
|
||||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Update interstitial page to point to the new console
|
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
# set CID
|
|
||||||
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
|
|
||||||
export PATH="$PATH:$PWD/kubo"
|
|
||||||
which ipfs
|
|
||||||
new_hash=$(cat ${{ matrix.app }}-ipfs-hash)
|
|
||||||
new_cid=$(ipfs cid format -v 1 -b base32 $new_hash)
|
|
||||||
|
|
||||||
(
|
|
||||||
cd ipfs-redirect
|
|
||||||
|
|
||||||
# configure git
|
|
||||||
git status
|
|
||||||
cat .git/config
|
|
||||||
git config --global user.email "vega-ci-bot@vega.xyz"
|
|
||||||
git config --global user.name "vega-ci-bot"
|
|
||||||
|
|
||||||
# update CID files
|
|
||||||
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
|
|
||||||
echo $new_hash > cidv0-mainnet.txt
|
|
||||||
echo $new_cid > cidv1-mainnet.txt
|
|
||||||
git add cidv0-mainnet.txt cidv1-mainnet.txt
|
|
||||||
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
|
|
||||||
echo $new_hash > cidv0-fairground.txt
|
|
||||||
echo $new_cid > cidv1-fairground.txt
|
|
||||||
git add cidv0-fairground.txt cidv1-fairground.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
# create commit
|
|
||||||
commit_msg="Automated hash update from ${{ github.ref }}"
|
|
||||||
git commit -m "$commit_msg"
|
|
||||||
git push -u origin "main"
|
|
||||||
)
|
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
name: Docker build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
projects:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
master:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
app: ${{ fromJSON(inputs.projects) }}
|
||||||
|
name: ${{ matrix.app }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
id: quemu
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Available platforms
|
||||||
|
run: echo ${{ steps.qemu.outputs.platforms }}
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
# https://docs.github.com/en/actions/learn-github-actions/contexts
|
||||||
|
# https://github.com/actions/checkout#Checkout-pull-request-HEAD-commit-instead-of-merge-commit
|
||||||
|
- name: Determine Docker Image tag
|
||||||
|
id: tags
|
||||||
|
run: |
|
||||||
|
npmVersion=$(cat .nvmrc | head -n 1)
|
||||||
|
versionTag=${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || github.event.pull_request.head.sha }}
|
||||||
|
echo ::set-output name=npmVersion::${npmVersion}
|
||||||
|
echo ::set-output name=version::${versionTag}
|
||||||
|
|
||||||
|
- name: Print config
|
||||||
|
run: |
|
||||||
|
git rev-parse --verify HEAD
|
||||||
|
git status
|
||||||
|
echo "steps.tags.outputs.version=${{ steps.tags.outputs.version }}"
|
||||||
|
|
||||||
|
- name: Build and export to local Docker
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
load: true
|
||||||
|
build-args: |
|
||||||
|
APP=${{ matrix.app }}
|
||||||
|
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
|
||||||
|
tags: |
|
||||||
|
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||||
|
|
||||||
|
- name: Sanity check docker image
|
||||||
|
run: |
|
||||||
|
echo "Check .env file"
|
||||||
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat .env
|
||||||
|
echo "Check ipfs-hash"
|
||||||
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat ipfs-hash
|
||||||
|
echo "List html directory"
|
||||||
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local ls -lah
|
||||||
|
|
||||||
|
- name: Log in to the Container registry
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
build-args: |
|
||||||
|
APP=${{ matrix.app }}
|
||||||
|
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
|
||||||
|
tags: |
|
||||||
|
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:latest
|
||||||
|
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ steps.tags.outputs.version }}
|
||||||
|
|
||||||
|
- name: Add preview label
|
||||||
|
uses: actions-ecosystem/action-add-labels@v1
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
with:
|
||||||
|
labels: ${{ matrix.app }}-preview
|
||||||
|
number: ${{ github.event.number }}
|
||||||
|
|
||||||
|
- name: Image digest
|
||||||
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
@@ -19,27 +19,29 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
name: Build & Publish - Tag
|
name: Build & Publish - Tag
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: 'read'
|
contents: 'read'
|
||||||
actions: 'read'
|
actions: 'read'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
- name: Setup node
|
fetch-depth: 0
|
||||||
|
- name: User Node.js 16
|
||||||
|
id: Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version: 16.15.1
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
- name: Restore node_modules from cache
|
||||||
cache: yarn
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: '**/node_modules'
|
||||||
|
key: node_modules-${{ hashFiles('**/yarn.lock') }}
|
||||||
- name: Install root dependencies
|
- name: Install root dependencies
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn install --frozen-lockfile
|
||||||
|
|
||||||
- name: Build project
|
- name: Build project
|
||||||
run: yarn nx build ${{inputs.project}}
|
run: yarn nx build ${{inputs.project}}
|
||||||
|
|
||||||
- name: Publish project to @vegaprotocol
|
- name: Publish project to @vegaprotocol
|
||||||
uses: JS-DevTools/npm-publish@v1
|
uses: JS-DevTools/npm-publish@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
name: 'Rollback console'
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: 'Version that should be set on rollback'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
rollback:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
timeout-minutes: 10
|
|
||||||
steps:
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Retag mainnet
|
|
||||||
run: |
|
|
||||||
docker pull vegaprotocol/trading:${{ inputs.version }}
|
|
||||||
docker tag vegaprotocol/trading:${{ inputs.version }} vegaprotocol/trading:mainnet
|
|
||||||
docker push vegaprotocol/trading:mainnet
|
|
||||||
docker run --rm vegaprotocol/trading:mainnet cat /ipfs-hash > ipfs-hash
|
|
||||||
|
|
||||||
- name: Trigger fleek deployment
|
|
||||||
run: |
|
|
||||||
# display info about app
|
|
||||||
curl -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"query": "query{getSiteById(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id latestDeploy{id status}}}"}' \
|
|
||||||
https://api.fleek.co/graphql
|
|
||||||
|
|
||||||
# trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
|
|
||||||
curl -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
|
||||||
https://api.fleek.co/graphql
|
|
||||||
|
|
||||||
- name: Check out ipfs-redirect
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
repository: 'vegaprotocol/ipfs-redirect'
|
|
||||||
path: 'ipfs-redirect'
|
|
||||||
fetch-depth: '0'
|
|
||||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Update console.vega.xyz DNS to redirect to the new console
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
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
|
|
||||||
export PATH="$PATH:$PWD/kubo"
|
|
||||||
which ipfs
|
|
||||||
new_hash=$(cat ipfs-hash)
|
|
||||||
new_cid=$(ipfs cid format -v 1 -b base32 $new_hash)
|
|
||||||
git config --global user.email "vega-ci-bot@vega.xyz"
|
|
||||||
git config --global user.name "vega-ci-bot"
|
|
||||||
echo $new_hash > ipfs-redirect/cidv0.txt
|
|
||||||
echo $new_cid > ipfs-redirect/cidv1.txt
|
|
||||||
|
|
||||||
(
|
|
||||||
cd ipfs-redirect
|
|
||||||
|
|
||||||
git status
|
|
||||||
branch_name="rollback-to-$new_hash"
|
|
||||||
git checkout -b "$branch_name"
|
|
||||||
commit_msg="hash rollback to $new_hash"
|
|
||||||
git add cidv0.txt cidv1.txt
|
|
||||||
git commit -m "$commit_msg"
|
|
||||||
git push -u origin "$branch_name" --force-with-lease
|
|
||||||
pr_url="$(gh pr create --title "${commit_msg}" --body 'automated pull request to update CIDs')"
|
|
||||||
echo $pr_url
|
|
||||||
# once auto merge get's enabled on documentation repo let's do follow up
|
|
||||||
sleep 5
|
|
||||||
gh pr merge "${pr_url}" --delete-branch --squash --admin
|
|
||||||
)
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
name: Unit tests & build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
jobs:
|
||||||
|
pr:
|
||||||
|
name: Test and lint - PR
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: 'read'
|
||||||
|
actions: 'read'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||||
|
uses: nrwl/nx-set-shas@v2
|
||||||
|
with:
|
||||||
|
main-branch-name: ${{ github.base_ref }}
|
||||||
|
- name: Use Node.js 16
|
||||||
|
id: Node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 16.15.1
|
||||||
|
- name: Restore node_modules from cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: '**/node_modules'
|
||||||
|
key: node_modules-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
- name: Install root dependencies
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
- name: Check formatting
|
||||||
|
run: yarn nx format:check
|
||||||
|
- name: Lint affected
|
||||||
|
run: yarn nx affected:lint --max-warnings=0
|
||||||
|
- name: Test affected
|
||||||
|
run: yarn nx affected:test
|
||||||
|
- name: Build affected
|
||||||
|
run: yarn nx affected:build
|
||||||
|
- name: Build affected spec
|
||||||
|
run: yarn nx affected --target=build-spec
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
# compiled output
|
# compiled output
|
||||||
/dist
|
/dist
|
||||||
/dist-result
|
|
||||||
/tmp
|
/tmp
|
||||||
/out-tsc
|
/out-tsc
|
||||||
/tools/executors/**/*.js
|
/tools/executors/**/*.js
|
||||||
@@ -47,8 +46,3 @@ cypress.env.json
|
|||||||
|
|
||||||
# Next.js
|
# Next.js
|
||||||
.next
|
.next
|
||||||
|
|
||||||
#cypress
|
|
||||||
/apps/**/cypress/reports/
|
|
||||||
/apps/**/cypress/downloads/
|
|
||||||
/apps/**/fixtures/wallet/node**
|
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ __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/stagnet3-tranches.json
|
||||||
apps/static/src/assets/testnet-tranches.json
|
apps/static/src/assets/testnet-tranches.json
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
module.exports = {
|
||||||
|
stories: [],
|
||||||
|
addons: [
|
||||||
|
'@storybook/addon-actions',
|
||||||
|
'@storybook/addon-viewport',
|
||||||
|
{
|
||||||
|
name: '@storybook/addon-docs',
|
||||||
|
options: {
|
||||||
|
configureJSX: true,
|
||||||
|
babelOptions: {},
|
||||||
|
sourceLoaderOptions: null,
|
||||||
|
transcludeMarkdown: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'@storybook/addon-controls',
|
||||||
|
'@storybook/addon-backgrounds',
|
||||||
|
'@storybook/addon-toolbars',
|
||||||
|
'@storybook/addon-measure',
|
||||||
|
'@storybook/addon-outline',
|
||||||
|
'@storybook/addon-a11y',
|
||||||
|
],
|
||||||
|
// uncomment the property below if you want to apply some webpack config globally
|
||||||
|
// webpackFinal: async (config, { configType }) => {
|
||||||
|
// // Make whatever fine-grained changes you need that should apply to all storybook configs
|
||||||
|
|
||||||
|
// // Return the altered config
|
||||||
|
// return config;
|
||||||
|
// },
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"exclude": [
|
||||||
|
"../**/*.spec.js",
|
||||||
|
"../**/*.test.js",
|
||||||
|
"../**/*.spec.ts",
|
||||||
|
"../**/*.test.ts",
|
||||||
|
"../**/*.spec.tsx",
|
||||||
|
"../**/*.test.tsx",
|
||||||
|
"../**/*.spec.jsx",
|
||||||
|
"../**/*.test.jsx"
|
||||||
|
],
|
||||||
|
"include": ["../**/*"]
|
||||||
|
}
|
||||||
@@ -4,28 +4,30 @@ FROM --platform=amd64 node:${NODE_VERSION}-alpine3.16 as build
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# Argument to allow building of different apps
|
# Argument to allow building of different apps
|
||||||
ARG APP
|
ARG APP
|
||||||
ARG ENV_NAME=""
|
|
||||||
RUN apk add --update --no-cache \
|
RUN apk add --update --no-cache \
|
||||||
python3==3.10.11-r0 \
|
python3 \
|
||||||
make==4.3-r0 \
|
make \
|
||||||
gcc==11.2.1_git20220219-r2 \
|
gcc \
|
||||||
g++==11.2.1_git20220219-r2
|
g++
|
||||||
COPY . ./
|
COPY . ./
|
||||||
RUN yarn --network-timeout 100000 --pure-lockfile
|
RUN yarn --network-timeout 100000 --pure-lockfile
|
||||||
# work around for different build process in trading
|
# work around for different build process in trading
|
||||||
RUN sh docker/docker-build.sh
|
RUN sh ./docker-build.sh
|
||||||
|
|
||||||
# Server environment
|
# Server environment
|
||||||
# if this fails you need to docker pull nginx:1.23-alpine and pin new SHA
|
# if this fails you need to docker pull nginx:1.23-alpine and pin new SHA
|
||||||
# this is to ensure that we run always same version of alpine to make sure ipfs is indempotent
|
# this is to ensure that we run always same version of alpine to make sure ipfs is indempotent
|
||||||
FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
|
FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
|
||||||
|
ARG APP
|
||||||
# configuration of system
|
# configuration of system
|
||||||
|
RUN apk add --no-cache bash go-ipfs
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
CMD ["/entrypoint.sh"]
|
||||||
|
|
||||||
# Copy dist
|
# Copy dist
|
||||||
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
|
WORKDIR /usr/share/nginx/html
|
||||||
RUN rm -rf /usr/share/nginx/html/*
|
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
COPY --from=build /app/dist/apps/${APP}/* /usr/share/nginx/html
|
COPY --from=build /app/dist/apps/${APP} /usr/share/nginx/html
|
||||||
RUN apk add --no-cache go-ipfs==0.16.0-r6 \
|
COPY ./apps/${APP}/.env .env
|
||||||
&& ipfs init \
|
RUN ipfs init && echo "$(ipfs add -rQ .)" > ipfs-hash
|
||||||
&& echo "$(ipfs add -rQ /usr/share/nginx/html)" > /ipfs-hash \
|
|
||||||
&& echo "ipfs hash of this build: $(cat /ipfs-hash)"
|
|
||||||
Vendored
+19
-1
@@ -1,2 +1,20 @@
|
|||||||
@Library('vega-shared-library') _
|
@Library('vega-shared-library') _
|
||||||
runApprobation ignoreFailure: false, frontendBranch: env.BRANCH_NAME, type: 'frontend'
|
|
||||||
|
def commitHash = 'UNKNOWN'
|
||||||
|
|
||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
options {
|
||||||
|
skipDefaultCheckout true
|
||||||
|
parallelsAlwaysFailFast()
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage('approbation') {
|
||||||
|
steps {
|
||||||
|
sh 'printenv'
|
||||||
|
checkout scm
|
||||||
|
runApprobation ignoreFailure: false, frontendBranch: env.BRANCH_NAME, type: 'frontend'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
.PHONY: latest-release
|
|
||||||
latest-release:
|
|
||||||
gh release list | head -n 1 | awk '{print $1}'
|
|
||||||
|
|
||||||
.PHONY: show-latest-release
|
|
||||||
show-latest-release:
|
|
||||||
gh release view `gh release list | head -n 1 | awk '{print $1}'`
|
|
||||||
|
|
||||||
.PHONY: recalculate-ipfs
|
|
||||||
recalculate-ipfs:
|
|
||||||
echo "ipfs hash inside the image"
|
|
||||||
docker run --rm ${TAG} cat /ipfs-hash
|
|
||||||
echo "recalculating ipfs hash"
|
|
||||||
docker run --rm ${TAG} ipfs add -r /usr/share/nginx/html
|
|
||||||
|
|
||||||
.PHONY: eject-ipfs-hash
|
|
||||||
unpack:
|
|
||||||
docker create --name=dist ${TAG}
|
|
||||||
docker cp dist:/usr/share/nginx/html dist
|
|
||||||
docker rm dist
|
|
||||||
@@ -72,7 +72,7 @@ Run `nx serve my-app` for a dev server. Navigate to the port specified in `app/<
|
|||||||
In order to generate the schemas for your GraphQL queries, you can run `GRAPHQL_SCHEMA_PATH=[YOUR SCHEMA FILE / API URL HERE] nx run types:generate`.
|
In order to generate the schemas for your GraphQL queries, you can run `GRAPHQL_SCHEMA_PATH=[YOUR SCHEMA FILE / API URL HERE] nx run types:generate`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export GRAPHQL_SCHEMA_PATH=https://api.n07.testnet.vega.xyz/graphql
|
export GRAPHQL_SCHEMA_PATH=https://api.n11.testnet.vega.xyz/graphql
|
||||||
yarn nx run types:generate
|
yarn nx run types:generate
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -103,68 +103,25 @@ In CI linting, formatting and also run. These checks can be seen in the [CI work
|
|||||||
|
|
||||||
Visit the [Nx Documentation](https://nx.dev/getting-started/intro) to learn more.
|
Visit the [Nx Documentation](https://nx.dev/getting-started/intro) to learn more.
|
||||||
|
|
||||||
# 🐋 Hosting a console
|
# Docker & Vegacapsule
|
||||||
|
|
||||||
To host a console there are two possible build scenarios for running the frontends: nx performed **outside** or **inside** docker build. For specific build instructions follow [build instructions](#build-instructions).
|
## Docker
|
||||||
|
|
||||||
In order to run a container on port 3000:
|
The [Dockerfile](./dockerfiles) for running the frontends is pretty basic, merely building the application with the APP arg that is passed in and serving the application from [nginx](./nginx/nginx.conf). The only complexity that exists is that there is a script which allows the passing of run time environment variables to the containers. See configuration below for how to do this.
|
||||||
|
|
||||||
|
You can build any of the containers locally with the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build --dockerfile dockerfiles/Dockerfile.cra . --build-arg APP=[YOUR APP] --tag=[TAG]
|
||||||
|
```
|
||||||
|
|
||||||
|
In order to run a container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -p 3000:80 [TAG]
|
docker run -p 3000:80 [TAG]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build instructions
|
Images ending with `.dist` are to pack locally created transpiled HTML files into nginx container for non-compatible with yarn architectures like M1 Mac
|
||||||
|
|
||||||
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 outside the docker
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./docker/prepare-dist.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
You can build any of the containers locally with the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
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
|
|
||||||
|
|
||||||
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 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`
|
|
||||||
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`.
|
|
||||||
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`
|
|
||||||
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. **it is not possible to calculate same ipfs hash on files that are result of copy operation**
|
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||||
NX_TENDERMINT_URL=http://localhost:26617
|
NX_TENDERMINT_URL=http://localhost:26617
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||||
NX_VEGA_URL=http://localhost:3008/graphql
|
NX_VEGA_URL=http://localhost:3028/query
|
||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_VEGA_CONFIG_URL=
|
NX_VEGA_CONFIG_URL=
|
||||||
|
|
||||||
@@ -17,4 +18,4 @@ NX_EXPLORER_PARTIES=1
|
|||||||
NX_EXPLORER_VALIDATORS=1
|
NX_EXPLORER_VALIDATORS=1
|
||||||
|
|
||||||
CYPRESS_VEGA_WALLET_API_TOKEN=
|
CYPRESS_VEGA_WALLET_API_TOKEN=
|
||||||
CYPRESS_VEGA_URL=http://localhost:3008/graphql
|
CYPRESS_VEGA_URL=http://localhost:3028/query
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
|
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||||
NX_TENDERMINT_URL=https://n04.d.vega.xyz/tm
|
NX_TENDERMINT_URL=https://n04.d.vega.xyz/tm
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
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
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
|
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||||
NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/
|
NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
|
||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.xyz/query
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||||
|
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
|
||||||
|
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
|
||||||
|
NX_VEGA_ENV=STAGNET3
|
||||||
|
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
|
||||||
|
|
||||||
|
# App flags
|
||||||
|
NX_EXPLORER_ASSETS=1
|
||||||
|
NX_EXPLORER_GENESIS=1
|
||||||
|
NX_EXPLORER_GOVERNANCE=1
|
||||||
|
NX_EXPLORER_MARKETS=1
|
||||||
|
NX_EXPLORER_ORACLES=1
|
||||||
|
NX_EXPLORER_TXS_LIST=0
|
||||||
|
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||||
|
NX_EXPLORER_PARTIES=1
|
||||||
|
NX_EXPLORER_VALIDATORS=1
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
|
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
|
||||||
NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm
|
NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
|
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.n11.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
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
const { defineConfig } = require('cypress');
|
const { defineConfig } = require('cypress');
|
||||||
|
|
||||||
module.exports = defineConfig({
|
module.exports = defineConfig({
|
||||||
reporter: '../../node_modules/cypress-mochawesome-reporter',
|
projectId: 'et4snf',
|
||||||
|
|
||||||
e2e: {
|
e2e: {
|
||||||
setupNodeEvents(on, config) {
|
setupNodeEvents(on, config) {
|
||||||
require('cypress-mochawesome-reporter/plugin')(on);
|
|
||||||
require('@cypress/grep/src/plugin')(config);
|
require('@cypress/grep/src/plugin')(config);
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
@@ -22,11 +21,10 @@ module.exports = defineConfig({
|
|||||||
chromeWebSecurity: false,
|
chromeWebSecurity: false,
|
||||||
viewportWidth: 1440,
|
viewportWidth: 1440,
|
||||||
viewportHeight: 900,
|
viewportHeight: 900,
|
||||||
testIsolation: false,
|
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
environment: 'CUSTOM',
|
environment: 'CUSTOM',
|
||||||
networkQueryUrl: 'http://localhost:3008/graphql',
|
networkQueryUrl: 'http://localhost:3028/query',
|
||||||
ethUrl: 'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
|
ethUrl: 'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
|
||||||
commitHash: 'dev',
|
commitHash: 'dev',
|
||||||
tsConfig: 'tsconfig.json',
|
tsConfig: 'tsconfig.json',
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "explorer-e2e",
|
|
||||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
"sourceRoot": "apps/explorer-e2e/src",
|
"sourceRoot": "apps/explorer-e2e/src",
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"targets": {
|
"targets": {
|
||||||
"e2e": {
|
"e2e": {
|
||||||
"executor": "@nx/cypress:cypress",
|
"executor": "@nrwl/cypress:cypress",
|
||||||
"options": {
|
"options": {
|
||||||
"cypressConfig": "apps/explorer-e2e/cypress.config.js",
|
"cypressConfig": "apps/explorer-e2e/cypress.config.js",
|
||||||
"devServerTarget": "explorer:serve"
|
"devServerTarget": "explorer:serve"
|
||||||
@@ -17,14 +16,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nx/linter:eslint",
|
"executor": "@nrwl/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "@nrwl/workspace:run-commands",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"options": {
|
"options": {
|
||||||
"command": "yarn tsc --project ./apps/explorer-e2e/"
|
"command": "yarn tsc --project ./apps/explorer-e2e/"
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
"governance.proposal.updateMarket.minVoterBalance",
|
"governance.proposal.updateMarket.minVoterBalance",
|
||||||
"governance.proposal.updateNetParam.minProposerBalance",
|
"governance.proposal.updateNetParam.minProposerBalance",
|
||||||
"governance.proposal.updateNetParam.minVoterBalance",
|
"governance.proposal.updateNetParam.minVoterBalance",
|
||||||
"governance.proposal.updateAsset.minProposerBalance",
|
|
||||||
"governance.proposal.updateAsset.minVoterBalance",
|
|
||||||
"reward.staking.delegation.maxPayoutPerEpoch",
|
"reward.staking.delegation.maxPayoutPerEpoch",
|
||||||
"reward.staking.delegation.maxPayoutPerParticipant",
|
"reward.staking.delegation.maxPayoutPerParticipant",
|
||||||
"reward.staking.delegation.minimumValidatorStake",
|
"reward.staking.delegation.minimumValidatorStake",
|
||||||
@@ -21,6 +19,9 @@
|
|||||||
"validators.delegation.minAmount"
|
"validators.delegation.minAmount"
|
||||||
],
|
],
|
||||||
"fiveDecimal": [
|
"fiveDecimal": [
|
||||||
|
"governance.proposal.updateAsset.minProposerBalance",
|
||||||
|
"governance.proposal.updateAsset.minVoterBalance",
|
||||||
|
"governance.proposal.updateAsset.requiredParticipation",
|
||||||
"market.fee.factors.infrastructureFee",
|
"market.fee.factors.infrastructureFee",
|
||||||
"market.fee.factors.makerFee",
|
"market.fee.factors.makerFee",
|
||||||
"market.liquidity.bondPenaltyParameter",
|
"market.liquidity.bondPenaltyParameter",
|
||||||
@@ -76,7 +77,6 @@
|
|||||||
"governance.proposal.updateNetParam.requiredMajority",
|
"governance.proposal.updateNetParam.requiredMajority",
|
||||||
"governance.proposal.updateNetParam.requiredParticipation",
|
"governance.proposal.updateNetParam.requiredParticipation",
|
||||||
"governance.proposal.updateMarket.minProposerEquityLikeShare",
|
"governance.proposal.updateMarket.minProposerEquityLikeShare",
|
||||||
"governance.proposal.updateAsset.requiredParticipation",
|
|
||||||
"validators.vote.required"
|
"validators.vote.required"
|
||||||
],
|
],
|
||||||
"duration": [
|
"duration": [
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ context('Asset page', { tags: '@regression' }, () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should open details page when clicked on "View details"', () => {
|
it('should open details page when clicked on "View details"', () => {
|
||||||
cy.getAssets().then((assets) => {
|
cy.getAssets().then((assets) => {
|
||||||
assets.forEach((asset) => {
|
assets.forEach((asset) => {
|
||||||
cy.get(`[row-id="${asset.id}"] [col-id="actions"] button`)
|
cy.get(`[row-id="${asset.id}"] [col-id="actions"] button`)
|
||||||
|
|||||||
@@ -9,22 +9,21 @@ context('Home Page', function () {
|
|||||||
it('should show connected environment stats', function () {
|
it('should show connected environment stats', function () {
|
||||||
const statTitles = {
|
const statTitles = {
|
||||||
0: 'Status',
|
0: 'Status',
|
||||||
1: 'Epoch',
|
1: 'Block height',
|
||||||
2: 'Block height',
|
2: 'Uptime',
|
||||||
3: 'Uptime',
|
3: 'Total nodes',
|
||||||
4: 'Total nodes',
|
4: 'Total staked',
|
||||||
5: 'Total staked',
|
5: 'Backlog',
|
||||||
6: 'Backlog',
|
6: 'Trades / second',
|
||||||
7: 'Trades / second',
|
7: 'Orders / block',
|
||||||
8: 'Orders / block',
|
8: 'Orders / second',
|
||||||
9: 'Orders / second',
|
9: 'Transactions / block',
|
||||||
10: 'Transactions / block',
|
10: 'Block time',
|
||||||
11: 'Block time',
|
11: 'Time',
|
||||||
12: 'Time',
|
12: 'App',
|
||||||
13: 'App',
|
13: 'Tendermint',
|
||||||
14: 'Tendermint',
|
14: 'Up since',
|
||||||
15: 'Up since',
|
15: 'Chain ID',
|
||||||
16: 'Chain ID',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
cy.get('[data-testid="stats-title"]')
|
cy.get('[data-testid="stats-title"]')
|
||||||
@@ -32,13 +31,42 @@ context('Home Page', function () {
|
|||||||
cy.wrap($list).should('contain.text', statTitles[index]);
|
cy.wrap($list).should('contain.text', statTitles[index]);
|
||||||
})
|
})
|
||||||
.then(($list) => {
|
.then(($list) => {
|
||||||
cy.wrap($list).should('have.length', 17);
|
cy.wrap($list).should('have.length', 16);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cy.get(statsValue).eq(0).should('contain.text', 'CONNECTED');
|
||||||
|
cy.get(statsValue).eq(1).should('not.be.empty');
|
||||||
|
cy.get(statsValue)
|
||||||
|
.eq(2)
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', /\d+d \d+h \d+m \d+s/i);
|
||||||
|
cy.get(statsValue).eq(3).should('contain.text', '2');
|
||||||
|
cy.get(statsValue)
|
||||||
|
.eq(4)
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', /\d+\.\d\d(?!\d)/i);
|
||||||
|
cy.get(statsValue).eq(5).should('contain.text', '0');
|
||||||
|
cy.get(statsValue).eq(6).should('contain.text', '0');
|
||||||
|
cy.get(statsValue).eq(7).should('contain.text', '0');
|
||||||
|
cy.get(statsValue).eq(8).should('contain.text', '0');
|
||||||
|
cy.get(statsValue).eq(9).should('not.be.empty');
|
||||||
|
cy.get(statsValue).eq(10).should('not.be.empty');
|
||||||
|
cy.get(statsValue).eq(11).should('not.be.empty');
|
||||||
|
cy.get(statsValue)
|
||||||
|
.eq(12)
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', /v\d+\.\d+\.\d+/i);
|
||||||
|
cy.get(statsValue)
|
||||||
|
.eq(13)
|
||||||
|
.invoke('text')
|
||||||
|
.should('match', /\d+\.\d+\.\d+/i);
|
||||||
|
cy.get(statsValue).eq(14).should('not.be.empty');
|
||||||
|
cy.get(statsValue).eq(15).should('not.be.empty');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Block height should be updating', function () {
|
it('Block height should be updating', function () {
|
||||||
cy.get(statsValue)
|
cy.get(statsValue)
|
||||||
.eq(2)
|
.eq(1)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.then((blockHeightTxt) => {
|
.then((blockHeightTxt) => {
|
||||||
cy.get(statsValue)
|
cy.get(statsValue)
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () {
|
it('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () {
|
||||||
cy.get_network_parameters().then((network_parameters) => {
|
cy.get_network_parameters().then((network_parameters) => {
|
||||||
network_parameters = Object.entries(network_parameters);
|
network_parameters = Object.entries(network_parameters);
|
||||||
network_parameters.forEach((network_parameter) => {
|
network_parameters.forEach((network_parameter) => {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const customNodeBtn = 'custom-node';
|
|||||||
context.skip('Node switcher', { tags: '@regression' }, function () {
|
context.skip('Node switcher', { tags: '@regression' }, function () {
|
||||||
beforeEach('visit home page', function () {
|
beforeEach('visit home page', function () {
|
||||||
cy.intercept('GET', 'https://static.vega.xyz/assets/capsule-network.json', {
|
cy.intercept('GET', 'https://static.vega.xyz/assets/capsule-network.json', {
|
||||||
hosts: ['http://localhost:3008/graphql'],
|
hosts: ['http://localhost:3028/query'],
|
||||||
}).as('nodeData');
|
}).as('nodeData');
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.wait('@nodeData');
|
cy.wait('@nodeData');
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ context.skip('Parties page', { tags: '@regression' }, function () {
|
|||||||
const jsonFields = '.hljs';
|
const jsonFields = '.hljs';
|
||||||
const sideMenuBackground = '.absolute';
|
const sideMenuBackground = '.absolute';
|
||||||
|
|
||||||
|
// Engage dark mode if not allready set
|
||||||
cy.get(sideMenuBackground)
|
cy.get(sideMenuBackground)
|
||||||
.should('have.css', 'background-color')
|
.should('have.css', 'background-color')
|
||||||
.then((background_color) => {
|
.then((background_color) => {
|
||||||
@@ -218,7 +219,7 @@ context.skip('Parties page', { tags: '@regression' }, function () {
|
|||||||
balance type asset {id symbol decimals}}}}}}}}';
|
balance type asset {id symbol decimals}}}}}}}}';
|
||||||
cy.request({
|
cy.request({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: `http://localhost:3008/graphql`,
|
url: `http://localhost:3028/query`,
|
||||||
body: {
|
body: {
|
||||||
query: mutation,
|
query: mutation,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,5 @@
|
|||||||
|
|
||||||
import '@vegaprotocol/cypress';
|
import '@vegaprotocol/cypress';
|
||||||
import './common.functions.js';
|
import './common.functions.js';
|
||||||
import 'cypress-mochawesome-reporter/register';
|
|
||||||
import registerCypressGrep from '@cypress/grep';
|
import registerCypressGrep from '@cypress/grep';
|
||||||
registerCypressGrep();
|
registerCypressGrep();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
[
|
[
|
||||||
"@nx/react/babel",
|
"@nrwl/react/babel",
|
||||||
{
|
{
|
||||||
"runtime": "automatic"
|
"runtime": "automatic"
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-17
@@ -1,21 +1,13 @@
|
|||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
|
||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.rocks
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
|
NX_VEGA_NETWORKS='{"SANDBOX":"https://sandbox.explorer.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz", "STAGNET3":"https://stagnet3.explorer.vega.xyz","VALIDATOR_TESTNET":"https://validator-testnet.fairground.wtf","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||||
NX_VEGA_ENV=STAGNET1
|
NX_VEGA_ENV=STAGNET3
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
|
|
||||||
NX_VEGA_TOKEN_URL=https://governance.stagnet1.vega.rocks
|
|
||||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
|
||||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
|
||||||
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.rocks/rest
|
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks
|
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
|
||||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
|
||||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases/tag/
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -3,8 +3,15 @@ NX_TENDERMINT_URL=http://localhost:26617
|
|||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
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/main/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
|
NX_EXPLORER_ASSETS=1
|
||||||
|
NX_EXPLORER_GENESIS=1
|
||||||
|
NX_EXPLORER_GOVERNANCE=1
|
||||||
|
NX_EXPLORER_MARKETS=1
|
||||||
|
NX_EXPLORER_ORACLES=1
|
||||||
NX_EXPLORER_TXS_LIST=0
|
NX_EXPLORER_TXS_LIST=0
|
||||||
|
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||||
|
NX_EXPLORER_PARTIES=1
|
||||||
|
NX_EXPLORER_VALIDATORS=1
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/tm
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
NX_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
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://dev.governance.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://dev.token.vega.xyz
|
||||||
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
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=/
|
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
# App configuration variables
|
# App configuration variables
|
||||||
NX_TENDERMINT_URL=https://be.vega.community
|
NX_TENDERMINT_URL=https://be.explorer.vega.xyz
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.explorer.vega.xyz/websocket
|
||||||
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_ENV=MAINNET
|
NX_VEGA_ENV=MAINNET
|
||||||
NX_BLOCK_EXPLORER=https://be.vega.community/rest
|
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/
|
||||||
NX_ETHERSCAN_URL=https://etherscan.io
|
NX_ETHERSCAN_URL=https://etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://token.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_CONSOLE_URL=https://console.vega.xyz
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# App configuration variables
|
|
||||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
|
||||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
|
||||||
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
|
|
||||||
NX_VEGA_ENV=MAINNET-MIRROR
|
|
||||||
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
|
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
|
||||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_TENDERMINT_URL=https://tm.be.mainnet-mirror.vega.xyz
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.xyz/websocket
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
|
||||||
|
NX_VEGA_ENV=MIRROR
|
||||||
|
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.xyz/rest/
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_VEGA_GOVERNANCE_URL=https://mainnet-mirror.token.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
|
|
||||||
|
# App flags
|
||||||
|
NX_EXPLORER_ASSETS=1
|
||||||
|
NX_EXPLORER_GENESIS=1
|
||||||
|
NX_EXPLORER_GOVERNANCE=1
|
||||||
|
NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||||
|
NX_EXPLORER_PARTIES=1
|
||||||
|
NX_EXPLORER_VALIDATORS=1
|
||||||
|
NX_EXPLORER_MARKETS=0
|
||||||
|
NX_EXPLORER_ORACLES=0
|
||||||
|
NX_EXPLORER_TXS_LIST=1
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# App configuration variables
|
||||||
|
NX_VEGA_ENV=SANDBOX
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
|
||||||
|
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
|
||||||
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||||
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_TENDERMINT_URL=https://tm.sandbox.vega.xyz
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.sandbox.vega.xyz/websocket
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_VEGA_GOVERNANCE_URL=https://sandbox.token.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -1,2 +1,14 @@
|
|||||||
# .env is stagnet1, so there are no overrides required
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
|
||||||
|
NX_VEGA_ENV=STAGNET1
|
||||||
|
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
|
||||||
|
NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
|
||||||
|
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||||
|
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||||
|
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
|
||||||
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_VEGA_GOVERNANCE_URL=https://stagnet1.token.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
|
||||||
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.stagnet3.vega.xyz/websocket
|
||||||
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
|
||||||
|
NX_VEGA_ENV=STAGNET3
|
||||||
|
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
|
||||||
|
NX_VEGA_GOVERNANCE_URL=https://stagnet3.token.vega.xyz
|
||||||
|
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases/
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -7,7 +7,5 @@ NX_VEGA_ENV=TESTNET
|
|||||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
NX_VEGA_GOVERNANCE_URL=https://token.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_CONSOLE_URL=https://console.fairground.wtf
|
|
||||||
@@ -7,9 +7,7 @@ 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_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
|
||||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks
|
||||||
|
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||||
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
|
||||||
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
|
||||||
@@ -4,5 +4,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
|
|||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_BLOCK_EXPLORER=
|
NX_BLOCK_EXPLORER=
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_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/main/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
||||||
"ignorePatterns": ["!**/*", "__generated__"],
|
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
|
|||||||
@@ -32,15 +32,15 @@ yarn nx serve explorer
|
|||||||
Example configurations are provided here:
|
Example configurations are provided here:
|
||||||
|
|
||||||
- [Mainnet](./.env.mainnet)
|
- [Mainnet](./.env.mainnet)
|
||||||
- [Mainnet-mirror](./.env.mainnet-mirror)
|
|
||||||
- [Devnet](./.env.devnet)
|
- [Devnet](./.env.devnet)
|
||||||
- [Capsule](./.env.capsule)
|
- [Capsule](./.env.capsule)
|
||||||
- [Testnet](./.env.testnet)
|
- [Testnet](./.env.testnet)
|
||||||
|
- [Stagnet3](./.env.stagnet3)
|
||||||
|
|
||||||
For convenience, you can boot the app injecting one of the configurations above by running:
|
For convenience, you can boot the app injecting one of the configurations above by running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn env-cmd -f .\apps\explorer\.env.{env} yarn nx run explorer:serve # e.g. stagnet1
|
yarn nx run explorer:serve --env={env} # e.g. stagnet3
|
||||||
```
|
```
|
||||||
|
|
||||||
There are a few different configuration options offered for this app:
|
There are a few different configuration options offered for this app:
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ export default {
|
|||||||
displayName: 'explorer',
|
displayName: 'explorer',
|
||||||
preset: '../../jest.preset.js',
|
preset: '../../jest.preset.js',
|
||||||
transform: {
|
transform: {
|
||||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
|
||||||
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
|
'^.+\\.[tj]sx?$': 'babel-jest',
|
||||||
},
|
},
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||||
coverageDirectory: '../../coverage/apps/explorer',
|
coverageDirectory: '../../coverage/apps/explorer',
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "explorer",
|
|
||||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
"sourceRoot": "apps/explorer/src",
|
"sourceRoot": "apps/explorer/src",
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"targets": {
|
"targets": {
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "@nx/webpack:webpack",
|
"executor": "./tools/executors/webpack:build",
|
||||||
"outputs": ["{options.outputPath}"],
|
"outputs": ["{options.outputPath}"],
|
||||||
"defaultConfiguration": "production",
|
"defaultConfiguration": "production",
|
||||||
"options": {
|
"options": {
|
||||||
@@ -39,7 +38,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"serve": {
|
"serve": {
|
||||||
"executor": "@nx/webpack:dev-server",
|
"executor": "./tools/executors/webpack:serve",
|
||||||
"options": {
|
"options": {
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"buildTarget": "explorer:build:development",
|
"buildTarget": "explorer:build:development",
|
||||||
@@ -53,36 +52,30 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nx/linter:eslint",
|
"executor": "@nrwl/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
"executor": "@nx/jest:jest",
|
"executor": "@nrwl/jest:jest",
|
||||||
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
"outputs": ["coverage/apps/explorer"],
|
||||||
"options": {
|
"options": {
|
||||||
"jestConfig": "apps/explorer/jest.config.ts",
|
"jestConfig": "apps/explorer/jest.config.ts",
|
||||||
"passWithNoTests": true
|
"passWithNoTests": true
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"ci": {
|
|
||||||
"ci": true,
|
|
||||||
"codeCoverage": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generate-types": {
|
"generate-types": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "@nrwl/workspace:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/spec-update-v0.72.0-preview.2/specs/v0.72.0-preview.2/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.67.3/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build-netlify": {
|
"build-netlify": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "@nrwl/workspace:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
"cp apps/explorer/netlify.toml netlify.toml",
|
"cp apps/explorer/netlify.toml netlify.toml",
|
||||||
@@ -91,7 +84,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"build-spec": {
|
"build-spec": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "@nrwl/workspace:run-commands",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"options": {
|
"options": {
|
||||||
"command": "yarn tsc --project ./apps/explorer/tsconfig.spec.json"
|
"command": "yarn tsc --project ./apps/explorer/tsconfig.spec.json"
|
||||||
|
|||||||
@@ -1,19 +1,9 @@
|
|||||||
import {
|
import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment';
|
||||||
AppFailure,
|
|
||||||
NetworkLoader,
|
|
||||||
NodeGuard,
|
|
||||||
NodeSwitcherDialog,
|
|
||||||
useEnvironment,
|
|
||||||
useInitializeEnv,
|
|
||||||
useNodeSwitcherStore,
|
|
||||||
} from '@vegaprotocol/environment';
|
|
||||||
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
|
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
|
||||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { router } from './routes/router-config';
|
import { router } from './routes/router-config';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import { Suspense } from 'react';
|
|
||||||
|
|
||||||
const splashLoading = (
|
const splashLoading = (
|
||||||
<Splash>
|
<Splash>
|
||||||
@@ -22,25 +12,10 @@ const splashLoading = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const { VEGA_URL } = useEnvironment();
|
|
||||||
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useNodeSwitcherStore(
|
|
||||||
(store) => [store.dialogOpen, store.setDialogOpen]
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<TendermintWebsocketProvider>
|
<TendermintWebsocketProvider>
|
||||||
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
||||||
<NodeGuard
|
<RouterProvider router={router} fallbackElement={splashLoading} />
|
||||||
skeleton={<div>{t('Loading')}</div>}
|
|
||||||
failure={<AppFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />}
|
|
||||||
>
|
|
||||||
<Suspense fallback={splashLoading}>
|
|
||||||
<RouterProvider router={router} fallbackElement={splashLoading} />
|
|
||||||
</Suspense>
|
|
||||||
</NodeGuard>
|
|
||||||
<NodeSwitcherDialog
|
|
||||||
open={nodeSwitcherOpen}
|
|
||||||
setOpen={setNodeSwitcherOpen}
|
|
||||||
/>
|
|
||||||
</NetworkLoader>
|
</NetworkLoader>
|
||||||
</TendermintWebsocketProvider>
|
</TendermintWebsocketProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ export type AssetBalanceProps = {
|
|||||||
assetId: string;
|
assetId: string;
|
||||||
price: string;
|
price: string;
|
||||||
showAssetLink?: boolean;
|
showAssetLink?: boolean;
|
||||||
showAssetSymbol?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,21 +16,18 @@ const AssetBalance = ({
|
|||||||
assetId,
|
assetId,
|
||||||
price,
|
price,
|
||||||
showAssetLink = true,
|
showAssetLink = true,
|
||||||
showAssetSymbol = false,
|
|
||||||
}: AssetBalanceProps) => {
|
}: AssetBalanceProps) => {
|
||||||
const { data: asset, loading } = useAssetDataProvider(assetId);
|
const { data: asset } = useAssetDataProvider(assetId);
|
||||||
|
|
||||||
const label =
|
const label =
|
||||||
!loading && asset && asset.decimals
|
asset && asset.decimals
|
||||||
? addDecimalsFormatNumber(price, asset.decimals)
|
? addDecimalsFormatNumber(price, asset.decimals)
|
||||||
: price;
|
: price;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inline-block">
|
<div className="inline-block">
|
||||||
<span>{label}</span>{' '}
|
<span>{label}</span>{' '}
|
||||||
{showAssetLink && asset?.id ? (
|
{showAssetLink && asset?.id ? <AssetLink assetId={assetId} /> : null}
|
||||||
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,17 +13,11 @@ const DEFAULT_DECIMALS = 18;
|
|||||||
* the governance asset first, which is set by a network parameter
|
* the governance asset first, which is set by a network parameter
|
||||||
*/
|
*/
|
||||||
const GovernanceAssetBalance = ({ price }: GovernanceAssetBalanceProps) => {
|
const GovernanceAssetBalance = ({ price }: GovernanceAssetBalanceProps) => {
|
||||||
const { data, loading } = useExplorerGovernanceAssetQuery();
|
const { data } = useExplorerGovernanceAssetQuery();
|
||||||
|
|
||||||
if (!loading && data && data.networkParameter?.value) {
|
if (data && data.networkParameter?.value) {
|
||||||
const governanceAssetId = data.networkParameter.value;
|
const governanceAssetId = data.networkParameter.value;
|
||||||
return (
|
return <AssetBalance price={price} assetId={governanceAssetId} />;
|
||||||
<AssetBalance
|
|
||||||
price={price}
|
|
||||||
showAssetSymbol={true}
|
|
||||||
assetId={governanceAssetId}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div className="inline-block">
|
<div className="inline-block">
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { useMemo } from 'react';
|
|
||||||
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||||
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridColumn } from 'ag-grid-react';
|
||||||
|
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
||||||
import { useRef, useLayoutEffect } from 'react';
|
import { useRef, useLayoutEffect } from 'react';
|
||||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
import type { RowClickedEvent } from 'ag-grid-community';
|
||||||
|
|
||||||
type AssetsTableProps = {
|
type AssetsTableProps = {
|
||||||
data: AssetFieldsFragment[] | null;
|
data: AssetFieldsFragment[] | null;
|
||||||
@@ -31,58 +31,6 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const columnDefs = useMemo<ColDef[]>(
|
|
||||||
() => [
|
|
||||||
{ headerName: t('Symbol'), field: 'symbol' },
|
|
||||||
{ headerName: t('Name'), field: 'name' },
|
|
||||||
{
|
|
||||||
flex: 2,
|
|
||||||
headerName: t('ID'),
|
|
||||||
field: 'id',
|
|
||||||
hide: window.innerWidth < BREAKPOINT_MD,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'type',
|
|
||||||
headerName: t('Type'),
|
|
||||||
field: 'source.__typename',
|
|
||||||
hide: window.innerWidth < BREAKPOINT_MD,
|
|
||||||
valueFormatter: ({ value }: { value?: string }) =>
|
|
||||||
value ? AssetTypeMapping[value].value : '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headerName: t('Status'),
|
|
||||||
field: 'status',
|
|
||||||
hide: window.innerWidth < BREAKPOINT_MD,
|
|
||||||
valueFormatter: ({ value }: { value?: string }) =>
|
|
||||||
value ? AssetStatusMapping[value].value : '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'actions',
|
|
||||||
headerName: '',
|
|
||||||
sortable: false,
|
|
||||||
filter: false,
|
|
||||||
resizable: false,
|
|
||||||
wrapText: true,
|
|
||||||
field: 'id',
|
|
||||||
cellRenderer: ({
|
|
||||||
value,
|
|
||||||
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
|
||||||
value ? (
|
|
||||||
<ButtonLink
|
|
||||||
onClick={(e) => {
|
|
||||||
navigate(value);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('View details')}
|
|
||||||
</ButtonLink>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[navigate]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AgGrid
|
<AgGrid
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@@ -98,11 +46,60 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
filterParams: { buttons: ['reset'] },
|
filterParams: { buttons: ['reset'] },
|
||||||
autoHeight: true,
|
autoHeight: true,
|
||||||
}}
|
}}
|
||||||
columnDefs={columnDefs}
|
|
||||||
suppressCellFocus={true}
|
suppressCellFocus={true}
|
||||||
onRowClicked={({ data }: RowClickedEvent) => {
|
onRowClicked={({ data }: RowClickedEvent) => {
|
||||||
navigate(data.id);
|
navigate(data.id);
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<AgGridColumn headerName={t('Symbol')} field="symbol" />
|
||||||
|
<AgGridColumn headerName={t('Name')} field="name" />
|
||||||
|
<AgGridColumn
|
||||||
|
flex="2"
|
||||||
|
headerName={t('ID')}
|
||||||
|
field="id"
|
||||||
|
hide={window.innerWidth < BREAKPOINT_MD}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="type"
|
||||||
|
headerName={t('Type')}
|
||||||
|
field="source.__typename"
|
||||||
|
hide={window.innerWidth < BREAKPOINT_MD}
|
||||||
|
valueFormatter={({ value }: { value?: string }) =>
|
||||||
|
value && AssetTypeMapping[value].value
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
headerName={t('Status')}
|
||||||
|
field="status"
|
||||||
|
hide={window.innerWidth < BREAKPOINT_MD}
|
||||||
|
valueFormatter={({ value }: { value?: string }) =>
|
||||||
|
value && AssetStatusMapping[value].value
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="actions"
|
||||||
|
headerName=""
|
||||||
|
sortable={false}
|
||||||
|
filter={false}
|
||||||
|
resizable={false}
|
||||||
|
wrapText={true}
|
||||||
|
field="id"
|
||||||
|
cellRenderer={({
|
||||||
|
value,
|
||||||
|
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
||||||
|
value ? (
|
||||||
|
<ButtonLink
|
||||||
|
onClick={(e) => {
|
||||||
|
navigate(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('View details')}
|
||||||
|
</ButtonLink>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AgGrid>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,29 @@
|
|||||||
import WS from 'jest-websocket-mock';
|
import WS from 'jest-websocket-mock';
|
||||||
import { render, screen } from '@testing-library/react';
|
import useWebSocket from 'react-use-websocket';
|
||||||
|
import {
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
fireEvent,
|
||||||
|
act,
|
||||||
|
waitFor,
|
||||||
|
} from '@testing-library/react';
|
||||||
|
import { TendermintWebsocketContext } from '../../contexts/websocket/tendermint-websocket-context';
|
||||||
import { BlocksRefetch } from './blocks-refetch';
|
import { BlocksRefetch } from './blocks-refetch';
|
||||||
|
|
||||||
const BlocksRefetchInWebsocketProvider = ({
|
const BlocksRefetchInWebsocketProvider = ({
|
||||||
callback,
|
callback,
|
||||||
|
mocketLocation,
|
||||||
}: {
|
}: {
|
||||||
callback: () => null;
|
callback: () => null;
|
||||||
|
mocketLocation: string;
|
||||||
}) => {
|
}) => {
|
||||||
return <BlocksRefetch refetch={callback} />;
|
const contextShape = useWebSocket(mocketLocation);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TendermintWebsocketContext.Provider value={{ ...contextShape }}>
|
||||||
|
<BlocksRefetch refetch={callback} />
|
||||||
|
</TendermintWebsocketContext.Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Blocks refetch', () => {
|
describe('Blocks refetch', () => {
|
||||||
@@ -16,8 +32,111 @@ describe('Blocks refetch', () => {
|
|||||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||||
new WebSocket(mocketLocation);
|
new WebSocket(mocketLocation);
|
||||||
|
|
||||||
render(<BlocksRefetchInWebsocketProvider callback={() => null} />);
|
render(
|
||||||
|
<BlocksRefetchInWebsocketProvider
|
||||||
|
callback={() => null}
|
||||||
|
mocketLocation={mocketLocation}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
await mocket.connected;
|
||||||
|
expect(screen.getByTestId('new-blocks')).toHaveTextContent('new blocks');
|
||||||
expect(screen.getByTestId('refresh')).toBeInTheDocument();
|
expect(screen.getByTestId('refresh')).toBeInTheDocument();
|
||||||
mocket.close();
|
mocket.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should initiate callback when the button is clicked', async () => {
|
||||||
|
const mocketLocation = 'wss:localhost:3003';
|
||||||
|
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||||
|
new WebSocket(mocketLocation);
|
||||||
|
|
||||||
|
const callback = jest.fn();
|
||||||
|
render(
|
||||||
|
<BlocksRefetchInWebsocketProvider
|
||||||
|
callback={callback}
|
||||||
|
mocketLocation={mocketLocation}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
await mocket.connected;
|
||||||
|
const button = screen.getByTestId('refresh');
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
fireEvent.click(button);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(callback.mock.calls.length).toEqual(1);
|
||||||
|
mocket.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show new blocks as websocket is correctly updated', async () => {
|
||||||
|
const mocketLocation = 'wss:localhost:3004';
|
||||||
|
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||||
|
new WebSocket(mocketLocation);
|
||||||
|
render(
|
||||||
|
<BlocksRefetchInWebsocketProvider
|
||||||
|
callback={() => null}
|
||||||
|
mocketLocation={mocketLocation}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
await mocket.connected;
|
||||||
|
|
||||||
|
// Ensuring we send an ID equal to the one the client subscribed with.
|
||||||
|
await waitFor(() => expect(mocket.messages.length).toEqual(1));
|
||||||
|
// @ts-ignore id on messages
|
||||||
|
const id = mocket.messages[0].id;
|
||||||
|
|
||||||
|
const newBlockMessage = {
|
||||||
|
id,
|
||||||
|
result: {
|
||||||
|
query: "tm.event = 'NewBlock'",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(screen.getByTestId('new-blocks')).toHaveTextContent('0 new blocks');
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
mocket.send(newBlockMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('new-blocks')).toHaveTextContent('1 new blocks');
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
mocket.send(newBlockMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('new-blocks')).toHaveTextContent('2 new blocks');
|
||||||
|
mocket.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will not show new blocks if websocket has wrong ID', async () => {
|
||||||
|
const mocketLocation = 'wss:localhost:3005';
|
||||||
|
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||||
|
new WebSocket(mocketLocation);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<BlocksRefetchInWebsocketProvider
|
||||||
|
callback={() => null}
|
||||||
|
mocketLocation={mocketLocation}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
await mocket.connected;
|
||||||
|
|
||||||
|
// Ensuring we send an ID equal to the one the client subscribed with.
|
||||||
|
await waitFor(() => expect(mocket.messages.length).toEqual(1));
|
||||||
|
|
||||||
|
const newBlockMessageBadId = {
|
||||||
|
id: 'blahblahblah',
|
||||||
|
result: {
|
||||||
|
query: "tm.event = 'NewBlock'",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(screen.getByTestId('new-blocks')).toHaveTextContent('0 new blocks');
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
mocket.send(newBlockMessageBadId);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('new-blocks')).toHaveTextContent('0 new blocks');
|
||||||
|
mocket.close();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,19 +1,36 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useTendermintWebsocket } from '../../hooks/use-tendermint-websocket';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Button, Icon } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
interface BlocksRefetchProps {
|
interface BlocksRefetchProps {
|
||||||
refetch: () => void;
|
refetch: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BlocksRefetch = ({ refetch }: BlocksRefetchProps) => {
|
export const BlocksRefetch = ({ refetch }: BlocksRefetchProps) => {
|
||||||
|
const [blocksToLoad, setBlocksToLoad] = useState<number>(0);
|
||||||
|
|
||||||
|
const { messages } = useTendermintWebsocket({
|
||||||
|
query: "tm.event = 'NewBlock'",
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (messages.length > 0) {
|
||||||
|
setBlocksToLoad((prev) => prev + 1);
|
||||||
|
}
|
||||||
|
}, [messages]);
|
||||||
|
|
||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
refetch();
|
refetch();
|
||||||
|
setBlocksToLoad(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button onClick={refresh} data-testid="refresh" size="xs">
|
<div className="mb-4">
|
||||||
<Icon name="refresh" className="!align-baseline mr-2" size={3} />
|
<span data-testid="new-blocks">{blocksToLoad} new blocks - </span>
|
||||||
{t('Load new')}
|
<ButtonLink onClick={refresh} data-testid="refresh">
|
||||||
</Button>
|
{t('refresh to see latest')}
|
||||||
|
</ButtonLink>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,75 +1,70 @@
|
|||||||
import {
|
import { NodeSwitcherDialog, useEnvironment } from '@vegaprotocol/environment';
|
||||||
useEnvironment,
|
|
||||||
useNodeSwitcherStore,
|
|
||||||
} from '@vegaprotocol/environment';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||||
import { Link, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink, Link } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useMemo } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { ENV } from '../../config/env';
|
import { ENV } from '../../config/env';
|
||||||
import { Routes } from '../../routes/route-names';
|
|
||||||
import { Link as RouteLink } from 'react-router-dom';
|
|
||||||
|
|
||||||
export const Footer = () => {
|
export const Footer = () => {
|
||||||
const { VEGA_URL, GIT_COMMIT_HASH, GIT_ORIGIN_URL } = useEnvironment();
|
const { VEGA_URL, GIT_COMMIT_HASH, GIT_ORIGIN_URL } = useEnvironment();
|
||||||
const setNodeSwitcherOpen = useNodeSwitcherStore(
|
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false);
|
||||||
(store) => store.setDialogOpen
|
|
||||||
);
|
|
||||||
|
|
||||||
const { screenSize } = useScreenDimensions();
|
const { screenSize } = useScreenDimensions();
|
||||||
const showFullFeedbackLabel = useMemo(
|
const showFullFeedbackLabel = useMemo(
|
||||||
() => ['md', 'lg', 'xl', 'xxl', 'xxxl'].includes(screenSize),
|
() => ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize),
|
||||||
[screenSize]
|
[screenSize]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<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">
|
<footer className="grid grid-rows-2 grid-cols-[1fr_auto] text-xs md:text-md md:flex md:col-span-2 px-4 py-2 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200">
|
||||||
{GIT_COMMIT_HASH && (
|
<div className="flex justify-between gap-2 align-middle">
|
||||||
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
{GIT_COMMIT_HASH && (
|
||||||
<p data-testid="git-commit-hash">
|
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
||||||
{t('Version')}:{' '}
|
<p data-testid="git-commit-hash">
|
||||||
<Link
|
{t('Version')}:{' '}
|
||||||
href={
|
<Link
|
||||||
GIT_ORIGIN_URL
|
href={
|
||||||
? `${GIT_ORIGIN_URL}/commit/${GIT_COMMIT_HASH}`
|
GIT_ORIGIN_URL
|
||||||
: undefined
|
? `${GIT_ORIGIN_URL}/commit/${GIT_COMMIT_HASH}`
|
||||||
}
|
: undefined
|
||||||
target={GIT_ORIGIN_URL ? '_blank' : undefined}
|
}
|
||||||
>
|
target={GIT_ORIGIN_URL ? '_blank' : undefined}
|
||||||
{GIT_COMMIT_HASH}
|
>
|
||||||
</Link>
|
{GIT_COMMIT_HASH}
|
||||||
</p>
|
</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="content-center flex pl-2 md:border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
||||||
|
{VEGA_URL && <NodeUrl url={VEGA_URL} />}
|
||||||
|
<Link className="ml-2" onClick={() => setNodeSwitcherOpen(true)}>
|
||||||
|
{t('Change')}
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="content-center flex pl-2 md:border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
|
||||||
{VEGA_URL && <NodeUrl url={VEGA_URL} />}
|
|
||||||
<Link className="ml-2" onClick={() => setNodeSwitcherOpen(true)}>
|
|
||||||
{t('Change')}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{ENV.addresses.feedback ? (
|
|
||||||
<div className="flex pl-2 content-center">
|
<div className="flex pl-2 content-center">
|
||||||
<ExternalLink href={ENV.addresses.feedback}>
|
<ExternalLink href={ENV.addresses.feedback}>
|
||||||
{showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')}
|
{showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')}
|
||||||
</ExternalLink>
|
</ExternalLink>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
</div>
|
||||||
</div>
|
</footer>
|
||||||
<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">
|
<NodeSwitcherDialog
|
||||||
<RouteLink to={`/${Routes.DISCLAIMER}`} className="underline">
|
open={nodeSwitcherOpen}
|
||||||
Disclaimer
|
setOpen={setNodeSwitcherOpen}
|
||||||
</RouteLink>
|
/>
|
||||||
</div>
|
</>
|
||||||
</footer>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NodeUrl = ({ url }: { url: string }) => {
|
const NodeUrl = ({ url }: { url: string }) => {
|
||||||
// get base url from api url, api sub domain
|
// get base url from api url, api sub domain
|
||||||
const urlObj = new URL(url);
|
const urlObj = new URL(url);
|
||||||
const nodeUrl = urlObj.origin.replace(/^[^.]+\./g, '');
|
const nodeUrl = urlObj.origin.replace(/^[^.]+\./g, '');
|
||||||
return <span className="cursor-default">{nodeUrl}</span>;
|
return (
|
||||||
|
<Link href={'https://' + nodeUrl} target="_blank">
|
||||||
|
{nodeUrl}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { Header } from './header';
|
|||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
|
||||||
jest.mock('@vegaprotocol/environment', () => ({
|
jest.mock('@vegaprotocol/environment', () => ({
|
||||||
...jest.requireActual('@vegaprotocol/environment'),
|
|
||||||
NetworkSwitcher: () => (
|
NetworkSwitcher: () => (
|
||||||
<div data-testid="network-switcher">NetworkSwitcher</div>
|
<div data-testid="network-switcher">NetworkSwitcher</div>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
export interface InfoBlockProps {
|
export interface InfoBlockProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export const AssetLink = ({
|
|||||||
if (asDialog) {
|
if (asDialog) {
|
||||||
open(assetId, e.target as HTMLElement);
|
open(assetId, e.target as HTMLElement);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/${Routes.ASSETS}/${asset?.id}`);
|
navigate(`${Routes.ASSETS}/${asset?.id}`);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,98 +1,33 @@
|
|||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import PartyLink from './party-link';
|
import PartyLink from './party-link';
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
|
||||||
import { ExplorerNodeNamesDocument } from '../../../routes/validators/__generated__/NodeNames';
|
|
||||||
import { act } from 'react-dom/test-utils';
|
|
||||||
const zeroes =
|
|
||||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
|
||||||
const mocks = [
|
|
||||||
{
|
|
||||||
request: {
|
|
||||||
query: ExplorerNodeNamesDocument,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
nodesConnection: {
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
id: '1',
|
|
||||||
name: 'Validator Node',
|
|
||||||
pubkey:
|
|
||||||
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e',
|
|
||||||
tmPubkey: 'tmPubkey1',
|
|
||||||
ethereumAddress: '0x123456789',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
id: '2',
|
|
||||||
name: 'Node 2',
|
|
||||||
pubkey: 'pubkey2',
|
|
||||||
tmPubkey: 'tmPubkey2',
|
|
||||||
ethereumAddress: '0xabcdef123',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
describe('PartyLink', () => {
|
describe('PartyLink', () => {
|
||||||
it('renders Network for 000.000 party', () => {
|
it('renders Network for 000.000 party', () => {
|
||||||
const screen = render(
|
const zeroes =
|
||||||
<MockedProvider>
|
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
<PartyLink id={zeroes} />
|
const screen = render(<PartyLink id={zeroes} />);
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(screen.getByText('Network')).toBeInTheDocument();
|
expect(screen.getByText('Network')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders Network for network party', () => {
|
it('renders Network for network party', () => {
|
||||||
const screen = render(
|
const screen = render(<PartyLink id="network" />);
|
||||||
<MockedProvider>
|
|
||||||
<PartyLink id="network" />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(screen.getByText('Network')).toBeInTheDocument();
|
expect(screen.getByText('Network')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders ID with no link for invalid party', () => {
|
it('renders ID with no link for invalid party', () => {
|
||||||
const screen = render(
|
const screen = render(<PartyLink id="this-party-is-not-valid" />);
|
||||||
<MockedProvider>
|
|
||||||
<PartyLink id="this-party-is-not-valid" />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(screen.getByTestId('invalid-party')).toBeInTheDocument();
|
expect(screen.getByTestId('invalid-party')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('if the key is a validator, render their name instead', async () => {
|
|
||||||
const screen = render(
|
|
||||||
<MockedProvider mocks={mocks}>
|
|
||||||
<MemoryRouter>
|
|
||||||
<PartyLink id="13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e" />
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
// Wait for hook to update with mock data
|
|
||||||
await act(() => new Promise((resolve) => setTimeout(resolve, 0)));
|
|
||||||
await expect(screen.getByText('Validator Node')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('links a valid party to the party page', () => {
|
it('links a valid party to the party page', () => {
|
||||||
const aValidParty =
|
const aValidParty =
|
||||||
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e';
|
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e';
|
||||||
|
|
||||||
const screen = render(
|
const screen = render(
|
||||||
<MockedProvider>
|
<MemoryRouter>
|
||||||
<MemoryRouter>
|
<PartyLink id={aValidParty} />
|
||||||
<PartyLink id={aValidParty} />
|
</MemoryRouter>
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const el = screen.getByText(aValidParty);
|
const el = screen.getByText(aValidParty);
|
||||||
|
|||||||
@@ -1,44 +1,22 @@
|
|||||||
import { Routes } from '../../../routes/route-names';
|
import { Routes } from '../../../routes/route-names';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { useMemo, type ComponentProps } from 'react';
|
import type { ComponentProps } from 'react';
|
||||||
import Hash from '../hash';
|
import Hash from '../hash';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { isValidPartyId } from '../../../routes/parties/id/components/party-id-error';
|
import { isValidPartyId } from '../../../routes/parties/id/components/party-id-error';
|
||||||
import { Icon, truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
|
|
||||||
import type { ExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
|
|
||||||
|
|
||||||
export const SPECIAL_CASE_NETWORK_ID =
|
export const SPECIAL_CASE_NETWORK_ID =
|
||||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
export const SPECIAL_CASE_NETWORK = 'network';
|
export const SPECIAL_CASE_NETWORK = 'network';
|
||||||
|
|
||||||
export function getNameForParty(id: string, data?: ExplorerNodeNamesQuery) {
|
|
||||||
if (!data || data?.nodesConnection?.edges?.length === 0) {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
const validator = data.nodesConnection.edges?.find((e) => {
|
|
||||||
return e?.node.pubkey === id;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (validator) {
|
|
||||||
return validator.node.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PartyLinkProps = Partial<ComponentProps<typeof Link>> & {
|
export type PartyLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||||
id: string;
|
id: string;
|
||||||
truncate?: boolean;
|
truncate?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
||||||
const { data } = useExplorerNodeNamesQuery();
|
|
||||||
const name = useMemo(() => getNameForParty(id, data), [data, id]);
|
|
||||||
const useName = name !== id;
|
|
||||||
|
|
||||||
// Some transactions will involve the 'network' party, which is alias for '000...000'
|
// Some transactions will involve the 'network' party, which is alias for '000...000'
|
||||||
// The party page does not handle this nicely, so in this case we render the word 'Network'
|
// The party page does not handle this nicely, so in this case we render the word 'Network'
|
||||||
if (id === SPECIAL_CASE_NETWORK || id === SPECIAL_CASE_NETWORK_ID) {
|
if (id === SPECIAL_CASE_NETWORK || id === SPECIAL_CASE_NETWORK_ID) {
|
||||||
@@ -60,20 +38,13 @@ const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="whitespace-nowrap">
|
<Link
|
||||||
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
className="underline font-mono"
|
||||||
<Link
|
{...props}
|
||||||
className="underline font-mono"
|
to={`/${Routes.PARTIES}/${id}`}
|
||||||
{...props}
|
>
|
||||||
to={`/${Routes.PARTIES}/${id}`}
|
<Hash text={truncate ? truncateMiddle(id) : id} />
|
||||||
>
|
</Link>
|
||||||
{useName ? (
|
|
||||||
name
|
|
||||||
) : (
|
|
||||||
<Hash text={truncate ? truncateMiddle(id, 4, 4) : id} />
|
|
||||||
)}
|
|
||||||
</Link>
|
|
||||||
</span>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
import type { MarketInfoWithData } from '@vegaprotocol/market-info';
|
||||||
import { PriceMonitoringBoundsInfoPanel } from '@vegaprotocol/markets';
|
import { LiquidityInfoPanel } from '@vegaprotocol/market-info';
|
||||||
|
import { LiquidityMonitoringParametersInfoPanel } from '@vegaprotocol/market-info';
|
||||||
import {
|
import {
|
||||||
LiquidityInfoPanel,
|
|
||||||
LiquidityMonitoringParametersInfoPanel,
|
|
||||||
InstrumentInfoPanel,
|
InstrumentInfoPanel,
|
||||||
KeyDetailsInfoPanel,
|
KeyDetailsInfoPanel,
|
||||||
LiquidityPriceRangeInfoPanel,
|
LiquidityPriceRangeInfoPanel,
|
||||||
@@ -13,96 +12,117 @@ import {
|
|||||||
RiskModelInfoPanel,
|
RiskModelInfoPanel,
|
||||||
RiskParametersInfoPanel,
|
RiskParametersInfoPanel,
|
||||||
SettlementAssetInfoPanel,
|
SettlementAssetInfoPanel,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/market-info';
|
||||||
import { MarketInfoTable } from '@vegaprotocol/markets';
|
import { MarketInfoTable } from '@vegaprotocol/market-info';
|
||||||
import type { DataSourceDefinition } from '@vegaprotocol/types';
|
import { Link } from 'react-router-dom';
|
||||||
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 settlementData = market.tradableInstrument.instrument.product
|
const panels = [
|
||||||
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
{
|
||||||
const terminationData = market.tradableInstrument.instrument.product
|
title: t('Key details'),
|
||||||
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
content: <KeyDetailsInfoPanel noBorder={false} market={market} />,
|
||||||
|
},
|
||||||
const getSigners = (data: DataSourceDefinition) => {
|
{
|
||||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
title: t('Instrument'),
|
||||||
const signers = data.sourceType.sourceType.signers || [];
|
content: <InstrumentInfoPanel noBorder={false} market={market} />,
|
||||||
|
},
|
||||||
return signers.map(({ signer }, i) => {
|
{
|
||||||
return (
|
title: t('Settlement asset'),
|
||||||
(signer.__typename === 'ETHAddress' && signer.address) ||
|
content: <SettlementAssetInfoPanel market={market} noBorder={false} />,
|
||||||
(signer.__typename === 'PubKey' && signer.key)
|
},
|
||||||
);
|
{
|
||||||
});
|
title: t('Metadata'),
|
||||||
}
|
content: <MetadataInfoPanel noBorder={false} market={market} />,
|
||||||
return [];
|
},
|
||||||
};
|
{
|
||||||
|
title: t('Risk model'),
|
||||||
const showTwoOracles = isEqual(
|
content: <RiskModelInfoPanel noBorder={false} market={market} />,
|
||||||
getSigners(settlementData),
|
},
|
||||||
getSigners(terminationData)
|
{
|
||||||
);
|
title: t('Risk parameters'),
|
||||||
|
content: <RiskParametersInfoPanel noBorder={false} market={market} />,
|
||||||
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
|
},
|
||||||
|
{
|
||||||
return (
|
title: t('Risk factors'),
|
||||||
<div>
|
content: <RiskFactorsInfoPanel noBorder={false} market={market} />,
|
||||||
<h2 className={headerClassName}>{t('Key details')}</h2>
|
},
|
||||||
<KeyDetailsInfoPanel market={market} />
|
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||||
<h2 className={headerClassName}>{t('Instrument')}</h2>
|
(trigger, i) => ({
|
||||||
<InstrumentInfoPanel market={market} />
|
title: t(`Price monitoring trigger ${i + 1}`),
|
||||||
<h2 className={headerClassName}>{t('Settlement asset')}</h2>
|
content: <MarketInfoTable noBorder={false} data={trigger} />,
|
||||||
<SettlementAssetInfoPanel market={market} />
|
})
|
||||||
<h2 className={headerClassName}>{t('Metadata')}</h2>
|
),
|
||||||
<MetadataInfoPanel market={market} />
|
...(market.data?.priceMonitoringBounds || []).map((trigger, i) => ({
|
||||||
<h2 className={headerClassName}>{t('Risk model')}</h2>
|
title: t(`Price monitoring bound ${i + 1}`),
|
||||||
<RiskModelInfoPanel market={market} />
|
content: (
|
||||||
<h2 className={headerClassName}>{t('Risk parameters')}</h2>
|
|
||||||
<RiskParametersInfoPanel market={market} />
|
|
||||||
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
|
||||||
<RiskFactorsInfoPanel market={market} />
|
|
||||||
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
|
||||||
<>
|
<>
|
||||||
<h2 className={headerClassName}>
|
<MarketInfoTable
|
||||||
{t('Price monitoring bounds %s', [(i + 1).toString()])}
|
noBorder={false}
|
||||||
</h2>
|
data={trigger}
|
||||||
<PriceMonitoringBoundsInfoPanel
|
decimalPlaces={market.decimalPlaces}
|
||||||
market={market}
|
omits={['referencePrice', '__typename']}
|
||||||
triggerIndex={i + 1}
|
/>
|
||||||
|
<MarketInfoTable
|
||||||
|
noBorder={false}
|
||||||
|
data={{ referencePrice: trigger.referencePrice }}
|
||||||
|
decimalPlaces={
|
||||||
|
market.tradableInstrument.instrument.product.settlementAsset
|
||||||
|
.decimals
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
{
|
||||||
|
title: t('Liquidity monitoring parameters'),
|
||||||
|
content: (
|
||||||
|
<LiquidityMonitoringParametersInfoPanel
|
||||||
|
noBorder={false}
|
||||||
|
market={market}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Liquidity'),
|
||||||
|
content: <LiquidityInfoPanel market={market} noBorder={false} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Liquidity price range'),
|
||||||
|
content: (
|
||||||
|
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Oracle'),
|
||||||
|
content: (
|
||||||
|
<OracleInfoPanel noBorder={false} market={market}>
|
||||||
|
<Link
|
||||||
|
className="text-xs hover:underline"
|
||||||
|
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData.id}`}
|
||||||
|
>
|
||||||
|
{t('View settlement data oracle specification')}
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
className="text-xs hover:underline"
|
||||||
|
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForTradingTermination.id}`}
|
||||||
|
>
|
||||||
|
{t('View termination oracle specification')}
|
||||||
|
</Link>
|
||||||
|
</OracleInfoPanel>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{panels.map((p) => (
|
||||||
|
<div key={p.title} className="mb-3">
|
||||||
|
<h2 className="font-alpha calt text-xl">{p.title}</h2>
|
||||||
|
{p.content}
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
{(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
</>
|
||||||
(trigger, i) => (
|
|
||||||
<>
|
|
||||||
<h2 className={headerClassName}>
|
|
||||||
{t('Price monitoring settings %s', [(i + 1).toString()])}
|
|
||||||
</h2>
|
|
||||||
<MarketInfoTable data={trigger} key={i} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
|
||||||
<LiquidityMonitoringParametersInfoPanel market={market} />
|
|
||||||
<h2 className={headerClassName}>{t('Liquidity')}</h2>
|
|
||||||
<LiquidityInfoPanel market={market} />
|
|
||||||
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
|
||||||
<LiquidityPriceRangeInfoPanel market={market} />
|
|
||||||
{showTwoOracles ? (
|
|
||||||
<>
|
|
||||||
<h2 className={headerClassName}>{t('Settlement oracle')}</h2>
|
|
||||||
<OracleInfoPanel market={market} type="settlementData" />
|
|
||||||
<h2 className={headerClassName}>{t('Termination oracle')}</h2>
|
|
||||||
<OracleInfoPanel market={market} type="termination" />
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<h2 className={headerClassName}>{t('Oracle')}</h2>
|
|
||||||
<OracleInfoPanel market={market} type="settlementData" />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { useMemo } from 'react';
|
import type { MarketFieldsFragment } from '@vegaprotocol/market-list';
|
||||||
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 { AgGridColumn } from 'ag-grid-react';
|
||||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type {
|
import type {
|
||||||
VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
VegaValueGetterParams,
|
VegaValueGetterParams,
|
||||||
@@ -40,79 +39,6 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const columnDefs = useMemo<ColDef[]>(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
colId: 'code',
|
|
||||||
headerName: t('Code'),
|
|
||||||
field: 'tradableInstrument.instrument.code',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'name',
|
|
||||||
headerName: t('Name'),
|
|
||||||
field: 'tradableInstrument.instrument.name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headerName: t('Status'),
|
|
||||||
field: 'state',
|
|
||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
|
||||||
valueGetter: ({
|
|
||||||
data,
|
|
||||||
}: VegaValueGetterParams<MarketFieldsFragment>) => {
|
|
||||||
return data?.state ? MarketStateMapping[data?.state] : '-';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'asset',
|
|
||||||
headerName: t('Settlement asset'),
|
|
||||||
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
|
||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
|
||||||
cellRenderer: ({
|
|
||||||
data,
|
|
||||||
}: VegaICellRendererParams<
|
|
||||||
MarketFieldsFragment,
|
|
||||||
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
|
||||||
>) => {
|
|
||||||
const value =
|
|
||||||
data?.tradableInstrument.instrument.product.settlementAsset;
|
|
||||||
return value ? (
|
|
||||||
<ButtonLink
|
|
||||||
onClick={(e) => {
|
|
||||||
openAssetDetailsDialog(value.id, e.target as HTMLElement);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{value.symbol}
|
|
||||||
</ButtonLink>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
flex: 2,
|
|
||||||
headerName: t('Market ID'),
|
|
||||||
field: 'id',
|
|
||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'actions',
|
|
||||||
headerName: '',
|
|
||||||
field: 'id',
|
|
||||||
cellRenderer: ({
|
|
||||||
value,
|
|
||||||
}: VegaICellRendererParams<MarketFieldsFragment, 'id'>) =>
|
|
||||||
value ? (
|
|
||||||
<Link className="underline" to={value}>
|
|
||||||
{t('View details')}
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[openAssetDetailsDialog]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AgGrid
|
<AgGrid
|
||||||
ref={gridRef}
|
ref={gridRef}
|
||||||
@@ -128,13 +54,79 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
filterParams: { buttons: ['reset'] },
|
filterParams: { buttons: ['reset'] },
|
||||||
autoHeight: true,
|
autoHeight: true,
|
||||||
}}
|
}}
|
||||||
columnDefs={columnDefs}
|
|
||||||
suppressCellFocus={true}
|
suppressCellFocus={true}
|
||||||
onRowClicked={({ data, event }: RowClickedEvent) => {
|
onRowClicked={({ data, event }: RowClickedEvent) => {
|
||||||
if ((event?.target as HTMLElement).tagName.toUpperCase() !== 'BUTTON') {
|
if ((event?.target as HTMLElement).tagName.toUpperCase() !== 'BUTTON') {
|
||||||
navigate(data.id);
|
navigate(data.id);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="code"
|
||||||
|
headerName={t('Code')}
|
||||||
|
field="tradableInstrument.instrument.code"
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="name"
|
||||||
|
headerName={t('Name')}
|
||||||
|
field="tradableInstrument.instrument.name"
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
headerName={t('Status')}
|
||||||
|
field="state"
|
||||||
|
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||||
|
valueGetter={({
|
||||||
|
data,
|
||||||
|
}: VegaValueGetterParams<MarketFieldsFragment, 'state'>) => {
|
||||||
|
return data?.state ? MarketStateMapping[data?.state] : '-';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="asset"
|
||||||
|
headerName={t('Settlement asset')}
|
||||||
|
field="tradableInstrument.instrument.product.settlementAsset"
|
||||||
|
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||||
|
cellRenderer={({
|
||||||
|
value,
|
||||||
|
}: VegaICellRendererParams<
|
||||||
|
MarketFieldsFragment,
|
||||||
|
'tradableInstrument.instrument.product.settlementAsset'
|
||||||
|
>) =>
|
||||||
|
value ? (
|
||||||
|
<ButtonLink
|
||||||
|
onClick={(e) => {
|
||||||
|
openAssetDetailsDialog(value.id, e.target as HTMLElement);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{value.symbol}
|
||||||
|
</ButtonLink>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
flex={2}
|
||||||
|
headerName={t('Market ID')}
|
||||||
|
field="id"
|
||||||
|
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="actions"
|
||||||
|
headerName=""
|
||||||
|
field="id"
|
||||||
|
cellRenderer={({
|
||||||
|
value,
|
||||||
|
}: VegaICellRendererParams<MarketFieldsFragment, 'id'>) =>
|
||||||
|
value ? (
|
||||||
|
<Link className="underline" to={value}>
|
||||||
|
{t('View details')}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AgGrid>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ fragment ExplorerDeterministicOrderFields on Order {
|
|||||||
remaining
|
remaining
|
||||||
size
|
size
|
||||||
rejectionReason
|
rejectionReason
|
||||||
peggedOrder {
|
|
||||||
reference
|
|
||||||
offset
|
|
||||||
}
|
|
||||||
party {
|
party {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } };
|
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } };
|
||||||
|
|
||||||
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
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 } } } } } };
|
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } } };
|
||||||
|
|
||||||
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
||||||
fragment ExplorerDeterministicOrderFields on Order {
|
fragment ExplorerDeterministicOrderFields on Order {
|
||||||
@@ -29,10 +29,6 @@ export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
|||||||
remaining
|
remaining
|
||||||
size
|
size
|
||||||
rejectionReason
|
rejectionReason
|
||||||
peggedOrder {
|
|
||||||
reference
|
|
||||||
offset
|
|
||||||
}
|
|
||||||
party {
|
party {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type Amend = components['schemas']['v1OrderAmendment'];
|
|||||||
|
|
||||||
function renderAmendOrderDetails(
|
function renderAmendOrderDetails(
|
||||||
id: string,
|
id: string,
|
||||||
version: number | undefined,
|
version: number,
|
||||||
amend: Amend,
|
amend: Amend,
|
||||||
mocks: MockedResponse[]
|
mocks: MockedResponse[]
|
||||||
) {
|
) {
|
||||||
@@ -25,11 +25,7 @@ function renderAmendOrderDetails(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderExistingAmend(
|
function renderExistingAmend(id: string, version: number, amend: Amend) {
|
||||||
id: string,
|
|
||||||
version: number | undefined,
|
|
||||||
amend: Amend
|
|
||||||
) {
|
|
||||||
const mocks = [
|
const mocks = [
|
||||||
{
|
{
|
||||||
request: {
|
request: {
|
||||||
@@ -53,7 +49,6 @@ function renderExistingAmend(
|
|||||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||||
price: '200',
|
price: '200',
|
||||||
side: 'BUY',
|
side: 'BUY',
|
||||||
peggedOrder: null,
|
|
||||||
remaining: '99',
|
remaining: '99',
|
||||||
rejectionReason: 'rejection',
|
rejectionReason: 'rejection',
|
||||||
reference: '123',
|
reference: '123',
|
||||||
@@ -82,56 +77,6 @@ function renderExistingAmend(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
request: {
|
|
||||||
query: ExplorerDeterministicOrderDocument,
|
|
||||||
variables: {
|
|
||||||
orderId: '123',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
orderByID: {
|
|
||||||
__typename: 'Order',
|
|
||||||
id: '123',
|
|
||||||
type: 'GTT',
|
|
||||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
|
||||||
version: 100,
|
|
||||||
createdAt: '123',
|
|
||||||
updatedAt: '456',
|
|
||||||
expiresAt: '789',
|
|
||||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
|
||||||
peggedOrder: null,
|
|
||||||
price: '200',
|
|
||||||
side: 'BUY',
|
|
||||||
remaining: '99',
|
|
||||||
rejectionReason: 'rejection',
|
|
||||||
reference: '123',
|
|
||||||
size: '200',
|
|
||||||
party: {
|
|
||||||
__typename: 'Party',
|
|
||||||
id: '234',
|
|
||||||
},
|
|
||||||
market: {
|
|
||||||
__typename: 'Market',
|
|
||||||
id: 'amend-to-order-latest-version',
|
|
||||||
state: 'STATUS_ACTIVE',
|
|
||||||
positionDecimalPlaces: 2,
|
|
||||||
decimalPlaces: '5',
|
|
||||||
tradableInstrument: {
|
|
||||||
instrument: {
|
|
||||||
name: 'amend-to-order-latest-version-test',
|
|
||||||
product: {
|
|
||||||
__typename: 'Future',
|
|
||||||
quoteName: '123',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
request: {
|
request: {
|
||||||
query: ExplorerMarketDocument,
|
query: ExplorerMarketDocument,
|
||||||
@@ -212,15 +157,4 @@ describe('Amend order details', () => {
|
|||||||
expect(await res.findByText('New price')).toBeInTheDocument();
|
expect(await res.findByText('New price')).toBeInTheDocument();
|
||||||
expect(await res.findByText('-7879')).toBeInTheDocument();
|
expect(await res.findByText('-7879')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Fetches latest version when version is not specified', async () => {
|
|
||||||
const amend: Amend = {
|
|
||||||
price: '-7879',
|
|
||||||
};
|
|
||||||
|
|
||||||
const res = renderExistingAmend('123', undefined, amend);
|
|
||||||
expect(
|
|
||||||
await res.findByText('amend-to-order-latest-version')
|
|
||||||
).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { wrapperClasses } from './deterministic-order-details';
|
|||||||
export interface AmendOrderDetailsProps {
|
export interface AmendOrderDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
amend: components['schemas']['v1OrderAmendment'];
|
amend: components['schemas']['v1OrderAmendment'];
|
||||||
// Version to fetch. Latest is provided by default
|
// Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0
|
||||||
version?: number;
|
version?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,11 +34,13 @@ export function getSideDeltaColour(delta: string): string {
|
|||||||
* @param param0
|
* @param param0
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
const AmendOrderDetails = ({
|
||||||
const variables = version ? { orderId: id, version } : { orderId: id };
|
id,
|
||||||
|
version = 0,
|
||||||
|
amend,
|
||||||
|
}: AmendOrderDetailsProps) => {
|
||||||
const { data, error } = useExplorerDeterministicOrderQuery({
|
const { data, error } = useExplorerDeterministicOrderQuery({
|
||||||
variables,
|
variables: { orderId: id, version },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error || (data && !data.orderByID)) {
|
if (error || (data && !data.orderByID)) {
|
||||||
|
|||||||
@@ -5,12 +5,11 @@ import PriceInMarket from '../price-in-market/price-in-market';
|
|||||||
import { Time } from '../time';
|
import { Time } from '../time';
|
||||||
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
||||||
import SizeInMarket from '../size-in-market/size-in-market';
|
import SizeInMarket from '../size-in-market/size-in-market';
|
||||||
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
|
||||||
|
|
||||||
export interface DeterministicOrderDetailsProps {
|
export interface DeterministicOrderDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
// Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0
|
// Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0
|
||||||
version?: number | null;
|
version?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const wrapperClasses =
|
export const wrapperClasses =
|
||||||
@@ -29,7 +28,7 @@ export const wrapperClasses =
|
|||||||
*/
|
*/
|
||||||
const DeterministicOrderDetails = ({
|
const DeterministicOrderDetails = ({
|
||||||
id,
|
id,
|
||||||
version = null,
|
version = 0,
|
||||||
}: DeterministicOrderDetailsProps) => {
|
}: DeterministicOrderDetailsProps) => {
|
||||||
const { data, error } = useExplorerDeterministicOrderQuery({
|
const { data, error } = useExplorerDeterministicOrderQuery({
|
||||||
variables: { orderId: id, version },
|
variables: { orderId: id, version },
|
||||||
@@ -69,35 +68,25 @@ const DeterministicOrderDetails = ({
|
|||||||
<span className="mx-5 text-base">@</span>
|
<span className="mx-5 text-base">@</span>
|
||||||
<PriceInMarket price={o.price} marketId={o.market.id} />
|
<PriceInMarket price={o.price} marketId={o.market.id} />
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-200">
|
<p className="text-gray-500 mb-4">
|
||||||
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
||||||
</p>
|
</p>
|
||||||
{o.peggedOrder ? (
|
|
||||||
<p className="text-gray-200">
|
|
||||||
{t('Price peg')}:{' '}
|
|
||||||
<TxOrderPeggedReference
|
|
||||||
side={o.side}
|
|
||||||
reference={o.peggedOrder.reference}
|
|
||||||
offset={o.peggedOrder.offset}
|
|
||||||
marketId={o.market.id}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{o.reference ? (
|
{o.reference ? (
|
||||||
<p className="text-gray-500 mt-4">
|
<p className="text-gray-500 mb-4">
|
||||||
<span>{t('Reference')}</span>: {o.reference}
|
<span>{t('Reference')}</span>: {o.reference}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="grid md:grid-cols-4 gap-x-6 mt-4">
|
<div className="grid md:grid-cols-4 gap-x-6">
|
||||||
<div className="mb-12 md:mb-0">
|
{version !== 0 ? null : (
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<div className="mb-12 md:mb-0">
|
||||||
{t('Status')}
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
</h2>
|
{t('Status')}
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
</h2>
|
||||||
{statusText[o.status]}
|
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
||||||
</h5>
|
{statusText[o.status]}
|
||||||
</div>
|
</h5>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="mb-12 md:mb-0">
|
<div className="mb-12 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">{t('Size')}</h2>
|
<h2 className="text-2xl font-bold text-dark mb-4">{t('Size')}</h2>
|
||||||
@@ -106,6 +95,17 @@ const DeterministicOrderDetails = ({
|
|||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{version !== 0 ? null : (
|
||||||
|
<div className="">
|
||||||
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
|
{t('Remaining')}
|
||||||
|
</h2>
|
||||||
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
|
<SizeInMarket size={o.remaining} marketId={o.market.id} />
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('Version')}
|
{t('Version')}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ const mock = {
|
|||||||
side: 'SIDE_BUY',
|
side: 'SIDE_BUY',
|
||||||
remaining: '100',
|
remaining: '100',
|
||||||
size: '100',
|
size: '100',
|
||||||
peggedOrder: null,
|
|
||||||
party: {
|
party: {
|
||||||
id: '456',
|
id: '456',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const PageHeader = ({
|
|||||||
copy = false,
|
copy = false,
|
||||||
className,
|
className,
|
||||||
}: PageHeaderProps) => {
|
}: PageHeaderProps) => {
|
||||||
const titleClasses = 'text-xl uppercase font-alpha calt';
|
const titleClasses = 'text-4xl xl:text-5xl uppercase font-alpha calt';
|
||||||
return (
|
return (
|
||||||
<header className={className}>
|
<header className={className}>
|
||||||
<span className={`${titleClasses} block`}>{prefix}</span>
|
<span className={`${titleClasses} block`}>{prefix}</span>
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
||||||
import { VoteProgress } from '@vegaprotocol/proposals';
|
import { VoteProgress } from '@vegaprotocol/proposals';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
|
import { AgGridColumn } from 'ag-grid-react';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import type {
|
import type {
|
||||||
VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
VegaValueFormatterParams,
|
VegaValueFormatterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import type { RowClickedEvent, 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 { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
|
||||||
NetworkParams,
|
|
||||||
useNetworkParams,
|
|
||||||
} from '@vegaprotocol/network-parameters';
|
|
||||||
import { ProposalStateMapping } from '@vegaprotocol/types';
|
import { ProposalStateMapping } from '@vegaprotocol/types';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
|
||||||
@@ -63,128 +61,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
title: '',
|
title: '',
|
||||||
content: null,
|
content: null,
|
||||||
});
|
});
|
||||||
const columnDefs = useMemo<ColDef[]>(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
colId: 'title',
|
|
||||||
headerName: t('Title'),
|
|
||||||
field: 'rationale.title',
|
|
||||||
flex: 2,
|
|
||||||
wrapText: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'type',
|
|
||||||
maxWidth: 180,
|
|
||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
|
||||||
headerName: t('Type'),
|
|
||||||
field: 'terms.change.__typename',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
maxWidth: 100,
|
|
||||||
headerName: t('State'),
|
|
||||||
field: 'state',
|
|
||||||
valueFormatter: ({
|
|
||||||
value,
|
|
||||||
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) => {
|
|
||||||
return value ? ProposalStateMapping[value] : '-';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'voting',
|
|
||||||
maxWidth: 100,
|
|
||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
|
||||||
headerName: t('Voting'),
|
|
||||||
cellRenderer: ({
|
|
||||||
data,
|
|
||||||
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
|
||||||
if (data) {
|
|
||||||
const yesTokens = new BigNumber(data.votes.yes.totalTokens);
|
|
||||||
const noTokens = new BigNumber(data.votes.no.totalTokens);
|
|
||||||
const totalTokensVoted = yesTokens.plus(noTokens);
|
|
||||||
const yesPercentage = totalTokensVoted.isZero()
|
|
||||||
? new BigNumber(0)
|
|
||||||
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
|
||||||
return (
|
|
||||||
<div className="uppercase flex h-full items-center justify-center pt-2">
|
|
||||||
<VoteProgress
|
|
||||||
threshold={requiredMajorityPercentage}
|
|
||||||
progress={yesPercentage}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return '-';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'cDate',
|
|
||||||
maxWidth: 150,
|
|
||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
|
||||||
headerName: t('Closing date'),
|
|
||||||
field: 'terms.closingDatetime',
|
|
||||||
valueFormatter: ({
|
|
||||||
value,
|
|
||||||
}: VegaValueFormatterParams<
|
|
||||||
ProposalListFieldsFragment,
|
|
||||||
'terms.closingDatetime'
|
|
||||||
>) => {
|
|
||||||
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'eDate',
|
|
||||||
maxWidth: 150,
|
|
||||||
hide: window.innerWidth <= BREAKPOINT_MD,
|
|
||||||
headerName: t('Enactment date'),
|
|
||||||
field: 'terms.enactmentDatetime',
|
|
||||||
valueFormatte: ({
|
|
||||||
value,
|
|
||||||
}: VegaValueFormatterParams<
|
|
||||||
ProposalListFieldsFragment,
|
|
||||||
'terms.enactmentDatetime'
|
|
||||||
>) => {
|
|
||||||
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
colId: 'actions',
|
|
||||||
minWidth: window.innerWidth > BREAKPOINT_MD ? 221 : 80,
|
|
||||||
maxWidth: 221,
|
|
||||||
sortable: false,
|
|
||||||
filter: false,
|
|
||||||
resizable: false,
|
|
||||||
cellRenderer: ({
|
|
||||||
data,
|
|
||||||
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
|
||||||
const proposalPage = tokenLink(
|
|
||||||
TOKEN_PROPOSAL.replace(':id', data?.id || '')
|
|
||||||
);
|
|
||||||
const openDialog = () => {
|
|
||||||
if (!data) return;
|
|
||||||
setDialog({
|
|
||||||
open: true,
|
|
||||||
title: data.rationale.title,
|
|
||||||
content: data.terms,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="pb-1">
|
|
||||||
<button className="underline max-md:hidden" onClick={openDialog}>
|
|
||||||
{t('View terms')}
|
|
||||||
</button>{' '}
|
|
||||||
<ExternalLink className="max-md:hidden" href={proposalPage}>
|
|
||||||
{t('Open in Governance')}
|
|
||||||
</ExternalLink>
|
|
||||||
<ExternalLink className="md:hidden" href={proposalPage}>
|
|
||||||
{t('Open')}
|
|
||||||
</ExternalLink>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[requiredMajorityPercentage, tokenLink]
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AgGrid
|
<AgGrid
|
||||||
@@ -203,7 +80,6 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
filterParams: { buttons: ['reset'] },
|
filterParams: { buttons: ['reset'] },
|
||||||
autoHeight: true,
|
autoHeight: true,
|
||||||
}}
|
}}
|
||||||
columnDefs={columnDefs}
|
|
||||||
suppressCellFocus={true}
|
suppressCellFocus={true}
|
||||||
onRowClicked={({ data, event }: RowClickedEvent) => {
|
onRowClicked={({ data, event }: RowClickedEvent) => {
|
||||||
if (
|
if (
|
||||||
@@ -215,7 +91,128 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
window.open(proposalPage, '_blank');
|
window.open(proposalPage, '_blank');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="title"
|
||||||
|
headerName={t('Title')}
|
||||||
|
field="rationale.title"
|
||||||
|
flex={2}
|
||||||
|
wrapText={true}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="type"
|
||||||
|
maxWidth={180}
|
||||||
|
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||||
|
headerName={t('Type')}
|
||||||
|
field="terms.change.__typename"
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
maxWidth={100}
|
||||||
|
headerName={t('State')}
|
||||||
|
field="state"
|
||||||
|
valueFormatter={({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) => {
|
||||||
|
return value ? ProposalStateMapping[value] : '-';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="voting"
|
||||||
|
maxWidth={100}
|
||||||
|
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||||
|
headerName={t('Voting')}
|
||||||
|
cellRenderer={({
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
||||||
|
if (data) {
|
||||||
|
const yesTokens = new BigNumber(data.votes.yes.totalTokens);
|
||||||
|
const noTokens = new BigNumber(data.votes.no.totalTokens);
|
||||||
|
const totalTokensVoted = yesTokens.plus(noTokens);
|
||||||
|
const yesPercentage = totalTokensVoted.isZero()
|
||||||
|
? new BigNumber(0)
|
||||||
|
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||||
|
return (
|
||||||
|
<div className="uppercase flex h-full items-center justify-center pt-2">
|
||||||
|
<VoteProgress
|
||||||
|
threshold={requiredMajorityPercentage}
|
||||||
|
progress={yesPercentage}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return '-';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="cDate"
|
||||||
|
maxWidth={150}
|
||||||
|
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||||
|
headerName={t('Closing date')}
|
||||||
|
field="terms.closingDatetime"
|
||||||
|
valueFormatter={({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<
|
||||||
|
ProposalListFieldsFragment,
|
||||||
|
'terms.closingDatetime'
|
||||||
|
>) => {
|
||||||
|
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="eDate"
|
||||||
|
maxWidth={150}
|
||||||
|
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||||
|
headerName={t('Enactment date')}
|
||||||
|
field="terms.enactmentDatetime"
|
||||||
|
valueFormatter={({
|
||||||
|
value,
|
||||||
|
}: VegaValueFormatterParams<
|
||||||
|
ProposalListFieldsFragment,
|
||||||
|
'terms.enactmentDatetime'
|
||||||
|
>) => {
|
||||||
|
return value ? getDateTimeFormat().format(new Date(value)) : '-';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<AgGridColumn
|
||||||
|
colId="actions"
|
||||||
|
minWidth={window.innerWidth > BREAKPOINT_MD ? 221 : 80}
|
||||||
|
maxWidth={221}
|
||||||
|
sortable={false}
|
||||||
|
filter={false}
|
||||||
|
resizable={false}
|
||||||
|
cellRenderer={({
|
||||||
|
data,
|
||||||
|
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
|
||||||
|
const proposalPage = tokenLink(
|
||||||
|
TOKEN_PROPOSAL.replace(':id', data?.id || '')
|
||||||
|
);
|
||||||
|
const openDialog = () => {
|
||||||
|
if (!data) return;
|
||||||
|
setDialog({
|
||||||
|
open: true,
|
||||||
|
title: data.rationale.title,
|
||||||
|
content: data.terms,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="pb-1">
|
||||||
|
<button
|
||||||
|
className="underline max-md:hidden"
|
||||||
|
onClick={openDialog}
|
||||||
|
>
|
||||||
|
{t('View terms')}
|
||||||
|
</button>{' '}
|
||||||
|
<ExternalLink className="max-md:hidden" href={proposalPage}>
|
||||||
|
{t('Open in Governance')}
|
||||||
|
</ExternalLink>
|
||||||
|
<ExternalLink className="md:hidden" href={proposalPage}>
|
||||||
|
{t('Open')}
|
||||||
|
</ExternalLink>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</AgGrid>
|
||||||
<JsonViewerDialog
|
<JsonViewerDialog
|
||||||
open={dialog.open}
|
open={dialog.open}
|
||||||
onChange={(isOpen) => setDialog({ ...dialog, open: isOpen })}
|
onChange={(isOpen) => setDialog({ ...dialog, open: isOpen })}
|
||||||
|
|||||||
+16
-43
@@ -1,24 +1,19 @@
|
|||||||
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
|
||||||
|
|
||||||
// https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go
|
// https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go
|
||||||
export const ErrorCodes = new Map([
|
export const ErrorCodes = new Map([
|
||||||
[51, 'Transaction failed validation'],
|
[51, 'Transaction failed validation'],
|
||||||
[60, 'Transaction could not be decoded'],
|
[60, 'Transaction could not be decoded'],
|
||||||
[70, 'Error'],
|
[70, 'Error'],
|
||||||
[71, 'Partial success/error'],
|
|
||||||
[80, 'Unknown command'],
|
[80, 'Unknown command'],
|
||||||
[89, 'Rejected as spam'],
|
[89, 'Rejected as spam'],
|
||||||
[0, 'Success'],
|
[0, 'Success'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const successCodes = new Set([0, 71]);
|
export const successCodes = new Set([0]);
|
||||||
|
|
||||||
interface ChainResponseCodeProps {
|
interface ChainResponseCodeProps {
|
||||||
code: number;
|
code: number;
|
||||||
hideLabel?: boolean;
|
hideLabel?: boolean;
|
||||||
error?: string;
|
error?: string;
|
||||||
hideIfOk?: boolean;
|
|
||||||
small?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,22 +25,10 @@ export const ChainResponseCode = ({
|
|||||||
code,
|
code,
|
||||||
hideLabel = false,
|
hideLabel = false,
|
||||||
error,
|
error,
|
||||||
hideIfOk = false,
|
|
||||||
small = false,
|
|
||||||
}: ChainResponseCodeProps) => {
|
}: ChainResponseCodeProps) => {
|
||||||
if (hideIfOk && code === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSuccess = successCodes.has(code);
|
const isSuccess = successCodes.has(code);
|
||||||
const size = small ? 3 : 4;
|
|
||||||
const successColour =
|
const icon = isSuccess ? '✅' : '❌';
|
||||||
code === 71 ? '!fill-vega-orange' : '!fill-vega-green-600';
|
|
||||||
const icon = isSuccess ? (
|
|
||||||
<Icon size={size} name="tick-circle" className={`${successColour}`} />
|
|
||||||
) : (
|
|
||||||
<Icon size={size} name="cross" className="!fill-vega-pink-500" />
|
|
||||||
);
|
|
||||||
const label = ErrorCodes.get(code) || 'Unknown response code';
|
const label = ErrorCodes.get(code) || 'Unknown response code';
|
||||||
|
|
||||||
// Hack for batches with many errors - see https://github.com/vegaprotocol/vega/issues/7245
|
// Hack for batches with many errors - see https://github.com/vegaprotocol/vega/issues/7245
|
||||||
@@ -53,28 +36,18 @@ export const ChainResponseCode = ({
|
|||||||
error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error;
|
error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<div title={`Response code: ${code} - ${label}`} className="inline-block">
|
||||||
description={
|
<span
|
||||||
<span>
|
className="mr-2"
|
||||||
Response code: {code} - {label}
|
aria-label={isSuccess ? 'Success' : 'Warning'}
|
||||||
</span>
|
role="img"
|
||||||
}
|
>
|
||||||
>
|
{icon}
|
||||||
<div className="mt-[-1px] inline-block">
|
</span>
|
||||||
<span
|
{hideLabel ? null : <span>{label}</span>}
|
||||||
className="mr-2"
|
{!hideLabel && !!displayError ? (
|
||||||
aria-label={isSuccess ? 'Success' : 'Warning'}
|
<span className="ml-1 whitespace-pre">— {displayError}</span>
|
||||||
role="img"
|
) : null}
|
||||||
>
|
</div>
|
||||||
{icon}
|
|
||||||
</span>
|
|
||||||
{hideLabel ? null : <span>{label}</span>}
|
|
||||||
{!hideLabel && !!displayError ? (
|
|
||||||
<span className="ml-1 whitespace-pre">
|
|
||||||
— {displayError}
|
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
import { render } from '@testing-library/react';
|
|
||||||
import type { TxDetailsOrderProps } from './tx-order-peg';
|
|
||||||
import { TxOrderPeggedReference, getMarketDecimals } from './tx-order-peg';
|
|
||||||
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
|
||||||
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
|
||||||
import { PeggedReference, Side } from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
// Mock the useExplorerMarketQuery hook
|
|
||||||
jest.mock('../../../links/market-link/__generated__/Market', () => ({
|
|
||||||
useExplorerMarketQuery: jest.fn().mockReturnValue({
|
|
||||||
data: {
|
|
||||||
market: { decimalPlaces: 0 },
|
|
||||||
},
|
|
||||||
loading: false,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('getSettlementAsset', () => {
|
|
||||||
it('should return the decimal places if data is defined', () => {
|
|
||||||
const data = {
|
|
||||||
market: {
|
|
||||||
__typename: 'Market',
|
|
||||||
id: '123',
|
|
||||||
decimalPlaces: 8,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = getMarketDecimals(data as Partial<ExplorerMarketQuery>);
|
|
||||||
|
|
||||||
expect(result).toEqual(8);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return 0 if data is undefined', () => {
|
|
||||||
const result = getMarketDecimals(undefined);
|
|
||||||
|
|
||||||
expect(result).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('TxOrderPeggedReference', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
// Mock the useExplorerMarketQuery hook return value
|
|
||||||
(useExplorerMarketQuery as jest.Mock).mockReturnValue({
|
|
||||||
data: {
|
|
||||||
settlementAsset: 'some-settlement-asset',
|
|
||||||
},
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render the offset and reference correctly', () => {
|
|
||||||
const props: TxDetailsOrderProps = {
|
|
||||||
side: Side.SIDE_BUY,
|
|
||||||
offset: '10',
|
|
||||||
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
|
||||||
marketId: 'some-market-id',
|
|
||||||
};
|
|
||||||
|
|
||||||
const { getByTestId } = render(<TxOrderPeggedReference {...props} />);
|
|
||||||
|
|
||||||
expect(getByTestId('pegged-reference')).toHaveTextContent('Mid + 10');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return null if the reference is "PEGGED_REFERENCE_UNSPECIFIED"', () => {
|
|
||||||
const props: TxDetailsOrderProps = {
|
|
||||||
side: Side.SIDE_BUY,
|
|
||||||
offset: '10',
|
|
||||||
reference: 'PEGGED_REFERENCE_UNSPECIFIED',
|
|
||||||
marketId: 'some-market-id',
|
|
||||||
};
|
|
||||||
|
|
||||||
const { container } = render(<TxOrderPeggedReference {...props} />);
|
|
||||||
|
|
||||||
expect(container.firstChild).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render the offset without formatting initially, then render the formatted version', () => {
|
|
||||||
const props: TxDetailsOrderProps = {
|
|
||||||
side: Side.SIDE_BUY,
|
|
||||||
offset: '10',
|
|
||||||
reference: PeggedReference.PEGGED_REFERENCE_BEST_ASK,
|
|
||||||
marketId: 'some-market-id',
|
|
||||||
};
|
|
||||||
|
|
||||||
(useExplorerMarketQuery as jest.Mock).mockReturnValue({
|
|
||||||
data: null,
|
|
||||||
loading: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const screen = render(<TxOrderPeggedReference {...props} />);
|
|
||||||
expect(screen.getByTestId('pegged-reference')).toHaveTextContent(
|
|
||||||
'Ask + 10'
|
|
||||||
);
|
|
||||||
|
|
||||||
(useExplorerMarketQuery as jest.Mock).mockReturnValue({
|
|
||||||
data: {
|
|
||||||
market: {
|
|
||||||
decimalPlaces: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
screen.rerender(<TxOrderPeggedReference {...props} />);
|
|
||||||
expect(screen.getByTestId('pegged-reference')).toHaveTextContent(
|
|
||||||
'Ask + 0.000000001'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import { TableCell, TableRow } from '../../../table';
|
|
||||||
import type { VegaPeggedReference } from '../liquidity-provision/liquidity-provision-details';
|
|
||||||
import { Side, PeggedReferenceMapping } from '@vegaprotocol/types';
|
|
||||||
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
|
||||||
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
|
||||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
|
||||||
|
|
||||||
export interface TxDetailsOrderProps {
|
|
||||||
offset: string;
|
|
||||||
reference: VegaPeggedReference;
|
|
||||||
marketId: string;
|
|
||||||
side: Side;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMarketDecimals(
|
|
||||||
data: ExplorerMarketQuery | undefined
|
|
||||||
): number {
|
|
||||||
return data?.market?.decimalPlaces || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Summarises an order's peg
|
|
||||||
*/
|
|
||||||
export const TxOrderPeggedReferenceRow = ({
|
|
||||||
offset,
|
|
||||||
reference,
|
|
||||||
marketId,
|
|
||||||
side,
|
|
||||||
}: TxDetailsOrderProps) => {
|
|
||||||
return (
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('Pegged order')}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<TxOrderPeggedReference
|
|
||||||
side={side}
|
|
||||||
offset={offset}
|
|
||||||
reference={reference}
|
|
||||||
marketId={marketId}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TxOrderPeggedReference = ({
|
|
||||||
offset,
|
|
||||||
reference,
|
|
||||||
marketId,
|
|
||||||
side,
|
|
||||||
}: TxDetailsOrderProps) => {
|
|
||||||
const { data, loading } = useExplorerMarketQuery({
|
|
||||||
variables: { id: marketId },
|
|
||||||
});
|
|
||||||
|
|
||||||
const direction = side === Side.SIDE_BUY ? '+' : '-';
|
|
||||||
const decimalPlaces = getMarketDecimals(data);
|
|
||||||
|
|
||||||
if (reference === 'PEGGED_REFERENCE_UNSPECIFIED') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span data-testid="pegged-reference">
|
|
||||||
{PeggedReferenceMapping[reference]}
|
|
||||||
{direction}
|
|
||||||
{!loading && data
|
|
||||||
? addDecimalsFormatNumber(offset, decimalPlaces)
|
|
||||||
: offset}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
+1
-1
@@ -30,7 +30,7 @@ export const BundleExists = ({
|
|||||||
// Note if this is wrong, the wrong decoder will be used which will give incorrect data
|
// Note if this is wrong, the wrong decoder will be used which will give incorrect data
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-auto h-10 max-w-lg border-2 border-solid border-vega-light-100 dark:border-vega-dark-200 p-5 mt-5">
|
<div className="w-auto max-w-lg border-2 border-solid border-vega-light-100 dark:border-vega-dark-200 p-5 mt-5">
|
||||||
<IconForBundleStatus status={status} />
|
<IconForBundleStatus status={status} />
|
||||||
<h1 className="text-xl pb-1">
|
<h1 className="text-xl pb-1">
|
||||||
{status === 'STATUS_ENABLED'
|
{status === 'STATUS_ENABLED'
|
||||||
|
|||||||
+12
-34
@@ -6,32 +6,10 @@ import {
|
|||||||
SPECIAL_CASE_NETWORK_ID,
|
SPECIAL_CASE_NETWORK_ID,
|
||||||
} from '../../../../links/party-link/party-link';
|
} from '../../../../links/party-link/party-link';
|
||||||
import SizeInAsset from '../../../../size-in-asset/size-in-asset';
|
import SizeInAsset from '../../../../size-in-asset/size-in-asset';
|
||||||
|
import { AccountTypeMapping } from '@vegaprotocol/types';
|
||||||
|
import { AccountType } from '@vegaprotocol/types';
|
||||||
import { headerClasses, wrapperClasses } from '../transfer-details';
|
import { headerClasses, wrapperClasses } from '../transfer-details';
|
||||||
import type { components } from '../../../../../../types/explorer';
|
import type { Transfer } from '../transfer-details';
|
||||||
|
|
||||||
type Transfer = components['schemas']['commandsv1Transfer'];
|
|
||||||
type AccountTypes = components['schemas']['vegaAccountType'];
|
|
||||||
|
|
||||||
const AccountType: Record<AccountTypes, string> = {
|
|
||||||
ACCOUNT_TYPE_UNSPECIFIED: 'Unspecified',
|
|
||||||
ACCOUNT_TYPE_INSURANCE: 'Insurance',
|
|
||||||
ACCOUNT_TYPE_SETTLEMENT: 'Settlement',
|
|
||||||
ACCOUNT_TYPE_MARGIN: 'Margin',
|
|
||||||
ACCOUNT_TYPE_GENERAL: 'General',
|
|
||||||
ACCOUNT_TYPE_FEES_INFRASTRUCTURE: 'Infrastructure',
|
|
||||||
ACCOUNT_TYPE_FEES_LIQUIDITY: 'Liquidity',
|
|
||||||
ACCOUNT_TYPE_FEES_MAKER: 'Maker',
|
|
||||||
ACCOUNT_TYPE_BOND: 'Bond',
|
|
||||||
ACCOUNT_TYPE_EXTERNAL: 'External',
|
|
||||||
ACCOUNT_TYPE_GLOBAL_INSURANCE: 'Global Insurance',
|
|
||||||
ACCOUNT_TYPE_GLOBAL_REWARD: 'Global Reward',
|
|
||||||
ACCOUNT_TYPE_PENDING_TRANSFERS: 'Pending Transfers',
|
|
||||||
ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: 'Maker Paid Fees',
|
|
||||||
ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: 'Maker Received Fees',
|
|
||||||
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: 'LP Received Fees',
|
|
||||||
ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: 'Market Proposers',
|
|
||||||
ACCOUNT_TYPE_HOLDING: 'Holding',
|
|
||||||
};
|
|
||||||
|
|
||||||
interface TransferParticipantsProps {
|
interface TransferParticipantsProps {
|
||||||
transfer: Transfer;
|
transfer: Transfer;
|
||||||
@@ -52,22 +30,22 @@ export function TransferParticipants({
|
|||||||
}: TransferParticipantsProps) {
|
}: TransferParticipantsProps) {
|
||||||
// This mapping is required as the global account types require a type to be set, while
|
// This mapping is required as the global account types require a type to be set, while
|
||||||
// the underlying protobufs allow for every field to be undefined.
|
// the underlying protobufs allow for every field to be undefined.
|
||||||
const fromAcct: AccountTypes =
|
const fromAcct =
|
||||||
transfer.fromAccountType &&
|
transfer.fromAccountType &&
|
||||||
transfer.fromAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
transfer.fromAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
||||||
? transfer.fromAccountType
|
? AccountType[transfer.fromAccountType]
|
||||||
: 'ACCOUNT_TYPE_GENERAL';
|
: AccountType.ACCOUNT_TYPE_GENERAL;
|
||||||
const fromAccountTypeLabel: string = transfer.fromAccountType
|
const fromAccountTypeLabel = transfer.fromAccountType
|
||||||
? AccountType[fromAcct]
|
? AccountTypeMapping[fromAcct]
|
||||||
: 'Unknown';
|
: 'Unknown';
|
||||||
|
|
||||||
const toAcct: AccountTypes =
|
const toAcct =
|
||||||
transfer.toAccountType &&
|
transfer.toAccountType &&
|
||||||
transfer.toAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
transfer.toAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
|
||||||
? transfer.toAccountType
|
? AccountType[transfer.toAccountType]
|
||||||
: 'ACCOUNT_TYPE_GENERAL';
|
: AccountType.ACCOUNT_TYPE_GENERAL;
|
||||||
const toAccountTypeLabel = transfer.fromAccountType
|
const toAccountTypeLabel = transfer.fromAccountType
|
||||||
? AccountType[toAcct]
|
? AccountTypeMapping[toAcct]
|
||||||
: 'Unknown';
|
: 'Unknown';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
|
|||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<h2 className={headerClasses}>{t('Active epochs')}</h2>
|
<h2 className={headerClasses}>{t('Active epochs')}</h2>
|
||||||
<div className="relative block rounded-lg py-6 text-center p-6">
|
<div className="relative block rounded-lg py-6 text-center p-6">
|
||||||
<div>
|
<p>
|
||||||
<EpochOverview id={recurring.startEpoch} />
|
<EpochOverview id={recurring.startEpoch} />
|
||||||
</div>
|
</p>
|
||||||
<p className="leading-10 my-2">
|
<p className="leading-10 my-2">
|
||||||
<IconForEpoch
|
<IconForEpoch
|
||||||
start={recurring.startEpoch}
|
start={recurring.startEpoch}
|
||||||
@@ -37,13 +37,13 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
|
|||||||
current={data?.epoch.id}
|
current={data?.epoch.id}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<p>
|
||||||
{recurring.endEpoch ? (
|
{recurring.endEpoch ? (
|
||||||
<EpochOverview id={recurring.endEpoch} />
|
<EpochOverview id={recurring.endEpoch} />
|
||||||
) : (
|
) : (
|
||||||
<span>{t('Forever')}</span>
|
<span>{t('Forever')}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { DispatchMetricLabels } from '@vegaprotocol/types';
|
|||||||
export type Metric = components['schemas']['vegaDispatchMetric'];
|
export type Metric = components['schemas']['vegaDispatchMetric'];
|
||||||
export type Strategy = components['schemas']['vegaDispatchStrategy'];
|
export type Strategy = components['schemas']['vegaDispatchStrategy'];
|
||||||
|
|
||||||
const metricLabels: Record<Metric, string> = {
|
const metricLabels = {
|
||||||
DISPATCH_METRIC_UNSPECIFIED: 'Unknown metric',
|
DISPATCH_METRIC_UNSPECIFIED: 'Unknown metric',
|
||||||
...DispatchMetricLabels,
|
...DispatchMetricLabels,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { TransferRepeat } from './blocks/transfer-repeat';
|
|||||||
import { TransferRewards } from './blocks/transfer-rewards';
|
import { TransferRewards } from './blocks/transfer-rewards';
|
||||||
import { TransferParticipants } from './blocks/transfer-participants';
|
import { TransferParticipants } from './blocks/transfer-participants';
|
||||||
|
|
||||||
export type Recurring = components['schemas']['commandsv1RecurringTransfer'];
|
export type Recurring = components['schemas']['v1RecurringTransfer'];
|
||||||
export type Metric = components['schemas']['vegaDispatchMetric'];
|
export type Metric = components['schemas']['vegaDispatchMetric'];
|
||||||
|
|
||||||
export const wrapperClasses =
|
export const wrapperClasses =
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
import { render } from '@testing-library/react';
|
|
||||||
import { TxDetailsLiquidityAmendment } from './tx-liquidity-amend';
|
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
|
||||||
|
|
||||||
describe('TxDetailsLiquidityAmendment', () => {
|
|
||||||
const mockTxData = {
|
|
||||||
hash: 'test',
|
|
||||||
command: {
|
|
||||||
liquidityProvisionAmendment: {
|
|
||||||
marketId: 'BTC-USD',
|
|
||||||
commitmentAmount: 100,
|
|
||||||
fee: '0.01',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const mockPubKey = '123';
|
|
||||||
const mockBlockData = {
|
|
||||||
result: {
|
|
||||||
block: {
|
|
||||||
header: {
|
|
||||||
height: '123',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
it('should render the component with correct data', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<TxDetailsLiquidityAmendment
|
|
||||||
txData={mockTxData as BlockExplorerTransactionResult}
|
|
||||||
pubKey={mockPubKey}
|
|
||||||
blockData={mockBlockData as TendermintBlocksResponse}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getByText('Market')).toBeInTheDocument();
|
|
||||||
expect(getByText('BTC-USD')).toBeInTheDocument();
|
|
||||||
expect(getByText('Commitment amount')).toBeInTheDocument();
|
|
||||||
expect(getByText('100')).toBeInTheDocument();
|
|
||||||
expect(getByText('Fee')).toBeInTheDocument();
|
|
||||||
expect(getByText('1%')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display awaiting message when tx data is undefined', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<TxDetailsLiquidityAmendment
|
|
||||||
txData={undefined}
|
|
||||||
pubKey={mockPubKey}
|
|
||||||
blockData={mockBlockData as TendermintBlocksResponse}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getByText('Awaiting Block Explorer transaction details')
|
|
||||||
).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display awaiting message when liquidityProvisionAmendment is undefined', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<TxDetailsLiquidityAmendment
|
|
||||||
txData={{ command: {} } as BlockExplorerTransactionResult}
|
|
||||||
pubKey={mockPubKey}
|
|
||||||
blockData={mockBlockData as TendermintBlocksResponse}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getByText('Awaiting Block Explorer transaction details')
|
|
||||||
).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -7,7 +7,6 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
|
|||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
||||||
import PriceInMarket from '../../price-in-market/price-in-market';
|
import PriceInMarket from '../../price-in-market/price-in-market';
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
export type LiquidityAmendment =
|
export type LiquidityAmendment =
|
||||||
components['schemas']['v1LiquidityProvisionAmendment'];
|
components['schemas']['v1LiquidityProvisionAmendment'];
|
||||||
@@ -35,10 +34,6 @@ export const TxDetailsLiquidityAmendment = ({
|
|||||||
txData.command.liquidityProvisionAmendment;
|
txData.command.liquidityProvisionAmendment;
|
||||||
const marketId: string = amendment.marketId || '-';
|
const marketId: string = amendment.marketId || '-';
|
||||||
|
|
||||||
const fee = amendment.fee
|
|
||||||
? new BigNumber(amendment.fee).times(100).toString()
|
|
||||||
: '-';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
@@ -68,7 +63,7 @@ export const TxDetailsLiquidityAmendment = ({
|
|||||||
{amendment.fee ? (
|
{amendment.fee ? (
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Fee')}</TableCell>
|
<TableCell>{t('Fee')}</TableCell>
|
||||||
<TableCell>{fee}%</TableCell>
|
<TableCell>{amendment.fee}%</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : null}
|
) : null}
|
||||||
</TableWithTbody>
|
</TableWithTbody>
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
import { render } from '@testing-library/react';
|
|
||||||
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
|
||||||
|
|
||||||
describe('TxDetailsLiquiditySubmission', () => {
|
|
||||||
const mockTxData = {
|
|
||||||
hash: 'test',
|
|
||||||
command: {
|
|
||||||
liquidityProvisionSubmission: {
|
|
||||||
marketId: 'BTC-USD',
|
|
||||||
commitmentAmount: 100,
|
|
||||||
fee: '0.01',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const mockPubKey = '123';
|
|
||||||
const mockBlockData = {
|
|
||||||
result: {
|
|
||||||
block: {
|
|
||||||
header: {
|
|
||||||
height: '123',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
it('should render the component with correct data', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<TxDetailsLiquiditySubmission
|
|
||||||
txData={mockTxData as BlockExplorerTransactionResult}
|
|
||||||
pubKey={mockPubKey}
|
|
||||||
blockData={mockBlockData as TendermintBlocksResponse}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getByText('Market')).toBeInTheDocument();
|
|
||||||
expect(getByText('BTC-USD')).toBeInTheDocument();
|
|
||||||
expect(getByText('Commitment amount')).toBeInTheDocument();
|
|
||||||
expect(getByText('100')).toBeInTheDocument();
|
|
||||||
expect(getByText('Fee')).toBeInTheDocument();
|
|
||||||
expect(getByText('1%')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display awaiting message when tx data is undefined', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<TxDetailsLiquiditySubmission
|
|
||||||
txData={undefined}
|
|
||||||
pubKey={mockPubKey}
|
|
||||||
blockData={mockBlockData as TendermintBlocksResponse}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getByText('Awaiting Block Explorer transaction details')
|
|
||||||
).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display awaiting message when liquidityProvisionSubmission is undefined', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<TxDetailsLiquiditySubmission
|
|
||||||
txData={{ command: {} } as BlockExplorerTransactionResult}
|
|
||||||
pubKey={mockPubKey}
|
|
||||||
blockData={mockBlockData as TendermintBlocksResponse}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getByText('Awaiting Block Explorer transaction details')
|
|
||||||
).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -7,7 +7,6 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
|
|||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
||||||
import PriceInMarket from '../../price-in-market/price-in-market';
|
import PriceInMarket from '../../price-in-market/price-in-market';
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
export type LiquiditySubmission =
|
export type LiquiditySubmission =
|
||||||
components['schemas']['v1LiquidityProvisionSubmission'];
|
components['schemas']['v1LiquidityProvisionSubmission'];
|
||||||
@@ -34,10 +33,6 @@ export const TxDetailsLiquiditySubmission = ({
|
|||||||
txData.command.liquidityProvisionSubmission;
|
txData.command.liquidityProvisionSubmission;
|
||||||
const marketId: string = submission.marketId || '-';
|
const marketId: string = submission.marketId || '-';
|
||||||
|
|
||||||
const fee = submission.fee
|
|
||||||
? new BigNumber(submission.fee).times(100).toString()
|
|
||||||
: '-';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
@@ -67,7 +62,7 @@ export const TxDetailsLiquiditySubmission = ({
|
|||||||
{submission.fee ? (
|
{submission.fee ? (
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Fee')}</TableCell>
|
<TableCell>{t('Fee')}</TableCell>
|
||||||
<TableCell>{fee}%</TableCell>
|
<TableCell>{submission.fee}%</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : null}
|
) : null}
|
||||||
</TableWithTbody>
|
</TableWithTbody>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
|
|||||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||||
import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
|
import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
|
||||||
import Hash from '../../links/hash';
|
import Hash from '../../links/hash';
|
||||||
import { TxOrderPeggedReferenceRow } from './order/tx-order-peg';
|
|
||||||
|
|
||||||
interface TxDetailsOrderProps {
|
interface TxDetailsOrderProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -30,8 +29,6 @@ export const TxDetailsOrder = ({
|
|||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
}
|
}
|
||||||
const marketId = txData.command.orderSubmission.marketId || '-';
|
const marketId = txData.command.orderSubmission.marketId || '-';
|
||||||
const reference = txData.command.orderSubmission.peggedOrder;
|
|
||||||
const side = txData.command.orderSubmission.side;
|
|
||||||
|
|
||||||
let deterministicId = '';
|
let deterministicId = '';
|
||||||
|
|
||||||
@@ -66,14 +63,6 @@ export const TxDetailsOrder = ({
|
|||||||
<MarketLink id={marketId} />
|
<MarketLink id={marketId} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
{reference ? (
|
|
||||||
<TxOrderPeggedReferenceRow
|
|
||||||
side={side}
|
|
||||||
offset={reference.offset}
|
|
||||||
reference={reference.reference}
|
|
||||||
marketId={marketId}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</TableWithTbody>
|
</TableWithTbody>
|
||||||
|
|
||||||
{deterministicId.length > 0 ? (
|
{deterministicId.length > 0 ? (
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint
|
|||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
import ProposalLink from '../../links/proposal-link/proposal-link';
|
import ProposalLink from '../../links/proposal-link/proposal-link';
|
||||||
import { VoteIcon } from '../../vote-icon/vote-icon';
|
|
||||||
|
|
||||||
interface TxProposalVoteProps {
|
interface TxProposalVoteProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -31,22 +30,27 @@ export const TxProposalVote = ({
|
|||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const vote = txData.command.voteSubmission.value === 'VALUE_YES';
|
const vote = txData.command.voteSubmission.value ? '👍' : '👎';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Proposal ID')}</TableCell>
|
||||||
|
<TableCell>{txData.command.voteSubmission.proposalId}</TableCell>
|
||||||
|
</TableRow>
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Proposal details')}</TableCell>
|
<TableCell>{t('Proposal details')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<ProposalLink id={txData.command.voteSubmission.proposalId} />
|
<ProposalLink id={txData.command.voteSubmission.proposalId} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Proposal')}</TableCell>
|
||||||
|
<TableCell>{txData.command.voteSubmission.proposalId}</TableCell>
|
||||||
|
</TableRow>
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Vote')}</TableCell>
|
<TableCell>{t('Vote')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>{vote}</TableCell>
|
||||||
<VoteIcon vote={vote} />
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableWithTbody>
|
</TableWithTbody>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
import type { Proposal } from './tx-proposal';
|
|
||||||
import { proposalRequiresSignatureBundle } from './tx-proposal';
|
|
||||||
|
|
||||||
describe('proposalRequiresSignatureBundle', () => {
|
|
||||||
it('should return false for freeform proposals, which do not require a signature bundle to enact', () => {
|
|
||||||
const mock = {
|
|
||||||
terms: {
|
|
||||||
newFreeform: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(proposalRequiresSignatureBundle(mock)).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return false for newMarket proposals, which do not require a signature bundle to enact', () => {
|
|
||||||
const mock = {
|
|
||||||
terms: {
|
|
||||||
newMarket: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(proposalRequiresSignatureBundle(mock)).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return true for newAsset proposals, which do require a signature bundle to enact', () => {
|
|
||||||
const mock = {
|
|
||||||
terms: {
|
|
||||||
newAsset: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(proposalRequiresSignatureBundle(mock)).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return true for updateAsset proposals, which do require a signature bundle to enact', () => {
|
|
||||||
const mock = {
|
|
||||||
terms: {
|
|
||||||
updateAsset: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(proposalRequiresSignatureBundle(mock)).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return false when bad data is supplied', () => {
|
|
||||||
expect(
|
|
||||||
proposalRequiresSignatureBundle(false as unknown as Proposal)
|
|
||||||
).toEqual(false);
|
|
||||||
expect(
|
|
||||||
proposalRequiresSignatureBundle(undefined as unknown as Proposal)
|
|
||||||
).toEqual(false);
|
|
||||||
expect(
|
|
||||||
proposalRequiresSignatureBundle({ test: false } as unknown as Proposal)
|
|
||||||
).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -28,16 +28,11 @@ interface TxProposalProps {
|
|||||||
* @returns boolean True if a signature bundle is required. Used to fetch a signature bundle
|
* @returns boolean True if a signature bundle is required. Used to fetch a signature bundle
|
||||||
*/
|
*/
|
||||||
export function proposalRequiresSignatureBundle(proposal?: Proposal): boolean {
|
export function proposalRequiresSignatureBundle(proposal?: Proposal): boolean {
|
||||||
const proposalsThatRequireBundles = ['newAsset', 'updateAsset'];
|
|
||||||
|
|
||||||
if (!proposal?.terms) {
|
if (!proposal?.terms) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return !!['newAsset', 'updateAsset'].filter((requiredIfExists) =>
|
||||||
return (
|
has(proposal.terms, requiredIfExists)
|
||||||
proposalsThatRequireBundles.filter((requiredIfExists) =>
|
|
||||||
has(proposal.terms, requiredIfExists)
|
|
||||||
).length > 0
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +81,6 @@ export const TxProposal = ({ txData, pubKey, blockData }: TxProposalProps) => {
|
|||||||
|
|
||||||
const tx = proposal.terms?.newAsset || proposal.terms?.updateAsset;
|
const tx = proposal.terms?.newAsset || proposal.terms?.updateAsset;
|
||||||
|
|
||||||
// This component is not rendered if no bundle is required
|
|
||||||
const SignatureBundleComponent = proposal.terms?.newAsset
|
const SignatureBundleComponent = proposal.terms?.newAsset
|
||||||
? ProposalSignatureBundleNewAsset
|
? ProposalSignatureBundleNewAsset
|
||||||
: ProposalSignatureBundleUpdateAsset;
|
: ProposalSignatureBundleUpdateAsset;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export { TxList } from './tx-list';
|
||||||
export { TxOrderType } from './tx-order-type';
|
export { TxOrderType } from './tx-order-type';
|
||||||
export { TxsInfiniteList } from './txs-infinite-list';
|
export { TxsInfiniteList } from './txs-infinite-list';
|
||||||
export { TxsInfiniteListItem } from './txs-infinite-list-item';
|
export { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
|
|
||||||
export interface FilterLabelProps {
|
|
||||||
filters: Set<string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the list (currently limited to 1) of filters set by the
|
|
||||||
* Transaction Filter
|
|
||||||
*/
|
|
||||||
export function FilterLabel({ filters }: FilterLabelProps) {
|
|
||||||
if (!filters || filters.size !== 1) {
|
|
||||||
return (
|
|
||||||
<span data-testid="filter-empty" className="uppercase">
|
|
||||||
{t('Filter')}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div data-testid="filter-selected">
|
|
||||||
<span className="uppercase">{t('Filters')}:</span>
|
|
||||||
<code className="bg-vega-light-150 dark:bg-vega-light-300 px-2 rounded-md capitalize dark:text-black">
|
|
||||||
{Array.from(filters)[0]}
|
|
||||||
</code>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user