Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77ae0408e0 | ||
|
|
51f076bca8 | ||
|
|
22eefb5d0d | ||
|
|
145bb13848 | ||
|
|
87000a33d5 |
@@ -1 +0,0 @@
|
||||
node_modules
|
||||
+8
-16
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": ["**/*"],
|
||||
"plugins": ["@nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
|
||||
"plugins": ["@nrwl/nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
|
||||
"settings": {
|
||||
"jsx-a11y": {
|
||||
"components": {
|
||||
@@ -18,7 +18,7 @@
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"extends": ["plugin:jsx-a11y/strict"],
|
||||
"rules": {
|
||||
"@nx/enforce-module-boundaries": [
|
||||
"@nrwl/nx/enforce-module-boundaries": [
|
||||
"error",
|
||||
{
|
||||
"enforceBuildableLibDependency": true,
|
||||
@@ -51,13 +51,12 @@
|
||||
"ul": ["list"],
|
||||
"ol": ["list"]
|
||||
}
|
||||
],
|
||||
"no-console": ["error", { "allow": ["warn", "error"] }]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"extends": ["plugin:@nx/typescript"],
|
||||
"extends": ["plugin:@nrwl/nx/typescript"],
|
||||
"rules": {
|
||||
"@typescript-eslint/ban-ts-comment": [
|
||||
"error",
|
||||
@@ -73,29 +72,22 @@
|
||||
"error",
|
||||
{
|
||||
"prefer": "type-imports",
|
||||
"disallowTypeAnnotations": true,
|
||||
"fixStyle": "inline-type-imports"
|
||||
"disallowTypeAnnotations": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-useless-constructor": 0,
|
||||
"curly": ["error", "multi-line"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.spec.ts", "*.spec.tsx"],
|
||||
"extends": ["plugin:@nx/typescript", "plugin:jest/recommended"],
|
||||
"extends": ["plugin:@nrwl/nx/typescript", "plugin:jest/recommended"],
|
||||
"rules": {
|
||||
"jest/consistent-test-it": [
|
||||
"error",
|
||||
{
|
||||
"fn": "it"
|
||||
}
|
||||
]
|
||||
"jest/consistent-test-it": ["error", { "fn": "it" }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"extends": ["plugin:@nx/javascript"],
|
||||
"extends": ["plugin:@nrwl/nx/javascript"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
* text eol=lf
|
||||
*.png binary
|
||||
*.ico binary
|
||||
*.woff2 binary
|
||||
|
||||
@@ -14,7 +14,8 @@ What we need to achieve and who for
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ]
|
||||
- [ ]
|
||||
- [ ] What do we need to do first
|
||||
- [ ] and then what?
|
||||
- [ ] Etc.
|
||||
|
||||
## Additional details / background info
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
---
|
||||
name: Feature Epic
|
||||
about: A template to capture and scope user requirements, high level process, and basic mockups for an upcoming feature as part of the initial core spec review process.
|
||||
title: 'FEATURE EPIC: '
|
||||
labels: feature-epic
|
||||
---
|
||||
|
||||
## Core Feature
|
||||
|
||||
<Name>
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Define high level requirements
|
||||
- [ ] Create basic mockups
|
||||
- [ ] Update "API Requirements" in core spec
|
||||
- [ ] Update "User-Interface Spec" in relevant front end repo
|
||||
- [ ] Create detailed user stories using normal template
|
||||
|
||||
## High Level Requirements
|
||||
|
||||
## Basic Mockups
|
||||
|
||||
## Link to API Requirements in Core spec
|
||||
|
||||
## Link to User Interface Specs
|
||||
|
||||
## Linked User Stories
|
||||
@@ -22,14 +22,11 @@ So that
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] UX (if needed)
|
||||
- [ ] Design (if needed)
|
||||
- [ ] Explore and sketch
|
||||
- [ ] Team and stakeholder review
|
||||
- [ ] Specs reviewed and created or adjusted
|
||||
- [ ] Implementation
|
||||
- [ ] Testing (unit and/or e2e)
|
||||
- [ ] Code review
|
||||
- [ ] QA review
|
||||
- [ ] Visual Design
|
||||
- [ ] Team review
|
||||
- [ ] Etc.
|
||||
|
||||
## Sketch
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
name: After Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
after-release:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 45
|
||||
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: Wait for publish to complete
|
||||
uses: lewagon/wait-on-check-action@v1.3.1
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name }}
|
||||
check-name: '(CD) publish dist / trading'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
wait-interval: 10
|
||||
|
||||
- name: resolve ipfs hashes for release
|
||||
run: |
|
||||
echo "Name: ${{ github.event.release.name }}"
|
||||
echo "Description: ${{ github.event.release.body }}"
|
||||
echo "Tag: ${{ github.event.release.tag_name }}"
|
||||
docker run --rm vegaprotocol/trading:mainnet 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 }}/
|
||||
|
||||
- name: Ensure 'Released' label exists
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
REPO="${{ github.repository }}"
|
||||
LABEL_EXIST=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/$REPO/labels/Released")
|
||||
if [[ "$LABEL_EXIST" == *"Not Found"* ]]; then
|
||||
curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-X POST "https://api.github.com/repos/$REPO/labels" \
|
||||
-d '{"name": "Released", "color": "FFFFFF"}'
|
||||
fi
|
||||
|
||||
- name: Extract issues from release notes
|
||||
id: extract-issues
|
||||
run: |
|
||||
ISSUES=$(echo "${{ github.event.release.body }}" | grep -o -E '#[0-9]+' | tr -d '#' | jq -R . | jq -cs .)
|
||||
echo "Issues to label: $ISSUES"
|
||||
echo "::set-output name=issue_numbers::$ISSUES"
|
||||
|
||||
- name: Add 'Released' label to issues
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
ISSUE_NUMBERS="${{ steps.extract-issues.outputs.issue_numbers }}"
|
||||
REPO="${{ github.repository }}"
|
||||
for ISSUE in $(echo "$ISSUE_NUMBERS" | jq -r '.[]'); do
|
||||
curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-X POST "https://api.github.com/repos/$REPO/issues/$ISSUE/labels" \
|
||||
-d '{"labels": ["Released"]}'
|
||||
done
|
||||
@@ -6,7 +6,7 @@ name: 'Add Issues To Project Board'
|
||||
types:
|
||||
- opened
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PROJECT_MANAGE_ACTION }}
|
||||
GH_TOKEN: ${{ secrets.GH_NEW_CARD_TO_PROJECT }}
|
||||
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
|
||||
ISSUE_ID: ${{ github.event.issue.node_id }}
|
||||
USER: ${{ github.actor }}
|
||||
|
||||
@@ -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
|
||||
@@ -5,24 +5,21 @@ on:
|
||||
branches:
|
||||
- release/*
|
||||
- develop
|
||||
- main
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- ready_for_review
|
||||
- reopened
|
||||
- edited
|
||||
- synchronize
|
||||
jobs:
|
||||
node-modules:
|
||||
# All jobs depend on node_modules, so none should run if the PR is in draft
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-22.04
|
||||
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
|
||||
@@ -34,30 +31,37 @@ jobs:
|
||||
${{ runner.os }}-cache-node-modules-
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
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-format:
|
||||
timeout-minutes: 20
|
||||
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: 35
|
||||
needs: node-modules
|
||||
runs-on: ubuntu-22.04
|
||||
name: '(CI) lint + format check'
|
||||
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@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
@@ -83,151 +87,61 @@ jobs:
|
||||
- name: Build affected spec
|
||||
run: yarn nx affected --target=build-spec
|
||||
|
||||
test-affected:
|
||||
timeout-minutes: 30
|
||||
needs: build-sources
|
||||
runs-on: ubuntu-22.04
|
||||
name: 'run unit test of affected apps'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
||||
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v3
|
||||
with:
|
||||
main-branch-name: develop
|
||||
|
||||
- name: Test affected
|
||||
run: yarn nx affected:test
|
||||
|
||||
build-sources:
|
||||
timeout-minutes: 30
|
||||
needs: lint-format
|
||||
runs-on: ubuntu-22.04
|
||||
name: 'Build sources of affected apps'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
||||
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v3
|
||||
with:
|
||||
main-branch-name: develop
|
||||
- name: Build affected
|
||||
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
||||
|
||||
# See affected apps
|
||||
- name: See affected apps
|
||||
run: |
|
||||
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
|
||||
python3 tools/ci/check-affected.py --github-ref="${{ github.ref }}" --branch-slug="$branch_slug" --event-name="${{ github.event_name }}"
|
||||
echo ">>>> debug"
|
||||
echo "NX Version: $nx_version"
|
||||
echo "NX_BASE: ${{ env.NX_BASE }}"
|
||||
echo "NX_HEAD: ${{ env.NX_HEAD }}"
|
||||
echo ">>>> eof debug"
|
||||
|
||||
- name: Verify script result
|
||||
run: |
|
||||
echo "Check outputs from script"
|
||||
echo "projects: ${{ env.PROJECTS }}"
|
||||
echo "projects-e2e: ${{ env.PROJECTS_E2E }}"
|
||||
echo "preview_governance: ${{ env.PREVIEW_GOVERNANCE }}"
|
||||
echo "preview_trading: ${{ env.PREVIEW_TRADING }}"
|
||||
echo "preview_explorer: ${{ env.PREVIEW_EXPLORER }}"
|
||||
echo "preview_tools: ${{ env.PREVIEW_TOOLS }}"
|
||||
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_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
|
||||
|
||||
- name: Build affected
|
||||
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
||||
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 }}
|
||||
|
||||
check-e2e-needed:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-sources
|
||||
name: '(CI) check if e2e needed'
|
||||
outputs:
|
||||
run-tests: ${{ steps.check-test.outputs.e2e-needed }}
|
||||
steps:
|
||||
- name: Check branch
|
||||
id: check-test
|
||||
run: |
|
||||
if [[ "${{ github.base_ref }}" == "develop" ]]; then
|
||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.base_ref }}" == "main" ]]; then
|
||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/"* ]]; then
|
||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "e2e-needed=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Print result
|
||||
run: |
|
||||
echo "e2e-needed: ${{ steps.check-test.outputs.e2e-needed }}"
|
||||
|
||||
cypress:
|
||||
needs: [build-sources, check-e2e-needed]
|
||||
needs: lint-test-build
|
||||
name: '(CI) cypress'
|
||||
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/cypress-run.yml
|
||||
secrets: inherit
|
||||
if: needs.check-e2e-needed.outputs.run-tests == 'true' && (contains(needs.build-sources.outputs.projects, 'governance') || contains(needs.build-sources.outputs.projects, 'explorer'))
|
||||
with:
|
||||
projects: ${{ needs.build-sources.outputs.projects-e2e }}
|
||||
tags: '@smoke'
|
||||
|
||||
console-e2e:
|
||||
needs: [build-sources, check-e2e-needed]
|
||||
name: '(CI) trading e2e python'
|
||||
uses: ./.github/workflows/console-test-run.yml
|
||||
secrets: inherit
|
||||
if: needs.check-e2e-needed.outputs.run-tests == 'true' && contains(needs.build-sources.outputs.projects, 'trading')
|
||||
with:
|
||||
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
|
||||
tags: '@smoke @regression'
|
||||
|
||||
publish-dist:
|
||||
needs: build-sources
|
||||
needs: lint-test-build
|
||||
name: '(CD) publish dist'
|
||||
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
|
||||
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/publish-dist.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
projects: ${{ needs.build-sources.outputs.projects }}
|
||||
projects: ${{ needs.lint-test-build.outputs.projects }}
|
||||
|
||||
dist-check:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- publish-dist
|
||||
- build-sources
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
||||
timeout-minutes: 60
|
||||
needs: publish-dist
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
name: '(CD) comment preview links'
|
||||
steps:
|
||||
- name: Find Comment
|
||||
@@ -237,57 +151,38 @@ jobs:
|
||||
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.build-sources.outputs.preview_governance }}" =~ $regex ]]; then
|
||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_governance }}"; do
|
||||
echo "waiting for governance preview: ${{ needs.build-sources.outputs.preview_governance }}"
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
if [[ "${{ needs.build-sources.outputs.preview_explorer }}" =~ $regex ]]; then
|
||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_explorer }}"; do
|
||||
echo "waiting for explorer preview: ${{ needs.build-sources.outputs.preview_explorer }}"
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
if [[ "${{ needs.build-sources.outputs.preview_trading }}" =~ $regex ]]; then
|
||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_trading }}"; do
|
||||
echo "waiting for trading preview: ${{ needs.build-sources.outputs.preview_trading }}"
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
if [[ "${{ needs.build-sources.outputs.preview_tools }}" =~ $regex ]]; then
|
||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_tools }}"; do
|
||||
echo "waiting for tools preview: ${{ needs.build-sources.outputs.preview_tools }}"
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
- name: Inject slug/short variables
|
||||
if: ${{ steps.fc.outputs.comment-id == 0 }}
|
||||
uses: rlespinasse/github-slug-action@v4
|
||||
with:
|
||||
prefix: CI_
|
||||
|
||||
- name: Create comment
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
if: ${{ steps.fc.outputs.comment-id == 0 }}
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
Previews
|
||||
* governance: ${{ needs.build-sources.outputs.preview_governance }}
|
||||
* explorer: ${{ needs.build-sources.outputs.preview_explorer }}
|
||||
* trading: ${{ needs.build-sources.outputs.preview_trading }}
|
||||
* tools: ${{ needs.build-sources.outputs.preview_tools }}
|
||||
- explorer https://explorer.${{ env.CI_GITHUB_REF_NAME }}.vega.rocks
|
||||
- trading https://trading.${{ env.CI_GITHUB_REF_NAME }}.vega.rocks
|
||||
- governance https://governance.${{ env.CI_GITHUB_REF_NAME }}.vega.rocks
|
||||
|
||||
# Report single result at the end, to avoid mess with required checks in PR
|
||||
cypress-check:
|
||||
name: '(CI) cypress - check'
|
||||
runs-on: ubuntu-latest
|
||||
needs: cypress
|
||||
steps:
|
||||
- run: echo Done!
|
||||
|
||||
# Report single result at the end, to avoid mess with required checks in PR
|
||||
cypress-result:
|
||||
if: ${{ always() }}
|
||||
needs: cypress
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- run: |
|
||||
result="${{ needs.cypress.result }}"
|
||||
echo "Result: $result"
|
||||
if [[ $result == "success" || $result == "skipped" ]]; then
|
||||
exit 0
|
||||
else
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#managing-caches
|
||||
name: cleanup caches by a branch
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
jobs:
|
||||
cleanup:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
gh extension install actions/gh-actions-cache
|
||||
|
||||
echo "Fetching list of cache key"
|
||||
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
|
||||
|
||||
## Setting this to not fail the workflow while deleting cache keys.
|
||||
set +e
|
||||
echo "Deleting caches..."
|
||||
for cacheKey in $cacheKeysForPR
|
||||
do
|
||||
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
|
||||
done
|
||||
echo "Done"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
@@ -1,272 +0,0 @@
|
||||
name: (CI) Console tests
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
github-sha:
|
||||
required: true
|
||||
type: string
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
console-test-branch:
|
||||
type: choice
|
||||
description: 'main: v0.73.13, develop: v0.74.0'
|
||||
options:
|
||||
- main
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
create-docker-image:
|
||||
name: Create docker image for console-test
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
#----------------------------------------------
|
||||
# check-out frontend-monorepo
|
||||
#----------------------------------------------
|
||||
- name: Checkout frontend-monorepo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.github-sha || github.sha }}
|
||||
#----------------------------------------------
|
||||
# cache node modules
|
||||
#----------------------------------------------
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
|
||||
- name: Cache node modules
|
||||
id: cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
||||
# comment out "restore-keys" if you need to rebuild yarn from 0
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cache-node-modules-
|
||||
#----------------------------------------------
|
||||
# install deps if cache missing
|
||||
#----------------------------------------------
|
||||
- name: yarn install
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: yarn install --pure-lockfile
|
||||
#----------------------------------------------
|
||||
# build trading
|
||||
#----------------------------------------------
|
||||
- name: Build trading app
|
||||
run: |
|
||||
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
|
||||
DIST_LOCATION=dist/apps/trading/exported
|
||||
mv $DIST_LOCATION dist-result
|
||||
tree dist-result
|
||||
|
||||
#----------------------------------------------
|
||||
# export trading app docker image
|
||||
#----------------------------------------------
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and export to local Docker
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
load: true
|
||||
build-args: |
|
||||
APP=trading
|
||||
ENV_NAME=stagnet1
|
||||
tags: ci/trading:local
|
||||
outputs: type=docker,dest=/tmp/console-image.tar
|
||||
|
||||
- name: Verify docker image created
|
||||
run: |
|
||||
echo ${{ steps.docker_build.outputs.digest }}
|
||||
echo ${{ steps.docker_build.outputs.imageid }}
|
||||
|
||||
- name: Upload docker image for console-test usage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: console-image
|
||||
path: /tmp/console-image.tar
|
||||
|
||||
console-test-branch:
|
||||
name: Choose console-test branch to run on
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
console-branch: ${{ steps.output-step.outputs.branch }}
|
||||
steps:
|
||||
- name: Workflow dispatch input
|
||||
id: dispatch-step
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: echo "branch=${{ inputs.console-test-branch }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Print Workflow dispatch input
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: echo ${{ steps.dispatch-step.outputs.branch }}
|
||||
|
||||
- name: Workflow_call input
|
||||
id: workflow_call-step
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
run: |
|
||||
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
||||
echo "branch=main" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
|
||||
echo "branch=main" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
|
||||
echo "branch=main" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "branch=develop" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Print Workflow_call input
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
run: echo ${{ steps.workflow_call-step.outputs.branch }}
|
||||
|
||||
- name: Set output
|
||||
id: output-step
|
||||
run: echo "branch=${{ steps.dispatch-step.outputs.branch || steps.workflow_call-step.outputs.branch }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Print final output
|
||||
run: echo ${{ steps.output-step.outputs.branch }}
|
||||
|
||||
run-tests:
|
||||
name: run-tests
|
||||
runs-on: 8-cores
|
||||
needs: [create-docker-image, console-test-branch]
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
#----------------------------------------------
|
||||
# load docker image
|
||||
#----------------------------------------------
|
||||
- name: Download docker image from previous job
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: console-image
|
||||
path: /tmp
|
||||
|
||||
- name: Load Docker image
|
||||
run: |
|
||||
docker load --input /tmp/console-image.tar
|
||||
docker image ls -a
|
||||
#----------------------------------------------
|
||||
# check-out frontend-monorepo
|
||||
#----------------------------------------------
|
||||
- name: Checkout frontend-monorepo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.github-sha || github.sha }}
|
||||
#----------------------------------------------
|
||||
# get vega version
|
||||
#----------------------------------------------
|
||||
- name: Set VEGA_VERSION from .env
|
||||
id: set_vega_version
|
||||
run: echo "VEGA_VERSION=$(grep VEGA_VERSION apps/trading/e2e/.env | cut -d '=' -f2)" >> $GITHUB_ENV
|
||||
#----------------------------------------------
|
||||
# ----- Setup python -----
|
||||
#----------------------------------------------
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
#----------------------------------------------
|
||||
# ----- install & configure poetry -----
|
||||
#----------------------------------------------
|
||||
- name: Install Poetry
|
||||
uses: snok/install-poetry@v1
|
||||
with:
|
||||
virtualenvs-create: true
|
||||
virtualenvs-in-project: true
|
||||
virtualenvs-path: .venv
|
||||
|
||||
#----------------------------------------------
|
||||
# install python dependencies
|
||||
#----------------------------------------------
|
||||
- name: Install dependencies
|
||||
run: poetry install --no-interaction --no-root
|
||||
working-directory: apps/trading/e2e
|
||||
#----------------------------------------------
|
||||
# install vega binaries
|
||||
#----------------------------------------------
|
||||
- name: Install vega binaries
|
||||
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
|
||||
working-directory: apps/trading/e2e
|
||||
#----------------------------------------------
|
||||
# install playwrightworking-directory: apps/trading/e2e
|
||||
#----------------------------------------------
|
||||
- name: install playwright
|
||||
run: poetry run playwright install --with-deps chromium
|
||||
working-directory: apps/trading/e2e
|
||||
#----------------------------------------------
|
||||
# run tests
|
||||
#----------------------------------------------
|
||||
- name: Run tests
|
||||
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v --numprocesses 4 --dist loadfile --durations=45
|
||||
working-directory: apps/trading/e2e
|
||||
#----------------------------------------------
|
||||
# upload traces
|
||||
#----------------------------------------------
|
||||
- name: Upload Playwright Trace
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-trace
|
||||
path: apps/trading/e2e/traces/
|
||||
retention-days: 15
|
||||
#----------------------------------------------
|
||||
# ----- upload logs -----
|
||||
#----------------------------------------------
|
||||
- name: Upload worker logs
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: worker-logs
|
||||
path: ./logs/
|
||||
retention-days: 15
|
||||
#----------------------------------------------
|
||||
# ----- upload market-sim logs -----
|
||||
#----------------------------------------------
|
||||
- name: Prepare and Zip market-sim-logs
|
||||
if: always()
|
||||
run: |
|
||||
parent_dir="/tmp/market-sim-logs"
|
||||
echo "Creating parent directory at $parent_dir"
|
||||
mkdir -p "$parent_dir"
|
||||
|
||||
echo "Waiting for vega-sim-* folders to be created..."
|
||||
sleep 10 # Waits 10 seconds to ensure all folders are created
|
||||
|
||||
echo "Before searching for vega-sim-* folders in /tmp..."
|
||||
folders=$(find /tmp -mindepth 1 -type d -name 'vega-sim-*' -print) || echo "Find command failed with exit code $?"
|
||||
|
||||
echo "After searching for vega-sim-* folders in /tmp..."
|
||||
|
||||
if [ -z "$folders" ]; then
|
||||
echo "No vega-sim-* folders found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Moving vega-sim-* folders to $parent_dir"
|
||||
echo "$folders" | xargs -I {} mv {} "$parent_dir/"
|
||||
|
||||
echo "Checking if $parent_dir is not empty..."
|
||||
if [ "$(ls -A $parent_dir)" ]; then
|
||||
echo "Zipping the parent directory..."
|
||||
zip -r market-sim-logs.zip "$parent_dir" && echo "Zip file created successfully."
|
||||
else
|
||||
echo "$parent_dir is empty. No zip file created."
|
||||
exit 0
|
||||
fi
|
||||
shell: /usr/bin/bash -e {0}
|
||||
|
||||
- name: Upload market-sim-logs
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: market-sim-logs
|
||||
path: market-sim-logs.zip
|
||||
retention-days: 15
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Cypress Console tests -- live environment
|
||||
|
||||
# This workflow runs using provided url
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
url:
|
||||
description: 'Url'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
cypress-run:
|
||||
name: Run Cypress Trading tests -- live environment
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.15.1
|
||||
|
||||
- name: Run Cypress tests
|
||||
uses: cypress-io/github-action@v4
|
||||
with:
|
||||
browser: chrome
|
||||
record: true
|
||||
project: ./apps/trading-e2e
|
||||
config: baseUrl=${{ github.event.inputs.url }}
|
||||
env: grepTags=@live
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -12,6 +12,7 @@ on:
|
||||
options:
|
||||
- explorer-e2e
|
||||
- governance-e2e
|
||||
- trading-e2e
|
||||
tags:
|
||||
description: 'Test tags to run'
|
||||
required: true
|
||||
|
||||
@@ -10,5 +10,5 @@ jobs:
|
||||
uses: ./.github/workflows/cypress-run.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
projects: '["explorer-e2e","governance-e2e"]'
|
||||
projects: '["explorer-e2e","governance-e2e","trading-e2e"]'
|
||||
tags: '@smoke @regression @slow'
|
||||
|
||||
@@ -13,36 +13,14 @@ on:
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
runner-choice:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
runner: ${{ steps.step.outputs.runner }}
|
||||
steps:
|
||||
- name: Check branch
|
||||
id: step
|
||||
run: |
|
||||
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
|
||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
|
||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "runner=self-hosted-runner" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Print runner
|
||||
run: echo ${{ steps.step.outputs.runner }}
|
||||
|
||||
e2e:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
project: ${{ fromJSON(inputs.projects) }}
|
||||
name: ${{ matrix.project }}
|
||||
needs: runner-choice
|
||||
runs-on: ${{ needs.runner-choice.outputs.runner }}
|
||||
timeout-minutes: 120
|
||||
runs-on: self-hosted-runner
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
# Checks if skip cache was requested
|
||||
- name: Set skip-nx-cache flag
|
||||
@@ -55,19 +33,9 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
path: './frontend-monorepo'
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './frontend-monorepo/.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
cache: yarn
|
||||
cache-dependency-path: './frontend-monorepo/yarn.lock'
|
||||
|
||||
# Restore node_modules from cache if possible
|
||||
- name: Restore node_modules from cache
|
||||
id: cache-node-modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
@@ -77,7 +45,6 @@ jobs:
|
||||
|
||||
# Install frontend dependencies
|
||||
- name: Install root dependencies
|
||||
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
||||
run: yarn install --frozen-lockfile
|
||||
working-directory: frontend-monorepo
|
||||
|
||||
@@ -93,14 +60,13 @@ jobs:
|
||||
- name: Run Vegacapsule network and Vega wallet
|
||||
id: setup-vega
|
||||
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
||||
timeout-minutes: 10
|
||||
|
||||
######
|
||||
## Run some 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
|
||||
env:
|
||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||
@@ -132,4 +98,4 @@ jobs:
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
name: test-report-${{ matrix.project }}
|
||||
path: frontend-monorepo/apps/${{ matrix.project }}/cypress/reports
|
||||
path: frontend-monorepo/apps/trading-e2e/cypress/reports
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
name: Verify PR title
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- reopened
|
||||
- synchronize
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lint_pr:
|
||||
@@ -18,14 +13,17 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
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: Install dependencies
|
||||
run: |
|
||||
rm package.json
|
||||
npm install --no-save @commitlint/cli@16.3.0 @commitlint/config-conventional@18.6.1 @commitlint/config-nx-scopes@18.6.1 nx@17.1.2
|
||||
- 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/cli@16.3.0 --config ./commitlint.config-ci.js
|
||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Generate tranches
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 */6 * * *'
|
||||
|
||||
jobs:
|
||||
master:
|
||||
name: Generate Queries
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
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
|
||||
@@ -19,53 +19,6 @@ jobs:
|
||||
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
|
||||
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
||||
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
|
||||
echo IS_MAIN_IMAGE=false >> $GITHUB_ENV
|
||||
|
||||
- name: Is dev image
|
||||
if: ${{ github.ref_name == 'develop' && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||
run: |
|
||||
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is main image
|
||||
if: ${{ github.ref_name == 'main' && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||
run: |
|
||||
echo IS_MAIN_IMAGE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is PR
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
echo IS_PR=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is mainnet release
|
||||
if: ${{ contains(github.ref, 'release/mainnet') && !contains(github.ref, 'mirror') }}
|
||||
run: |
|
||||
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is testnet release
|
||||
if: ${{ contains(github.ref, 'release/testnet') }}
|
||||
run: |
|
||||
echo IS_TESTNET_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is IPFS Release
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( env.IS_MAINNET_RELEASE == 'true' || env.IS_TESTNET_RELEASE == 'true' ) }}
|
||||
run: |
|
||||
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is S3 Release
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' && github.ref_name != 'main'}}
|
||||
run: |
|
||||
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Set up QEMU
|
||||
id: quemu
|
||||
@@ -77,23 +30,15 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to the Container registry (ghcr)
|
||||
if: ${{ env.IS_PR == 'true' }}
|
||||
- name: Log in to the Container registry
|
||||
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' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
@@ -106,36 +51,46 @@ jobs:
|
||||
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' }}
|
||||
- name: Define variables
|
||||
run: |
|
||||
python3 tools/ci/define-dist-variables.py --github-ref="${{ github.ref }}" --app="${{ matrix.app }}"
|
||||
|
||||
- name: Verify script result
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
run: |
|
||||
echo "BUCKET_NAME=${{ env.BUCKET_NAME }}"
|
||||
echo "ENV_NAME=${{ env.ENV_NAME }}"
|
||||
envName=''
|
||||
dockerfile="dist.Dockerfile"
|
||||
if [[ "${{ github.event_name }}" = "push" ]]; then
|
||||
domain="vega.rocks"
|
||||
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
||||
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
|
||||
if [[ "${{ github.ref }}" =~ .*mainnet.* ]]; then
|
||||
domain="vega.community"
|
||||
if [[ "${{ matrix.app }}" = "trading" ]]; then
|
||||
dockerfile="ipfs.Dockerfile"
|
||||
fi
|
||||
fi
|
||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||
envName="stagnet3"
|
||||
fi
|
||||
bucketName="${{ matrix.app }}.${envName}.${domain}"
|
||||
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
|
||||
fi
|
||||
nodeVersion=$(cat .nvmrc | head -n 1)
|
||||
echo ENV_NAME=${envName} >> $GITHUB_ENV
|
||||
echo NODE_VERSION=${nodeVersion} >> $GITHUB_ENV
|
||||
echo DOCKERFILE=docker/${dockerfile} >> $GITHUB_ENV
|
||||
|
||||
- name: Build local dist
|
||||
if: ${{ env.DOCKERFILE != 'docker/ipfs.Dockerfile' }}
|
||||
run: |
|
||||
envCmd=""
|
||||
flags=""
|
||||
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
|
||||
envCmd="yarn env-cmd -f ./apps/${{ matrix.app }}/.env.${{ env.ENV_NAME }}"
|
||||
if [[ "${{ env.ENV_NAME }}" != "ops-vega" ]]; then
|
||||
flags="--env=${{ env.ENV_NAME }}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${{ matrix.app }}" = "trading" ]; then
|
||||
$envCmd yarn nx export trading || (yarn install && $envCmd yarn nx export trading)
|
||||
yarn nx export trading $flags || (yarn install && yarn nx export trading $flags)
|
||||
DIST_LOCATION=dist/apps/trading/exported
|
||||
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
||||
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
||||
DIST_LOCATION=dist/storybook/ui-toolkit
|
||||
elif [ "${{ matrix.app }}" = "static" ]; then
|
||||
yarn nx build static || (yarn install && yarn nx build static)
|
||||
else
|
||||
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
|
||||
fi
|
||||
if [[ -z "$DIST_LOCATION" ]]; then
|
||||
yarn nx build ${{ matrix.app }} $flags || (yarn install && yarn nx build ${{ matrix.app }} $flags)
|
||||
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
||||
fi
|
||||
mv $DIST_LOCATION dist-result
|
||||
@@ -143,92 +98,62 @@ jobs:
|
||||
|
||||
- name: Build and export to local Docker
|
||||
id: docker_build
|
||||
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
file: ${{ env.DOCKERFILE }}
|
||||
load: true
|
||||
build-args: |
|
||||
APP=${{ matrix.app }}
|
||||
NODE_VERSION=${{ env.NODE_VERSION }}
|
||||
ENV_NAME=${{ env.ENV_NAME }}
|
||||
tags: |
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||
|
||||
- name: Image digest
|
||||
if: ${{ env.IS_PR == 'true' }}
|
||||
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
|
||||
- name: Sanity check docker image
|
||||
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
|
||||
run: |
|
||||
echo "Check ipfs-hash"
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash'
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash
|
||||
if [[ "${{ env.DOCKERFILE }}" = "docker/ipfs.Dockerfile" ]]; then
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
|
||||
fi
|
||||
|
||||
echo "List html directory"
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'apk add --update tree; tree /usr/share/nginx/html'
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree .'
|
||||
|
||||
- name: Publish dist as docker image (ghcr)
|
||||
- name: Copy dist to local filesystem
|
||||
if: ${{ env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' }}
|
||||
run: |
|
||||
docker create --name=dist ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||
docker cp dist:/usr/share/nginx/html dist
|
||||
|
||||
echo "check local dist files"
|
||||
tree dist/html
|
||||
mv dist/html dist-result
|
||||
|
||||
- name: Publish dist as docker image
|
||||
uses: docker/build-push-action@v3
|
||||
continue-on-error: true
|
||||
id: ghcr-push
|
||||
if: ${{ env.IS_PR == 'true' }}
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
file: ${{ env.DOCKERFILE }}
|
||||
push: true
|
||||
build-args: |
|
||||
APP=${{ matrix.app }}
|
||||
NODE_VERSION=${{ env.NODE_VERSION }}
|
||||
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' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == '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' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
|
||||
|
||||
- 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' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
|
||||
|
||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
||||
- name: Publish dist to s3
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
# s3 releases are not happening for trading on mainnet - it's IPFS
|
||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
with:
|
||||
args: --acl private --follow-symlinks --delete
|
||||
env:
|
||||
@@ -238,106 +163,9 @@ jobs:
|
||||
AWS_REGION: 'eu-west-1'
|
||||
SOURCE_DIR: 'dist-result'
|
||||
|
||||
- name: Install aws CLI
|
||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||
uses: unfor19/install-aws-cli-action@master
|
||||
|
||||
- name: Perform cache invalidation
|
||||
if: ${{ env.IS_S3_RELEASE == 'true' }}
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: 'eu-west-1'
|
||||
run: |
|
||||
echo "Looking for distribution for bucket: ${{ env.BUCKET_NAME }}"
|
||||
id=$(aws cloudfront list-distributions | jq -Mrc '.DistributionList.Items | .[] | select(.DefaultCacheBehavior.TargetOriginId == "${{ env.BUCKET_NAME }}") | .Id')
|
||||
echo "Found id is: ${id}"
|
||||
aws cloudfront create-invalidation --distribution-id $id --paths "/*"
|
||||
|
||||
- name: Add preview label
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
if: ${{ env.IS_PR == 'true' }}
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
labels: ${{ matrix.app }}-preview
|
||||
number: ${{ github.event.number }}
|
||||
|
||||
- name: Trigger fleek deployment
|
||||
# release to ipfs happens only on mainnet (represented by main branch) for trading
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
|
||||
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
|
||||
if ! git diff --cached --exit-code; then
|
||||
commit_msg="Automated hash update from ${{ github.ref }}"
|
||||
git commit -m "$commit_msg"
|
||||
git push -u origin "main"
|
||||
fi
|
||||
)
|
||||
|
||||
@@ -15,7 +15,6 @@ on:
|
||||
- types
|
||||
- utils
|
||||
- i18n
|
||||
- wallet
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
@@ -29,7 +28,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
|
||||
@@ -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
|
||||
)
|
||||
+2
-13
@@ -2,7 +2,6 @@
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/dist-result
|
||||
/tmp
|
||||
/out-tsc
|
||||
/tools/executors/**/*.js
|
||||
@@ -48,15 +47,5 @@ cypress.env.json
|
||||
# Next.js
|
||||
.next
|
||||
|
||||
# cypress
|
||||
/apps/**/cypress/reports/
|
||||
/apps/**/cypress/downloads/
|
||||
/apps/**/fixtures/wallet/node**
|
||||
|
||||
# apps/trading/e2e
|
||||
__pycache__/
|
||||
apps/trading/e2e/logs/
|
||||
apps/trading/e2e/.pytest_cache/
|
||||
apps/trading/e2e/traces/
|
||||
|
||||
.nx/
|
||||
#cypress
|
||||
/apps/trading-e2e/cypress/reports/
|
||||
|
||||
@@ -3,3 +3,6 @@
|
||||
|
||||
# Lint commit messages to ensure they follow conventional commit standards
|
||||
yarn commitlint --edit "${1}"
|
||||
|
||||
# Lint all staged files
|
||||
yarn lint-staged
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
# Auto-format all files
|
||||
yarn nx format:write
|
||||
|
||||
# Lint all staged files
|
||||
yarn lint-staged
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
# Lint all staged files - this brings more value as pre-commit
|
||||
# yarn nx format:check
|
||||
|
||||
# Test all projects with changes
|
||||
# yarn nx affected -t test --exclude trading
|
||||
+1
-13
@@ -1,23 +1,11 @@
|
||||
# Add files here to ignore them from prettier formatting
|
||||
|
||||
/dist
|
||||
/dist-result
|
||||
/coverage
|
||||
__generated__
|
||||
__generated___
|
||||
|
||||
apps/static/src/assets/devnet-tranches.json
|
||||
apps/static/src/assets/mainnet-tranches.json
|
||||
apps/static/src/assets/stagnet3-tranches.json
|
||||
apps/static/src/assets/testnet-tranches.json
|
||||
|
||||
/apps/**/cypress/reports/
|
||||
/apps/**/cypress/downloads/
|
||||
|
||||
/.nx/cache
|
||||
|
||||
# apps/trading/e2e
|
||||
__pycache__/
|
||||
apps/trading/e2e/logs/
|
||||
apps/trading/e2e/.pytest_cache/
|
||||
apps/trading/e2e/traces/
|
||||
.pytest_cache/
|
||||
|
||||
@@ -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": ["../**/*"]
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
# path to a directory with all packages
|
||||
storage: ../tmp/local-registry/storage
|
||||
|
||||
# a list of other known repositories we can talk to
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: https://registry.yarnpkg.com
|
||||
maxage: 60m
|
||||
|
||||
packages:
|
||||
'**':
|
||||
# give all users (including non-authenticated users) full access
|
||||
# because it is a local registry
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: $all
|
||||
|
||||
# if package is not available locally, proxy requests to npm registry
|
||||
proxy: npmjs
|
||||
|
||||
# log settings
|
||||
logs:
|
||||
type: stdout
|
||||
format: pretty
|
||||
level: warn
|
||||
|
||||
publish:
|
||||
allow_offline: true # set offline to true to allow publish offline
|
||||
@@ -1,4 +1,2 @@
|
||||
* @vegaprotocol/frontend
|
||||
apps/ @vegaprotocol/frontend-qa
|
||||
libs/ @vegaprotocol/frontend-qa
|
||||
*.graphql @vegaprotocol/core
|
||||
|
||||
Vendored
+19
-1
@@ -1,2 +1,20 @@
|
||||
@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 -rQ /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
|
||||
@@ -4,7 +4,7 @@ The front-end monorepo provides a toolkit for building apps that interact with V
|
||||
|
||||
This repository is managed using [Nx](https://nx.dev).
|
||||
|
||||
## 🔎 Applications in this repo
|
||||
# 🔎 Applications in this repo
|
||||
|
||||
### [Block explorer](./apps/explorer)
|
||||
|
||||
@@ -30,7 +30,7 @@ Hosting for static content being shared across apps, for example fonts.
|
||||
|
||||
The utility dApp for validators wishing to add or remove themselves as a signer of the multisig contract.
|
||||
|
||||
## 🧱 Libraries in this repo
|
||||
# 🧱 Libraries in this repo
|
||||
|
||||
### [UI toolkit](./libs/ui-toolkit)
|
||||
|
||||
@@ -53,7 +53,7 @@ A utility library for connecting to the Ethereum network and interacting with Ve
|
||||
|
||||
Generic react helpers that can be used across multiple applications, along with other utilities.
|
||||
|
||||
## 💻 Develop
|
||||
# 💻 Develop
|
||||
|
||||
### Set up
|
||||
|
||||
@@ -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`.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
@@ -103,82 +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.
|
||||
|
||||
## 🐋 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:
|
||||
|
||||
```bash
|
||||
docker run -p 3000:80 [TAG]
|
||||
```
|
||||
|
||||
On top of that there are two possible scenarios for running docker image - using nginx server (default) of ipfs daemon.
|
||||
|
||||
to run ipfs on port 3000:
|
||||
|
||||
```bash
|
||||
docker run -p 3000:80 [TAG] /run-ipfs.sh
|
||||
```
|
||||
|
||||
to run nginx on port 3000:
|
||||
|
||||
```bash
|
||||
docker run -p 3000:80 [TAG]
|
||||
```
|
||||
|
||||
## Build instructions
|
||||
|
||||
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of Console either for the web, or ready for pinning on IPFS.
|
||||
|
||||
### nx build inside the docker
|
||||
|
||||
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build). The multistage builds ensures consistent CPU architecture and build toolchains are used so that the result will be identical.
|
||||
|
||||
```bash
|
||||
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=20.11 --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
|
||||
```
|
||||
|
||||
### Computing ipfs-hash of the build
|
||||
|
||||
At the moment this feature is important only for Console releases.
|
||||
|
||||
Each docker build finishes with hash calculation for ` dist`` directory. Resulting hash is added to file named as `/ipfs-hash`. Once docker image is produced you can run following commad to display ipfs-hash:
|
||||
|
||||
```bash
|
||||
make recalculate-ipfs TAG=vegaprotocol/trading:{YOUR_VERSION}
|
||||
```
|
||||
|
||||
**updating hash:** recompiling dist directory (even if there are no changed to source code) results in different hash computed by ipfs command.
|
||||
|
||||
### nx build outside the docker
|
||||
|
||||
This Docker image packages a pre-built `dist` folder into an [`nginx`](https://hub.docker.com/_/nginx)([server configuration](./nginx/nginx.conf)) docker image. In this case, the application on docker host machine from source.
|
||||
|
||||
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
|
||||
```
|
||||
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 -f docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
||||
docker build --dockerfile dockerfiles/Dockerfile.cra . --build-arg APP=[YOUR APP] --tag=[TAG]
|
||||
```
|
||||
|
||||
### Verifying ipfs-hash of existing current application version
|
||||
In order to run a container:
|
||||
|
||||
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:
|
||||
```bash
|
||||
docker run -p 3000:80 [TAG]
|
||||
```
|
||||
|
||||
1. Show latest release by running: `make latest-release`. You need to configure [`gh`](https://cli.github.com/) for this step to work, otherwise please provide release manually from [github](https://github.com/vegaprotocol/frontend-monorepo/releases) or [dockerhub](https://hub.docker.com/r/vegaprotocol/trading)
|
||||
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
|
||||
Images ending with `.dist` are to pack locally created transpiled HTML files into nginx container for non-compatible with yarn architectures like M1 Mac
|
||||
|
||||
## Config
|
||||
|
||||
@@ -226,6 +169,6 @@ Note: The script is only needed if capsule was built for first time or fresh. To
|
||||
vega wallet service run -n DV --load-tokens --tokens-passphrase-file passphrase --no-version-check --automatic-consent --home ~/.vegacapsule/testnet/wallet
|
||||
```
|
||||
|
||||
## 📑 License
|
||||
# 📑 License
|
||||
|
||||
[MIT](./LICENSE)
|
||||
|
||||
@@ -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_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_CONFIG_URL=
|
||||
|
||||
@@ -16,10 +17,5 @@ NX_EXPLORER_NETWORK_PARAMETERS=1
|
||||
NX_EXPLORER_PARTIES=1
|
||||
NX_EXPLORER_VALIDATORS=1
|
||||
|
||||
CYPRESS_VEGA_URL=http://localhost:3008/graphql
|
||||
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
||||
CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545
|
||||
CYPRESS_FAUCET_URL=http://localhost:1790/api/v1/mint
|
||||
CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65
|
||||
CYPRESS_VEGA_WALLET_URL=http://localhost:1789
|
||||
CYPRESS_VEGA_WALLET_API_TOKEN=
|
||||
CYPRESS_VEGA_URL=http://localhost:3028/query
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
# 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_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||
NX_VEGA_ENV=DEVNET
|
||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# 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_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_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -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,10 +1,10 @@
|
||||
# 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_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_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {
|
||||
"cypress/unsafe-to-chain-command": 0
|
||||
}
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
const { defineConfig } = require('cypress');
|
||||
|
||||
module.exports = defineConfig({
|
||||
reporter: '../../node_modules/cypress-mochawesome-reporter',
|
||||
projectId: 'et4snf',
|
||||
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
require('cypress-mochawesome-reporter/plugin')(on);
|
||||
require('@cypress/grep/src/plugin')(config);
|
||||
return config;
|
||||
},
|
||||
@@ -23,11 +22,10 @@ module.exports = defineConfig({
|
||||
viewportWidth: 1440,
|
||||
viewportHeight: 900,
|
||||
testIsolation: false,
|
||||
experimentalMemoryManagement: true,
|
||||
},
|
||||
env: {
|
||||
environment: 'CUSTOM',
|
||||
networkQueryUrl: 'http://localhost:3008/graphql',
|
||||
networkQueryUrl: 'http://localhost:3028/query',
|
||||
ethUrl: 'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
|
||||
commitHash: 'dev',
|
||||
tsConfig: 'tsconfig.json',
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"name": "explorer-e2e",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/explorer-e2e/src",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"e2e": {
|
||||
"executor": "@nx/cypress:cypress",
|
||||
"executor": "@nrwl/cypress:cypress",
|
||||
"options": {
|
||||
"cypressConfig": "apps/explorer-e2e/cypress.config.js",
|
||||
"devServerTarget": "explorer:serve"
|
||||
@@ -17,14 +16,14 @@
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "nx:run-commands",
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"outputs": [],
|
||||
"options": {
|
||||
"command": "yarn tsc --project ./apps/explorer-e2e/"
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"proposalSubmission": {
|
||||
"rationale": {
|
||||
"title": "Test new asset proposal",
|
||||
"description": "E2E test for proposals"
|
||||
},
|
||||
"terms": {
|
||||
"newAsset": {
|
||||
"changes": {
|
||||
"name": "USDT Coin",
|
||||
"symbol": "USDT",
|
||||
"decimals": "18",
|
||||
"quantum": "1",
|
||||
"erc20": {
|
||||
"contractAddress": "0xb404c51bbc10dcbe948077f18a4b8e553d160084",
|
||||
"withdrawThreshold": "10",
|
||||
"lifetimeLimit": "10"
|
||||
}
|
||||
}
|
||||
},
|
||||
"closingTimestamp": 1724339572,
|
||||
"enactmentTimestamp": 1724339572,
|
||||
"validationTimestamp": 1692799617
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,6 @@
|
||||
"governance.proposal.updateMarket.minVoterBalance",
|
||||
"governance.proposal.updateNetParam.minProposerBalance",
|
||||
"governance.proposal.updateNetParam.minVoterBalance",
|
||||
"governance.proposal.updateAsset.minProposerBalance",
|
||||
"governance.proposal.updateAsset.minVoterBalance",
|
||||
"reward.staking.delegation.maxPayoutPerEpoch",
|
||||
"reward.staking.delegation.maxPayoutPerParticipant",
|
||||
"reward.staking.delegation.minimumValidatorStake",
|
||||
@@ -21,6 +19,9 @@
|
||||
"validators.delegation.minAmount"
|
||||
],
|
||||
"fiveDecimal": [
|
||||
"governance.proposal.updateAsset.minProposerBalance",
|
||||
"governance.proposal.updateAsset.minVoterBalance",
|
||||
"governance.proposal.updateAsset.requiredParticipation",
|
||||
"market.fee.factors.infrastructureFee",
|
||||
"market.fee.factors.makerFee",
|
||||
"market.liquidity.bondPenaltyParameter",
|
||||
@@ -76,7 +77,6 @@
|
||||
"governance.proposal.updateNetParam.requiredMajority",
|
||||
"governance.proposal.updateNetParam.requiredParticipation",
|
||||
"governance.proposal.updateMarket.minProposerEquityLikeShare",
|
||||
"governance.proposal.updateAsset.requiredParticipation",
|
||||
"validators.vote.required"
|
||||
],
|
||||
"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) => {
|
||||
assets.forEach((asset) => {
|
||||
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 () {
|
||||
const statTitles = {
|
||||
0: 'Status',
|
||||
1: 'Epoch',
|
||||
2: 'Block height',
|
||||
3: 'Uptime',
|
||||
4: 'Total nodes',
|
||||
5: 'Total staked',
|
||||
6: 'Backlog',
|
||||
7: 'Trades / second',
|
||||
8: 'Orders / block',
|
||||
9: 'Orders / second',
|
||||
10: 'Transactions / block',
|
||||
11: 'Block time',
|
||||
12: 'Time',
|
||||
13: 'App',
|
||||
14: 'Tendermint',
|
||||
15: 'Up since',
|
||||
16: 'Chain ID',
|
||||
1: 'Block height',
|
||||
2: 'Uptime',
|
||||
3: 'Total nodes',
|
||||
4: 'Total staked',
|
||||
5: 'Backlog',
|
||||
6: 'Trades / second',
|
||||
7: 'Orders / block',
|
||||
8: 'Orders / second',
|
||||
9: 'Transactions / block',
|
||||
10: 'Block time',
|
||||
11: 'Time',
|
||||
12: 'App',
|
||||
13: 'Tendermint',
|
||||
14: 'Up since',
|
||||
15: 'Chain ID',
|
||||
};
|
||||
|
||||
cy.get('[data-testid="stats-title"]')
|
||||
@@ -32,13 +31,42 @@ context('Home Page', function () {
|
||||
cy.wrap($list).should('contain.text', statTitles[index]);
|
||||
})
|
||||
.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 () {
|
||||
cy.get(statsValue)
|
||||
.eq(2)
|
||||
.eq(1)
|
||||
.invoke('text')
|
||||
.then((blockHeightTxt) => {
|
||||
cy.get(statsValue)
|
||||
|
||||
@@ -1,168 +1,19 @@
|
||||
import { createSuccessorMarketProposal } from '../support/governance.functions';
|
||||
|
||||
context('Market page', { tags: '@regression' }, function () {
|
||||
//Tests set to skip until market bug for capsule checkpoint is fixed
|
||||
context.skip('Market page', { tags: '@regression' }, function () {
|
||||
describe('Verify elements on page', function () {
|
||||
const marketHeaders = 'markets-heading';
|
||||
const marketHeaders = '[data-testid="markets-header"]';
|
||||
const marketNavigation = 'a[href="/markets"]';
|
||||
|
||||
before('Create market', function () {
|
||||
it('Markets page is displayed', function () {
|
||||
cy.visit('/');
|
||||
cy.createMarket();
|
||||
cy.get(marketNavigation).click();
|
||||
cy.common_validate_blocks_data_displayed(marketHeaders);
|
||||
});
|
||||
|
||||
beforeEach('Get market id', function () {
|
||||
cy.navigate_to('markets');
|
||||
cy.get('[col-id="id"]').last().invoke('text').as('createdMarketId');
|
||||
});
|
||||
|
||||
it('Market displayed on market page', function () {
|
||||
cy.navigate_to('markets');
|
||||
cy.getByTestId(marketHeaders).should('be.visible');
|
||||
cy.get(`[row-id="${this.createdMarketId}"]`)
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.get_element_by_col_id('code').should('have.text', 'TEST.24h');
|
||||
cy.get_element_by_col_id('name').should('have.text', 'Test market 1');
|
||||
cy.get_element_by_col_id('state').should('have.text', 'Pending');
|
||||
cy.get_element_by_col_id('asset').should('have.text', 'fUSDC');
|
||||
cy.get_element_by_col_id('id').should(
|
||||
'have.text',
|
||||
this.createdMarketId
|
||||
);
|
||||
cy.get_element_by_col_id('actions')
|
||||
.find('a')
|
||||
.should('have.attr', 'href', `/markets/${this.createdMarketId}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to go to market details page', function () {
|
||||
cy.navigate_to('markets');
|
||||
cy.contains('Test market 1').click();
|
||||
cy.getByTestId(marketHeaders).should('have.text', 'Test market 1');
|
||||
cy.validate_element_from_table('Name', 'Test market 1');
|
||||
cy.validate_element_from_table('Trading Mode', 'Opening auction');
|
||||
cy.validate_element_from_table('Market Decimal Places', '5');
|
||||
cy.validate_element_from_table('Position Decimal Places', '5');
|
||||
cy.validate_element_from_table('Settlement Asset Decimal Places', '5');
|
||||
// Instrument
|
||||
cy.validate_element_from_table('Market Name', 'Test market 1');
|
||||
cy.validate_element_from_table('Code', 'TEST.24h');
|
||||
cy.validate_element_from_table('Product Type', 'Future');
|
||||
cy.validate_element_from_table('Quote Name', 'fUSDC');
|
||||
// Settlement Asset
|
||||
cy.validate_element_from_table('Quote Name', 'fUSDC');
|
||||
cy.validate_element_from_table('Symbol', 'fUSDC');
|
||||
cy.validate_element_from_table('Decimals', '5');
|
||||
cy.validate_element_from_table('Quantum', '0.00');
|
||||
cy.validate_element_from_table('Status', 'Enabled');
|
||||
cy.validate_element_from_table('Max faucet amount', '10,000,000.00');
|
||||
cy.validate_element_from_table(
|
||||
'Infrastructure fee account balance',
|
||||
'0.00'
|
||||
);
|
||||
cy.validate_element_from_table(
|
||||
'Global reward pool account balance',
|
||||
'0.00'
|
||||
);
|
||||
// Metadata
|
||||
cy.validate_element_from_table('Sector', 'tech');
|
||||
cy.validate_element_from_table('Source', 'docs.vega.xyz');
|
||||
// Risk model
|
||||
cy.validate_element_from_table('Tau', '0.0001140771161');
|
||||
cy.validate_element_from_table('Risk Aversion Parameter', '0.01');
|
||||
// Risk parameters
|
||||
// cy.validate_element_from_table('R', '0.016')
|
||||
cy.validate_element_from_table('Sigma', '0.5');
|
||||
// Risk factors
|
||||
cy.validate_element_from_table('Short', '0.0143218738374871');
|
||||
cy.validate_element_from_table('Long', '0.0141450471498822');
|
||||
// Price monitoring settings 1
|
||||
cy.validate_element_from_table('Horizon Secs', '43,200');
|
||||
cy.validate_element_from_table('Probability', '1');
|
||||
cy.validate_element_from_table('Auction Extension Secs', '600');
|
||||
// Liquidity Monitoring
|
||||
cy.validate_element_from_table('Triggering Ratio', '0.7');
|
||||
cy.validate_element_from_table('Time Window', '3,600');
|
||||
cy.validate_element_from_table('Scaling Factor', '10');
|
||||
// Liquidity
|
||||
cy.validate_element_from_table('Target Stake', '0.00 fUSDC');
|
||||
cy.validate_element_from_table('Supplied Stake', '0.00 fUSDC');
|
||||
// Liquidity price range
|
||||
cy.validate_element_from_table(
|
||||
'Liquidity Price Range',
|
||||
'95.00% of mid price'
|
||||
);
|
||||
cy.validate_element_from_table('Lowest Price', '0.00 fUSDC');
|
||||
cy.validate_element_from_table('Highest Price', '0.00 fUSDC');
|
||||
cy.getByTestId('oracle-spec-links')
|
||||
.should('have.attr', 'href')
|
||||
.and(
|
||||
'contain',
|
||||
'/oracles/bf242aa5c9f64fcbb77808aa8582e73711519f4b35264eb797a80f1803590a24'
|
||||
);
|
||||
|
||||
// Able to view Json
|
||||
cy.contains('View JSON').click();
|
||||
cy.get('.language-json').should('exist');
|
||||
cy.getByTestId('icon-cross').click();
|
||||
});
|
||||
|
||||
// Skipping due to resize observer loop limit error
|
||||
it.skip('Markets page displayed on mobile', function () {
|
||||
it('Markets page displayed on mobile', function () {
|
||||
cy.common_switch_to_mobile_and_click_toggle();
|
||||
cy.navigate_to('markets', true);
|
||||
cy.getByTestId(marketHeaders).should('be.visible');
|
||||
cy.get(`[row-id="${this.createdMarketId}"]`)
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.get_element_by_col_id('code').should('have.text', 'TEST.24h');
|
||||
cy.get_element_by_col_id('name').should('have.text', 'Test market 1');
|
||||
cy.get_element_by_col_id('state').should('have.text', 'Pending');
|
||||
cy.get_element_by_col_id('asset').should('have.text', 'fUSDC');
|
||||
cy.get_element_by_col_id('id').should(
|
||||
'have.text',
|
||||
this.createdMarketId
|
||||
);
|
||||
cy.get_element_by_col_id('actions')
|
||||
.find('a')
|
||||
.should('have.attr', 'href', `/markets/${this.createdMarketId}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to go to market details page for successor market', function () {
|
||||
const successionLineItem = 'succession-line-item';
|
||||
const successionLineMarketId = 'succession-line-item-market-id';
|
||||
|
||||
createSuccessorMarketProposal(this.createdMarketId);
|
||||
cy.navigate_to('markets');
|
||||
cy.reload();
|
||||
cy.contains('Token test market', { timeout: 8000 }).should('be.visible');
|
||||
cy.get('[row-index="0"]')
|
||||
.invoke('attr', 'row-id')
|
||||
.as('successorMarketId');
|
||||
cy.contains('Token test market').click();
|
||||
cy.getByTestId(marketHeaders).should('have.text', 'Token test market');
|
||||
cy.validate_element_from_table('Triggering Ratio', '0.7');
|
||||
cy.validate_element_from_table('Time Window', '3,600');
|
||||
cy.validate_element_from_table('Scaling Factor', '10');
|
||||
|
||||
cy.getByTestId(successionLineItem)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.contains('Test market 1');
|
||||
cy.getByTestId(successionLineMarketId).should(
|
||||
'have.text',
|
||||
this.createdMarketId
|
||||
);
|
||||
});
|
||||
cy.getByTestId(successionLineItem)
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.contains('Token test market');
|
||||
cy.getByTestId(successionLineMarketId).should(
|
||||
'have.text',
|
||||
this.successorMarketId
|
||||
);
|
||||
});
|
||||
cy.get(marketNavigation).click();
|
||||
cy.common_validate_blocks_data_displayed(marketHeaders);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
context('Network parameters page', { tags: '@smoke' }, function () {
|
||||
before('navigate to network parameter page', function () {
|
||||
cy.fixture('net_parameter_format_lookup').as('networkParameterFormat');
|
||||
cy.visit('/network-parameters');
|
||||
});
|
||||
describe('Verify elements on page', function () {
|
||||
beforeEach(() => {
|
||||
cy.visit('/network-parameters');
|
||||
});
|
||||
|
||||
const networkParametersHeader = '[data-testid="network-param-header"]';
|
||||
const tableRows = '[data-testid="key-value-table-row"]';
|
||||
|
||||
@@ -13,7 +16,6 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
// 0006-NETW-021
|
||||
it('should list each of the network parameters available', function () {
|
||||
cy.get_network_parameters().then((network_parameters) => {
|
||||
const numberOfNetworkParametersInSystem =
|
||||
@@ -136,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) => {
|
||||
network_parameters = Object.entries(network_parameters);
|
||||
network_parameters.forEach((network_parameter) => {
|
||||
@@ -196,19 +198,6 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
// 0006-NETW-022 0006-NETW-023
|
||||
it('governance assets should be correctly grouped', function () {
|
||||
cy.getByTestId('governance')
|
||||
.should('exist')
|
||||
.parent()
|
||||
.should('have.attr', 'href', '/network-parameters#governance');
|
||||
cy.get('[id="governance-proposal-asset"]')
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.getByTestId('key-value-table-row').should('have.length', 8);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to see network parameters - on mobile', function () {
|
||||
cy.switchToMobile();
|
||||
cy.get_network_parameters().then((network_parameters) => {
|
||||
|
||||
@@ -6,7 +6,7 @@ const customNodeBtn = 'custom-node';
|
||||
context.skip('Node switcher', { tags: '@regression' }, function () {
|
||||
beforeEach('visit home page', function () {
|
||||
cy.intercept('GET', 'https://static.vega.xyz/assets/capsule-network.json', {
|
||||
hosts: ['http://localhost:3008/graphql'],
|
||||
hosts: ['http://localhost:3028/query'],
|
||||
}).as('nodeData');
|
||||
cy.visit('/');
|
||||
cy.wait('@nodeData');
|
||||
@@ -40,7 +40,7 @@ context.skip('Node switcher', { tags: '@regression' }, function () {
|
||||
const errorTypeTxt = 'Error: invalid url';
|
||||
const nodeErrorTxt = 'fakeUrl is not a valid url.';
|
||||
|
||||
cy.getByTestId('node-url-custom').click({ force: true });
|
||||
cy.getByTestId('node-url-custom').click();
|
||||
|
||||
cy.getByTestId(customNodeBtn).within(() => {
|
||||
cy.get('input').clear().type('fakeUrl');
|
||||
|
||||
@@ -169,6 +169,7 @@ context.skip('Parties page', { tags: '@regression' }, function () {
|
||||
const jsonFields = '.hljs';
|
||||
const sideMenuBackground = '.absolute';
|
||||
|
||||
// Engage dark mode if not allready set
|
||||
cy.get(sideMenuBackground)
|
||||
.should('have.css', 'background-color')
|
||||
.then((background_color) => {
|
||||
@@ -218,7 +219,7 @@ context.skip('Parties page', { tags: '@regression' }, function () {
|
||||
balance type asset {id symbol decimals}}}}}}}}';
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: `http://localhost:3008/graphql`,
|
||||
url: `http://localhost:3028/query`,
|
||||
body: {
|
||||
query: mutation,
|
||||
},
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import { getNewAssetTxBody } from '../support/governance.functions';
|
||||
|
||||
context('Proposal page', { tags: '@smoke' }, function () {
|
||||
describe.skip('Verify elements on page', function () {
|
||||
const proposalHeading = 'proposals-heading';
|
||||
const dateTimeRegex =
|
||||
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
|
||||
|
||||
before('Create market proposal', function () {
|
||||
cy.visit('/');
|
||||
cy.createMarket();
|
||||
});
|
||||
|
||||
it('Able to view proposal', function () {
|
||||
const proposalTitle = 'Add Lorem Ipsum market';
|
||||
|
||||
cy.navigate_to('governanceProposals');
|
||||
cy.getByTestId(proposalHeading).should('be.visible');
|
||||
cy.contains(proposalTitle)
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
||||
cy.get_element_by_col_id('type').should('have.text', 'NewMarket');
|
||||
cy.get_element_by_col_id('state').should('have.text', 'Enacted');
|
||||
cy.get('[col-id="cDate"]')
|
||||
.invoke('text')
|
||||
.should('match', dateTimeRegex);
|
||||
cy.get('[col-id="eDate"]')
|
||||
.invoke('text')
|
||||
.should('match', dateTimeRegex);
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and('contains', 'https://governance.fairground.wtf/proposals/');
|
||||
cy.contains('View terms').should('exist').click();
|
||||
});
|
||||
cy.getByTestId('dialog-title').should('have.text', proposalTitle);
|
||||
cy.get('.language-json').should('exist');
|
||||
cy.getByTestId('icon-cross').click();
|
||||
});
|
||||
|
||||
it('Proposal page displayed on mobile', function () {
|
||||
const proposalTitle = 'Add Lorem Ipsum market';
|
||||
|
||||
cy.common_switch_to_mobile_and_click_toggle();
|
||||
cy.navigate_to('governanceProposals', true);
|
||||
cy.getByTestId(proposalHeading).should('be.visible');
|
||||
cy.get('[row-index="0"]').within(() => {
|
||||
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('Able to view new asset proposal', function () {
|
||||
const proposalTitle = 'Test new asset proposal';
|
||||
const newAssetProposalBody = getNewAssetTxBody();
|
||||
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
||||
|
||||
cy.visit('/');
|
||||
cy.navigate_to('governanceProposals');
|
||||
cy.contains(proposalTitle)
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
|
||||
cy.get_element_by_col_id('type').should('have.text', 'NewAsset');
|
||||
cy.get_element_by_col_id('state').should(
|
||||
'have.text',
|
||||
'Waiting for Node Vote'
|
||||
);
|
||||
cy.get('[col-id="cDate"]')
|
||||
.invoke('text')
|
||||
.should('match', dateTimeRegex);
|
||||
cy.get('[col-id="eDate"]')
|
||||
.invoke('text')
|
||||
.should('match', dateTimeRegex);
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and('contains', 'https://governance.fairground.wtf/proposals/');
|
||||
cy.contains('View terms').should('exist').click();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -40,7 +40,7 @@ context.skip('Transactions page', function () {
|
||||
.first()
|
||||
.click({ force: true });
|
||||
} else {
|
||||
cy.log('Unable to find any transactions on page');
|
||||
cy.slack('Unable to find any transactions on page');
|
||||
cy.screenshot();
|
||||
}
|
||||
});
|
||||
@@ -78,7 +78,7 @@ context.skip('Transactions page', function () {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cy.log('Unable to find any transactions on page');
|
||||
cy.slack('Unable to find any transactions on page');
|
||||
cy.screenshot();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,11 +7,7 @@ context('Validator page', { tags: '@smoke' }, function () {
|
||||
it('should be able to see validator tiles', function () {
|
||||
cy.getNodes().then((nodes) => {
|
||||
nodes.forEach((node) => {
|
||||
if (node.rankingScore.performanceScore > 0) {
|
||||
cy.get(`[validator-id="${node.id}"]`).should('be.visible');
|
||||
} else {
|
||||
cy.get(`[validator-id="${node.id}"]`).should('not.exist');
|
||||
}
|
||||
cy.get(`[validator-id="${node.id}"]`).should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ Cypress.Commands.add('switchToMobile', () => {
|
||||
Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () {
|
||||
cy.viewport('iphone-x');
|
||||
cy.visit('/');
|
||||
cy.get('[data-testid="button-menu-drawer"]').click();
|
||||
cy.get('[data-testid="open-menu"]').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('monitor_clipboard', () => {
|
||||
@@ -88,49 +88,3 @@ Cypress.Commands.add('convert_number_to_max_four_decimal', (number) => {
|
||||
maximumFractionDigits: 4,
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('navigate_to', (page, mobileView = false) => {
|
||||
const navigation = {
|
||||
transactions: '/txs',
|
||||
blocks: '/blocks',
|
||||
oracles: '/oracles',
|
||||
validators: '/validators',
|
||||
parties: '/parties',
|
||||
assets: '/assets',
|
||||
markets: '/markets',
|
||||
governanceProposals: '/governance',
|
||||
networkParameters: '/network-parameters',
|
||||
genesisParameters: '/genesis',
|
||||
};
|
||||
|
||||
const topLevelRoutes = ['transactions', 'blocks', 'oracles', 'validators'];
|
||||
|
||||
cy.getByTestId('navigation').within(() => {
|
||||
if (!topLevelRoutes.includes(page) && mobileView === false) {
|
||||
cy.getByTestId('other').first().click();
|
||||
}
|
||||
cy.get(`[href="${navigation[page]}"]`).first().click();
|
||||
});
|
||||
cy.url().should('include', navigation[page]);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('get_element_by_col_id', (elementName) => {
|
||||
cy.get(`[col-id="${elementName}"]`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
'validate_element_from_table',
|
||||
(tableRowName, tableRowValue) => {
|
||||
cy.contains(tableRowName)
|
||||
.parentsUntil("[data-testid='key-value-table-row']")
|
||||
.siblings()
|
||||
.should('have.text', tableRowValue);
|
||||
}
|
||||
);
|
||||
|
||||
Cypress.Commands.add(
|
||||
'validate_proposal_change_type',
|
||||
(tableRowName, changeType) => {
|
||||
cy.contains(tableRowName).siblings().should('have.text', changeType);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
import { addSeconds, millisecondsToSeconds } from 'date-fns';
|
||||
|
||||
export function createSuccessorMarketProposal(parentMarketId) {
|
||||
cy.VegaWalletSubmitProposal(getSuccessorTxBody(parentMarketId));
|
||||
}
|
||||
|
||||
function getSuccessorTxBody(parentMarketId) {
|
||||
const MIN_CLOSE_SEC = 500;
|
||||
const MIN_ENACT_SEC = 700;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||
|
||||
return {
|
||||
proposalSubmission: {
|
||||
rationale: {
|
||||
title: 'Test successor market proposal details',
|
||||
description: 'E2E test for successor market',
|
||||
},
|
||||
terms: {
|
||||
newMarket: {
|
||||
changes: {
|
||||
decimalPlaces: '5',
|
||||
positionDecimalPlaces: '5',
|
||||
linearSlippageFactor: '0.001',
|
||||
quadraticSlippageFactor: '0',
|
||||
instrument: {
|
||||
name: 'Token test market',
|
||||
code: 'TEST.24h',
|
||||
future: {
|
||||
settlementAsset:
|
||||
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc',
|
||||
quoteName: 'fUSDC',
|
||||
dataSourceSpecForSettlementData: {
|
||||
external: {
|
||||
oracle: {
|
||||
signers: [
|
||||
{
|
||||
pubKey: {
|
||||
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
|
||||
},
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
key: {
|
||||
name: 'prices.BTC.value',
|
||||
type: 'TYPE_INTEGER',
|
||||
numberDecimalPlaces: '0',
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
operator: 'OPERATOR_GREATER_THAN',
|
||||
value: '0',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
external: {
|
||||
oracle: {
|
||||
signers: [
|
||||
{
|
||||
pubKey: {
|
||||
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
|
||||
},
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
key: {
|
||||
name: 'trading.terminated.ETH5',
|
||||
type: 'TYPE_BOOLEAN',
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
operator: 'OPERATOR_EQUALS',
|
||||
value: 'true',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecBinding: {
|
||||
settlementDataProperty: 'prices.BTC.value',
|
||||
tradingTerminationProperty: 'trading.terminated.ETH5',
|
||||
},
|
||||
},
|
||||
},
|
||||
metadata: [
|
||||
'sector:food',
|
||||
'sector:materials',
|
||||
'source:docs.vega.xyz',
|
||||
],
|
||||
priceMonitoringParameters: {
|
||||
triggers: [
|
||||
{
|
||||
horizon: '43200',
|
||||
probability: '0.9999999',
|
||||
auctionExtension: '600',
|
||||
},
|
||||
],
|
||||
},
|
||||
liquidityMonitoringParameters: {
|
||||
targetStakeParameters: {
|
||||
timeWindow: '3600',
|
||||
scalingFactor: 10,
|
||||
},
|
||||
triggeringRatio: '0.7',
|
||||
auctionExtension: '1',
|
||||
},
|
||||
logNormal: {
|
||||
tau: 0.0001140771161,
|
||||
riskAversionParameter: 0.01,
|
||||
params: {
|
||||
mu: 0,
|
||||
r: 0.016,
|
||||
sigma: 0.5,
|
||||
},
|
||||
},
|
||||
successor: {
|
||||
parentMarketId: parentMarketId,
|
||||
insurancePoolFraction: '0.75',
|
||||
},
|
||||
liquiditySlaParameters: {
|
||||
priceRange: '0.95',
|
||||
commitmentMinTimeFraction: '0.5',
|
||||
performanceHysteresisEpochs: 2,
|
||||
slaCompetitionFactor: '0.75',
|
||||
},
|
||||
},
|
||||
},
|
||||
closingTimestamp,
|
||||
enactmentTimestamp,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getNewAssetTxBody() {
|
||||
const MIN_CLOSE_SEC = 500;
|
||||
const MIN_ENACT_SEC = 700;
|
||||
const MIN_VALID_SEC = 60;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||
const validationDate = addSeconds(new Date(), MIN_VALID_SEC);
|
||||
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||
const validationTimestamp = millisecondsToSeconds(validationDate.getTime());
|
||||
|
||||
return {
|
||||
proposalSubmission: {
|
||||
rationale: {
|
||||
title: 'Test new asset proposal',
|
||||
description: 'E2E test for proposals',
|
||||
},
|
||||
terms: {
|
||||
newAsset: {
|
||||
changes: {
|
||||
name: 'USDT Coin',
|
||||
symbol: 'USDT',
|
||||
decimals: '18',
|
||||
quantum: '1',
|
||||
erc20: {
|
||||
contractAddress: '0xb404c51bbc10dcbe948077f18a4b8e553d160084',
|
||||
withdrawThreshold: '10',
|
||||
lifetimeLimit: '10',
|
||||
},
|
||||
},
|
||||
},
|
||||
closingTimestamp,
|
||||
enactmentTimestamp,
|
||||
validationTimestamp,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -15,6 +15,5 @@
|
||||
|
||||
import '@vegaprotocol/cypress';
|
||||
import './common.functions.js';
|
||||
import 'cypress-mochawesome-reporter/register';
|
||||
import registerCypressGrep from '@cypress/grep';
|
||||
registerCypressGrep();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
"@nrwl/react/babel",
|
||||
{
|
||||
"runtime": "automatic"
|
||||
}
|
||||
|
||||
+9
-15
@@ -1,19 +1,13 @@
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.rocks
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
|
||||
NX_VEGA_ENV=STAGNET1
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
|
||||
NX_VEGA_TOKEN_URL=https://governance.stagnet1.vega.rocks
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
||||
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.rocks/rest
|
||||
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_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
|
||||
NX_VEGA_NETWORKS='{"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=STAGNET3
|
||||
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
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV=CUSTOM
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=/
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_TXS_LIST=0
|
||||
|
||||
NX_TENDERMINT_URL=http://localhost:26617
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||
NX_VEGA_ENV=CUSTOM
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||
|
||||
# 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,13 +1,11 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/tm
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||
NX_VEGA_ENV=DEVNET
|
||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||
NX_VEGA_GOVERNANCE_URL=https://dev.governance.vega.xyz
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://dev.token.vega.xyz
|
||||
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_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=/
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
@@ -1,14 +1,9 @@
|
||||
# App configuration variables
|
||||
NX_SENTRY_DSN=https://b3a56b03eda842faad731f3ea9dfd1bc@o286262.ingest.sentry.io/6242427
|
||||
NX_TENDERMINT_URL=https://be.explorer.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.explorer.vega.xyz/websocket
|
||||
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_BLOCK_EXPLORER=https://be.vega.community/rest
|
||||
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
||||
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
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/
|
||||
NX_ETHERSCAN_URL=https://etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://token.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
@@ -1,14 +0,0 @@
|
||||
# App configuration variables
|
||||
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_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
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||
@@ -1,3 +1,14 @@
|
||||
# .env is stagnet1, so there are no overrides required
|
||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.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
|
||||
@@ -1,14 +1,11 @@
|
||||
# App configuration variables
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
||||
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
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://token.fairground.wtf
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
@@ -4,13 +4,10 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/maste
|
||||
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
||||
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
|
||||
NX_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
|
||||
NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks
|
||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
||||
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/
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||
@@ -3,6 +3,5 @@ NX_TENDERMINT_URL=http://localhost:26607/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
|
||||
NX_VEGA_ENV=CUSTOM
|
||||
NX_BLOCK_EXPLORER=
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||
NX_VEGA_EXPLORER_URL=/
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*", "__generated__"],
|
||||
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
|
||||
@@ -32,15 +32,15 @@ yarn nx serve explorer
|
||||
Example configurations are provided here:
|
||||
|
||||
- [Mainnet](./.env.mainnet)
|
||||
- [Mainnet-mirror](./.env.mainnet-mirror)
|
||||
- [Devnet](./.env.devnet)
|
||||
- [Capsule](./.env.capsule)
|
||||
- [Testnet](./.env.testnet)
|
||||
- [Stagnet3](./.env.stagnet3)
|
||||
|
||||
For convenience, you can boot the app injecting one of the configurations above by running:
|
||||
|
||||
```bash
|
||||
yarn env-cmd -f .\apps\explorer\.env.{env} yarn nx run explorer:serve # e.g. stagnet1
|
||||
yarn nx run explorer:serve --env={env} # e.g. stagnet3
|
||||
```
|
||||
|
||||
There are a few different configuration options offered for this app:
|
||||
|
||||
@@ -4,8 +4,8 @@ export default {
|
||||
displayName: 'explorer',
|
||||
preset: '../../jest.preset.js',
|
||||
transform: {
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
||||
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
|
||||
'^.+\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/apps/explorer',
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
+19
-10
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"name": "explorer",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/explorer/src",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/webpack:webpack",
|
||||
"executor": "./tools/executors/webpack:build",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
@@ -39,7 +38,7 @@
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nx/webpack:dev-server",
|
||||
"executor": "./tools/executors/webpack:serve",
|
||||
"options": {
|
||||
"port": 3000,
|
||||
"buildTarget": "explorer:build:development",
|
||||
@@ -53,29 +52,39 @@
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/apps/explorer"],
|
||||
"options": {
|
||||
"jestConfig": "apps/explorer/jest.config.ts"
|
||||
"jestConfig": "apps/explorer/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
},
|
||||
"generate-types": {
|
||||
"executor": "nx:run-commands",
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.73.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.67.3/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||
]
|
||||
}
|
||||
},
|
||||
"build-netlify": {
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"cp apps/explorer/netlify.toml netlify.toml",
|
||||
"nx build explorer"
|
||||
]
|
||||
}
|
||||
},
|
||||
"build-spec": {
|
||||
"executor": "nx:run-commands",
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"outputs": [],
|
||||
"options": {
|
||||
"command": "yarn tsc --project ./apps/explorer/tsconfig.spec.json"
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
import '../i18n';
|
||||
import {
|
||||
NetworkLoader,
|
||||
NodeFailure,
|
||||
NodeGuard,
|
||||
NodeSwitcherDialog,
|
||||
useEnvironment,
|
||||
useInitializeEnv,
|
||||
useNodeSwitcherStore,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment';
|
||||
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
|
||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
||||
import { RouterProvider } from 'react-router-dom';
|
||||
import { useRouterConfig } from './routes/router-config';
|
||||
import { createBrowserRouter } from 'react-router-dom';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Suspense } from 'react';
|
||||
import { router } from './routes/router-config';
|
||||
|
||||
const splashLoading = (
|
||||
<Splash>
|
||||
@@ -24,33 +12,11 @@ const splashLoading = (
|
||||
);
|
||||
|
||||
function App() {
|
||||
const { VEGA_URL } = useEnvironment();
|
||||
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useNodeSwitcherStore(
|
||||
(store) => [store.dialogOpen, store.setDialogOpen]
|
||||
);
|
||||
return (
|
||||
<TendermintWebsocketProvider>
|
||||
<Suspense fallback={splashLoading}>
|
||||
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
||||
<NodeGuard
|
||||
skeleton={<div>{t('Loading')}</div>}
|
||||
failure={
|
||||
<NodeFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />
|
||||
}
|
||||
>
|
||||
<Suspense fallback={splashLoading}>
|
||||
<RouterProvider
|
||||
router={createBrowserRouter(useRouterConfig())}
|
||||
fallbackElement={splashLoading}
|
||||
/>
|
||||
</Suspense>
|
||||
</NodeGuard>
|
||||
<NodeSwitcherDialog
|
||||
open={nodeSwitcherOpen}
|
||||
setOpen={setNodeSwitcherOpen}
|
||||
/>
|
||||
</NetworkLoader>
|
||||
</Suspense>
|
||||
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
||||
<RouterProvider router={router} fallbackElement={splashLoading} />
|
||||
</NetworkLoader>
|
||||
</TendermintWebsocketProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { AssetLink } from '../links';
|
||||
|
||||
export type AssetBalanceProps = {
|
||||
assetId: string;
|
||||
price: string;
|
||||
showAssetLink?: boolean;
|
||||
showAssetSymbol?: boolean;
|
||||
rounded?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -18,26 +16,18 @@ const AssetBalance = ({
|
||||
assetId,
|
||||
price,
|
||||
showAssetLink = true,
|
||||
showAssetSymbol = false,
|
||||
rounded = false,
|
||||
}: AssetBalanceProps) => {
|
||||
const { data: asset, loading } = useAssetDataProvider(assetId);
|
||||
const { data: asset } = useAssetDataProvider(assetId);
|
||||
|
||||
const label =
|
||||
!loading && asset && asset.decimals
|
||||
? addDecimalsFixedFormatNumber(
|
||||
price,
|
||||
asset.decimals,
|
||||
rounded ? 0 : undefined
|
||||
)
|
||||
asset && asset.decimals
|
||||
? addDecimalsFormatNumber(price, asset.decimals)
|
||||
: price;
|
||||
|
||||
return (
|
||||
<div className="inline-block">
|
||||
<span className="font-mono">{label}</span>{' '}
|
||||
{showAssetLink && asset?.id ? (
|
||||
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
|
||||
) : null}
|
||||
<span>{label}</span>{' '}
|
||||
{showAssetLink && asset?.id ? <AssetLink assetId={assetId} /> : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,17 +13,11 @@ const DEFAULT_DECIMALS = 18;
|
||||
* the governance asset first, which is set by a network parameter
|
||||
*/
|
||||
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;
|
||||
return (
|
||||
<AssetBalance
|
||||
price={price}
|
||||
showAssetSymbol={true}
|
||||
assetId={governanceAssetId}
|
||||
/>
|
||||
);
|
||||
return <AssetBalance price={price} assetId={governanceAssetId} />;
|
||||
} else {
|
||||
return (
|
||||
<div className="inline-block">
|
||||
|
||||
@@ -1,30 +1,24 @@
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
useAssetTypeMapping,
|
||||
useAssetStatusMapping,
|
||||
type AssetFieldsFragment,
|
||||
} from '@vegaprotocol/assets';
|
||||
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { type AgGridReact } from 'ag-grid-react';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { type VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridColumn } from 'ag-grid-react';
|
||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
||||
import { useRef, useLayoutEffect } from 'react';
|
||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { type ColDef } from 'ag-grid-community';
|
||||
import type { RowClickedEvent } from 'ag-grid-community';
|
||||
|
||||
type AssetsTableProps = {
|
||||
data: AssetFieldsFragment[] | null;
|
||||
};
|
||||
export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||
const assetTypeMapping = useAssetTypeMapping();
|
||||
const assetStatusMapping = useAssetStatusMapping();
|
||||
const navigate = useNavigate();
|
||||
const ref = useRef<AgGridReact>(null);
|
||||
const showColumnsOnDesktop = () => {
|
||||
ref.current?.api.setColumnsVisible(
|
||||
ref.current?.columnApi.setColumnsVisible(
|
||||
['id', 'type', 'status'],
|
||||
window.innerWidth > BREAKPOINT_MD
|
||||
);
|
||||
@@ -37,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={() => {
|
||||
navigate(value);
|
||||
}}
|
||||
>
|
||||
{t('View details')}
|
||||
</ButtonLink>
|
||||
) : (
|
||||
''
|
||||
),
|
||||
},
|
||||
],
|
||||
[navigate, assetStatusMapping, assetTypeMapping]
|
||||
);
|
||||
|
||||
return (
|
||||
<AgGrid
|
||||
ref={ref}
|
||||
@@ -104,11 +46,60 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||
filterParams: { buttons: ['reset'] },
|
||||
autoHeight: true,
|
||||
}}
|
||||
columnDefs={columnDefs}
|
||||
suppressCellFocus={true}
|
||||
onRowClicked={({ data }: RowClickedEvent) => {
|
||||
navigate(data.id);
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<AgGridColumn headerName={t('Symbol')} field="symbol" />
|
||||
<AgGridColumn headerName={t('Name')} field="name" />
|
||||
<AgGridColumn
|
||||
flex="2"
|
||||
headerName={t('ID')}
|
||||
field="id"
|
||||
hide={window.innerWidth < BREAKPOINT_MD}
|
||||
/>
|
||||
<AgGridColumn
|
||||
colId="type"
|
||||
headerName={t('Type')}
|
||||
field="source.__typename"
|
||||
hide={window.innerWidth < BREAKPOINT_MD}
|
||||
valueFormatter={({ value }: { value?: string }) =>
|
||||
value && AssetTypeMapping[value].value
|
||||
}
|
||||
/>
|
||||
<AgGridColumn
|
||||
headerName={t('Status')}
|
||||
field="status"
|
||||
hide={window.innerWidth < BREAKPOINT_MD}
|
||||
valueFormatter={({ value }: { value?: string }) =>
|
||||
value && AssetStatusMapping[value].value
|
||||
}
|
||||
/>
|
||||
<AgGridColumn
|
||||
colId="actions"
|
||||
headerName=""
|
||||
sortable={false}
|
||||
filter={false}
|
||||
resizable={false}
|
||||
wrapText={true}
|
||||
field="id"
|
||||
cellRenderer={({
|
||||
value,
|
||||
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
||||
value ? (
|
||||
<ButtonLink
|
||||
onClick={(e) => {
|
||||
navigate(value);
|
||||
}}
|
||||
>
|
||||
{t('View details')}
|
||||
</ButtonLink>
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
/>
|
||||
</AgGrid>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,29 @@
|
||||
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';
|
||||
|
||||
const BlocksRefetchInWebsocketProvider = ({
|
||||
callback,
|
||||
mocketLocation,
|
||||
}: {
|
||||
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', () => {
|
||||
@@ -16,8 +32,111 @@ describe('Blocks refetch', () => {
|
||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||
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();
|
||||
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 { Button, Icon } from '@vegaprotocol/ui-toolkit';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
interface BlocksRefetchProps {
|
||||
refetch: () => void;
|
||||
}
|
||||
|
||||
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 = () => {
|
||||
refetch();
|
||||
setBlocksToLoad(0);
|
||||
};
|
||||
|
||||
return (
|
||||
<Button onClick={refresh} data-testid="refresh" size="xs">
|
||||
<Icon name="refresh" className="!align-baseline mr-2" size={3} />
|
||||
{t('Load new')}
|
||||
</Button>
|
||||
<div className="mb-4">
|
||||
<span data-testid="new-blocks">{blocksToLoad} new blocks - </span>
|
||||
<ButtonLink onClick={refresh} data-testid="refresh">
|
||||
{t('refresh to see latest')}
|
||||
</ButtonLink>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
import {
|
||||
useEnvironment,
|
||||
useNodeSwitcherStore,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { NodeSwitcherDialog, useEnvironment } from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import { Link, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { useMemo } from 'react';
|
||||
import { ExternalLink, Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { ENV } from '../../config/env';
|
||||
import { Routes } from '../../routes/route-names';
|
||||
import { Link as RouteLink } from 'react-router-dom';
|
||||
|
||||
export const Footer = () => {
|
||||
const { VEGA_URL, GIT_COMMIT_HASH, GIT_ORIGIN_URL } = useEnvironment();
|
||||
const setNodeSwitcherOpen = useNodeSwitcherStore(
|
||||
(store) => store.setDialogOpen
|
||||
);
|
||||
|
||||
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false);
|
||||
const { screenSize } = useScreenDimensions();
|
||||
const showFullFeedbackLabel = useMemo(
|
||||
() => ['md', 'lg', 'xl', 'xxl', 'xxxl'].includes(screenSize),
|
||||
@@ -23,59 +15,56 @@ export const Footer = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<footer className="grid grid-cols-[1fr_auto] items-center text-xs md:text-md lg:flex md:col-span-2 px-4 pt-2 pb-3 gap-4 border-t border-vega-light-200 dark:border-vega-dark-200">
|
||||
<div className="flex justify-between gap-2 align-middle">
|
||||
{GIT_COMMIT_HASH && (
|
||||
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
||||
<p data-testid="git-commit-hash">
|
||||
{t('Version')}:{' '}
|
||||
<Link
|
||||
href={
|
||||
GIT_ORIGIN_URL
|
||||
? `${GIT_ORIGIN_URL}/commit/${GIT_COMMIT_HASH}`
|
||||
: undefined
|
||||
}
|
||||
target={GIT_ORIGIN_URL ? '_blank' : undefined}
|
||||
>
|
||||
{GIT_COMMIT_HASH}
|
||||
</Link>
|
||||
</p>
|
||||
<>
|
||||
<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">
|
||||
<div className="flex justify-between gap-2 align-middle">
|
||||
{GIT_COMMIT_HASH && (
|
||||
<div className="content-center flex border-r border-neutral-700 dark:border-neutral-300 pr-4">
|
||||
<p data-testid="git-commit-hash">
|
||||
{t('Version')}:{' '}
|
||||
<Link
|
||||
href={
|
||||
GIT_ORIGIN_URL
|
||||
? `${GIT_ORIGIN_URL}/commit/${GIT_COMMIT_HASH}`
|
||||
: undefined
|
||||
}
|
||||
target={GIT_ORIGIN_URL ? '_blank' : undefined}
|
||||
>
|
||||
{GIT_COMMIT_HASH}
|
||||
</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 className="content-center flex pr-4 md:border-r border-neutral-700 dark:border-neutral-300">
|
||||
<span className="pr-2">{VEGA_URL && <NodeUrl url={VEGA_URL} />}</span>
|
||||
<Link
|
||||
className="ml-2 underline-offset-4"
|
||||
onClick={() => setNodeSwitcherOpen(true)}
|
||||
>
|
||||
{t('Change')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{ENV.addresses.feedback ? (
|
||||
<div className="flex pl-2 content-center">
|
||||
<ExternalLink href={ENV.addresses.feedback}>
|
||||
{showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')}
|
||||
</ExternalLink>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="pl-2 align-center lg:align-right lg:flex lg:justify-end gap-2 align-middle lg:max-w-xs lg:ml-auto">
|
||||
<RouteLink
|
||||
to={`/${Routes.DISCLAIMER}`}
|
||||
className="underline underline-offset-4"
|
||||
>
|
||||
Disclaimer
|
||||
</RouteLink>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</footer>
|
||||
<NodeSwitcherDialog
|
||||
open={nodeSwitcherOpen}
|
||||
setOpen={setNodeSwitcherOpen}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const NodeUrl = ({ url }: { url: string }) => {
|
||||
const NodeUrl = ({ url }: { url: string }) => {
|
||||
// get base url from api url, api sub domain
|
||||
const urlObj = new URL(url);
|
||||
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';
|
||||
|
||||
jest.mock('@vegaprotocol/environment', () => ({
|
||||
...jest.requireActual('@vegaprotocol/environment'),
|
||||
NetworkSwitcher: () => (
|
||||
<div data-testid="network-switcher">NetworkSwitcher</div>
|
||||
),
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Routes } from '../../routes/route-names';
|
||||
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
||||
import type { Navigable } from '../../routes/router-config';
|
||||
import { isNavigable } from '../../routes/router-config';
|
||||
import { useRouterConfig } from '../../routes/router-config';
|
||||
import { routerConfig } from '../../routes/router-config';
|
||||
import { useMemo } from 'react';
|
||||
import compact from 'lodash/compact';
|
||||
import { Search } from '../search';
|
||||
@@ -26,7 +26,6 @@ const routeToNavigationItem = (r: Navigable) => (
|
||||
);
|
||||
|
||||
export const Header = () => {
|
||||
const routerConfig = useRouterConfig();
|
||||
const isHome = Boolean(useMatch(Routes.HOME));
|
||||
const pages = routerConfig[0].children || [];
|
||||
const mainItems = compact(
|
||||
@@ -41,7 +40,6 @@ export const Header = () => {
|
||||
Routes.ASSETS,
|
||||
Routes.MARKETS,
|
||||
Routes.GOVERNANCE,
|
||||
Routes.TREASURY,
|
||||
Routes.NETWORK_PARAMETERS,
|
||||
Routes.GENESIS,
|
||||
].map((n) => pages.find((r) => r.path === n))
|
||||
@@ -97,10 +95,7 @@ export const Header = () => {
|
||||
{mainItems.map(routeToNavigationItem)}
|
||||
{groupedItems && groupedItems.length > 0 && (
|
||||
<NavigationItem>
|
||||
<NavigationTrigger
|
||||
isActive={Boolean(isOnOther)}
|
||||
data-testid="other"
|
||||
>
|
||||
<NavigationTrigger isActive={Boolean(isOnOther)}>
|
||||
{t('Other')}
|
||||
</NavigationTrigger>
|
||||
<NavigationContent>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import React from 'react';
|
||||
|
||||
export interface InfoBlockProps {
|
||||
title: string;
|
||||
|
||||
@@ -43,7 +43,7 @@ export const AssetLink = ({
|
||||
if (asDialog) {
|
||||
open(assetId, e.target as HTMLElement);
|
||||
} else {
|
||||
navigate(`/${Routes.ASSETS}/${asset?.id}`);
|
||||
navigate(`${Routes.ASSETS}/${asset?.id}`);
|
||||
}
|
||||
}}
|
||||
{...props}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
|
||||
import { DATA_SOURCES } from '../../../config';
|
||||
import Hash from '../hash';
|
||||
|
||||
export enum EthExplorerLinkTypes {
|
||||
block = 'block',
|
||||
address = 'address',
|
||||
tx = 'tx',
|
||||
}
|
||||
|
||||
export type EthExplorerLinkProps = Partial<typeof HTMLAnchorElement> & {
|
||||
id: string;
|
||||
type: EthExplorerLinkTypes;
|
||||
};
|
||||
|
||||
export const EthExplorerLink = ({
|
||||
id,
|
||||
type,
|
||||
...props
|
||||
}: EthExplorerLinkProps) => {
|
||||
const link = `${DATA_SOURCES.ethExplorerUrl}/${type}/${id}`;
|
||||
return (
|
||||
<a
|
||||
className="underline external font-mono"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
{...props}
|
||||
href={link}
|
||||
>
|
||||
<Hash text={id} />
|
||||
</a>
|
||||
);
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
import type { ChainIdMapping } from './external-chain';
|
||||
import { SUPPORTED_CHAIN_IDS, SUPPORTED_CHAIN_LABELS } from './external-chain';
|
||||
|
||||
export const SUPPORTED_CHAIN_ICON_URLS: ChainIdMapping = {
|
||||
'1': '/assets/chain-eth-logo.svg',
|
||||
'100': '/assets/chain-gno-logo.svg',
|
||||
'42161': '/assets/chain-arb-logo.svg',
|
||||
'11155111': '/assets/chain-eth-logo.svg',
|
||||
};
|
||||
|
||||
export type ExternalChainIconProps = {
|
||||
chainId?: string;
|
||||
};
|
||||
|
||||
export const ExternalChainIcon = ({
|
||||
// If chainID is not provided, default to a non-existent chain
|
||||
chainId = '-1',
|
||||
}: ExternalChainIconProps) => {
|
||||
if (SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
||||
const url = SUPPORTED_CHAIN_ICON_URLS[chainId];
|
||||
const alt = SUPPORTED_CHAIN_LABELS[chainId];
|
||||
|
||||
return (
|
||||
<img
|
||||
src={url}
|
||||
className="inline-block w-4 h-4 mr-1 dark:invert"
|
||||
alt={alt}
|
||||
title={alt}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
export type ChainIdMapping = {
|
||||
[K in typeof SUPPORTED_CHAIN_IDS[number]]: string;
|
||||
};
|
||||
export const SUPPORTED_CHAIN_IDS: string[] = ['1', '100', '42161', '11155111'];
|
||||
|
||||
export const SUPPORTED_CHAIN_LABELS: ChainIdMapping = {
|
||||
'1': 'Ethereum',
|
||||
'100': 'Gnosis',
|
||||
'42161': 'Arbitrum',
|
||||
'11155111': 'Sepolia',
|
||||
};
|
||||
|
||||
export function getExternalExplorerLink(chainId: string, type: string) {
|
||||
if (SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
||||
switch (chainId) {
|
||||
case '1':
|
||||
return 'https://etherscan.io';
|
||||
case '100':
|
||||
return 'https://gnosisscan.io';
|
||||
case '42161':
|
||||
return 'https://arbiscan.io';
|
||||
case '11155111':
|
||||
return 'https://sepolia.etherscan.io';
|
||||
default:
|
||||
return '#';
|
||||
}
|
||||
} else {
|
||||
return '#';
|
||||
}
|
||||
}
|
||||
|
||||
export function getExternalChainLabel(chainId?: string) {
|
||||
if (chainId && SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
||||
return SUPPORTED_CHAIN_LABELS[chainId];
|
||||
} else {
|
||||
return 'Custom Chain';
|
||||
}
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
import Hash from '../hash';
|
||||
import { getExternalExplorerLink } from './external-chain';
|
||||
import { ExternalChainIcon } from './external-chain-icon';
|
||||
|
||||
export enum EthExplorerLinkTypes {
|
||||
block = 'block',
|
||||
address = 'address',
|
||||
tx = 'tx',
|
||||
}
|
||||
|
||||
export type ExternalExplorerLinkProps = Partial<typeof HTMLAnchorElement> & {
|
||||
id: string;
|
||||
type: EthExplorerLinkTypes;
|
||||
// Defaults to Ethereum Mainnet, as chain support was added late
|
||||
chain?: string;
|
||||
code?: boolean;
|
||||
};
|
||||
|
||||
export const ExternalExplorerLink = ({
|
||||
id,
|
||||
type,
|
||||
chain = '1',
|
||||
code = false,
|
||||
...props
|
||||
}: ExternalExplorerLinkProps) => {
|
||||
const link = `${getExternalExplorerLink(chain, type)}/${type}/${id}${
|
||||
code ? '#code' : ''
|
||||
}`;
|
||||
return (
|
||||
<a
|
||||
className="underline external font-mono"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
{...props}
|
||||
href={link}
|
||||
>
|
||||
<ExternalChainIcon chainId={chain} />
|
||||
<Hash text={id} />
|
||||
</a>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
export type HashProps = React.HTMLProps<HTMLSpanElement> & {
|
||||
export type HashProps = {
|
||||
text: string;
|
||||
truncate?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -8,16 +7,10 @@ export type HashProps = React.HTMLProps<HTMLSpanElement> & {
|
||||
* are broken when they need to wrap. This will remove the need
|
||||
* for a lot of the overflow scrolling that currently exists.
|
||||
*/
|
||||
const Hash = ({ text, truncate = false }: HashProps) => {
|
||||
const h = truncate ? text.slice(0, 6) : text;
|
||||
|
||||
const Hash = ({ text }: HashProps) => {
|
||||
return (
|
||||
<code
|
||||
title={text}
|
||||
className="break-all font-mono"
|
||||
style={{ wordWrap: 'break-word' }}
|
||||
>
|
||||
{h}
|
||||
<code className="break-all font-mono" style={{ wordWrap: 'break-word' }}>
|
||||
{text}
|
||||
</code>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,5 +2,4 @@ export { default as BlockLink } from './block-link/block-link';
|
||||
export { default as PartyLink } from './party-link/party-link';
|
||||
export { default as NodeLink } from './node-link/node-link';
|
||||
export { default as MarketLink } from './market-link/market-link';
|
||||
export { default as NetworkParameterLink } from './network-parameter-link/network-parameter-link';
|
||||
export * from './asset-link/asset-link';
|
||||
|
||||
@@ -3,7 +3,6 @@ query ExplorerMarket($id: ID!) {
|
||||
id
|
||||
decimalPlaces
|
||||
positionDecimalPlaces
|
||||
state
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
name
|
||||
@@ -14,14 +13,9 @@ query ExplorerMarket($id: ID!) {
|
||||
decimals
|
||||
}
|
||||
}
|
||||
... on Perpetual {
|
||||
quoteName
|
||||
settlementAsset {
|
||||
decimals
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
+2
-8
@@ -8,7 +8,7 @@ export type ExplorerMarketQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Perpetual', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Spot' } } } } | null };
|
||||
export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } } } } | null };
|
||||
|
||||
|
||||
export const ExplorerMarketDocument = gql`
|
||||
@@ -17,7 +17,6 @@ export const ExplorerMarketDocument = gql`
|
||||
id
|
||||
decimalPlaces
|
||||
positionDecimalPlaces
|
||||
state
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
name
|
||||
@@ -28,15 +27,10 @@ export const ExplorerMarketDocument = gql`
|
||||
decimals
|
||||
}
|
||||
}
|
||||
... on Perpetual {
|
||||
quoteName
|
||||
settlementAsset {
|
||||
decimals
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
state
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -61,11 +61,7 @@ describe('Market link component', () => {
|
||||
instrument: {
|
||||
name: 'test-label',
|
||||
product: {
|
||||
__typename: 'Future',
|
||||
quoteName: 'dai',
|
||||
settlementAsset: {
|
||||
decimals: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -91,6 +87,6 @@ describe('Market link component', () => {
|
||||
};
|
||||
|
||||
const res = render(renderComponent('123', [mock]));
|
||||
expect(await res.findByTitle('123')).toBeInTheDocument();
|
||||
expect(await res.findByText('123')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,7 +23,6 @@ const MarketLink = ({
|
||||
}: MarketLinkProps) => {
|
||||
const { data, error, loading } = useExplorerMarketQuery({
|
||||
variables: { id },
|
||||
fetchPolicy: 'cache-first',
|
||||
});
|
||||
|
||||
let label = <span>{id}</span>;
|
||||
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Routes } from '../../../routes/route-names';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import type { ComponentProps } from 'react';
|
||||
import Hash from '../hash';
|
||||
|
||||
export type NetworkParameterLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||
parameter: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Links a given network parameter to the relevant page and anchor on the page
|
||||
*/
|
||||
const NetworkParameterLink = ({
|
||||
parameter,
|
||||
...props
|
||||
}: NetworkParameterLinkProps) => {
|
||||
return (
|
||||
<Link
|
||||
className="underline"
|
||||
{...props}
|
||||
to={`/${Routes.NETWORK_PARAMETERS}#${parameter}`}
|
||||
>
|
||||
<Hash text={parameter} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default NetworkParameterLink;
|
||||
@@ -1,57 +0,0 @@
|
||||
import OracleLink, { getStatusString } from './oracle-link';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
describe('getStatusString', () => {
|
||||
it("returns 'Unknown' for undefined status", () => {
|
||||
expect(getStatusString(undefined)).toBe('Unknown');
|
||||
});
|
||||
|
||||
it('returns the correct string for a known status', () => {
|
||||
expect(getStatusString('STATUS_ACTIVE')).toBe('Active');
|
||||
expect(getStatusString('STATUS_DEACTIVATED')).toBe('Deactivated');
|
||||
});
|
||||
});
|
||||
|
||||
describe('OracleLink', () => {
|
||||
it('renders the truncated Oracle ID', () => {
|
||||
const id = '123456789';
|
||||
render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<OracleLink id={id} />
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
const idElement = screen.getByText(id.slice(0, 6));
|
||||
expect(idElement).toBeInTheDocument();
|
||||
expect(idElement).toHaveAttribute('title', id);
|
||||
});
|
||||
|
||||
it('renders the Oracle status', () => {
|
||||
const id = '123';
|
||||
const status = 'STATUS_ACTIVE';
|
||||
render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<OracleLink id={id} status={status} data-testid="link" />
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(screen.getByTestId('link')).toHaveAttribute('data-status', 'Active');
|
||||
});
|
||||
|
||||
it('renders the Oracle data indicator', () => {
|
||||
const id = '123';
|
||||
const hasSeenOracleReports = true;
|
||||
render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<OracleLink id={id} hasSeenOracleReports={hasSeenOracleReports} />
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(screen.getByTestId('oracle-data-indicator')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -3,93 +3,20 @@ import { Link } from 'react-router-dom';
|
||||
|
||||
import type { ComponentProps } from 'react';
|
||||
import Hash from '../hash';
|
||||
import { Tooltip, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
DataSourceSpecStatus,
|
||||
DataSourceSpecStatusMapping,
|
||||
} from '@vegaprotocol/types';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
|
||||
/**
|
||||
* Returns a human-readable string for the given status, or a meaningful
|
||||
* default if the status is unrecognised
|
||||
* @param status string status
|
||||
*/
|
||||
export function getStatusString(status: string | undefined): string {
|
||||
if (status && status in DataSourceSpecStatus) {
|
||||
return DataSourceSpecStatusMapping[status as DataSourceSpecStatus];
|
||||
}
|
||||
|
||||
return t('Unknown');
|
||||
}
|
||||
|
||||
export type OracleLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||
// The Oracle ID
|
||||
id: string;
|
||||
// If available, the oracle status
|
||||
status?: string;
|
||||
// If the oracle has corresponding data in the OracleDataConnection
|
||||
hasSeenOracleReports?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given an Oracle ID, renders a data-dense link to the Oracle page. Data density is achieved by:
|
||||
* - Colour coding the link based on the Oracle's status
|
||||
* - Showing a small indicator if the Oracle has matched data
|
||||
* - Showing a tooltip with the Oracle's status and whether it has matched data
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export const OracleLink = ({
|
||||
id,
|
||||
status,
|
||||
hasSeenOracleReports = false,
|
||||
...props
|
||||
}: OracleLinkProps) => {
|
||||
const bgColour =
|
||||
status === 'STATUS_ACTIVE'
|
||||
? 'bg-yellow-100 hover:bg-yellow-200 border-yellow-200 dark:bg-yellow-200 dark:border-yellow-200 dark:text-gray-900 dark:border-yellow-300'
|
||||
: 'bg-gray-100 hover:bg-gray-200 border-gray-200';
|
||||
const indicatorColour =
|
||||
status === 'STATUS_ACTIVE'
|
||||
? 'bg-yellow-300 hover:bg-yellow-500 dark:bg-yellow-500'
|
||||
: 'bg-gray-300 hover:bg-gray-500';
|
||||
|
||||
const description = (
|
||||
<div>
|
||||
<p>
|
||||
<strong>{`Status: `}</strong>
|
||||
{getStatusString(status)}
|
||||
</p>
|
||||
<p>
|
||||
<strong>{`Matched data: `}</strong>
|
||||
{hasSeenOracleReports ? (
|
||||
<VegaIcon name={VegaIconNames.TICK} />
|
||||
) : (
|
||||
<VegaIcon name={VegaIconNames.CROSS} />
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const OracleLink = ({ id, ...props }: OracleLinkProps) => {
|
||||
return (
|
||||
<Tooltip description={description}>
|
||||
<Link
|
||||
className={`pl-2 pr-2 font-mono dark:text-black ${bgColour} rounded-sm border-solid border-2 relative`}
|
||||
{...props}
|
||||
to={`/${Routes.ORACLES}/${id}`}
|
||||
data-status={getStatusString(status)}
|
||||
>
|
||||
<Hash text={id} truncate={true} />
|
||||
{hasSeenOracleReports ? (
|
||||
<strong
|
||||
data-testid="oracle-data-indicator"
|
||||
className={`absolute top-0 right-0 w-1 h-full font-thin ${indicatorColour}`}
|
||||
title="Oracle has matched data"
|
||||
></strong>
|
||||
) : null}
|
||||
</Link>
|
||||
</Tooltip>
|
||||
<Link
|
||||
className="underline font-mono"
|
||||
{...props}
|
||||
to={`/${Routes.ORACLES}/${id}`}
|
||||
>
|
||||
<Hash text={id} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,98 +1,33 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import PartyLink from './party-link';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { ExplorerNodeNamesDocument } from '../../../routes/validators/__generated__/NodeNames';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
const zeroes =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: ExplorerNodeNamesDocument,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
nodesConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: '1',
|
||||
name: 'Validator Node',
|
||||
pubkey:
|
||||
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e',
|
||||
tmPubkey: 'tmPubkey1',
|
||||
ethereumAddress: '0x123456789',
|
||||
},
|
||||
},
|
||||
{
|
||||
node: {
|
||||
id: '2',
|
||||
name: 'Node 2',
|
||||
pubkey: 'pubkey2',
|
||||
tmPubkey: 'tmPubkey2',
|
||||
ethereumAddress: '0xabcdef123',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe('PartyLink', () => {
|
||||
it('renders Network for 000.000 party', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<PartyLink id={zeroes} />
|
||||
</MockedProvider>
|
||||
);
|
||||
const zeroes =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const screen = render(<PartyLink id={zeroes} />);
|
||||
expect(screen.getByText('Network')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders Network for network party', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<PartyLink id="network" />
|
||||
</MockedProvider>
|
||||
);
|
||||
const screen = render(<PartyLink id="network" />);
|
||||
expect(screen.getByText('Network')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders ID with no link for invalid party', () => {
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<PartyLink id="this-party-is-not-valid" />
|
||||
</MockedProvider>
|
||||
);
|
||||
const screen = render(<PartyLink id="this-party-is-not-valid" />);
|
||||
expect(screen.getByTestId('invalid-party')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('if the key is a validator, render their name instead', async () => {
|
||||
const screen = render(
|
||||
<MockedProvider mocks={mocks}>
|
||||
<MemoryRouter>
|
||||
<PartyLink id="13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e" />
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
// Wait for hook to update with mock data
|
||||
await act(() => new Promise((resolve) => setTimeout(resolve, 0)));
|
||||
await expect(screen.getByText('Validator Node')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('links a valid party to the party page', () => {
|
||||
const aValidParty =
|
||||
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e';
|
||||
|
||||
const screen = render(
|
||||
<MockedProvider>
|
||||
<MemoryRouter>
|
||||
<PartyLink id={aValidParty} />
|
||||
</MemoryRouter>
|
||||
</MockedProvider>
|
||||
<MemoryRouter>
|
||||
<PartyLink id={aValidParty} />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const el = screen.getByText(aValidParty);
|
||||
|
||||
@@ -1,58 +1,28 @@
|
||||
import { Routes } from '../../../routes/route-names';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useMemo, type ComponentProps } from 'react';
|
||||
import type { ComponentProps } from 'react';
|
||||
import Hash from '../hash';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { isValidPartyId } from '../../../routes/parties/id/components/party-id-error';
|
||||
import { Icon, truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
||||
import { useExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
|
||||
import type { ExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
|
||||
import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const SPECIAL_CASE_NETWORK_ID =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
export const SPECIAL_CASE_NETWORK = 'network';
|
||||
|
||||
export function getNameForParty(id: string, data?: ExplorerNodeNamesQuery) {
|
||||
if (!data || data?.nodesConnection?.edges?.length === 0) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const validator = data.nodesConnection.edges?.find((e) => {
|
||||
return e?.node.pubkey === id;
|
||||
});
|
||||
|
||||
if (validator) {
|
||||
return validator.node.name;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
export type PartyLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||
id: string;
|
||||
truncate?: boolean;
|
||||
networkLabel?: string;
|
||||
truncateLength?: number;
|
||||
};
|
||||
|
||||
const PartyLink = ({
|
||||
id,
|
||||
truncate = false,
|
||||
truncateLength = 4,
|
||||
networkLabel = t('Network'),
|
||||
...props
|
||||
}: PartyLinkProps) => {
|
||||
const { data } = useExplorerNodeNamesQuery();
|
||||
const name = useMemo(() => getNameForParty(id, data), [data, id]);
|
||||
const useName = name !== id;
|
||||
|
||||
const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
||||
// Some transactions will involve the 'network' party, which is alias for '000...000'
|
||||
// The party page does not handle this nicely, so in this case we render the word 'Network'
|
||||
if (id === SPECIAL_CASE_NETWORK || id === SPECIAL_CASE_NETWORK_ID) {
|
||||
return (
|
||||
<span className="font-mono" data-testid="network">
|
||||
{networkLabel}
|
||||
{t('Network')}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -68,24 +38,13 @@ const PartyLink = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
||||
<Link
|
||||
className="underline font-mono"
|
||||
{...props}
|
||||
to={`/${Routes.PARTIES}/${id}`}
|
||||
>
|
||||
{useName ? (
|
||||
name
|
||||
) : (
|
||||
<Hash
|
||||
text={
|
||||
truncate ? truncateMiddle(id, truncateLength, truncateLength) : id
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
</span>
|
||||
<Link
|
||||
className="underline font-mono"
|
||||
{...props}
|
||||
to={`/${Routes.PARTIES}/${id}`}
|
||||
>
|
||||
<Hash text={truncate ? truncateMiddle(id) : id} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
query ExplorerProposal($id: ID!) {
|
||||
proposal(id: $id) {
|
||||
... on Proposal {
|
||||
id
|
||||
rationale {
|
||||
title
|
||||
description
|
||||
}
|
||||
id
|
||||
rationale {
|
||||
title
|
||||
description
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user