Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
186aa12ed3 |
+1
-3
@@ -73,11 +73,9 @@
|
|||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"prefer": "type-imports",
|
"prefer": "type-imports",
|
||||||
"disallowTypeAnnotations": true,
|
"disallowTypeAnnotations": true
|
||||||
"fixStyle": "inline-type-imports"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"@typescript-eslint/no-useless-constructor": 0,
|
|
||||||
"curly": ["error", "multi-line"]
|
"curly": ["error", "multi-line"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
* text eol=lf
|
* text eol=lf
|
||||||
*.png binary
|
*.png binary
|
||||||
*.ico binary
|
*.ico binary
|
||||||
*.woff2 binary
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Related issues 🔗
|
# Related issues 🔗
|
||||||
|
|
||||||
Closes #[Issue number here]
|
Issue: #[Issue number here]
|
||||||
|
|
||||||
# Description ℹ️
|
# Description ℹ️
|
||||||
|
|
||||||
|
|||||||
@@ -82,38 +82,3 @@ jobs:
|
|||||||
https://${{ env.IPFS_V1 }}.ipfs.dweb.link/
|
https://${{ env.IPFS_V1 }}.ipfs.dweb.link/
|
||||||
https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/
|
https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/
|
||||||
ipfs://${{ env.IPFS_V0 }}/
|
ipfs://${{ env.IPFS_V0 }}/
|
||||||
|
|
||||||
- name: Ensure 'Released' label exists
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
REPO="${{ github.repository }}"
|
|
||||||
LABEL_EXIST=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
"https://api.github.com/repos/$REPO/labels/Released")
|
|
||||||
if [[ "$LABEL_EXIST" == *"Not Found"* ]]; then
|
|
||||||
curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
-X POST "https://api.github.com/repos/$REPO/labels" \
|
|
||||||
-d '{"name": "Released", "color": "FFFFFF"}'
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Extract issues from release notes
|
|
||||||
id: extract-issues
|
|
||||||
run: |
|
|
||||||
ISSUES=$(echo "${{ github.event.release.body }}" | grep -o -E '#[0-9]+' | tr -d '#' | jq -R . | jq -cs .)
|
|
||||||
echo "Issues to label: $ISSUES"
|
|
||||||
echo "::set-output name=issue_numbers::$ISSUES"
|
|
||||||
|
|
||||||
- name: Add 'Released' label to issues
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
ISSUE_NUMBERS="${{ steps.extract-issues.outputs.issue_numbers }}"
|
|
||||||
REPO="${{ github.repository }}"
|
|
||||||
for ISSUE in $(echo "$ISSUE_NUMBERS" | jq -r '.[]'); do
|
|
||||||
curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
-X POST "https://api.github.com/repos/$REPO/issues/$ISSUE/labels" \
|
|
||||||
-d '{"labels": ["Released"]}'
|
|
||||||
done
|
|
||||||
|
|||||||
@@ -5,17 +5,15 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- release/*
|
- release/*
|
||||||
- develop
|
- develop
|
||||||
- main
|
|
||||||
pull_request:
|
pull_request:
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
- ready_for_review
|
- ready_for_review
|
||||||
- reopened
|
- reopened
|
||||||
|
- edited
|
||||||
- synchronize
|
- synchronize
|
||||||
jobs:
|
jobs:
|
||||||
node-modules:
|
node-modules:
|
||||||
# All jobs depend on node_modules, so none should run if the PR is in draft
|
|
||||||
if: github.event.pull_request.draft == false
|
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
name: 'Cache yarn modules'
|
name: 'Cache yarn modules'
|
||||||
steps:
|
steps:
|
||||||
@@ -23,6 +21,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: Cache node modules
|
||||||
id: cache
|
id: cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -34,21 +33,29 @@ jobs:
|
|||||||
${{ runner.os }}-cache-node-modules-
|
${{ runner.os }}-cache-node-modules-
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|
||||||
- name: yarn install
|
- name: yarn install
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
run: yarn install --pure-lockfile
|
run: yarn install --pure-lockfile
|
||||||
|
|
||||||
lint-format:
|
lint-pr-title:
|
||||||
timeout-minutes: 20
|
needs: node-modules
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
name: Verify PR title
|
||||||
|
uses: ./.github/workflows/lint-pr.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
lint-test-build:
|
||||||
|
timeout-minutes: 60
|
||||||
needs: node-modules
|
needs: node-modules
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
name: '(CI) lint + format check'
|
name: '(CI) lint + unit test + build'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -57,7 +64,7 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
@@ -74,76 +81,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
main-branch-name: develop
|
main-branch-name: develop
|
||||||
|
|
||||||
- name: Check formatting
|
|
||||||
run: yarn nx format:check
|
|
||||||
|
|
||||||
- name: Lint affected
|
|
||||||
run: yarn nx affected:lint --max-warnings=0
|
|
||||||
|
|
||||||
- name: Build affected spec
|
|
||||||
run: yarn nx affected --target=build-spec
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# See affected apps
|
# See affected apps
|
||||||
- name: See affected apps
|
- name: See affected apps
|
||||||
run: |
|
run: |
|
||||||
@@ -160,8 +97,21 @@ jobs:
|
|||||||
echo "preview_explorer: ${{ env.PREVIEW_EXPLORER }}"
|
echo "preview_explorer: ${{ env.PREVIEW_EXPLORER }}"
|
||||||
echo "preview_tools: ${{ env.PREVIEW_TOOLS }}"
|
echo "preview_tools: ${{ env.PREVIEW_TOOLS }}"
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
run: yarn nx format:check
|
||||||
|
|
||||||
|
- name: Lint affected
|
||||||
|
run: yarn nx affected:lint --max-warnings=0
|
||||||
|
|
||||||
|
- name: Build affected spec
|
||||||
|
run: yarn nx affected --target=build-spec
|
||||||
|
|
||||||
|
- name: Test affected
|
||||||
|
run: yarn nx affected:test
|
||||||
|
|
||||||
- name: Build affected
|
- name: Build affected
|
||||||
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
projects: ${{ env.PROJECTS }}
|
projects: ${{ env.PROJECTS }}
|
||||||
projects-e2e: ${{ env.PROJECTS_E2E }}
|
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||||
@@ -170,62 +120,39 @@ jobs:
|
|||||||
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
||||||
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
||||||
|
|
||||||
check-e2e-needed:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build-sources
|
|
||||||
name: '(CI) check if e2e needed'
|
|
||||||
outputs:
|
|
||||||
run-tests: ${{ steps.check-test.outputs.e2e-needed }}
|
|
||||||
steps:
|
|
||||||
- name: Check branch
|
|
||||||
id: check-test
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.base_ref }}" == "develop" ]]; then
|
|
||||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.base_ref }}" == "main" ]]; then
|
|
||||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/"* ]]; then
|
|
||||||
echo "e2e-needed=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "e2e-needed=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
- name: Print result
|
|
||||||
run: |
|
|
||||||
echo "e2e-needed: ${{ steps.check-test.outputs.e2e-needed }}"
|
|
||||||
|
|
||||||
cypress:
|
|
||||||
needs: [build-sources, check-e2e-needed]
|
|
||||||
name: '(CI) cypress'
|
|
||||||
if: ${{ needs.check-e2e-needed.outputs.run-tests == 'true' }}
|
|
||||||
uses: ./.github/workflows/cypress-run.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
projects: ${{ needs.build-sources.outputs.projects-e2e }}
|
|
||||||
tags: '@smoke'
|
|
||||||
|
|
||||||
console-e2e:
|
console-e2e:
|
||||||
needs: [build-sources, check-e2e-needed]
|
needs: lint-test-build
|
||||||
name: '(CI) trading e2e python'
|
name: '(CI) console python'
|
||||||
uses: ./.github/workflows/console-test-run.yml
|
uses: ./.github/workflows/console-test-run.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
if: needs.check-e2e-needed.outputs.run-tests == 'true' && contains(needs.build-sources.outputs.projects, 'trading')
|
if: ${{ contains(fromJSON(needs.lint-test-build.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
|
||||||
with:
|
with:
|
||||||
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
|
cypress:
|
||||||
|
needs: lint-test-build
|
||||||
|
name: '(CI) cypress'
|
||||||
|
# if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
|
||||||
|
uses: ./.github/workflows/cypress-run.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
|
||||||
|
tags: '@smoke'
|
||||||
|
|
||||||
publish-dist:
|
publish-dist:
|
||||||
needs: build-sources
|
needs: lint-test-build
|
||||||
name: '(CD) publish dist'
|
name: '(CD) publish dist'
|
||||||
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
|
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }}
|
||||||
uses: ./.github/workflows/publish-dist.yml
|
uses: ./.github/workflows/publish-dist.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
projects: ${{ needs.build-sources.outputs.projects }}
|
projects: ${{ needs.lint-test-build.outputs.projects }}
|
||||||
|
|
||||||
dist-check:
|
dist-check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
- publish-dist
|
- publish-dist
|
||||||
- build-sources
|
- lint-test-build
|
||||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }}
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
name: '(CD) comment preview links'
|
name: '(CD) comment preview links'
|
||||||
@@ -241,27 +168,27 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url
|
||||||
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
|
||||||
if [[ "${{ needs.build-sources.outputs.preview_governance }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_governance }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
|
||||||
echo "waiting for governance preview: ${{ needs.build-sources.outputs.preview_governance }}"
|
echo "waiting for governance preview: ${{ needs.lint-test-build.outputs.preview_governance }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.build-sources.outputs.preview_explorer }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_explorer }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
|
||||||
echo "waiting for explorer preview: ${{ needs.build-sources.outputs.preview_explorer }}"
|
echo "waiting for explorer preview: ${{ needs.lint-test-build.outputs.preview_explorer }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.build-sources.outputs.preview_trading }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_trading }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
|
||||||
echo "waiting for trading preview: ${{ needs.build-sources.outputs.preview_trading }}"
|
echo "waiting for trading preview: ${{ needs.lint-test-build.outputs.preview_trading }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ "${{ needs.build-sources.outputs.preview_tools }}" =~ $regex ]]; then
|
if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then
|
||||||
until curl --insecure --location --fail "${{ needs.build-sources.outputs.preview_tools }}"; do
|
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
|
||||||
echo "waiting for tools preview: ${{ needs.build-sources.outputs.preview_tools }}"
|
echo "waiting for tools preview: ${{ needs.lint-test-build.outputs.preview_tools }}"
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
@@ -273,10 +200,10 @@ jobs:
|
|||||||
issue-number: ${{ github.event.pull_request.number }}
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
body: |
|
body: |
|
||||||
Previews
|
Previews
|
||||||
* governance: ${{ needs.build-sources.outputs.preview_governance }}
|
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
|
||||||
* explorer: ${{ needs.build-sources.outputs.preview_explorer }}
|
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
|
||||||
* trading: ${{ needs.build-sources.outputs.preview_trading }}
|
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
|
||||||
* tools: ${{ needs.build-sources.outputs.preview_tools }}
|
* tools: ${{ needs.lint-test-build.outputs.preview_tools }}
|
||||||
|
|
||||||
# Report single result at the end, to avoid mess with required checks in PR
|
# Report single result at the end, to avoid mess with required checks in PR
|
||||||
cypress-check:
|
cypress-check:
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#managing-caches
|
|
||||||
name: cleanup caches by a branch
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- closed
|
|
||||||
jobs:
|
|
||||||
cleanup:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Cleanup
|
|
||||||
run: |
|
|
||||||
gh extension install actions/gh-actions-cache
|
|
||||||
|
|
||||||
echo "Fetching list of cache key"
|
|
||||||
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
|
|
||||||
|
|
||||||
## Setting this to not fail the workflow while deleting cache keys.
|
|
||||||
set +e
|
|
||||||
echo "Deleting caches..."
|
|
||||||
for cacheKey in $cacheKeysForPR
|
|
||||||
do
|
|
||||||
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
|
|
||||||
done
|
|
||||||
echo "Done"
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
REPO: ${{ github.repository }}
|
|
||||||
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
|
|
||||||
@@ -6,37 +6,23 @@ on:
|
|||||||
github-sha:
|
github-sha:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
console-test-branch:
|
|
||||||
type: choice
|
|
||||||
description: 'main: v0.73.5, develop: v0.73.5'
|
|
||||||
options:
|
|
||||||
- main
|
|
||||||
- develop
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
create-docker-image:
|
run-tests:
|
||||||
name: Create docker image for console-test
|
name: run-tests
|
||||||
runs-on: ubuntu-22.04
|
runs-on: 8-cores
|
||||||
timeout-minutes: 45
|
timeout-minutes: 20
|
||||||
steps:
|
steps:
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# check-out frontend-monorepo
|
# check-out frontend-monorepo
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Checkout frontend-monorepo
|
- name: Checkout console test repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.github-sha || github.sha }}
|
ref: ${{ inputs.github-sha }}
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# cache node modules
|
# cache node modules
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: setup node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: Cache node modules
|
||||||
id: cache
|
id: cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -47,6 +33,15 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-cache-node-modules-
|
${{ runner.os }}-cache-node-modules-
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
|
# setup node
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version-file: '.nvmrc'
|
||||||
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
cache: yarn
|
||||||
|
#----------------------------------------------
|
||||||
# install deps if cache missing
|
# install deps if cache missing
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: yarn install
|
- name: yarn install
|
||||||
@@ -55,124 +50,39 @@ jobs:
|
|||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# build trading
|
# build trading
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Build trading app
|
- name: Build affected spec
|
||||||
run: |
|
run: |
|
||||||
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
|
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
|
# run trading server
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
|
- name: Run trading server
|
||||||
- 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: |
|
run: |
|
||||||
echo ${{ steps.docker_build.outputs.digest }}
|
docker run -d -p 80:4200 -v $PWD/docker/nginx.conf:/etc/nginx/conf.d/default.conf -v $PWD/dist/apps/trading/exported:/usr/share/nginx/html nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
|
||||||
echo ${{ steps.docker_build.outputs.imageid }}
|
sleep 5
|
||||||
|
docker ps
|
||||||
- name: Upload docker image for console-test usage
|
#----------------------------------------------
|
||||||
uses: actions/upload-artifact@v3
|
# check if container persists between runs
|
||||||
with:
|
#----------------------------------------------
|
||||||
name: console-image
|
- name: Check server
|
||||||
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: |
|
run: |
|
||||||
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
docker ps
|
||||||
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
|
# check-out tests repo
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Download docker image from previous job
|
- name: Checkout console test repo
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: console-image
|
|
||||||
path: /tmp
|
|
||||||
|
|
||||||
- name: Load Docker image
|
|
||||||
run: |
|
|
||||||
docker load --input /tmp/console-image.tar
|
|
||||||
docker image ls -a
|
|
||||||
#----------------------------------------------
|
|
||||||
# check-out frontend-monorepo
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Checkout frontend-monorepo
|
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.github-sha || github.sha }}
|
repository: vegaprotocol/console-test
|
||||||
|
path: './console-test'
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# get vega version
|
# set-up python
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Set VEGA_VERSION from .env
|
- name: Set up python
|
||||||
id: set_vega_version
|
id: setup-python
|
||||||
run: echo "VEGA_VERSION=$(grep VEGA_VERSION apps/trading/e2e/.env | cut -d '=' -f2)" >> $GITHUB_ENV
|
|
||||||
#----------------------------------------------
|
|
||||||
# ----- Setup python -----
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10.11'
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# ----- install & configure poetry -----
|
# ----- install & configure poetry -----
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
@@ -181,32 +91,45 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
virtualenvs-create: true
|
virtualenvs-create: true
|
||||||
virtualenvs-in-project: true
|
virtualenvs-in-project: true
|
||||||
virtualenvs-path: .venv
|
virtualenvs-path: console-test/.venv
|
||||||
|
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install python dependencies
|
# load cached venv if cache exists
|
||||||
|
#----------------------------------------------
|
||||||
|
- name: Load cached venv
|
||||||
|
id: cached-poetry-dependencies
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: console-test/.venv
|
||||||
|
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
|
||||||
|
#----------------------------------------------
|
||||||
|
# install dependencies if cache does not exist
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
working-directory: ./console-test
|
||||||
|
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
|
||||||
run: poetry install --no-interaction --no-root
|
run: poetry install --no-interaction --no-root
|
||||||
working-directory: apps/trading/e2e
|
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install vega binaries
|
# install vega binaries
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Install vega binaries
|
- name: Install vega binaries
|
||||||
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
|
working-directory: ./console-test
|
||||||
working-directory: apps/trading/e2e
|
run: poetry run python -m vega_sim.tools.load_binaries --force --latest
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# install playwrightworking-directory: apps/trading/e2e
|
# install playwright
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: install playwright
|
- name: install playwright
|
||||||
run: poetry run playwright install --with-deps chromium
|
run: poetry run playwright install
|
||||||
working-directory: apps/trading/e2e
|
working-directory: ./console-test
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# run tests
|
# run tests
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 1 --dist loadfile --durations=45
|
working-directory: ./console-test
|
||||||
working-directory: apps/trading/e2e
|
run: poetry run pytest -v -s --numprocesses auto --dist loadfile --durations=20
|
||||||
|
- name: Check files
|
||||||
|
run: |
|
||||||
|
ls -al .
|
||||||
|
ls -al console-test
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
# upload traces
|
# upload traces
|
||||||
#----------------------------------------------
|
#----------------------------------------------
|
||||||
@@ -215,58 +138,5 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: playwright-trace
|
name: playwright-trace
|
||||||
path: apps/trading/e2e/traces/
|
path: ./traces/
|
||||||
retention-days: 15
|
|
||||||
#----------------------------------------------
|
|
||||||
# ----- upload logs -----
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Upload worker logs
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: worker-logs
|
|
||||||
path: ./logs/
|
|
||||||
retention-days: 15
|
|
||||||
#----------------------------------------------
|
|
||||||
# ----- upload market-sim logs -----
|
|
||||||
#----------------------------------------------
|
|
||||||
- name: Prepare and Zip market-sim-logs
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
parent_dir="/tmp/market-sim-logs"
|
|
||||||
echo "Creating parent directory at $parent_dir"
|
|
||||||
mkdir -p "$parent_dir"
|
|
||||||
|
|
||||||
echo "Waiting for vega-sim-* folders to be created..."
|
|
||||||
sleep 10 # Waits 10 seconds to ensure all folders are created
|
|
||||||
|
|
||||||
echo "Before searching for vega-sim-* folders in /tmp..."
|
|
||||||
folders=$(find /tmp -mindepth 1 -type d -name 'vega-sim-*' -print) || echo "Find command failed with exit code $?"
|
|
||||||
|
|
||||||
echo "After searching for vega-sim-* folders in /tmp..."
|
|
||||||
|
|
||||||
if [ -z "$folders" ]; then
|
|
||||||
echo "No vega-sim-* folders found."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Moving vega-sim-* folders to $parent_dir"
|
|
||||||
echo "$folders" | xargs -I {} mv {} "$parent_dir/"
|
|
||||||
|
|
||||||
echo "Checking if $parent_dir is not empty..."
|
|
||||||
if [ "$(ls -A $parent_dir)" ]; then
|
|
||||||
echo "Zipping the parent directory..."
|
|
||||||
zip -r market-sim-logs.zip "$parent_dir" && echo "Zip file created successfully."
|
|
||||||
else
|
|
||||||
echo "$parent_dir is empty. No zip file created."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
shell: /usr/bin/bash -e {0}
|
|
||||||
|
|
||||||
- name: Upload market-sim-logs
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: market-sim-logs
|
|
||||||
path: market-sim-logs.zip
|
|
||||||
retention-days: 15
|
retention-days: 15
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Use Node.js 20
|
- name: Use Node.js 16
|
||||||
id: Node
|
id: Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version: 16.15.1
|
||||||
|
|
||||||
- name: Run Cypress tests
|
- name: Run Cypress tests
|
||||||
uses: cypress-io/github-action@v4
|
uses: cypress-io/github-action@v4
|
||||||
|
|||||||
@@ -13,35 +13,13 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
runner-choice:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
runner: ${{ steps.step.outputs.runner }}
|
|
||||||
steps:
|
|
||||||
- name: Check branch
|
|
||||||
id: step
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
|
||||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
|
|
||||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
|
|
||||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "runner=self-hosted-runner" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Print runner
|
|
||||||
run: echo ${{ steps.step.outputs.runner }}
|
|
||||||
|
|
||||||
e2e:
|
e2e:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
project: ${{ fromJSON(inputs.projects) }}
|
project: ${{ fromJSON(inputs.projects) }}
|
||||||
name: ${{ matrix.project }}
|
name: ${{ matrix.project }}
|
||||||
needs: runner-choice
|
runs-on: self-hosted-runner
|
||||||
runs-on: ${{ needs.runner-choice.outputs.runner }}
|
|
||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
steps:
|
steps:
|
||||||
# Checks if skip cache was requested
|
# Checks if skip cache was requested
|
||||||
@@ -57,17 +35,8 @@ jobs:
|
|||||||
path: './frontend-monorepo'
|
path: './frontend-monorepo'
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: './frontend-monorepo/.nvmrc'
|
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
|
||||||
cache: yarn
|
|
||||||
cache-dependency-path: './frontend-monorepo/yarn.lock'
|
|
||||||
|
|
||||||
# Restore node_modules from cache if possible
|
# Restore node_modules from cache if possible
|
||||||
- name: Restore node_modules from cache
|
- name: Restore node_modules from cache
|
||||||
id: cache-node-modules
|
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@@ -77,7 +46,6 @@ jobs:
|
|||||||
|
|
||||||
# Install frontend dependencies
|
# Install frontend dependencies
|
||||||
- name: Install root dependencies
|
- name: Install root dependencies
|
||||||
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn install --frozen-lockfile
|
||||||
working-directory: frontend-monorepo
|
working-directory: frontend-monorepo
|
||||||
|
|
||||||
@@ -93,14 +61,13 @@ jobs:
|
|||||||
- name: Run Vegacapsule network and Vega wallet
|
- name: Run Vegacapsule network and Vega wallet
|
||||||
id: setup-vega
|
id: setup-vega
|
||||||
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
||||||
timeout-minutes: 10
|
|
||||||
|
|
||||||
######
|
######
|
||||||
## Run some tests
|
## Run some tests
|
||||||
######
|
######
|
||||||
|
|
||||||
- name: Run Cypress tests
|
- name: Run Cypress tests
|
||||||
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --browser chrome --env.grepTags="${{ inputs.tags }}"
|
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --browser chrome --env.grepTags="${{ inputs.tags }}"
|
||||||
working-directory: frontend-monorepo
|
working-directory: frontend-monorepo
|
||||||
env:
|
env:
|
||||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
|||||||
@@ -2,12 +2,7 @@
|
|||||||
name: Verify PR title
|
name: Verify PR title
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
workflow_call:
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- edited
|
|
||||||
- reopened
|
|
||||||
- synchronize
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint_pr:
|
lint_pr:
|
||||||
@@ -16,16 +11,21 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Cache node modules
|
||||||
run: |
|
uses: actions/cache@v3
|
||||||
rm package.json
|
with:
|
||||||
npm install --no-save @commitlint/cli @commitlint/config-conventional @commitlint/config-nx-scopes nx
|
path: node_modules
|
||||||
|
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
||||||
|
|
||||||
- name: Check PR title
|
- name: Check PR title
|
||||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
||||||
|
|||||||
@@ -30,18 +30,12 @@ jobs:
|
|||||||
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
||||||
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
||||||
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
|
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
|
||||||
echo IS_MAIN_IMAGE=false >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Is dev image
|
- name: Is dev image
|
||||||
if: ${{ github.ref_name == 'develop' && github.event_name == 'push' && matrix.app == 'trading' }}
|
if: ${{ contains(github.ref, 'develop') && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||||
run: |
|
run: |
|
||||||
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
|
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Is main image
|
|
||||||
if: ${{ github.ref_name == 'main' && github.event_name == 'push' && matrix.app == 'trading' }}
|
|
||||||
run: |
|
|
||||||
echo IS_MAIN_IMAGE=true >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Is PR
|
- name: Is PR
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
run: |
|
run: |
|
||||||
@@ -63,7 +57,7 @@ jobs:
|
|||||||
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Is S3 Release
|
- name: Is S3 Release
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' && github.ref_name != 'main'}}
|
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' }}
|
||||||
run: |
|
run: |
|
||||||
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -87,13 +81,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Log in to the Container registry (docker hub)
|
- name: Log in to the Container registry (docker hub)
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
@@ -161,10 +155,10 @@ jobs:
|
|||||||
- name: Sanity check docker image
|
- name: Sanity check docker image
|
||||||
run: |
|
run: |
|
||||||
echo "Check ipfs-hash"
|
echo "Check ipfs-hash"
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash'
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash > ${{ matrix.app }}-ipfs-hash
|
||||||
echo "List html directory"
|
echo "List html directory"
|
||||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'apk add --update tree; tree /usr/share/nginx/html'
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree /usr/share/nginx/html'
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr)
|
- name: Publish dist as docker image (ghcr)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
@@ -185,7 +179,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
id: dockerhub-push
|
id: dockerhub-push
|
||||||
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
|
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/node-outside-docker.Dockerfile
|
file: docker/node-outside-docker.Dockerfile
|
||||||
@@ -195,7 +189,7 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || '' }}
|
||||||
|
|
||||||
- name: Publish dist as docker image (ghcr - retry)
|
- name: Publish dist as docker image (ghcr - retry)
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
@@ -222,7 +216,7 @@ jobs:
|
|||||||
ENV_NAME=${{ env.ENV_NAME }}
|
ENV_NAME=${{ env.ENV_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
|
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
|
||||||
|
|
||||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
||||||
- name: Publish dist to s3
|
- name: Publish dist to s3
|
||||||
@@ -335,9 +329,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# create commit
|
# create commit
|
||||||
if ! git diff --cached --exit-code; then
|
commit_msg="Automated hash update from ${{ github.ref }}"
|
||||||
commit_msg="Automated hash update from ${{ github.ref }}"
|
git commit -m "$commit_msg"
|
||||||
git commit -m "$commit_msg"
|
git push -u origin "main"
|
||||||
git push -u origin "main"
|
|
||||||
fi
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||||
|
|||||||
+1
-9
@@ -48,15 +48,7 @@ cypress.env.json
|
|||||||
# Next.js
|
# Next.js
|
||||||
.next
|
.next
|
||||||
|
|
||||||
# cypress
|
#cypress
|
||||||
/apps/**/cypress/reports/
|
/apps/**/cypress/reports/
|
||||||
/apps/**/cypress/downloads/
|
/apps/**/cypress/downloads/
|
||||||
/apps/**/fixtures/wallet/node**
|
/apps/**/fixtures/wallet/node**
|
||||||
|
|
||||||
# apps/trading/e2e
|
|
||||||
__pycache__/
|
|
||||||
apps/trading/e2e/logs/
|
|
||||||
apps/trading/e2e/.pytest_cache/
|
|
||||||
apps/trading/e2e/traces/
|
|
||||||
|
|
||||||
.nx/
|
|
||||||
|
|||||||
@@ -3,3 +3,6 @@
|
|||||||
|
|
||||||
# Lint commit messages to ensure they follow conventional commit standards
|
# Lint commit messages to ensure they follow conventional commit standards
|
||||||
yarn commitlint --edit "${1}"
|
yarn commitlint --edit "${1}"
|
||||||
|
|
||||||
|
# Lint all staged files
|
||||||
|
yarn lint-staged
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
# Auto-format all files
|
|
||||||
yarn nx format:write
|
|
||||||
|
|
||||||
# Lint all staged files
|
|
||||||
yarn lint-staged
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
# Lint all staged files - this brings more value as pre-commit
|
|
||||||
# yarn nx format:check
|
|
||||||
|
|
||||||
# Test all projects with changes
|
|
||||||
# yarn nx affected -t test --exclude trading
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
# Add files here to ignore them from prettier formatting
|
# Add files here to ignore them from prettier formatting
|
||||||
|
|
||||||
/dist
|
/dist
|
||||||
/dist-result
|
|
||||||
/coverage
|
/coverage
|
||||||
__generated__
|
__generated__
|
||||||
__generated___
|
__generated___
|
||||||
@@ -9,15 +8,3 @@ __generated___
|
|||||||
apps/static/src/assets/devnet-tranches.json
|
apps/static/src/assets/devnet-tranches.json
|
||||||
apps/static/src/assets/mainnet-tranches.json
|
apps/static/src/assets/mainnet-tranches.json
|
||||||
apps/static/src/assets/testnet-tranches.json
|
apps/static/src/assets/testnet-tranches.json
|
||||||
|
|
||||||
/apps/**/cypress/reports/
|
|
||||||
/apps/**/cypress/downloads/
|
|
||||||
|
|
||||||
/.nx/cache
|
|
||||||
|
|
||||||
# apps/trading/e2e
|
|
||||||
__pycache__/
|
|
||||||
apps/trading/e2e/logs/
|
|
||||||
apps/trading/e2e/.pytest_cache/
|
|
||||||
apps/trading/e2e/traces/
|
|
||||||
.pytest_cache/
|
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
* @vegaprotocol/frontend
|
* @vegaprotocol/frontend
|
||||||
apps/ @vegaprotocol/frontend-qa
|
|
||||||
libs/ @vegaprotocol/frontend-qa
|
|
||||||
*.graphql @vegaprotocol/core
|
*.graphql @vegaprotocol/core
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ recalculate-ipfs:
|
|||||||
echo "ipfs hash inside the image"
|
echo "ipfs hash inside the image"
|
||||||
docker run --rm ${TAG} cat /ipfs-hash
|
docker run --rm ${TAG} cat /ipfs-hash
|
||||||
echo "recalculating ipfs hash"
|
echo "recalculating ipfs hash"
|
||||||
docker run --rm ${TAG} ipfs add -rQ /usr/share/nginx/html
|
docker run --rm ${TAG} ipfs add -r /usr/share/nginx/html
|
||||||
|
|
||||||
.PHONY: eject-ipfs-hash
|
.PHONY: eject-ipfs-hash
|
||||||
unpack:
|
unpack:
|
||||||
|
|||||||
@@ -113,47 +113,13 @@ In order to run a container on port 3000:
|
|||||||
docker run -p 3000:80 [TAG]
|
docker run -p 3000:80 [TAG]
|
||||||
```
|
```
|
||||||
|
|
||||||
On top of that there are two possible scenarios for running docker image - using nginx server (default) of ipfs daemon.
|
|
||||||
|
|
||||||
to run ipfs on port 3000:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -p 3000:80 [TAG] /run-ipfs.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
to run nginx on port 3000:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -p 3000:80 [TAG]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build instructions
|
## Build instructions
|
||||||
|
|
||||||
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of Console either for the web, or ready for pinning on IPFS.
|
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of console either for the web, or ready for pinning on IPFS
|
||||||
|
|
||||||
### nx build inside the docker
|
|
||||||
|
|
||||||
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build). The multistage builds ensures consistent CPU architecture and build toolchains are used so that the result will be identical.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=20.9.1 --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
|
|
||||||
```
|
|
||||||
|
|
||||||
### Computing ipfs-hash of the build
|
|
||||||
|
|
||||||
At the moment this feature is important only for Console releases.
|
|
||||||
|
|
||||||
Each docker build finishes with hash calculation for ` dist`` directory. Resulting hash is added to file named as `/ipfs-hash`. Once docker image is produced you can run following commad to display ipfs-hash:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make recalculate-ipfs TAG=vegaprotocol/trading:{YOUR_VERSION}
|
|
||||||
```
|
|
||||||
|
|
||||||
**updating hash:** recompiling dist directory (even if there are no changed to source code) results in different hash computed by ipfs command.
|
|
||||||
|
|
||||||
### nx build outside the docker
|
### nx build outside the docker
|
||||||
|
|
||||||
This Docker image packages a pre-built `dist` folder into an [`nginx`](https://hub.docker.com/_/nginx)([server configuration](./nginx/nginx.conf)) docker image. In this case, the application on docker host machine from source.
|
Packaging prepared dist into [`nginx`](https://hub.docker.com/_/nginx)([server configuration](./nginx/nginx.conf)) docker image involves building the application on docker host machine from source.
|
||||||
|
|
||||||
As a prerequisite you need to perform build of `dist` directory and move its content for specific application to `dist-result` directory. Use following script to do it with a single command:
|
As a prerequisite you need to perform build of `dist` directory and move its content for specific application to `dist-result` directory. Use following script to do it with a single command:
|
||||||
|
|
||||||
@@ -164,21 +130,41 @@ As a prerequisite you need to perform build of `dist` directory and move its con
|
|||||||
You can build any of the containers locally with the following command:
|
You can build any of the containers locally with the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build -f docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
docker build --dockerfile docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### nx build inside the docker
|
||||||
|
|
||||||
|
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build) example.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=$(cat .nvmrc) --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Computing ipfs-hash of the build
|
||||||
|
|
||||||
|
At the moment this feature is important only for `trading` (console) releases.
|
||||||
|
|
||||||
|
Each docker build finishes with hash calculation for dist directory. Resulting hash is added to file named as `/ipfs-hash`. Once docker image is produced you can run following commad to display ipfs-hash:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make recalculate-ipfs TAG=vegaprotocol/trading:{YOUR_VERSION}
|
||||||
|
```
|
||||||
|
|
||||||
|
**updating hash:** recompiling dist directory (even if there are no changed to source code) results in different hash computed by ipfs command.
|
||||||
|
|
||||||
### Verifying ipfs-hash of existing current application version
|
### Verifying ipfs-hash of existing current application version
|
||||||
|
|
||||||
An IPFS CID will be attached to every [release](https://github.com/vegaprotocol/frontend-monorepo/releases). If you are intending to pin an application on IPFS, you can check that your build matches by running the following steps:
|
An IPFS CID will be attached to every [release](https://github.com/vegaprotocol/frontend-monorepo/releases). If you are intending to pin an application on IPFS, you can check that your build matches by running the following steps:
|
||||||
|
|
||||||
1. Show latest release by running: `make latest-release`. You need to configure [`gh`](https://cli.github.com/) for this step to work, otherwise please provide release manually from [github](https://github.com/vegaprotocol/frontend-monorepo/releases) or [dockerhub](https://hub.docker.com/r/vegaprotocol/trading)
|
1. Show latest release by runnning: `make latest-release`. You need to configure [`gh`](https://cli.github.com/) for this step to work, otherwise please provide release manually from [github](https://github.com/vegaprotocol/frontend-monorepo/releases) or [dockerhub](https://hub.docker.com/r/vegaprotocol/trading)
|
||||||
2. Set RELEASE environment variable to value that you want to validate: `export RELEASE=$(make latest-release)` or `export RELEASE=vXX.XX.XX`
|
2. Set RELEASE environment variable to value that you want to validate: `export RELEASE=$(make latest-release)` or `export RELEASE=vXX.XX.XX`
|
||||||
3. Set TAG environment variable to image that you want to validate: `export TAG=vegaprotocol/trading:$RELEASE`
|
3. Set TAG environment variable to image that you want to validate: `export TAG=vegaprotocol/trading:$RELEASE`
|
||||||
4. Download docker image with the desired release `docker pull $TAG`.
|
4. Download docker image with the desired release `docker pull $TAG`.
|
||||||
5. Recalculate hash: `make recalculate-ipfs`
|
5. Recalculate hash: `make recalculate-ipfs`
|
||||||
6. You should see exactly same hash produced by ipfs command as one placed with the release notes: `make show-latest-release`
|
6. You should see exactly same hash produced by ipfs command as one placed with the release notes: `make show-latest-release`
|
||||||
7. If you want to extract dist from docker image to your local filesystem you can run following command: `make unpack`
|
7. If you want to extract dist from docker image to your local filesystem you can run following command: `make unpack`
|
||||||
8. Now `dist` directory contains valid application build
|
8. Now `dist` directory contains valid application build. **it is not possible to calculate same ipfs hash on files that are result of copy operation**
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
|||||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||||
NX_VEGA_ENV=DEVNET
|
NX_VEGA_ENV=DEVNET
|
||||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocke
|
|||||||
NX_VEGA_URL=https://api.vega.community/graphql
|
NX_VEGA_URL=https://api.vega.community/graphql
|
||||||
NX_VEGA_ENV=MAINNET
|
NX_VEGA_ENV=MAINNET
|
||||||
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
|
|||||||
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
||||||
NX_VEGA_ENV=TESTNET
|
NX_VEGA_ENV=TESTNET
|
||||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -4,9 +4,7 @@
|
|||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
"rules": {
|
"rules": {}
|
||||||
"cypress/unsafe-to-chain-command": 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nx/eslint:lint",
|
"executor": "@nx/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
|
||||||
|
|||||||
@@ -36,9 +36,10 @@ context('Market page', { tags: '@regression' }, function () {
|
|||||||
|
|
||||||
it('Able to go to market details page', function () {
|
it('Able to go to market details page', function () {
|
||||||
cy.navigate_to('markets');
|
cy.navigate_to('markets');
|
||||||
cy.contains('Test market 1').click();
|
cy.get_element_by_col_id('actions').eq(1).click();
|
||||||
cy.getByTestId(marketHeaders).should('have.text', 'Test market 1');
|
cy.getByTestId(marketHeaders).should('have.text', 'Test market 1');
|
||||||
cy.validate_element_from_table('Name', 'Test market 1');
|
cy.validate_element_from_table('Name', 'Test market 1');
|
||||||
|
cy.validate_element_from_table('Market ID', this.createdMarketId);
|
||||||
cy.validate_element_from_table('Trading Mode', 'Opening auction');
|
cy.validate_element_from_table('Trading Mode', 'Opening auction');
|
||||||
cy.validate_element_from_table('Market Decimal Places', '5');
|
cy.validate_element_from_table('Market Decimal Places', '5');
|
||||||
cy.validate_element_from_table('Position Decimal Places', '5');
|
cy.validate_element_from_table('Position Decimal Places', '5');
|
||||||
@@ -86,13 +87,15 @@ context('Market page', { tags: '@regression' }, function () {
|
|||||||
// Liquidity
|
// Liquidity
|
||||||
cy.validate_element_from_table('Target Stake', '0.00 fUSDC');
|
cy.validate_element_from_table('Target Stake', '0.00 fUSDC');
|
||||||
cy.validate_element_from_table('Supplied Stake', '0.00 fUSDC');
|
cy.validate_element_from_table('Supplied Stake', '0.00 fUSDC');
|
||||||
|
cy.validate_element_from_table('Market Value Proxy', '0.00 fUSDC');
|
||||||
// Liquidity price range
|
// Liquidity price range
|
||||||
cy.validate_element_from_table(
|
cy.validate_element_from_table(
|
||||||
'Liquidity Price Range',
|
'Liquidity Price Range',
|
||||||
'95.00% of mid price'
|
'1,000.00% of mid price'
|
||||||
);
|
);
|
||||||
cy.validate_element_from_table('Lowest Price', '0.00 fUSDC');
|
cy.validate_element_from_table('Lowest Price', '0.00 fUSDC');
|
||||||
cy.validate_element_from_table('Highest Price', '0.00 fUSDC');
|
cy.validate_element_from_table('Highest Price', '0.00 fUSDC');
|
||||||
|
|
||||||
cy.getByTestId('oracle-spec-links')
|
cy.getByTestId('oracle-spec-links')
|
||||||
.should('have.attr', 'href')
|
.should('have.attr', 'href')
|
||||||
.and(
|
.and(
|
||||||
@@ -141,8 +144,11 @@ context('Market page', { tags: '@regression' }, function () {
|
|||||||
.as('successorMarketId');
|
.as('successorMarketId');
|
||||||
cy.contains('Token test market').click();
|
cy.contains('Token test market').click();
|
||||||
cy.getByTestId(marketHeaders).should('have.text', 'Token test market');
|
cy.getByTestId(marketHeaders).should('have.text', 'Token test market');
|
||||||
|
cy.validate_proposal_change_type('Triggering Ratio', 'Added');
|
||||||
cy.validate_element_from_table('Triggering Ratio', '0.7');
|
cy.validate_element_from_table('Triggering Ratio', '0.7');
|
||||||
|
cy.validate_proposal_change_type('Time Window', 'Added');
|
||||||
cy.validate_element_from_table('Time Window', '3,600');
|
cy.validate_element_from_table('Time Window', '3,600');
|
||||||
|
cy.validate_proposal_change_type('Scaling Factor', 'Added');
|
||||||
cy.validate_element_from_table('Scaling Factor', '10');
|
cy.validate_element_from_table('Scaling Factor', '10');
|
||||||
|
|
||||||
cy.getByTestId(successionLineItem)
|
cy.getByTestId(successionLineItem)
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
context('Network parameters page', { tags: '@smoke' }, function () {
|
context('Network parameters page', { tags: '@smoke' }, function () {
|
||||||
before('navigate to network parameter page', function () {
|
before('navigate to network parameter page', function () {
|
||||||
cy.fixture('net_parameter_format_lookup').as('networkParameterFormat');
|
cy.fixture('net_parameter_format_lookup').as('networkParameterFormat');
|
||||||
cy.visit('/network-parameters');
|
|
||||||
});
|
});
|
||||||
describe('Verify elements on page', function () {
|
describe('Verify elements on page', function () {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/network-parameters');
|
||||||
|
});
|
||||||
|
|
||||||
const networkParametersHeader = '[data-testid="network-param-header"]';
|
const networkParametersHeader = '[data-testid="network-param-header"]';
|
||||||
const tableRows = '[data-testid="key-value-table-row"]';
|
const tableRows = '[data-testid="key-value-table-row"]';
|
||||||
|
|
||||||
@@ -13,7 +16,6 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
|||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 0006-NETW-021
|
|
||||||
it('should list each of the network parameters available', function () {
|
it('should list each of the network parameters available', function () {
|
||||||
cy.get_network_parameters().then((network_parameters) => {
|
cy.get_network_parameters().then((network_parameters) => {
|
||||||
const numberOfNetworkParametersInSystem =
|
const numberOfNetworkParametersInSystem =
|
||||||
@@ -196,19 +198,6 @@ context('Network parameters page', { tags: '@smoke' }, function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 0006-NETW-022 0006-NETW-023
|
|
||||||
it('governance assets should be correctly grouped', function () {
|
|
||||||
cy.getByTestId('governance')
|
|
||||||
.should('exist')
|
|
||||||
.parent()
|
|
||||||
.should('have.attr', 'href', '/network-parameters#governance');
|
|
||||||
cy.get('[id="governance-proposal-asset"]')
|
|
||||||
.parent()
|
|
||||||
.within(() => {
|
|
||||||
cy.getByTestId('key-value-table-row').should('have.length', 8);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to see network parameters - on mobile', function () {
|
it('should be able to see network parameters - on mobile', function () {
|
||||||
cy.switchToMobile();
|
cy.switchToMobile();
|
||||||
cy.get_network_parameters().then((network_parameters) => {
|
cy.get_network_parameters().then((network_parameters) => {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ context.skip('Node switcher', { tags: '@regression' }, function () {
|
|||||||
const errorTypeTxt = 'Error: invalid url';
|
const errorTypeTxt = 'Error: invalid url';
|
||||||
const nodeErrorTxt = 'fakeUrl is not a valid url.';
|
const nodeErrorTxt = 'fakeUrl is not a valid url.';
|
||||||
|
|
||||||
cy.getByTestId('node-url-custom').click({ force: true });
|
cy.getByTestId('node-url-custom').click();
|
||||||
|
|
||||||
cy.getByTestId(customNodeBtn).within(() => {
|
cy.getByTestId(customNodeBtn).within(() => {
|
||||||
cy.get('input').clear().type('fakeUrl');
|
cy.get('input').clear().type('fakeUrl');
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
|||||||
cy.getByTestId('icon-cross').click();
|
cy.getByTestId('icon-cross').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Proposal page displayed on mobile', function () {
|
it.skip('Proposal page displayed on mobile', function () {
|
||||||
const proposalTitle = 'Add Lorem Ipsum market';
|
const proposalTitle = 'Add Lorem Ipsum market';
|
||||||
|
|
||||||
cy.common_switch_to_mobile_and_click_toggle();
|
cy.common_switch_to_mobile_and_click_toggle();
|
||||||
@@ -55,7 +55,7 @@ context('Proposal page', { tags: '@smoke' }, function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('Able to view new asset proposal', function () {
|
it('Able to view new asset proposal', function () {
|
||||||
const proposalTitle = 'Test new asset proposal';
|
const proposalTitle = 'Test new asset proposal';
|
||||||
const newAssetProposalBody = getNewAssetTxBody();
|
const newAssetProposalBody = getNewAssetTxBody();
|
||||||
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
cy.VegaWalletSubmitProposal(newAssetProposalBody);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ function getSuccessorTxBody(parentMarketId) {
|
|||||||
positionDecimalPlaces: '5',
|
positionDecimalPlaces: '5',
|
||||||
linearSlippageFactor: '0.001',
|
linearSlippageFactor: '0.001',
|
||||||
quadraticSlippageFactor: '0',
|
quadraticSlippageFactor: '0',
|
||||||
|
lpPriceRange: '10',
|
||||||
instrument: {
|
instrument: {
|
||||||
name: 'Token test market',
|
name: 'Token test market',
|
||||||
code: 'TEST.24h',
|
code: 'TEST.24h',
|
||||||
@@ -129,12 +130,6 @@ function getSuccessorTxBody(parentMarketId) {
|
|||||||
parentMarketId: parentMarketId,
|
parentMarketId: parentMarketId,
|
||||||
insurancePoolFraction: '0.75',
|
insurancePoolFraction: '0.75',
|
||||||
},
|
},
|
||||||
liquiditySlaParameters: {
|
|
||||||
priceRange: '0.95',
|
|
||||||
commitmentMinTimeFraction: '0.5',
|
|
||||||
performanceHysteresisEpochs: 2,
|
|
||||||
slaCompetitionFactor: '0.75',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
closingTimestamp,
|
closingTimestamp,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ NX_VEGA_ENV=CUSTOM
|
|||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_TXS_LIST=0
|
NX_EXPLORER_TXS_LIST=0
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
|||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/
|
||||||
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://be.vega.community
|
NX_TENDERMINT_URL=https://be.vega.community
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
|
||||||
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
# .env is stagnet1, so there are no overrides required
|
# .env is stagnet1, so there are no overrides required
|
||||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}'
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf
|
|||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||||
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
|
|||||||
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks
|
||||||
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
|
||||||
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
|
|
||||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||||
|
|||||||
@@ -5,5 +5,4 @@ NX_VEGA_ENV=CUSTOM
|
|||||||
NX_BLOCK_EXPLORER=
|
NX_BLOCK_EXPLORER=
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||||
NX_VEGA_EXPLORER_URL=/
|
NX_VEGA_EXPLORER_URL=/
|
||||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[[redirects]]
|
||||||
|
from = "/*"
|
||||||
|
to = "/index.html"
|
||||||
|
status = 200
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nx/eslint:lint",
|
"executor": "@nx/linter:eslint",
|
||||||
"outputs": ["{options.outputFile}"],
|
"outputs": ["{options.outputFile}"],
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
|
||||||
@@ -63,14 +63,30 @@
|
|||||||
"executor": "@nx/jest:jest",
|
"executor": "@nx/jest:jest",
|
||||||
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
"outputs": ["{workspaceRoot}/coverage/apps/explorer"],
|
||||||
"options": {
|
"options": {
|
||||||
"jestConfig": "apps/explorer/jest.config.ts"
|
"jestConfig": "apps/explorer/jest.config.ts",
|
||||||
|
"passWithNoTests": true
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"ci": {
|
||||||
|
"ci": true,
|
||||||
|
"codeCoverage": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generate-types": {
|
"generate-types": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"options": {
|
"options": {
|
||||||
"commands": [
|
"commands": [
|
||||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.73.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.72.3/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"build-netlify": {
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"commands": [
|
||||||
|
"cp apps/explorer/netlify.toml netlify.toml",
|
||||||
|
"nx build explorer"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import '../i18n';
|
|
||||||
import {
|
import {
|
||||||
|
AppFailure,
|
||||||
NetworkLoader,
|
NetworkLoader,
|
||||||
NodeFailure,
|
|
||||||
NodeGuard,
|
NodeGuard,
|
||||||
NodeSwitcherDialog,
|
NodeSwitcherDialog,
|
||||||
useEnvironment,
|
useEnvironment,
|
||||||
@@ -12,8 +11,7 @@ import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-web
|
|||||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { useRouterConfig } from './routes/router-config';
|
import { router } from './routes/router-config';
|
||||||
import { createBrowserRouter } from 'react-router-dom';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
@@ -30,27 +28,20 @@ function App() {
|
|||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<TendermintWebsocketProvider>
|
<TendermintWebsocketProvider>
|
||||||
<Suspense fallback={splashLoading}>
|
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
||||||
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
<NodeGuard
|
||||||
<NodeGuard
|
skeleton={<div>{t('Loading')}</div>}
|
||||||
skeleton={<div>{t('Loading')}</div>}
|
failure={<AppFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />}
|
||||||
failure={
|
>
|
||||||
<NodeFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />
|
<Suspense fallback={splashLoading}>
|
||||||
}
|
<RouterProvider router={router} fallbackElement={splashLoading} />
|
||||||
>
|
</Suspense>
|
||||||
<Suspense fallback={splashLoading}>
|
</NodeGuard>
|
||||||
<RouterProvider
|
<NodeSwitcherDialog
|
||||||
router={createBrowserRouter(useRouterConfig())}
|
open={nodeSwitcherOpen}
|
||||||
fallbackElement={splashLoading}
|
setOpen={setNodeSwitcherOpen}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</NetworkLoader>
|
||||||
</NodeGuard>
|
|
||||||
<NodeSwitcherDialog
|
|
||||||
open={nodeSwitcherOpen}
|
|
||||||
setOpen={setNodeSwitcherOpen}
|
|
||||||
/>
|
|
||||||
</NetworkLoader>
|
|
||||||
</Suspense>
|
|
||||||
</TendermintWebsocketProvider>
|
</TendermintWebsocketProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useAssetDataProvider } from '@vegaprotocol/assets';
|
import { useAssetDataProvider } from '@vegaprotocol/assets';
|
||||||
import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
import { AssetLink } from '../links';
|
import { AssetLink } from '../links';
|
||||||
|
|
||||||
export type AssetBalanceProps = {
|
export type AssetBalanceProps = {
|
||||||
@@ -23,12 +23,12 @@ const AssetBalance = ({
|
|||||||
|
|
||||||
const label =
|
const label =
|
||||||
!loading && asset && asset.decimals
|
!loading && asset && asset.decimals
|
||||||
? addDecimalsFixedFormatNumber(price, asset.decimals)
|
? addDecimalsFormatNumber(price, asset.decimals)
|
||||||
: price;
|
: price;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inline-block">
|
<div className="inline-block">
|
||||||
<span className="font-mono">{label}</span>{' '}
|
<span>{label}</span>{' '}
|
||||||
{showAssetLink && asset?.id ? (
|
{showAssetLink && asset?.id ? (
|
||||||
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
|
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -1,30 +1,24 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import {
|
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||||
useAssetTypeMapping,
|
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
||||||
useAssetStatusMapping,
|
|
||||||
type AssetFieldsFragment,
|
|
||||||
} from '@vegaprotocol/assets';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { type AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import { type VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
||||||
import { useRef, useLayoutEffect } from 'react';
|
import { useRef, useLayoutEffect } from 'react';
|
||||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { type ColDef } from 'ag-grid-community';
|
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
||||||
import type { RowClickedEvent } from 'ag-grid-community';
|
|
||||||
|
|
||||||
type AssetsTableProps = {
|
type AssetsTableProps = {
|
||||||
data: AssetFieldsFragment[] | null;
|
data: AssetFieldsFragment[] | null;
|
||||||
};
|
};
|
||||||
export const AssetsTable = ({ data }: AssetsTableProps) => {
|
export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||||
const assetTypeMapping = useAssetTypeMapping();
|
|
||||||
const assetStatusMapping = useAssetStatusMapping();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const ref = useRef<AgGridReact>(null);
|
const ref = useRef<AgGridReact>(null);
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
ref.current?.api.setColumnsVisible(
|
ref.current?.columnApi.setColumnsVisible(
|
||||||
['id', 'type', 'status'],
|
['id', 'type', 'status'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
@@ -53,14 +47,14 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
field: 'source.__typename',
|
field: 'source.__typename',
|
||||||
hide: window.innerWidth < BREAKPOINT_MD,
|
hide: window.innerWidth < BREAKPOINT_MD,
|
||||||
valueFormatter: ({ value }: { value?: string }) =>
|
valueFormatter: ({ value }: { value?: string }) =>
|
||||||
value ? assetTypeMapping[value].value : '',
|
value ? AssetTypeMapping[value].value : '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headerName: t('Status'),
|
headerName: t('Status'),
|
||||||
field: 'status',
|
field: 'status',
|
||||||
hide: window.innerWidth < BREAKPOINT_MD,
|
hide: window.innerWidth < BREAKPOINT_MD,
|
||||||
valueFormatter: ({ value }: { value?: string }) =>
|
valueFormatter: ({ value }: { value?: string }) =>
|
||||||
value ? assetStatusMapping[value].value : '',
|
value ? AssetStatusMapping[value].value : '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colId: 'actions',
|
colId: 'actions',
|
||||||
@@ -75,7 +69,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
|
||||||
value ? (
|
value ? (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
onClick={() => {
|
onClick={(e) => {
|
||||||
navigate(value);
|
navigate(value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -86,7 +80,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[navigate, assetStatusMapping, assetTypeMapping]
|
[navigate]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { Routes } from '../../routes/route-names';
|
|||||||
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
||||||
import type { Navigable } from '../../routes/router-config';
|
import type { Navigable } from '../../routes/router-config';
|
||||||
import { isNavigable } from '../../routes/router-config';
|
import { isNavigable } from '../../routes/router-config';
|
||||||
import { useRouterConfig } from '../../routes/router-config';
|
import { routerConfig } from '../../routes/router-config';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import { Search } from '../search';
|
import { Search } from '../search';
|
||||||
@@ -26,7 +26,6 @@ const routeToNavigationItem = (r: Navigable) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const routerConfig = useRouterConfig();
|
|
||||||
const isHome = Boolean(useMatch(Routes.HOME));
|
const isHome = Boolean(useMatch(Routes.HOME));
|
||||||
const pages = routerConfig[0].children || [];
|
const pages = routerConfig[0].children || [];
|
||||||
const mainItems = compact(
|
const mainItems = compact(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export type HashProps = {
|
export type HashProps = {
|
||||||
text: string;
|
text: string;
|
||||||
truncate?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -8,16 +7,10 @@ export type HashProps = {
|
|||||||
* are broken when they need to wrap. This will remove the need
|
* are broken when they need to wrap. This will remove the need
|
||||||
* for a lot of the overflow scrolling that currently exists.
|
* for a lot of the overflow scrolling that currently exists.
|
||||||
*/
|
*/
|
||||||
const Hash = ({ text, truncate = false }: HashProps) => {
|
const Hash = ({ text }: HashProps) => {
|
||||||
const h = truncate ? text.slice(0, 6) : text;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<code
|
<code className="break-all font-mono" style={{ wordWrap: 'break-word' }}>
|
||||||
title={text}
|
{text}
|
||||||
className="break-all font-mono"
|
|
||||||
style={{ wordWrap: 'break-word' }}
|
|
||||||
>
|
|
||||||
{h}
|
|
||||||
</code>
|
</code>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ query ExplorerMarket($id: ID!) {
|
|||||||
id
|
id
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
positionDecimalPlaces
|
positionDecimalPlaces
|
||||||
state
|
|
||||||
tradableInstrument {
|
tradableInstrument {
|
||||||
instrument {
|
instrument {
|
||||||
name
|
name
|
||||||
@@ -14,14 +13,9 @@ query ExplorerMarket($id: ID!) {
|
|||||||
decimals
|
decimals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
... on Perpetual {
|
|
||||||
quoteName
|
|
||||||
settlementAsset {
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-8
@@ -8,7 +8,7 @@ export type ExplorerMarketQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Perpetual', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Spot' } } } } | null };
|
export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } } } } | null };
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerMarketDocument = gql`
|
export const ExplorerMarketDocument = gql`
|
||||||
@@ -17,7 +17,6 @@ export const ExplorerMarketDocument = gql`
|
|||||||
id
|
id
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
positionDecimalPlaces
|
positionDecimalPlaces
|
||||||
state
|
|
||||||
tradableInstrument {
|
tradableInstrument {
|
||||||
instrument {
|
instrument {
|
||||||
name
|
name
|
||||||
@@ -28,15 +27,10 @@ export const ExplorerMarketDocument = gql`
|
|||||||
decimals
|
decimals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
... on Perpetual {
|
|
||||||
quoteName
|
|
||||||
settlementAsset {
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -61,11 +61,7 @@ describe('Market link component', () => {
|
|||||||
instrument: {
|
instrument: {
|
||||||
name: 'test-label',
|
name: 'test-label',
|
||||||
product: {
|
product: {
|
||||||
__typename: 'Future',
|
|
||||||
quoteName: 'dai',
|
quoteName: 'dai',
|
||||||
settlementAsset: {
|
|
||||||
decimals: 8,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -91,6 +87,6 @@ describe('Market link component', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const res = render(renderComponent('123', [mock]));
|
const res = render(renderComponent('123', [mock]));
|
||||||
expect(await res.findByTitle('123')).toBeInTheDocument();
|
expect(await res.findByText('123')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ const MarketLink = ({
|
|||||||
}: MarketLinkProps) => {
|
}: MarketLinkProps) => {
|
||||||
const { data, error, loading } = useExplorerMarketQuery({
|
const { data, error, loading } = useExplorerMarketQuery({
|
||||||
variables: { id },
|
variables: { id },
|
||||||
fetchPolicy: 'cache-first',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let label = <span>{id}</span>;
|
let label = <span>{id}</span>;
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
import OracleLink, { getStatusString } from './oracle-link';
|
|
||||||
import { render, screen } from '@testing-library/react';
|
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
|
||||||
|
|
||||||
describe('getStatusString', () => {
|
|
||||||
it("returns 'Unknown' for undefined status", () => {
|
|
||||||
expect(getStatusString(undefined)).toBe('Unknown');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the correct string for a known status', () => {
|
|
||||||
expect(getStatusString('STATUS_ACTIVE')).toBe('Active');
|
|
||||||
expect(getStatusString('STATUS_DEACTIVATED')).toBe('Deactivated');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('OracleLink', () => {
|
|
||||||
it('renders the truncated Oracle ID', () => {
|
|
||||||
const id = '123456789';
|
|
||||||
render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<OracleLink id={id} />
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
const idElement = screen.getByText(id.slice(0, 6));
|
|
||||||
expect(idElement).toBeInTheDocument();
|
|
||||||
expect(idElement).toHaveAttribute('title', id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders the Oracle status', () => {
|
|
||||||
const id = '123';
|
|
||||||
const status = 'STATUS_ACTIVE';
|
|
||||||
render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<OracleLink id={id} status={status} data-testid="link" />
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(screen.getByTestId('link')).toHaveAttribute('data-status', 'Active');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders the Oracle data indicator', () => {
|
|
||||||
const id = '123';
|
|
||||||
const hasSeenOracleReports = true;
|
|
||||||
render(
|
|
||||||
<MockedProvider>
|
|
||||||
<MemoryRouter>
|
|
||||||
<OracleLink id={id} hasSeenOracleReports={hasSeenOracleReports} />
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(screen.getByTestId('oracle-data-indicator')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -3,93 +3,20 @@ import { Link } from 'react-router-dom';
|
|||||||
|
|
||||||
import type { ComponentProps } from 'react';
|
import type { ComponentProps } from 'react';
|
||||||
import Hash from '../hash';
|
import Hash from '../hash';
|
||||||
import { Tooltip, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import {
|
|
||||||
DataSourceSpecStatus,
|
|
||||||
DataSourceSpecStatusMapping,
|
|
||||||
} from '@vegaprotocol/types';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a human-readable string for the given status, or a meaningful
|
|
||||||
* default if the status is unrecognised
|
|
||||||
* @param status string status
|
|
||||||
*/
|
|
||||||
export function getStatusString(status: string | undefined): string {
|
|
||||||
if (status && status in DataSourceSpecStatus) {
|
|
||||||
return DataSourceSpecStatusMapping[status as DataSourceSpecStatus];
|
|
||||||
}
|
|
||||||
|
|
||||||
return t('Unknown');
|
|
||||||
}
|
|
||||||
|
|
||||||
export type OracleLinkProps = Partial<ComponentProps<typeof Link>> & {
|
export type OracleLinkProps = Partial<ComponentProps<typeof Link>> & {
|
||||||
// The Oracle ID
|
|
||||||
id: string;
|
id: string;
|
||||||
// If available, the oracle status
|
|
||||||
status?: string;
|
|
||||||
// If the oracle has corresponding data in the OracleDataConnection
|
|
||||||
hasSeenOracleReports?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const OracleLink = ({ id, ...props }: OracleLinkProps) => {
|
||||||
* Given an Oracle ID, renders a data-dense link to the Oracle page. Data density is achieved by:
|
|
||||||
* - Colour coding the link based on the Oracle's status
|
|
||||||
* - Showing a small indicator if the Oracle has matched data
|
|
||||||
* - Showing a tooltip with the Oracle's status and whether it has matched data
|
|
||||||
*
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const OracleLink = ({
|
|
||||||
id,
|
|
||||||
status,
|
|
||||||
hasSeenOracleReports = false,
|
|
||||||
...props
|
|
||||||
}: OracleLinkProps) => {
|
|
||||||
const bgColour =
|
|
||||||
status === 'STATUS_ACTIVE'
|
|
||||||
? 'bg-yellow-100 hover:bg-yellow-200 border-yellow-200 dark:bg-yellow-200 dark:border-yellow-200 dark:text-gray-900 dark:border-yellow-300'
|
|
||||||
: 'bg-gray-100 hover:bg-gray-200 border-gray-200';
|
|
||||||
const indicatorColour =
|
|
||||||
status === 'STATUS_ACTIVE'
|
|
||||||
? 'bg-yellow-300 hover:bg-yellow-500 dark:bg-yellow-500'
|
|
||||||
: 'bg-gray-300 hover:bg-gray-500';
|
|
||||||
|
|
||||||
const description = (
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<strong>{`Status: `}</strong>
|
|
||||||
{getStatusString(status)}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>{`Matched data: `}</strong>
|
|
||||||
{hasSeenOracleReports ? (
|
|
||||||
<VegaIcon name={VegaIconNames.TICK} />
|
|
||||||
) : (
|
|
||||||
<VegaIcon name={VegaIconNames.CROSS} />
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip description={description}>
|
<Link
|
||||||
<Link
|
className="underline font-mono"
|
||||||
className={`pl-2 pr-2 font-mono dark:text-black ${bgColour} rounded-sm border-solid border-2 relative`}
|
{...props}
|
||||||
{...props}
|
to={`/${Routes.ORACLES}/${id}`}
|
||||||
to={`/${Routes.ORACLES}/${id}`}
|
>
|
||||||
data-status={getStatusString(status)}
|
<Hash text={id} />
|
||||||
>
|
</Link>
|
||||||
<Hash text={id} truncate={true} />
|
|
||||||
{hasSeenOracleReports ? (
|
|
||||||
<strong
|
|
||||||
data-testid="oracle-data-indicator"
|
|
||||||
className={`absolute top-0 right-0 w-1 h-full font-thin ${indicatorColour}`}
|
|
||||||
title="Oracle has matched data"
|
|
||||||
></strong>
|
|
||||||
) : null}
|
|
||||||
</Link>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span className="whitespace-nowrap">
|
||||||
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
{useName && <Icon size={4} name="cube" className="mr-2" />}
|
||||||
<Link
|
<Link
|
||||||
className="underline font-mono"
|
className="underline font-mono"
|
||||||
|
|||||||
@@ -1,41 +1,37 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
LiquidityPriceRangeInfoPanel,
|
|
||||||
LiquiditySLAParametersInfoPanel,
|
|
||||||
MarginScalingFactorsPanel,
|
|
||||||
PriceMonitoringBoundsInfoPanel,
|
PriceMonitoringBoundsInfoPanel,
|
||||||
SuccessionLineInfoPanel,
|
SuccessionLineInfoPanel,
|
||||||
getDataSourceSpecForSettlementData,
|
|
||||||
getDataSourceSpecForTradingTermination,
|
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
LiquidityInfoPanel,
|
LiquidityInfoPanel,
|
||||||
LiquidityMonitoringParametersInfoPanel,
|
LiquidityMonitoringParametersInfoPanel,
|
||||||
InstrumentInfoPanel,
|
InstrumentInfoPanel,
|
||||||
KeyDetailsInfoPanel,
|
KeyDetailsInfoPanel,
|
||||||
|
LiquidityPriceRangeInfoPanel,
|
||||||
MetadataInfoPanel,
|
MetadataInfoPanel,
|
||||||
OracleInfoPanel,
|
OracleInfoPanel,
|
||||||
RiskFactorsInfoPanel,
|
RiskFactorsInfoPanel,
|
||||||
RiskModelInfoPanel,
|
RiskModelInfoPanel,
|
||||||
|
RiskParametersInfoPanel,
|
||||||
SettlementAssetInfoPanel,
|
SettlementAssetInfoPanel,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import { MarketInfoTable } from '@vegaprotocol/markets';
|
import { MarketInfoTable } from '@vegaprotocol/markets';
|
||||||
import type { DataSourceFragment } from '@vegaprotocol/markets';
|
import type { DataSourceDefinition } from '@vegaprotocol/types';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
|
||||||
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||||
if (!market) return null;
|
if (!market) return null;
|
||||||
const { product } = market.tradableInstrument.instrument;
|
|
||||||
const settlementDataSource = getDataSourceSpecForSettlementData(product);
|
|
||||||
const terminationDataSource = getDataSourceSpecForTradingTermination(product);
|
|
||||||
|
|
||||||
const getSigners = ({ data }: DataSourceFragment) => {
|
const settlementData = market.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
||||||
|
const terminationData = market.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
||||||
|
|
||||||
|
const getSigners = (data: DataSourceDefinition) => {
|
||||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||||
const signers =
|
const signers = data.sourceType.sourceType.signers || [];
|
||||||
('signers' in data.sourceType.sourceType &&
|
|
||||||
data.sourceType.sourceType.signers) ||
|
|
||||||
[];
|
|
||||||
|
|
||||||
return signers.map(({ signer }, i) => {
|
return signers.map(({ signer }, i) => {
|
||||||
return (
|
return (
|
||||||
@@ -47,13 +43,10 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const showTwoOracles =
|
const showTwoOracles = isEqual(
|
||||||
settlementDataSource &&
|
getSigners(settlementData),
|
||||||
terminationDataSource &&
|
getSigners(terminationData)
|
||||||
isEqual(
|
);
|
||||||
getSigners(settlementDataSource),
|
|
||||||
getSigners(terminationDataSource)
|
|
||||||
);
|
|
||||||
|
|
||||||
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
|
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
|
||||||
|
|
||||||
@@ -69,8 +62,8 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
<MetadataInfoPanel market={market} />
|
<MetadataInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Risk model')}</h2>
|
<h2 className={headerClassName}>{t('Risk model')}</h2>
|
||||||
<RiskModelInfoPanel market={market} />
|
<RiskModelInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Margin scaling factors')}</h2>
|
<h2 className={headerClassName}>{t('Risk parameters')}</h2>
|
||||||
<MarginScalingFactorsPanel market={market} />
|
<RiskParametersInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
<h2 className={headerClassName}>{t('Risk factors')}</h2>
|
||||||
<RiskFactorsInfoPanel market={market} />
|
<RiskFactorsInfoPanel market={market} />
|
||||||
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
|
||||||
@@ -96,12 +89,10 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
)}
|
)}
|
||||||
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
|
||||||
<LiquidityMonitoringParametersInfoPanel market={market} />
|
<LiquidityMonitoringParametersInfoPanel market={market} />
|
||||||
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
|
||||||
<LiquidityPriceRangeInfoPanel market={market} />
|
|
||||||
<h2 className={headerClassName}>{t('Liquidity SLA protocol')}</h2>
|
|
||||||
<LiquiditySLAParametersInfoPanel market={market} />
|
|
||||||
<h2 className={headerClassName}>{t('Liquidity')}</h2>
|
<h2 className={headerClassName}>{t('Liquidity')}</h2>
|
||||||
<LiquidityInfoPanel market={market} />
|
<LiquidityInfoPanel market={market} />
|
||||||
|
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
|
||||||
|
<LiquidityPriceRangeInfoPanel market={market} />
|
||||||
{showTwoOracles ? (
|
{showTwoOracles ? (
|
||||||
<>
|
<>
|
||||||
<h2 className={headerClassName}>{t('Settlement oracle')}</h2>
|
<h2 className={headerClassName}>{t('Settlement oracle')}</h2>
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { getAsset, type MarketFieldsFragment } from '@vegaprotocol/markets';
|
import type { MarketFieldsFragment } from '@vegaprotocol/markets';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { type AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { type ColDef } from 'ag-grid-community';
|
import type { ColDef } from 'ag-grid-community';
|
||||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import {
|
import type {
|
||||||
type VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
type VegaValueGetterParams,
|
VegaValueGetterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { useRef, useLayoutEffect } from 'react';
|
import { useRef, useLayoutEffect } from 'react';
|
||||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||||
import { MarketStateMapping } from '@vegaprotocol/types';
|
import { MarketStateMapping } from '@vegaprotocol/types';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import { type RowClickedEvent } from 'ag-grid-community';
|
import type { RowClickedEvent } from 'ag-grid-community';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
type MarketsTableProps = {
|
type MarketsTableProps = {
|
||||||
@@ -29,7 +29,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
const gridRef = useRef<AgGridReact>(null);
|
const gridRef = useRef<AgGridReact>(null);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
gridRef.current?.api.setColumnsVisible(
|
gridRef.current?.columnApi.setColumnsVisible(
|
||||||
['id', 'state', 'asset'],
|
['id', 'state', 'asset'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
@@ -73,7 +73,8 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
|||||||
MarketFieldsFragment,
|
MarketFieldsFragment,
|
||||||
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
||||||
>) => {
|
>) => {
|
||||||
const value = data && getAsset(data);
|
const value =
|
||||||
|
data?.tradableInstrument.instrument.product.settlementAsset;
|
||||||
return value ? (
|
return value ? (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { render, waitFor } from '@testing-library/react';
|
import { render, waitFor } from '@testing-library/react';
|
||||||
import { NestedDataList, sortNestedDataByChildren } from './nested-data-list';
|
import {
|
||||||
|
BORDER_COLOURS,
|
||||||
|
NestedDataList,
|
||||||
|
sortNestedDataByChildren,
|
||||||
|
} from './nested-data-list';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
const mockData = {
|
const mockData = {
|
||||||
@@ -57,6 +61,38 @@ describe('NestedDataList', () => {
|
|||||||
expect(parent[0].querySelector('li')).toHaveClass('pl-4 border-l-4 pt-2');
|
expect(parent[0].querySelector('li')).toHaveClass('pl-4 border-l-4 pt-2');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should repeat the border colours in the correct order', () => {
|
||||||
|
const colourMockData = {
|
||||||
|
t0: {
|
||||||
|
t1: {
|
||||||
|
t2: {
|
||||||
|
t3: {
|
||||||
|
t4: {
|
||||||
|
t5: {
|
||||||
|
t6: {
|
||||||
|
t7: {
|
||||||
|
t8: {
|
||||||
|
hello: 'world',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const tree = render(<NestedDataList data={colourMockData} />);
|
||||||
|
const { getByTestId } = tree;
|
||||||
|
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const item = getByTestId(`T${i}`);
|
||||||
|
const expected = BORDER_COLOURS.light[i % 5];
|
||||||
|
expect(item.style.borderColor.toUpperCase()).toBe(expected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should sort the data by values with children', () => {
|
it('should sort the data by values with children', () => {
|
||||||
const mockData = {
|
const mockData = {
|
||||||
nonce: '5980890939790185837',
|
nonce: '5980890939790185837',
|
||||||
|
|||||||
@@ -31,9 +31,6 @@ fragment ExplorerDeterministicOrderFields on Order {
|
|||||||
... on Future {
|
... on Future {
|
||||||
quoteName
|
quoteName
|
||||||
}
|
}
|
||||||
... on Perpetual {
|
|
||||||
quoteName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } };
|
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } };
|
||||||
|
|
||||||
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
||||||
orderId: Types.Scalars['ID'];
|
orderId: Types.Scalars['ID'];
|
||||||
@@ -11,7 +11,7 @@ export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } } };
|
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } } };
|
||||||
|
|
||||||
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
||||||
fragment ExplorerDeterministicOrderFields on Order {
|
fragment ExplorerDeterministicOrderFields on Order {
|
||||||
@@ -47,9 +47,6 @@ export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
|
|||||||
... on Future {
|
... on Future {
|
||||||
quoteName
|
quoteName
|
||||||
}
|
}
|
||||||
... on Perpetual {
|
|
||||||
quoteName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function renderAmendOrderDetails(
|
|||||||
mocks: MockedResponse[]
|
mocks: MockedResponse[]
|
||||||
) {
|
) {
|
||||||
return render(
|
return render(
|
||||||
<MockedProvider mocks={mocks}>
|
<MockedProvider mocks={mocks} addTypename={false}>
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<AmendOrderDetails version={version} id={id} amend={amend} />
|
<AmendOrderDetails version={version} id={id} amend={amend} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
@@ -44,18 +44,18 @@ function renderExistingAmend(
|
|||||||
orderByID: {
|
orderByID: {
|
||||||
__typename: 'Order',
|
__typename: 'Order',
|
||||||
id: '123',
|
id: '123',
|
||||||
type: Schema.OrderType.TYPE_LIMIT,
|
type: 'GTT',
|
||||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||||
version: version ? version.toString() : '',
|
version: version,
|
||||||
createdAt: '123',
|
createdAt: '123',
|
||||||
updatedAt: '456',
|
updatedAt: '456',
|
||||||
expiresAt: '789',
|
expiresAt: '789',
|
||||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||||
price: '200',
|
price: '200',
|
||||||
side: Schema.Side.SIDE_BUY,
|
side: 'BUY',
|
||||||
peggedOrder: null,
|
peggedOrder: null,
|
||||||
remaining: '99',
|
remaining: '99',
|
||||||
rejectionReason: Schema.OrderRejectionReason.ORDER_ERROR_NOT_FOUND,
|
rejectionReason: 'rejection',
|
||||||
reference: '123',
|
reference: '123',
|
||||||
size: '100',
|
size: '100',
|
||||||
party: {
|
party: {
|
||||||
@@ -65,9 +65,9 @@ function renderExistingAmend(
|
|||||||
market: {
|
market: {
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
id: '789',
|
id: '789',
|
||||||
state: Schema.MarketState.STATE_ACTIVE,
|
state: 'STATUS_ACTIVE',
|
||||||
positionDecimalPlaces: 2,
|
positionDecimalPlaces: 2,
|
||||||
decimalPlaces: 0,
|
decimalPlaces: '5',
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
@@ -94,18 +94,18 @@ function renderExistingAmend(
|
|||||||
orderByID: {
|
orderByID: {
|
||||||
__typename: 'Order',
|
__typename: 'Order',
|
||||||
id: '123',
|
id: '123',
|
||||||
type: Schema.OrderType.TYPE_LIMIT,
|
type: 'GTT',
|
||||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||||
version: '100',
|
version: 100,
|
||||||
createdAt: '123',
|
createdAt: '123',
|
||||||
updatedAt: '456',
|
updatedAt: '456',
|
||||||
expiresAt: '789',
|
expiresAt: '789',
|
||||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||||
peggedOrder: null,
|
peggedOrder: null,
|
||||||
price: '200',
|
price: '200',
|
||||||
side: Schema.Side.SIDE_BUY,
|
side: 'BUY',
|
||||||
remaining: '99',
|
remaining: '99',
|
||||||
rejectionReason: Schema.OrderRejectionReason.ORDER_ERROR_NOT_FOUND,
|
rejectionReason: 'rejection',
|
||||||
reference: '123',
|
reference: '123',
|
||||||
size: '200',
|
size: '200',
|
||||||
party: {
|
party: {
|
||||||
@@ -114,10 +114,10 @@ function renderExistingAmend(
|
|||||||
},
|
},
|
||||||
market: {
|
market: {
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
id: '8888',
|
id: 'amend-to-order-latest-version',
|
||||||
state: Schema.MarketState.STATE_ACTIVE,
|
state: 'STATUS_ACTIVE',
|
||||||
positionDecimalPlaces: 2,
|
positionDecimalPlaces: 2,
|
||||||
decimalPlaces: 0,
|
decimalPlaces: '5',
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
name: 'amend-to-order-latest-version-test',
|
name: 'amend-to-order-latest-version-test',
|
||||||
@@ -136,13 +136,13 @@ function renderExistingAmend(
|
|||||||
request: {
|
request: {
|
||||||
query: ExplorerMarketDocument,
|
query: ExplorerMarketDocument,
|
||||||
variables: {
|
variables: {
|
||||||
id: '8888',
|
id: '789',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
data: {
|
data: {
|
||||||
market: {
|
market: {
|
||||||
id: '8888',
|
id: '789',
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
positionDecimalPlaces: 2,
|
positionDecimalPlaces: 2,
|
||||||
state: 'irrelevant-test-data',
|
state: 'irrelevant-test-data',
|
||||||
@@ -150,11 +150,7 @@ function renderExistingAmend(
|
|||||||
instrument: {
|
instrument: {
|
||||||
name: 'test-label',
|
name: 'test-label',
|
||||||
product: {
|
product: {
|
||||||
__typename: 'Future',
|
|
||||||
quoteName: 'dai',
|
quoteName: 'dai',
|
||||||
settlementAsset: {
|
|
||||||
decimals: 8,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -219,10 +215,12 @@ describe('Amend order details', () => {
|
|||||||
|
|
||||||
it('Fetches latest version when version is not specified', async () => {
|
it('Fetches latest version when version is not specified', async () => {
|
||||||
const amend: Amend = {
|
const amend: Amend = {
|
||||||
price: '123',
|
price: '-7879',
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = renderExistingAmend('123', undefined, amend);
|
const res = renderExistingAmend('123', undefined, amend);
|
||||||
expect(await res.findByText('test-label')).toBeInTheDocument();
|
expect(
|
||||||
|
await res.findByText('amend-to-order-latest-version')
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-12 lg:mb-0">
|
<div className="mb-12 lg:mb-0">
|
||||||
<div className="relative block rounded-lg px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block rounded-lg px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="display-5 mb-4 text-3xl font-bold">
|
<h2 className="text-3xl font-bold mb-4 display-5">
|
||||||
{t('Order not found')}
|
{t('Order not found')}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mb-12 text-gray-500">
|
<p className="text-gray-500 mb-12">
|
||||||
{t('No order created from this transaction')}
|
{t('No order created from this transaction')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,24 +68,24 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-12 lg:mb-0">
|
<div className="mb-12 lg:mb-0">
|
||||||
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="display-5 mb-4 text-3xl font-bold">
|
<h2 className="text-3xl font-bold mb-4 display-5">
|
||||||
{t('Edits to ')}
|
{t('Edits to ')}
|
||||||
{sideText[o.side]}
|
{sideText[o.side]}
|
||||||
{t(' order')}
|
{t(' order')}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="mb-4 text-gray-500">
|
<p className="text-gray-500 mb-4">
|
||||||
In <MarketLink id={o.market.id} />, updated at{' '}
|
In <MarketLink id={o.market.id} />, updated at{' '}
|
||||||
<Time date={o.updatedAt} />.
|
<Time date={o.updatedAt} />.
|
||||||
</div>
|
</p>
|
||||||
|
|
||||||
<div className="grid gap-x-6 md:grid-cols-4">
|
<div className="grid md:grid-cols-4 gap-x-6">
|
||||||
{amend.sizeDelta && amend.sizeDelta !== '0' ? (
|
{amend.sizeDelta && amend.sizeDelta !== '0' ? (
|
||||||
<div className="mb-12 md:mb-0">
|
<div className="mb-12 md:mb-0">
|
||||||
<h2 className="text-dark mb-4 text-2xl font-bold">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('New size')}
|
{t('New size')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5
|
<h5
|
||||||
className={`mb-0 text-lg font-medium capitalize text-gray-500 ${getSideDeltaColour(
|
className={`text-lg font-medium text-gray-500 mb-0 capitalize ${getSideDeltaColour(
|
||||||
amend.sizeDelta
|
amend.sizeDelta
|
||||||
)}`}
|
)}`}
|
||||||
>
|
>
|
||||||
@@ -96,10 +96,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
|
|
||||||
{amend.price && amend.price !== '0' ? (
|
{amend.price && amend.price !== '0' ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-dark mb-4 text-2xl font-bold">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('New price')}
|
{t('New price')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="mb-0 text-lg font-medium text-gray-500">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
<PriceInMarket price={amend.price} marketId={o.market.id} />
|
<PriceInMarket price={amend.price} marketId={o.market.id} />
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
@@ -108,10 +108,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
{amend.peggedReference &&
|
{amend.peggedReference &&
|
||||||
amend.peggedReference !== 'PEGGED_REFERENCE_UNSPECIFIED' ? (
|
amend.peggedReference !== 'PEGGED_REFERENCE_UNSPECIFIED' ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-dark mb-4 text-2xl font-bold">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('New reference')}
|
{t('New reference')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="mb-0 text-lg font-medium text-gray-500">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
{peggedReference[amend.peggedReference]}
|
{peggedReference[amend.peggedReference]}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
@@ -119,10 +119,10 @@ const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
|
|||||||
|
|
||||||
{amend.peggedOffset ? (
|
{amend.peggedOffset ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
<h2 className="text-dark mb-4 text-2xl font-bold">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('New offset')}
|
{t('New offset')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="mb-0 text-lg font-medium text-gray-500">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
{amend.peggedOffset}
|
{amend.peggedOffset}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { Time } from '../time';
|
|||||||
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
|
||||||
import SizeInMarket from '../size-in-market/size-in-market';
|
import SizeInMarket from '../size-in-market/size-in-market';
|
||||||
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
|
||||||
import { OrderTypeMapping } from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
export interface DeterministicOrderDetailsProps {
|
export interface DeterministicOrderDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -60,7 +59,7 @@ const DeterministicOrderDetails = ({
|
|||||||
const o = data.orderByID;
|
const o = data.orderByID;
|
||||||
return (
|
return (
|
||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<div className="mb-0">
|
<div className="mb-12 lg:mb-0">
|
||||||
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
<div className="relative block px-3 py-6 md:px-6 lg:-mr-7">
|
||||||
<h2 className="text-3xl font-bold mb-4 display-5">
|
<h2 className="text-3xl font-bold mb-4 display-5">
|
||||||
<abbr title={tifFull[o.timeInForce]} className="bb-dotted mr-2">
|
<abbr title={tifFull[o.timeInForce]} className="bb-dotted mr-2">
|
||||||
@@ -70,7 +69,7 @@ const DeterministicOrderDetails = ({
|
|||||||
<span className="mx-5 text-base">@</span>
|
<span className="mx-5 text-base">@</span>
|
||||||
<PriceInMarket price={o.price} marketId={o.market.id} />
|
<PriceInMarket price={o.price} marketId={o.market.id} />
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-400 dark:text-gray-600">
|
<p className="text-gray-200">
|
||||||
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
|
||||||
</p>
|
</p>
|
||||||
{o.peggedOrder ? (
|
{o.peggedOrder ? (
|
||||||
@@ -84,14 +83,15 @@ const DeterministicOrderDetails = ({
|
|||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{o.reference ? (
|
{o.reference ? (
|
||||||
<p className="text-gray-500 mt-4">
|
<p className="text-gray-500 mt-4">
|
||||||
<span>{t('Reference')}</span>: {o.reference}
|
<span>{t('Reference')}</span>: {o.reference}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-x-6 mt-4">
|
<div className="grid md:grid-cols-4 gap-x-6 mt-4">
|
||||||
<div className="mb-6 md:mb-0">
|
<div className="mb-12 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('Status')}
|
{t('Status')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
|
||||||
@@ -99,33 +99,21 @@ const DeterministicOrderDetails = ({
|
|||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-6 md:mb-0">
|
<div className="mb-12 md:mb-0">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-4">{t('Size')}</h2>
|
||||||
{t('Size')}
|
|
||||||
</h2>
|
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
<SizeInMarket size={o.size} marketId={o.market.id} />
|
<SizeInMarket size={o.size} marketId={o.market.id} />
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-6 md:mb-0">
|
<div className="">
|
||||||
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
<h2 className="text-2xl font-bold text-dark mb-4">
|
||||||
{t('Version')}
|
{t('Version')}
|
||||||
</h2>
|
</h2>
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
||||||
{o.version}
|
{o.version}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
{o.type ? (
|
|
||||||
<div className="mb-6 md:mb-0">
|
|
||||||
<h2 className="text-2xl font-bold text-dark mb-0 md:mb-4">
|
|
||||||
{t('Type')}
|
|
||||||
</h2>
|
|
||||||
<h5 className="text-lg font-medium text-gray-500 mb-0">
|
|
||||||
{OrderTypeMapping[o.type]}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ const PriceInMarket = ({
|
|||||||
label = addDecimalsFormatNumber(price, data.market.decimalPlaces);
|
label = addDecimalsFormatNumber(price, data.market.decimalPlaces);
|
||||||
} else if (
|
} else if (
|
||||||
decimalSource === 'SETTLEMENT_ASSET' &&
|
decimalSource === 'SETTLEMENT_ASSET' &&
|
||||||
data.market &&
|
|
||||||
'settlementAsset' in data.market.tradableInstrument.instrument.product &&
|
|
||||||
data.market?.tradableInstrument.instrument.product.settlementAsset
|
data.market?.tradableInstrument.instrument.product.settlementAsset
|
||||||
) {
|
) {
|
||||||
label = addDecimalsFormatNumber(
|
label = addDecimalsFormatNumber(
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { type ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
||||||
import { VoteProgress } from '@vegaprotocol/proposals';
|
import { VoteProgress } from '@vegaprotocol/proposals';
|
||||||
import { type AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import {
|
import type {
|
||||||
type VegaICellRendererParams,
|
VegaICellRendererParams,
|
||||||
type VegaValueFormatterParams,
|
VegaValueFormatterParams,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { type ColDef } from 'ag-grid-community';
|
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
|
||||||
import type { RowClickedEvent } from 'ag-grid-community';
|
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import {
|
import {
|
||||||
@@ -34,7 +33,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
const { params } = useNetworkParams([
|
const { params } = useNetworkParams([
|
||||||
NetworkParams.governance_proposal_market_requiredMajority,
|
NetworkParams.governance_proposal_market_requiredMajority,
|
||||||
]);
|
]);
|
||||||
const tokenLink = useLinks(DApp.Governance);
|
const tokenLink = useLinks(DApp.Token);
|
||||||
const requiredMajorityPercentage = useMemo(() => {
|
const requiredMajorityPercentage = useMemo(() => {
|
||||||
const requiredMajority =
|
const requiredMajority =
|
||||||
params?.governance_proposal_market_requiredMajority ?? 1;
|
params?.governance_proposal_market_requiredMajority ?? 1;
|
||||||
@@ -44,11 +43,11 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
const gridRef = useRef<AgGridReact>(null);
|
const gridRef = useRef<AgGridReact>(null);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const showColumnsOnDesktop = () => {
|
const showColumnsOnDesktop = () => {
|
||||||
gridRef.current?.api.setColumnsVisible(
|
gridRef.current?.columnApi.setColumnsVisible(
|
||||||
['voting', 'cDate', 'eDate', 'type'],
|
['voting', 'cDate', 'eDate', 'type'],
|
||||||
window.innerWidth > BREAKPOINT_MD
|
window.innerWidth > BREAKPOINT_MD
|
||||||
);
|
);
|
||||||
gridRef.current?.api.setColumnWidth(
|
gridRef.current?.columnApi.setColumnWidth(
|
||||||
'actions',
|
'actions',
|
||||||
window.innerWidth > BREAKPOINT_MD ? 221 : 80
|
window.innerWidth > BREAKPOINT_MD ? 221 : 80
|
||||||
);
|
);
|
||||||
@@ -106,7 +105,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
|||||||
? new BigNumber(0)
|
? new BigNumber(0)
|
||||||
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full items-center justify-center pt-2 uppercase">
|
<div className="uppercase flex h-full items-center justify-center pt-2">
|
||||||
<VoteProgress
|
<VoteProgress
|
||||||
threshold={requiredMajorityPercentage}
|
threshold={requiredMajorityPercentage}
|
||||||
progress={yesPercentage}
|
progress={yesPercentage}
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
|
||||||
import {
|
|
||||||
CopyWithTooltip,
|
|
||||||
VegaIcon,
|
|
||||||
VegaIconNames,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
|
|
||||||
interface SignatureProps {
|
|
||||||
signature: BlockExplorerTransactionResult['signature'];
|
|
||||||
}
|
|
||||||
|
|
||||||
const valueClass =
|
|
||||||
'font-mono px-2.5 py-0.5 text-xs max-w-[200px] cursor-pointer';
|
|
||||||
const valueClassClosed = 'text-ellipsis overflow-hidden';
|
|
||||||
const valueClassOpen = 'break-words text-left';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Viewer component for a vega signature. Featuers copy and pasting, truncation
|
|
||||||
*
|
|
||||||
* @param signature
|
|
||||||
*/
|
|
||||||
export const Signature = ({ signature }: SignatureProps) => {
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
if (!signature || !signature.value || !signature.version || !signature.algo) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="inline-flex border rounded signature-component relative pr-[20px]">
|
|
||||||
<div
|
|
||||||
className="bg-gray-100 px-2.5 py-0.5 text-xs text-gray-500 select-none cursor-default"
|
|
||||||
title={`${signature.algo}`}
|
|
||||||
>
|
|
||||||
<span>v{signature.version}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
isOpen
|
|
||||||
? `${valueClass} ${valueClassOpen}`
|
|
||||||
: `${valueClass} ${valueClassClosed}`
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<CopyWithTooltip text={signature.value}>
|
|
||||||
<span title={signature.value}>{signature.value}</span>
|
|
||||||
</CopyWithTooltip>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={() => setIsOpen(!isOpen)}
|
|
||||||
className="absolute top-[-3px] right-0 pr-2"
|
|
||||||
title={t('Show full signature')}
|
|
||||||
>
|
|
||||||
<VegaIcon name={isOpen ? VegaIconNames.EYE_OFF : VegaIconNames.EYE} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -22,9 +22,5 @@ export const TimeAgo = ({ date, ...props }: TimeAgoProps) => {
|
|||||||
return <>{t('Date unknown')}</>;
|
return <>{t('Date unknown')}</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <span {...props}>{t(`${distanceToNow} ago`)}</span>;
|
||||||
<span {...props} title={date} className="underline decoration-dotted">
|
|
||||||
{t(`${distanceToNow} ago`)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import isUndefined from 'lodash/isUndefined';
|
|||||||
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
|
||||||
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
|
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
|
||||||
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
|
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
|
||||||
import { TxDetailsContractCall } from './tx-contract-call';
|
|
||||||
|
|
||||||
interface ChainEventProps {
|
interface ChainEventProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -39,7 +38,7 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { builtin, erc20, erc20Multisig, stakingEvent, contractCall } =
|
const { builtin, erc20, erc20Multisig, stakingEvent } =
|
||||||
txData.command.chainEvent;
|
txData.command.chainEvent;
|
||||||
|
|
||||||
// Builtin Asset events
|
// Builtin Asset events
|
||||||
@@ -141,10 +140,6 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contractCall) {
|
|
||||||
return <TxDetailsContractCall contractCall={contractCall} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we hit this return, tx-shared-details should give a basic overview
|
// If we hit this return, tx-shared-details should give a basic overview
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { decodeEthCallResult } from './tx-contract-call';
|
|
||||||
import { base64 } from 'ethers/lib/utils';
|
|
||||||
import { defaultAbiCoder } from '@ethersproject/abi';
|
|
||||||
import { BigNumber } from '@ethersproject/bignumber';
|
|
||||||
|
|
||||||
describe('decodeEthCallResult', () => {
|
|
||||||
it('should decode contractData correctly (mocked)', () => {
|
|
||||||
const mockContractData = base64.encode(
|
|
||||||
defaultAbiCoder.encode(['int256'], [BigNumber.from(123)])
|
|
||||||
);
|
|
||||||
const result = decodeEthCallResult(mockContractData);
|
|
||||||
expect(result).toBe('123');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should decode contractData correctly (known data)', () => {
|
|
||||||
const mockContractData = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADH8cueyY=';
|
|
||||||
const result = decodeEthCallResult(mockContractData);
|
|
||||||
expect(result).toBe('3435020581670');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return "-" when an error occurs', () => {
|
|
||||||
const mockContractData = 'invalid_data';
|
|
||||||
const result = decodeEthCallResult(mockContractData);
|
|
||||||
expect(result).toBe('-');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
import { TableCell, TableRow } from '../../../table';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import {
|
|
||||||
EthExplorerLink,
|
|
||||||
EthExplorerLinkTypes,
|
|
||||||
} from '../../../links/eth-explorer-link/eth-explorer-link';
|
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
|
|
||||||
import { BigNumber } from 'ethers';
|
|
||||||
import OracleLink from '../../../links/oracle-link/oracle-link';
|
|
||||||
import { useExplorerOracleSpecByIdQuery } from '../../../../routes/oracles/__generated__/Oracles';
|
|
||||||
import { OracleEthSource } from '../../../../routes/oracles/components/oracle-eth-source';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes the b64/ABIcoded result from an eth cal
|
|
||||||
* @param data
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function decodeEthCallResult(contractData: string): string {
|
|
||||||
try {
|
|
||||||
const rawResult = defaultAbiCoder.decode(
|
|
||||||
['int256'],
|
|
||||||
base64.decode(contractData)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Finally, convert the resulting BigNumber in to a string
|
|
||||||
const res = BigNumber.from(rawResult[0]).toString();
|
|
||||||
return res;
|
|
||||||
} catch (e) {
|
|
||||||
return '-';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TxDetailsContractCallProps {
|
|
||||||
contractCall: components['schemas']['vegaEthContractCallEvent'];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TxDetailsContractCall = ({
|
|
||||||
contractCall,
|
|
||||||
}: TxDetailsContractCallProps) => {
|
|
||||||
const { data } = useExplorerOracleSpecByIdQuery({
|
|
||||||
variables: {
|
|
||||||
id: contractCall.specId || '1',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!contractCall || !contractCall.result) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{contractCall.specId && (
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('Oracle')}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<OracleLink
|
|
||||||
id={contractCall.specId}
|
|
||||||
hasSeenOracleReports={true}
|
|
||||||
status={data?.oracleSpec?.dataSourceSpec.spec.status || '-'}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
{contractCall.blockHeight && (
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('ETH block')}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<EthExplorerLink
|
|
||||||
id={contractCall.blockHeight}
|
|
||||||
type={EthExplorerLinkTypes.block}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
{data?.oracleSpec?.dataSourceSpec && (
|
|
||||||
<OracleEthSource
|
|
||||||
sourceType={data.oracleSpec.dataSourceSpec.spec.data.sourceType}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('Result')}</TableCell>
|
|
||||||
<TableCell>{decodeEthCallResult(contractCall.result)}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
query ExplorerSettlementAssetForMarket($id: ID!) {
|
||||||
|
market(id: $id) {
|
||||||
|
id
|
||||||
|
decimalPlaces
|
||||||
|
}
|
||||||
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type ExplorerSettlementAssetForMarketQueryVariables = Types.Exact<{
|
||||||
|
id: Types.Scalars['ID'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ExplorerSettlementAssetForMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number } | null };
|
||||||
|
|
||||||
|
|
||||||
|
export const ExplorerSettlementAssetForMarketDocument = gql`
|
||||||
|
query ExplorerSettlementAssetForMarket($id: ID!) {
|
||||||
|
market(id: $id) {
|
||||||
|
id
|
||||||
|
decimalPlaces
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useExplorerSettlementAssetForMarketQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useExplorerSettlementAssetForMarketQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useExplorerSettlementAssetForMarketQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useExplorerSettlementAssetForMarketQuery({
|
||||||
|
* variables: {
|
||||||
|
* id: // value for 'id'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useExplorerSettlementAssetForMarketQuery(baseOptions: Apollo.QueryHookOptions<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>(ExplorerSettlementAssetForMarketDocument, options);
|
||||||
|
}
|
||||||
|
export function useExplorerSettlementAssetForMarketLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>(ExplorerSettlementAssetForMarketDocument, options);
|
||||||
|
}
|
||||||
|
export type ExplorerSettlementAssetForMarketQueryHookResult = ReturnType<typeof useExplorerSettlementAssetForMarketQuery>;
|
||||||
|
export type ExplorerSettlementAssetForMarketLazyQueryHookResult = ReturnType<typeof useExplorerSettlementAssetForMarketLazyQuery>;
|
||||||
|
export type ExplorerSettlementAssetForMarketQueryResult = Apollo.QueryResult<ExplorerSettlementAssetForMarketQuery, ExplorerSettlementAssetForMarketQueryVariables>;
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { Side } from '@vegaprotocol/types';
|
||||||
|
import type { LiquidityOrder } from '@vegaprotocol/types';
|
||||||
|
import { PeggedReference } from '@vegaprotocol/types';
|
||||||
|
import { LiquidityProvisionDetailsRow } from './liquidity-provision-details-row';
|
||||||
|
import type { VegaSide } from './liquidity-provision-details-row';
|
||||||
|
|
||||||
|
describe('LiquidityProvisionDetails component', () => {
|
||||||
|
function renderComponent(
|
||||||
|
order: LiquidityOrder,
|
||||||
|
side: VegaSide,
|
||||||
|
normaliseProportionsTo: number,
|
||||||
|
marketId: string
|
||||||
|
) {
|
||||||
|
return render(
|
||||||
|
<MockedProvider>
|
||||||
|
<table>
|
||||||
|
<tbody data-testid="container">
|
||||||
|
<LiquidityProvisionDetailsRow
|
||||||
|
order={order}
|
||||||
|
marketId={marketId}
|
||||||
|
normaliseProportionsTo={normaliseProportionsTo}
|
||||||
|
side={side}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('renders null for an order with no proportion', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
offset: '1',
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_BUY,
|
||||||
|
100,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
expect(res.getByTestId('container')).toBeEmptyDOMElement();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders null for a null order', () => {
|
||||||
|
const res = renderComponent(
|
||||||
|
null as unknown as LiquidityOrder,
|
||||||
|
Side.SIDE_BUY,
|
||||||
|
100,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
expect(res.getByTestId('container')).toBeEmptyDOMElement();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders a row when the order is as expected', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
offset: '1',
|
||||||
|
proportion: 20,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_BUY,
|
||||||
|
100,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
// Row test ids and keys are based on the side, reference and proportion
|
||||||
|
expect(res.getByTestId('SIDE_BUY-20-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('+1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Mid')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('20%')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('normalises offsets when normaliseToProportion is not 100', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
offset: '1',
|
||||||
|
proportion: 20,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_BEST_BID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_SELL,
|
||||||
|
50,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
// Row test ids and keys are based on the side, reference and proportion - and that proportion is scaled
|
||||||
|
expect(res.getByTestId('SIDE_SELL-40-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Best Bid')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('40%')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles a missing offset gracefully (should not happen)', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
proportion: 20,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_BEST_BID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_SELL,
|
||||||
|
50,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
// Row test ids and keys are based on the side, reference and proportion - and that proportion is scaled
|
||||||
|
expect(res.getByTestId('SIDE_SELL-40-')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('-')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles a missing reference gracefully (should not happen)', () => {
|
||||||
|
const mockOrder = {
|
||||||
|
offset: '1',
|
||||||
|
proportion: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(
|
||||||
|
mockOrder as LiquidityOrder,
|
||||||
|
Side.SIDE_SELL,
|
||||||
|
50,
|
||||||
|
'123'
|
||||||
|
);
|
||||||
|
// Row test ids and keys are based on the side, reference and proportion - and that proportion is scaled
|
||||||
|
expect(res.getByTestId('SIDE_SELL-40-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('40%')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('-')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import type { components } from '../../../../../../types/explorer';
|
||||||
|
import { TableRow } from '../../../../table';
|
||||||
|
import { LiquidityProvisionOffset } from './liquidity-provision-offset';
|
||||||
|
|
||||||
|
export type VegaPeggedReference = components['schemas']['vegaPeggedReference'];
|
||||||
|
export type VegaSide = components['schemas']['vegaSide'];
|
||||||
|
|
||||||
|
export type LiquidityProvisionOrder =
|
||||||
|
components['schemas']['vegaLiquidityOrder'];
|
||||||
|
|
||||||
|
export const LiquidityReferenceLabel: Record<VegaPeggedReference, string> = {
|
||||||
|
PEGGED_REFERENCE_BEST_ASK: t('Best Ask'),
|
||||||
|
PEGGED_REFERENCE_BEST_BID: t('Best Bid'),
|
||||||
|
PEGGED_REFERENCE_MID: t('Mid'),
|
||||||
|
PEGGED_REFERENCE_UNSPECIFIED: '-',
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LiquidityProvisionDetailsRowProps = {
|
||||||
|
order?: LiquidityProvisionOrder;
|
||||||
|
marketId?: string;
|
||||||
|
side: VegaSide;
|
||||||
|
// If this is
|
||||||
|
normaliseProportionsTo: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Note: offset is formatted by settlement asset on the market, assuming that is available
|
||||||
|
* Note: Due to the mix of references (MID vs BEST_X), it's not possible to correctly order
|
||||||
|
* the orders by their actual distance from a midpoint. This would require us knowing
|
||||||
|
* the best bid (now or at placement) and the mid. Getting the data for *now* would be
|
||||||
|
* misleading for LP submissions in the past. There is no API for getting <mid />
|
||||||
|
* at the time of a transaction.
|
||||||
|
*/
|
||||||
|
export function LiquidityProvisionDetailsRow({
|
||||||
|
normaliseProportionsTo,
|
||||||
|
order,
|
||||||
|
side,
|
||||||
|
marketId,
|
||||||
|
}: LiquidityProvisionDetailsRowProps) {
|
||||||
|
if (!order || !order.proportion) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const proportion =
|
||||||
|
normaliseProportionsTo === 100
|
||||||
|
? order.proportion
|
||||||
|
: Math.round((order.proportion / normaliseProportionsTo) * 100);
|
||||||
|
|
||||||
|
const key = `${side}-${proportion}-${order.offset ? order.offset : ''}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow modifier="bordered" key={key} data-testid={key}>
|
||||||
|
<td className="text-right px-2">
|
||||||
|
{order.offset && marketId ? (
|
||||||
|
<LiquidityProvisionOffset
|
||||||
|
offset={order.offset}
|
||||||
|
side={side}
|
||||||
|
marketId={marketId}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
'-'
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="text-center">
|
||||||
|
{order.reference ? LiquidityReferenceLabel[order.reference] : '-'}
|
||||||
|
</td>
|
||||||
|
<td className="text-center">{proportion}%</td>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { LiquidityProvisionMid } from './liquidity-provision-mid';
|
||||||
|
|
||||||
|
describe('LiquidityProvisionMid component', () => {
|
||||||
|
function renderComponent() {
|
||||||
|
return render(
|
||||||
|
<table>
|
||||||
|
<tbody data-testid="container">
|
||||||
|
<LiquidityProvisionMid />
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('renders a basic row that spans the whole table', () => {
|
||||||
|
const res = renderComponent();
|
||||||
|
const display = res.getByTestId('mid-display');
|
||||||
|
expect(res.getByTestId('mid')).toBeInTheDocument();
|
||||||
|
expect(display).toBeInTheDocument();
|
||||||
|
expect(display).toHaveAttribute('colspan', '3');
|
||||||
|
});
|
||||||
|
});
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
import { TableRow } from '../../../../table';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In a LiquidityProvision table, this row is the midpoint. Above our LP orders on the
|
||||||
|
* buy side, below are LP orders on the sell side. This component simply divides them.
|
||||||
|
*
|
||||||
|
* There is no API that can give us the mid price when the order was created, and even
|
||||||
|
* if there was it isn't clear that would be appropriate for this centre row. So instead
|
||||||
|
* it's a simple divider.
|
||||||
|
*/
|
||||||
|
export function LiquidityProvisionMid() {
|
||||||
|
return (
|
||||||
|
<TableRow modifier="bordered" data-testid="mid">
|
||||||
|
<td data-testid="mid-display" colSpan={3} className="bg-white"></td>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { ExplorerSettlementAssetForMarketDocument } from '../__generated__/Explorer-settlement-asset';
|
||||||
|
import type { ExplorerSettlementAssetForMarketQuery } from '../__generated__/Explorer-settlement-asset';
|
||||||
|
import type { VegaSide } from './liquidity-provision-details-row';
|
||||||
|
import {
|
||||||
|
getFormattedOffset,
|
||||||
|
LiquidityProvisionOffset,
|
||||||
|
} from './liquidity-provision-offset';
|
||||||
|
const decimalsMock: ExplorerSettlementAssetForMarketQuery = {
|
||||||
|
market: {
|
||||||
|
id: '123',
|
||||||
|
__typename: 'Market',
|
||||||
|
decimalPlaces: 5,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('LiquidityProvisionOffset component', () => {
|
||||||
|
function renderComponent(
|
||||||
|
offset: string,
|
||||||
|
side: VegaSide,
|
||||||
|
marketId: string,
|
||||||
|
mocks: MockedResponse[]
|
||||||
|
) {
|
||||||
|
return render(
|
||||||
|
<MockedProvider mocks={mocks}>
|
||||||
|
<LiquidityProvisionOffset
|
||||||
|
offset={offset}
|
||||||
|
side={side}
|
||||||
|
marketId={marketId}
|
||||||
|
/>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('renders a simple row before market data comes in', () => {
|
||||||
|
const res = renderComponent('1', 'SIDE_BUY', '123', []);
|
||||||
|
expect(res.getByText('+1')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('replaces unformatted with formatted if the market data comes in', () => {
|
||||||
|
const mock = {
|
||||||
|
request: {
|
||||||
|
query: ExplorerSettlementAssetForMarketDocument,
|
||||||
|
variables: {
|
||||||
|
id: '123',
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: decimalsMock,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const res = renderComponent('1', 'SIDE_BUY', '123', [mock]);
|
||||||
|
expect(res.getByText('+1')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getFormattedOffset returns the unformatted offset if there is not enough data', () => {
|
||||||
|
const res = getFormattedOffset('1', {});
|
||||||
|
expect(res).toEqual('1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getFormattedOffset decimal formats a number if it comes in with market data', () => {
|
||||||
|
const res = getFormattedOffset('1', decimalsMock);
|
||||||
|
expect(res).toEqual('0.00001');
|
||||||
|
});
|
||||||
|
});
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
import { useExplorerSettlementAssetForMarketQuery } from '../__generated__/Explorer-settlement-asset';
|
||||||
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
import type { ExplorerSettlementAssetForMarketQuery } from '../__generated__/Explorer-settlement-asset';
|
||||||
|
import type { VegaSide } from './liquidity-provision-details-row';
|
||||||
|
|
||||||
|
export type LiquidityProvisionOffsetProps = {
|
||||||
|
side: VegaSide;
|
||||||
|
offset: string;
|
||||||
|
marketId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correctly formats an LP's offset according to the market settlement decimal places.
|
||||||
|
* Initially this will appear unformatted, then when the query loads in the proper formatted
|
||||||
|
* value will be displayed
|
||||||
|
*
|
||||||
|
* @see getFormattedOffset
|
||||||
|
*/
|
||||||
|
export function LiquidityProvisionOffset({
|
||||||
|
side,
|
||||||
|
offset,
|
||||||
|
marketId,
|
||||||
|
}: LiquidityProvisionOffsetProps) {
|
||||||
|
const { data } = useExplorerSettlementAssetForMarketQuery({
|
||||||
|
variables: {
|
||||||
|
id: marketId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// getFormattedOffset handles missing results/loading states
|
||||||
|
const formattedOffset = getFormattedOffset(offset, data);
|
||||||
|
|
||||||
|
const label = side === 'SIDE_BUY' ? '+' : '-';
|
||||||
|
const className = side === 'SIDE_BUY' ? 'text-vega-green' : 'text-vega-pink';
|
||||||
|
return <span className={className}>{`${label}${formattedOffset}`}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the work of formatting the number now we have the market decimal places.
|
||||||
|
* If no market data is assigned (i.e. during loading, or if the market doesn't exist)
|
||||||
|
* this function will return the unformatted number
|
||||||
|
*
|
||||||
|
* @see LiquidityProvisionOffset
|
||||||
|
* @param data the result of a ExplorerSettlementAssetForMarketQuery
|
||||||
|
* @param offset the unformatted offset
|
||||||
|
* @returns string the offset of this lp order formatted with the settlement decimal places
|
||||||
|
*/
|
||||||
|
export function getFormattedOffset(
|
||||||
|
offset: string,
|
||||||
|
data?: ExplorerSettlementAssetForMarketQuery
|
||||||
|
) {
|
||||||
|
const decimals = data?.market?.decimalPlaces;
|
||||||
|
|
||||||
|
if (!decimals) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addDecimalsFormatNumber(offset, decimals);
|
||||||
|
}
|
||||||
+209
@@ -0,0 +1,209 @@
|
|||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import type { LiquidityOrder } from '@vegaprotocol/types';
|
||||||
|
import { PeggedReference } from '@vegaprotocol/types';
|
||||||
|
import type { LiquiditySubmission } from '../tx-liquidity-submission';
|
||||||
|
import {
|
||||||
|
LiquidityProvisionDetails,
|
||||||
|
sumProportions,
|
||||||
|
} from './liquidity-provision-details';
|
||||||
|
|
||||||
|
function mockProportion(proportion: number): LiquidityOrder {
|
||||||
|
return {
|
||||||
|
proportion,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
offset: '1',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
describe('sumProportions function', () => {
|
||||||
|
it('returns 0 if the side is undefined', () => {
|
||||||
|
const side: LiquidityOrder[] = undefined as unknown as LiquidityOrder[];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 0 if the side is empty', () => {
|
||||||
|
const side: LiquidityOrder[] = [];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sums 1 item correctly (under 100%)', () => {
|
||||||
|
const side: LiquidityOrder[] = [mockProportion(10)];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sums 2 item correctly (exactly 100%)', () => {
|
||||||
|
const side: LiquidityOrder[] = [mockProportion(50), mockProportion(50)];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sums 3 item correctly to over 100%', () => {
|
||||||
|
const side: LiquidityOrder[] = [
|
||||||
|
mockProportion(20),
|
||||||
|
mockProportion(40),
|
||||||
|
mockProportion(50),
|
||||||
|
];
|
||||||
|
const res = sumProportions(side);
|
||||||
|
|
||||||
|
expect(res).toEqual(110);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('LiquidityProvisionDetails component', () => {
|
||||||
|
function renderComponent(provision: LiquiditySubmission) {
|
||||||
|
return render(
|
||||||
|
<MockedProvider>
|
||||||
|
<LiquidityProvisionDetails provision={provision} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
it('handles an LP with no buys or sells by returning empty (should never happen)', () => {
|
||||||
|
const mock: LiquiditySubmission = {};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.container).toBeEmptyDOMElement();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles an LP with no sells by just rendering buys', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
buys: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('Price offset')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Price reference')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Proportion')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles an LP with no buys by just rendering sells', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
sells: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('Price offset')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Price reference')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Proportion')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_SELL-50-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_SELL-50-2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles an LP with sells by just rendering buys', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
buys: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('Price offset')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Price reference')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Proportion')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles an LP with both sides', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
buys: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sells: [
|
||||||
|
{
|
||||||
|
offset: '4',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 50,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('Price offset')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Price reference')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('Proportion')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-1')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_BUY-50-2')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_SELL-50-4')).toBeInTheDocument();
|
||||||
|
expect(res.getByTestId('SIDE_SELL-50-2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('normalises proportions when they do not total 100%', () => {
|
||||||
|
const mock: LiquiditySubmission = {
|
||||||
|
marketId: '123',
|
||||||
|
buys: [
|
||||||
|
{
|
||||||
|
offset: '1',
|
||||||
|
proportion: 25,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: '2',
|
||||||
|
proportion: 30,
|
||||||
|
reference: PeggedReference.PEGGED_REFERENCE_MID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = renderComponent(mock);
|
||||||
|
expect(res.getByText('45%')).toBeInTheDocument();
|
||||||
|
expect(res.getByText('55%')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
import type { components } from '../../../../../types/explorer';
|
||||||
|
import type { LiquiditySubmission } from '../tx-liquidity-submission';
|
||||||
|
import { TableRow } from '../../../table';
|
||||||
|
import { LiquidityProvisionMid } from './components/liquidity-provision-mid';
|
||||||
|
import { LiquidityProvisionDetailsRow } from './components/liquidity-provision-details-row';
|
||||||
|
import { Side } from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
export type VegaPeggedReference = components['schemas']['vegaPeggedReference'];
|
||||||
|
|
||||||
|
export type LiquidityProvisionOrder =
|
||||||
|
components['schemas']['vegaLiquidityOrder'];
|
||||||
|
|
||||||
|
export const LiquidityReferenceLabel: Record<VegaPeggedReference, string> = {
|
||||||
|
PEGGED_REFERENCE_BEST_ASK: t('Best Ask'),
|
||||||
|
PEGGED_REFERENCE_BEST_BID: t('Best Bid'),
|
||||||
|
PEGGED_REFERENCE_MID: t('Mid'),
|
||||||
|
PEGGED_REFERENCE_UNSPECIFIED: '-',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a side of a liquidity provision order, returns the total
|
||||||
|
* It should be 100%, but it isn't always and if it isn't the proportion
|
||||||
|
* reported for each order should be scaled
|
||||||
|
*
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
export function sumProportions(
|
||||||
|
side: LiquiditySubmission['buys'] | LiquiditySubmission['sells']
|
||||||
|
): number {
|
||||||
|
if (!side || side.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return side.reduce((total, o) => total + (o.proportion || 0), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LiquidityProvisionDetailsProps = {
|
||||||
|
provision: LiquiditySubmission;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a table displaying all buys and sells in this LP. It is valid for there
|
||||||
|
* to be no buys or sells.
|
||||||
|
*
|
||||||
|
* It might seem logical to turn proportions in to values based on the total commitment
|
||||||
|
* but based on the current API structure it is awkward, and given that non-LP orders
|
||||||
|
* will change the amount that is actually deployed vs assigned to a level, we decided
|
||||||
|
* not to bother going down that route.
|
||||||
|
*/
|
||||||
|
export function LiquidityProvisionDetails({
|
||||||
|
provision,
|
||||||
|
}: LiquidityProvisionDetailsProps) {
|
||||||
|
if (!provision.buys?.length && !provision.sells?.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// We need to do some additional calcs if these aren't both 100
|
||||||
|
const buyTotal = sumProportions(provision.buys);
|
||||||
|
const sellTotal = sumProportions(provision.sells);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<th className="px-2 pb-1">{t('Price offset')}</th>
|
||||||
|
<th className="px-2 pb-1">{t('Price reference')}</th>
|
||||||
|
<th className="px-2 pb-1">{t('Proportion')}</th>
|
||||||
|
</TableRow>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{provision.buys?.map((b, i) => (
|
||||||
|
<LiquidityProvisionDetailsRow
|
||||||
|
order={b}
|
||||||
|
marketId={provision.marketId}
|
||||||
|
side={Side.SIDE_BUY}
|
||||||
|
key={`SIDE_BUY-${i}`}
|
||||||
|
normaliseProportionsTo={buyTotal}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<LiquidityProvisionMid />
|
||||||
|
{provision.sells?.map((s, i) => (
|
||||||
|
<LiquidityProvisionDetailsRow
|
||||||
|
order={s}
|
||||||
|
marketId={provision.marketId}
|
||||||
|
side={Side.SIDE_SELL}
|
||||||
|
key={`SIDE_SELL-${i}`}
|
||||||
|
normaliseProportionsTo={sellTotal}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,20 +1,11 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import { TableCell, TableRow } from '../../../table';
|
import { TableCell, TableRow } from '../../../table';
|
||||||
|
import type { VegaPeggedReference } from '../liquidity-provision/liquidity-provision-details';
|
||||||
import { Side, PeggedReferenceMapping } from '@vegaprotocol/types';
|
import { Side, PeggedReferenceMapping } from '@vegaprotocol/types';
|
||||||
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
||||||
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
|
||||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
export type VegaPeggedReference = components['schemas']['vegaPeggedReference'];
|
|
||||||
|
|
||||||
export const LiquidityReferenceLabel: Record<VegaPeggedReference, string> = {
|
|
||||||
PEGGED_REFERENCE_BEST_ASK: t('Best Ask'),
|
|
||||||
PEGGED_REFERENCE_BEST_BID: t('Best Bid'),
|
|
||||||
PEGGED_REFERENCE_MID: t('Mid'),
|
|
||||||
PEGGED_REFERENCE_UNSPECIFIED: '-',
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface TxDetailsOrderProps {
|
export interface TxDetailsOrderProps {
|
||||||
offset: string;
|
offset: string;
|
||||||
reference: VegaPeggedReference;
|
reference: VegaPeggedReference;
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ export const BundleSigners = ({
|
|||||||
tx,
|
tx,
|
||||||
id,
|
id,
|
||||||
}: BundleSignersProps) => {
|
}: BundleSignersProps) => {
|
||||||
const tokenLink = useLinks(DApp.Governance);
|
const tokenLink = useLinks(DApp.Token);
|
||||||
|
|
||||||
const bridgeFunction: BridgeFunction =
|
const bridgeFunction: BridgeFunction =
|
||||||
tx?.changes?.erc20 && 'contractAddress' in tx.changes.erc20
|
tx?.changes?.erc20 && 'contractAddress' in tx.changes.erc20
|
||||||
|
|||||||
-54
@@ -1,54 +0,0 @@
|
|||||||
import * as Types from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client';
|
|
||||||
import * as Apollo from '@apollo/client';
|
|
||||||
const defaultOptions = {} as const;
|
|
||||||
export type ExplorerReferralCodeOwnerQueryVariables = Types.Exact<{
|
|
||||||
id: Types.Scalars['ID'];
|
|
||||||
}>;
|
|
||||||
|
|
||||||
|
|
||||||
export type ExplorerReferralCodeOwnerQuery = { __typename?: 'Query', referralSets: { __typename?: 'ReferralSetConnection', edges: Array<{ __typename?: 'ReferralSetEdge', node: { __typename?: 'ReferralSet', createdAt: any, updatedAt: any, referrer: string } } | null> } };
|
|
||||||
|
|
||||||
|
|
||||||
export const ExplorerReferralCodeOwnerDocument = gql`
|
|
||||||
query ExplorerReferralCodeOwner($id: ID!) {
|
|
||||||
referralSets(id: $id) {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
referrer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __useExplorerReferralCodeOwnerQuery__
|
|
||||||
*
|
|
||||||
* To run a query within a React component, call `useExplorerReferralCodeOwnerQuery` and pass it any options that fit your needs.
|
|
||||||
* When your component renders, `useExplorerReferralCodeOwnerQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
|
||||||
* you can use to render your UI.
|
|
||||||
*
|
|
||||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const { data, loading, error } = useExplorerReferralCodeOwnerQuery({
|
|
||||||
* variables: {
|
|
||||||
* id: // value for 'id'
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function useExplorerReferralCodeOwnerQuery(baseOptions: Apollo.QueryHookOptions<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>) {
|
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
|
||||||
return Apollo.useQuery<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>(ExplorerReferralCodeOwnerDocument, options);
|
|
||||||
}
|
|
||||||
export function useExplorerReferralCodeOwnerLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>) {
|
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
|
||||||
return Apollo.useLazyQuery<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>(ExplorerReferralCodeOwnerDocument, options);
|
|
||||||
}
|
|
||||||
export type ExplorerReferralCodeOwnerQueryHookResult = ReturnType<typeof useExplorerReferralCodeOwnerQuery>;
|
|
||||||
export type ExplorerReferralCodeOwnerLazyQueryHookResult = ReturnType<typeof useExplorerReferralCodeOwnerLazyQuery>;
|
|
||||||
export type ExplorerReferralCodeOwnerQueryResult = Apollo.QueryResult<ExplorerReferralCodeOwnerQuery, ExplorerReferralCodeOwnerQueryVariables>;
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
query ExplorerReferralCodeOwner($id: ID!) {
|
|
||||||
referralSets(id: $id) {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
referrer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
import { render, waitFor } from '@testing-library/react';
|
|
||||||
import type { MockedResponse } from '@apollo/client/testing';
|
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
|
||||||
import { ReferralCodeOwner } from './referral-code-owner';
|
|
||||||
import type { ReferralCodeOwnerProps } from './referral-code-owner';
|
|
||||||
import { ExplorerReferralCodeOwnerDocument } from './__generated__/code-owner';
|
|
||||||
const renderComponent = (
|
|
||||||
props: ReferralCodeOwnerProps,
|
|
||||||
mocks: MockedResponse[]
|
|
||||||
) => {
|
|
||||||
return render(
|
|
||||||
<MockedProvider mocks={mocks}>
|
|
||||||
<MemoryRouter>
|
|
||||||
<ReferralCodeOwner {...props} />
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('ReferralCodeOwner', () => {
|
|
||||||
it('should render loading state', () => {
|
|
||||||
const mocks = [
|
|
||||||
{
|
|
||||||
request: {
|
|
||||||
query: ExplorerReferralCodeOwnerDocument,
|
|
||||||
variables: {
|
|
||||||
id: 'ABC123',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
|
||||||
|
|
||||||
expect(getByText('Loading...')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render error state', async () => {
|
|
||||||
const errorMessage = 'Error fetching referrer: ABC123';
|
|
||||||
const mocks = [
|
|
||||||
{
|
|
||||||
request: {
|
|
||||||
query: ExplorerReferralCodeOwnerDocument,
|
|
||||||
variables: {
|
|
||||||
id: 'ABC123',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
error: new Error('nope'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(getByText(errorMessage)).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render link to referring party', async () => {
|
|
||||||
const referrerId = 'DEF789';
|
|
||||||
|
|
||||||
const mocks = [
|
|
||||||
{
|
|
||||||
request: {
|
|
||||||
query: ExplorerReferralCodeOwnerDocument,
|
|
||||||
variables: {
|
|
||||||
id: 'ABC123',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
data: {
|
|
||||||
referralSets: {
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
__typename: 'ReferralSet',
|
|
||||||
referrer: referrerId,
|
|
||||||
createdAt: '123',
|
|
||||||
updatedAt: '456',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const { getByText } = renderComponent({ code: 'ABC123' }, mocks);
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(getByText(referrerId)).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { TableCell } from '../../../table';
|
|
||||||
import { useExplorerReferralCodeOwnerQuery } from './__generated__/code-owner';
|
|
||||||
import { PartyLink } from '../../../links';
|
|
||||||
|
|
||||||
export interface ReferralCodeOwnerProps {
|
|
||||||
code: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the owner of a referral code
|
|
||||||
*/
|
|
||||||
export const ReferralCodeOwner = ({ code }: ReferralCodeOwnerProps) => {
|
|
||||||
const { data, error, loading } = useExplorerReferralCodeOwnerQuery({
|
|
||||||
variables: {
|
|
||||||
id: code,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const referrer = data?.referralSets.edges[0]?.node.referrer || '';
|
|
||||||
return (
|
|
||||||
<TableCell>
|
|
||||||
{loading && 'Loading...'}
|
|
||||||
{error && `Error fetching referrer: ${code}`}
|
|
||||||
{referrer.length > 0 && <PartyLink id={referrer} />}
|
|
||||||
</TableCell>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
import { render } from '@testing-library/react';
|
|
||||||
import { ReferralTeam } from './team';
|
|
||||||
import type { CreateReferralSet } from './team';
|
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
|
||||||
|
|
||||||
describe('ReferralTeam', () => {
|
|
||||||
const team = {
|
|
||||||
name: 'Test Team',
|
|
||||||
teamUrl: 'https://example.com/team',
|
|
||||||
avatarUrl: 'https://example.com/avatar',
|
|
||||||
closed: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockTx: CreateReferralSet = {
|
|
||||||
team,
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockId = '123456';
|
|
||||||
const mockCreator = 'JohnDoe';
|
|
||||||
|
|
||||||
it('should render the team name', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(getByText('Test Team')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render the team ID', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(getByText('Id')).toBeInTheDocument();
|
|
||||||
expect(getByText(mockId)).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render the creator', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(getByText('Creator')).toBeInTheDocument();
|
|
||||||
expect(getByText(mockCreator)).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render the team URL', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(getByText('Team URL')).toBeInTheDocument();
|
|
||||||
expect(getByText(team.teamUrl)).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render the avatar URL', () => {
|
|
||||||
const { getByText } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(getByText('Avatar')).toBeInTheDocument();
|
|
||||||
expect(getByText(team.avatarUrl)).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render the open status as a tick if closed is falsy', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<ReferralTeam tx={mockTx} id={mockId} creator={mockCreator} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(getByTestId('open-yes')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render the open status as a cross if it is truthy', () => {
|
|
||||||
const m = {
|
|
||||||
team: {
|
|
||||||
closed: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<MockedProvider>
|
|
||||||
<ReferralTeam tx={m} id={mockId} creator={mockCreator} />
|
|
||||||
</MockedProvider>
|
|
||||||
);
|
|
||||||
expect(getByTestId('open-no')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
import {
|
|
||||||
VegaIcon,
|
|
||||||
Icon,
|
|
||||||
KeyValueTable,
|
|
||||||
KeyValueTableRow,
|
|
||||||
VegaIconNames,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
|
||||||
import type { components } from '../../../../../types/explorer';
|
|
||||||
import Hash from '../../../links/hash';
|
|
||||||
import { t } from 'i18next';
|
|
||||||
import { PartyLink } from '../../../links';
|
|
||||||
|
|
||||||
export type CreateReferralSet = components['schemas']['v1CreateReferralSet'];
|
|
||||||
export type ReferralTeam = CreateReferralSet['team'];
|
|
||||||
|
|
||||||
export interface ReferralTeamProps {
|
|
||||||
tx: CreateReferralSet;
|
|
||||||
id: string;
|
|
||||||
creator: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the details for a team in a CreateReferralSet or UpdateReferralSet transaction.
|
|
||||||
*
|
|
||||||
* Intentionally does not render the avatar image or link to the team url.
|
|
||||||
*/
|
|
||||||
export const ReferralTeam = ({ tx, id, creator }: ReferralTeamProps) => {
|
|
||||||
if (!tx.team) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section>
|
|
||||||
<div className="inline-block mr-2 leading-none">
|
|
||||||
<VegaIcon name={VegaIconNames.TEAM} />
|
|
||||||
</div>
|
|
||||||
{tx.team.name && (
|
|
||||||
<h3 className="inline-block leading-loose">{tx.team.name}</h3>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="min-w-fit max-w-2xl block">
|
|
||||||
<KeyValueTable>
|
|
||||||
<KeyValueTableRow>
|
|
||||||
{t('Id')}
|
|
||||||
<Hash text={id} truncate={false} />
|
|
||||||
</KeyValueTableRow>
|
|
||||||
<KeyValueTableRow>
|
|
||||||
{t('Creator')}
|
|
||||||
<PartyLink id={creator} truncate={false} />
|
|
||||||
</KeyValueTableRow>
|
|
||||||
{tx.team.teamUrl && (
|
|
||||||
<KeyValueTableRow>
|
|
||||||
{t('Team URL')}
|
|
||||||
<Hash text={tx.team.teamUrl} truncate={false} />
|
|
||||||
</KeyValueTableRow>
|
|
||||||
)}
|
|
||||||
{tx.team.avatarUrl && (
|
|
||||||
<KeyValueTableRow>
|
|
||||||
{t('Avatar')}
|
|
||||||
<Hash text={tx.team.avatarUrl} truncate={false} />
|
|
||||||
</KeyValueTableRow>
|
|
||||||
)}
|
|
||||||
<KeyValueTableRow>
|
|
||||||
{t('Open')}
|
|
||||||
<span data-testid={!tx.team.closed ? 'open-yes' : 'open-no'}>
|
|
||||||
{!tx.team.closed ? <Icon name="tick" /> : <Icon name="cross" />}
|
|
||||||
</span>
|
|
||||||
</KeyValueTableRow>
|
|
||||||
</KeyValueTable>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -9,7 +9,6 @@ import { Time } from '../../../time';
|
|||||||
import { ChainResponseCode } from '../chain-response-code/chain-reponse.code';
|
import { ChainResponseCode } from '../chain-response-code/chain-reponse.code';
|
||||||
import { TxDataView } from '../../tx-data-view';
|
import { TxDataView } from '../../tx-data-view';
|
||||||
import Hash from '../../../links/hash';
|
import Hash from '../../../links/hash';
|
||||||
import { Signature } from '../../../signature/signature';
|
|
||||||
|
|
||||||
interface TxDetailsSharedProps {
|
interface TxDetailsSharedProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -27,8 +26,7 @@ export const sharedHeaderProps = {
|
|||||||
className: 'align-top',
|
className: 'align-top',
|
||||||
};
|
};
|
||||||
|
|
||||||
// The incoming type field is usually the right thing to show. Exceptions are listed here
|
const Labels: Record<BlockExplorerTransactionResult['type'], string> = {
|
||||||
const LabelOverrides: Record<BlockExplorerTransactionResult['type'], string> = {
|
|
||||||
'Stop Orders Submission': 'Stop Order',
|
'Stop Orders Submission': 'Stop Order',
|
||||||
'Stop Orders Cancellation': 'Cancel Stop Order',
|
'Stop Orders Cancellation': 'Cancel Stop Order',
|
||||||
};
|
};
|
||||||
@@ -51,7 +49,7 @@ export const TxDetailsShared = ({
|
|||||||
const time: string = blockData?.result.block.header.time || '';
|
const time: string = blockData?.result.block.header.time || '';
|
||||||
const height: string = blockData?.result.block.header.height || txData.block;
|
const height: string = blockData?.result.block.header.height || txData.block;
|
||||||
|
|
||||||
const type = LabelOverrides[txData.type] || txData.type;
|
const type = Labels[txData.type] || txData.type;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -77,12 +75,6 @@ export const TxDetailsShared = ({
|
|||||||
<BlockLink height={height} />
|
<BlockLink height={height} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell {...sharedHeaderProps}>{t('Signature')}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<Signature signature={txData.signature} />
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell {...sharedHeaderProps}>{t('Time')}</TableCell>
|
<TableCell {...sharedHeaderProps}>{t('Time')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
|||||||
@@ -33,14 +33,6 @@ const AccountType: Record<AccountTypes, string> = {
|
|||||||
ACCOUNT_TYPE_HOLDING: 'Holding',
|
ACCOUNT_TYPE_HOLDING: 'Holding',
|
||||||
ACCOUNT_TYPE_LIQUIDITY_FEES_BONUS_DISTRIBUTION: 'Bonus Distribution',
|
ACCOUNT_TYPE_LIQUIDITY_FEES_BONUS_DISTRIBUTION: 'Bonus Distribution',
|
||||||
ACCOUNT_TYPE_LP_LIQUIDITY_FEES: 'LP Liquidity Fees',
|
ACCOUNT_TYPE_LP_LIQUIDITY_FEES: 'LP Liquidity Fees',
|
||||||
ACCOUNT_TYPE_NETWORK_TREASURY: 'Network Treasury',
|
|
||||||
ACCOUNT_TYPE_VESTING_REWARDS: 'Vesting Rewards',
|
|
||||||
ACCOUNT_TYPE_VESTED_REWARDS: 'Vested Rewards',
|
|
||||||
ACCOUNT_TYPE_REWARD_AVERAGE_POSITION: 'Reward Average Position',
|
|
||||||
ACCOUNT_TYPE_REWARD_RELATIVE_RETURN: 'Reward Relative Return',
|
|
||||||
ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY: 'Reward Return Volatility',
|
|
||||||
ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING: 'Reward Validator Ranking',
|
|
||||||
ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD: 'Pending Fee Referral Reward',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TransferParticipantsProps {
|
interface TransferParticipantsProps {
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
|
||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
|
||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
|
||||||
import { ReferralCodeOwner } from './referrals/referral-code-owner';
|
|
||||||
|
|
||||||
interface TxDetailsApplyReferralCodeProps {
|
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
|
||||||
pubKey: string | undefined;
|
|
||||||
blockData: TendermintBlocksResponse | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
|
||||||
*/
|
|
||||||
export const TxDetailsApplyReferralCode = ({
|
|
||||||
txData,
|
|
||||||
pubKey,
|
|
||||||
blockData,
|
|
||||||
}: TxDetailsApplyReferralCodeProps) => {
|
|
||||||
if (!txData || !txData.command.applyReferralCode || !txData.signature) {
|
|
||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const referralCode = txData.command.applyReferralCode.id;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
|
||||||
<TxDetailsShared
|
|
||||||
txData={txData}
|
|
||||||
pubKey={pubKey}
|
|
||||||
blockData={blockData}
|
|
||||||
/>
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('Applied Code')}</TableCell>
|
|
||||||
<TableCell>{referralCode}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('Referrer')}</TableCell>
|
|
||||||
<ReferralCodeOwner code={referralCode} />
|
|
||||||
</TableRow>
|
|
||||||
</TableWithTbody>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
import { TableWithTbody } from '../../table';
|
import { TableWithTbody } from '../../table';
|
||||||
import { ChainEvent } from './chain-events';
|
|
||||||
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import { ChainEvent } from './chain-events';
|
||||||
|
|
||||||
interface TxDetailsChainEventProps {
|
interface TxDetailsChainEventProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
|
||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
|
||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
|
||||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
|
||||||
import { ReferralTeam } from './referrals/team';
|
|
||||||
|
|
||||||
interface TxDetailsCreateReferralProps {
|
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
|
||||||
pubKey: string | undefined;
|
|
||||||
blockData: TendermintBlocksResponse | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
|
||||||
*/
|
|
||||||
export const TxDetailsCreateReferralSet = ({
|
|
||||||
txData,
|
|
||||||
pubKey,
|
|
||||||
blockData,
|
|
||||||
}: TxDetailsCreateReferralProps) => {
|
|
||||||
if (!txData || !txData.command.createReferralSet || !txData.signature) {
|
|
||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = txSignatureToDeterministicId(txData.signature.value);
|
|
||||||
|
|
||||||
const isTeam = txData.command.createReferralSet.isTeam || false;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
|
||||||
<TxDetailsShared
|
|
||||||
txData={txData}
|
|
||||||
pubKey={pubKey}
|
|
||||||
blockData={blockData}
|
|
||||||
/>
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{isTeam ? t('Team ID') : t('Referral code')}</TableCell>
|
|
||||||
<TableCell>{id}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableWithTbody>
|
|
||||||
|
|
||||||
<ReferralTeam
|
|
||||||
tx={txData.command.createReferralSet}
|
|
||||||
id={id}
|
|
||||||
creator={txData.submitter}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -3,8 +3,8 @@ import { DATA_SOURCES } from '../../../config';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||||
import { TxDetailsOrder } from './tx-order';
|
import { TxDetailsOrder } from './tx-order';
|
||||||
import { type BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
import { type TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
import { TxDetailsHeartbeat } from './tx-hearbeat';
|
import { TxDetailsHeartbeat } from './tx-hearbeat';
|
||||||
import { TxDetailsGeneric } from './tx-generic';
|
import { TxDetailsGeneric } from './tx-generic';
|
||||||
import { TxDetailsBatch } from './tx-batch';
|
import { TxDetailsBatch } from './tx-batch';
|
||||||
@@ -16,6 +16,7 @@ import { TxDetailsOrderAmend } from './tx-order-amend';
|
|||||||
import { TxDetailsWithdrawSubmission } from './tx-withdraw-submission';
|
import { TxDetailsWithdrawSubmission } from './tx-withdraw-submission';
|
||||||
import { TxDetailsDelegate } from './tx-delegation';
|
import { TxDetailsDelegate } from './tx-delegation';
|
||||||
import { TxDetailsUndelegate } from './tx-undelegation';
|
import { TxDetailsUndelegate } from './tx-undelegation';
|
||||||
|
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
||||||
import { TxDetailsLiquidityAmendment } from './tx-liquidity-amend';
|
import { TxDetailsLiquidityAmendment } from './tx-liquidity-amend';
|
||||||
import { TxDetailsLiquidityCancellation } from './tx-liquidity-cancel';
|
import { TxDetailsLiquidityCancellation } from './tx-liquidity-cancel';
|
||||||
import { TxDetailsDataSubmission } from './tx-data-submission';
|
import { TxDetailsDataSubmission } from './tx-data-submission';
|
||||||
@@ -27,11 +28,6 @@ import { TxDetailsStateVariable } from './tx-state-variable-proposal';
|
|||||||
import { TxProposal } from './tx-proposal';
|
import { TxProposal } from './tx-proposal';
|
||||||
import { TxDetailsTransfer } from './tx-transfer';
|
import { TxDetailsTransfer } from './tx-transfer';
|
||||||
import { TxDetailsStopOrderSubmission } from './tx-stop-order-submission';
|
import { TxDetailsStopOrderSubmission } from './tx-stop-order-submission';
|
||||||
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
|
||||||
import { TxDetailsCreateReferralSet } from './tx-create-referral-set';
|
|
||||||
import { TxDetailsApplyReferralCode } from './tx-apply-referral-code';
|
|
||||||
import { TxDetailsUpdateReferralSet } from './tx-update-referral-set';
|
|
||||||
import { TxDetailsJoinTeam } from './tx-join-team';
|
|
||||||
|
|
||||||
interface TxDetailsWrapperProps {
|
interface TxDetailsWrapperProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
@@ -111,7 +107,7 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
|||||||
return TxDetailsWithdrawSubmission;
|
return TxDetailsWithdrawSubmission;
|
||||||
case 'Liquidity Provision Order':
|
case 'Liquidity Provision Order':
|
||||||
return TxDetailsLiquiditySubmission;
|
return TxDetailsLiquiditySubmission;
|
||||||
case 'Amend Liquidity Provision Order':
|
case 'Amend LiquidityProvision Order':
|
||||||
return TxDetailsLiquidityAmendment;
|
return TxDetailsLiquidityAmendment;
|
||||||
case 'Cancel LiquidityProvision Order':
|
case 'Cancel LiquidityProvision Order':
|
||||||
return TxDetailsLiquidityCancellation;
|
return TxDetailsLiquidityCancellation;
|
||||||
@@ -125,14 +121,6 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
|||||||
return TxDetailsStopOrderSubmission;
|
return TxDetailsStopOrderSubmission;
|
||||||
case 'Transfer Funds':
|
case 'Transfer Funds':
|
||||||
return TxDetailsTransfer;
|
return TxDetailsTransfer;
|
||||||
case 'Create Referral Set':
|
|
||||||
return TxDetailsCreateReferralSet;
|
|
||||||
case 'Update Referral Set':
|
|
||||||
return TxDetailsUpdateReferralSet;
|
|
||||||
case 'Apply Referral Code':
|
|
||||||
return TxDetailsApplyReferralCode;
|
|
||||||
case 'Join Team':
|
|
||||||
return TxDetailsJoinTeam;
|
|
||||||
default:
|
default:
|
||||||
return TxDetailsGeneric;
|
return TxDetailsGeneric;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
|
||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
|
||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
|
||||||
import { ReferralCodeOwner } from './referrals/referral-code-owner';
|
|
||||||
|
|
||||||
interface TxDetailsJoinTeamProps {
|
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
|
||||||
pubKey: string | undefined;
|
|
||||||
blockData: TendermintBlocksResponse | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The signature can be turned in to an id with txSignatureToDeterministicId but
|
|
||||||
*/
|
|
||||||
export const TxDetailsJoinTeam = ({
|
|
||||||
txData,
|
|
||||||
pubKey,
|
|
||||||
blockData,
|
|
||||||
}: TxDetailsJoinTeamProps) => {
|
|
||||||
if (!txData || !txData.command.joinTeam || !txData.signature) {
|
|
||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const team = txData.command.joinTeam.id;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
|
||||||
<TxDetailsShared
|
|
||||||
txData={txData}
|
|
||||||
pubKey={pubKey}
|
|
||||||
blockData={blockData}
|
|
||||||
/>
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('Team')}</TableCell>
|
|
||||||
<TableCell>{team}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{t('Referrer')}</TableCell>
|
|
||||||
<ReferralCodeOwner code={team} />
|
|
||||||
</TableRow>
|
|
||||||
</TableWithTbody>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -5,6 +5,7 @@ import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint
|
|||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
|
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
||||||
import PriceInMarket from '../../price-in-market/price-in-market';
|
import PriceInMarket from '../../price-in-market/price-in-market';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
@@ -39,32 +40,40 @@ export const TxDetailsLiquidityAmendment = ({
|
|||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
<>
|
||||||
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
<TableRow modifier="bordered">
|
<TxDetailsShared
|
||||||
<TableCell>{t('Market')}</TableCell>
|
txData={txData}
|
||||||
<TableCell>
|
pubKey={pubKey}
|
||||||
<MarketLink id={marketId} />
|
blockData={blockData}
|
||||||
</TableCell>
|
/>
|
||||||
</TableRow>
|
|
||||||
{amendment.commitmentAmount ? (
|
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Commitment amount')}</TableCell>
|
<TableCell>{t('Market')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<PriceInMarket
|
<MarketLink id={marketId} />
|
||||||
price={amendment.commitmentAmount}
|
|
||||||
marketId={marketId}
|
|
||||||
decimalSource="SETTLEMENT_ASSET"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : null}
|
{amendment.commitmentAmount ? (
|
||||||
{amendment.fee ? (
|
<TableRow modifier="bordered">
|
||||||
<TableRow modifier="bordered">
|
<TableCell>{t('Commitment amount')}</TableCell>
|
||||||
<TableCell>{t('Fee')}</TableCell>
|
<TableCell>
|
||||||
<TableCell>{fee}%</TableCell>
|
<PriceInMarket
|
||||||
</TableRow>
|
price={amendment.commitmentAmount}
|
||||||
) : null}
|
marketId={marketId}
|
||||||
</TableWithTbody>
|
decimalSource="SETTLEMENT_ASSET"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
|
{amendment.fee ? (
|
||||||
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Fee')}</TableCell>
|
||||||
|
<TableCell>{fee}%</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
|
</TableWithTbody>
|
||||||
|
|
||||||
|
<LiquidityProvisionDetails provision={amendment} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
|
||||||
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
describe('TxDetailsLiquiditySubmission', () => {
|
||||||
|
const mockTxData = {
|
||||||
|
hash: 'test',
|
||||||
|
command: {
|
||||||
|
liquidityProvisionSubmission: {
|
||||||
|
marketId: 'BTC-USD',
|
||||||
|
commitmentAmount: 100,
|
||||||
|
fee: '0.01',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockPubKey = '123';
|
||||||
|
const mockBlockData = {
|
||||||
|
result: {
|
||||||
|
block: {
|
||||||
|
header: {
|
||||||
|
height: '123',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should render the component with correct data', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<MemoryRouter>
|
||||||
|
<TxDetailsLiquiditySubmission
|
||||||
|
txData={mockTxData as BlockExplorerTransactionResult}
|
||||||
|
pubKey={mockPubKey}
|
||||||
|
blockData={mockBlockData as TendermintBlocksResponse}
|
||||||
|
/>
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(getByText('Market')).toBeInTheDocument();
|
||||||
|
expect(getByText('BTC-USD')).toBeInTheDocument();
|
||||||
|
expect(getByText('Commitment amount')).toBeInTheDocument();
|
||||||
|
expect(getByText('100')).toBeInTheDocument();
|
||||||
|
expect(getByText('Fee')).toBeInTheDocument();
|
||||||
|
expect(getByText('1%')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display awaiting message when tx data is undefined', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<MemoryRouter>
|
||||||
|
<TxDetailsLiquiditySubmission
|
||||||
|
txData={undefined}
|
||||||
|
pubKey={mockPubKey}
|
||||||
|
blockData={mockBlockData as TendermintBlocksResponse}
|
||||||
|
/>
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getByText('Awaiting Block Explorer transaction details')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display awaiting message when liquidityProvisionSubmission is undefined', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<MockedProvider>
|
||||||
|
<MemoryRouter>
|
||||||
|
<TxDetailsLiquiditySubmission
|
||||||
|
txData={{ command: {} } as BlockExplorerTransactionResult}
|
||||||
|
pubKey={mockPubKey}
|
||||||
|
blockData={mockBlockData as TendermintBlocksResponse}
|
||||||
|
/>
|
||||||
|
</MemoryRouter>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getByText('Awaiting Block Explorer transaction details')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,30 +1,31 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||||
import { MarketLink } from '../../links';
|
import { MarketLink } from '../../links/';
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||||
import type { components } from '../../../../types/explorer';
|
import type { components } from '../../../../types/explorer';
|
||||||
|
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
||||||
import PriceInMarket from '../../price-in-market/price-in-market';
|
import PriceInMarket from '../../price-in-market/price-in-market';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
export type LiquiditySubmission =
|
export type LiquiditySubmission =
|
||||||
components['schemas']['v1LiquidityProvisionSubmission'];
|
components['schemas']['v1LiquidityProvisionSubmission'];
|
||||||
|
|
||||||
interface TxDetailsLiquidityAmendmentProps {
|
interface TxDetailsLiquiditySubmissionProps {
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
txData: BlockExplorerTransactionResult | undefined;
|
||||||
pubKey: string | undefined;
|
pubKey: string | undefined;
|
||||||
blockData: TendermintBlocksResponse | undefined;
|
blockData: TendermintBlocksResponse | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An existing liquidity order is being created.
|
* Someone cancelled an order
|
||||||
*/
|
*/
|
||||||
export const TxDetailsLiquiditySubmission = ({
|
export const TxDetailsLiquiditySubmission = ({
|
||||||
txData,
|
txData,
|
||||||
pubKey,
|
pubKey,
|
||||||
blockData,
|
blockData,
|
||||||
}: TxDetailsLiquidityAmendmentProps) => {
|
}: TxDetailsLiquiditySubmissionProps) => {
|
||||||
if (!txData || !txData.command.liquidityProvisionSubmission) {
|
if (!txData || !txData.command.liquidityProvisionSubmission) {
|
||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||||
}
|
}
|
||||||
@@ -38,38 +39,40 @@ export const TxDetailsLiquiditySubmission = ({
|
|||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
<>
|
||||||
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
<TableRow modifier="bordered">
|
<TxDetailsShared
|
||||||
<TableCell>{t('Market')}</TableCell>
|
txData={txData}
|
||||||
<TableCell>
|
pubKey={pubKey}
|
||||||
<MarketLink id={marketId} />
|
blockData={blockData}
|
||||||
</TableCell>
|
/>
|
||||||
</TableRow>
|
|
||||||
{submission.commitmentAmount ? (
|
|
||||||
<TableRow modifier="bordered">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Commitment amount')}</TableCell>
|
<TableCell>{t('Market')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<PriceInMarket
|
<MarketLink id={marketId} />
|
||||||
price={submission.commitmentAmount}
|
|
||||||
marketId={marketId}
|
|
||||||
decimalSource="SETTLEMENT_ASSET"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : null}
|
{submission.commitmentAmount ? (
|
||||||
{submission.fee ? (
|
<TableRow modifier="bordered">
|
||||||
<TableRow modifier="bordered">
|
<TableCell>{t('Commitment amount')}</TableCell>
|
||||||
<TableCell>{t('Fee')}</TableCell>
|
<TableCell>
|
||||||
<TableCell>{fee}%</TableCell>
|
<PriceInMarket
|
||||||
</TableRow>
|
price={submission.commitmentAmount}
|
||||||
) : null}
|
marketId={marketId}
|
||||||
{submission.reference ? (
|
decimalSource="SETTLEMENT_ASSET"
|
||||||
<TableRow modifier="bordered">
|
/>
|
||||||
<TableCell>{t('Reference')}</TableCell>
|
</TableCell>
|
||||||
<TableCell>{submission.reference}</TableCell>
|
</TableRow>
|
||||||
</TableRow>
|
) : null}
|
||||||
) : null}
|
{submission.fee ? (
|
||||||
</TableWithTbody>
|
<TableRow modifier="bordered">
|
||||||
|
<TableCell>{t('Fee')}</TableCell>
|
||||||
|
<TableCell>{fee}%</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : null}
|
||||||
|
</TableWithTbody>
|
||||||
|
|
||||||
|
<LiquidityProvisionDetails provision={submission} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import {
|
|||||||
SPECIAL_CASE_NETWORK,
|
SPECIAL_CASE_NETWORK,
|
||||||
SPECIAL_CASE_NETWORK_ID,
|
SPECIAL_CASE_NETWORK_ID,
|
||||||
} from '../../links/party-link/party-link';
|
} from '../../links/party-link/party-link';
|
||||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
|
||||||
|
|
||||||
type Transfer = components['schemas']['commandsv1Transfer'];
|
type Transfer = components['schemas']['commandsv1Transfer'];
|
||||||
|
|
||||||
@@ -64,16 +63,10 @@ export const TxDetailsTransfer = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||||
<TableRow modifier="bordered" data-testid="type">
|
<TableRow modifier="bordered">
|
||||||
<TableCell {...sharedHeaderProps}>{t('Type')}</TableCell>
|
<TableCell {...sharedHeaderProps}>{t('Type')}</TableCell>
|
||||||
<TableCell>{getTypeLabelForTransfer(transfer)}</TableCell>
|
<TableCell>{getTypeLabelForTransfer(transfer)}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow modifier="bordered" data-testid="id">
|
|
||||||
<TableCell {...sharedHeaderProps}>{t('Transfer ID')}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
{txSignatureToDeterministicId(txData.signature.value)}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
<TxDetailsShared
|
<TxDetailsShared
|
||||||
txData={txData}
|
txData={txData}
|
||||||
pubKey={pubKey}
|
pubKey={pubKey}
|
||||||
@@ -81,7 +74,7 @@ export const TxDetailsTransfer = ({
|
|||||||
hideTypeRow={true}
|
hideTypeRow={true}
|
||||||
/>
|
/>
|
||||||
{from ? (
|
{from ? (
|
||||||
<TableRow modifier="bordered" data-testid="from">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('From')}</TableCell>
|
<TableCell>{t('From')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<PartyLink id={from} />
|
<PartyLink id={from} />
|
||||||
@@ -89,7 +82,7 @@ export const TxDetailsTransfer = ({
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
) : null}
|
) : null}
|
||||||
{transfer.to ? (
|
{transfer.to ? (
|
||||||
<TableRow modifier="bordered" data-testid="to">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('To')}</TableCell>
|
<TableCell>{t('To')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<PartyLink id={transfer.to} />
|
<PartyLink id={transfer.to} />
|
||||||
@@ -97,7 +90,7 @@ export const TxDetailsTransfer = ({
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
) : null}
|
) : null}
|
||||||
{transfer.asset && transfer.amount ? (
|
{transfer.asset && transfer.amount ? (
|
||||||
<TableRow modifier="bordered" data-testid="amount">
|
<TableRow modifier="bordered">
|
||||||
<TableCell>{t('Amount')}</TableCell>
|
<TableCell>{t('Amount')}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<SizeInAsset assetId={transfer.asset} size={transfer.amount} />
|
<SizeInAsset assetId={transfer.asset} size={transfer.amount} />
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
|
||||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
|
||||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
|
||||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
|
||||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
|
||||||
import { ReferralTeam } from './referrals/team';
|
|
||||||
|
|
||||||
interface TxDetailsUpdateReferralProps {
|
|
||||||
txData: BlockExplorerTransactionResult | undefined;
|
|
||||||
pubKey: string | undefined;
|
|
||||||
blockData: TendermintBlocksResponse | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A copy of create referral set, effectively.
|
|
||||||
* Updating a referral set without a team doesn't make sense,
|
|
||||||
* but is valid, so this component ignores sense.
|
|
||||||
*/
|
|
||||||
export const TxDetailsUpdateReferralSet = ({
|
|
||||||
txData,
|
|
||||||
pubKey,
|
|
||||||
blockData,
|
|
||||||
}: TxDetailsUpdateReferralProps) => {
|
|
||||||
if (!txData || !txData.command.updateReferralSet || !txData.signature) {
|
|
||||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = txSignatureToDeterministicId(txData.signature.value);
|
|
||||||
|
|
||||||
const isTeam = txData.command.updateReferralSet.isTeam || false;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
|
||||||
<TxDetailsShared
|
|
||||||
txData={txData}
|
|
||||||
pubKey={pubKey}
|
|
||||||
blockData={blockData}
|
|
||||||
/>
|
|
||||||
<TableRow modifier="bordered">
|
|
||||||
<TableCell>{isTeam ? t('Team ID') : t('Referral code')}</TableCell>
|
|
||||||
<TableCell>{id}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableWithTbody>
|
|
||||||
|
|
||||||
<ReferralTeam
|
|
||||||
tx={txData.command.updateReferralSet}
|
|
||||||
id={id}
|
|
||||||
creator={txData.submitter}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user