Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2df8dc555a | ||
|
|
c06c580fe3 |
@@ -5,12 +5,12 @@ on:
|
||||
branches:
|
||||
- release/*
|
||||
- develop
|
||||
- main
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- ready_for_review
|
||||
- reopened
|
||||
- edited
|
||||
- synchronize
|
||||
jobs:
|
||||
node-modules:
|
||||
@@ -42,6 +42,13 @@ jobs:
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: yarn install --pure-lockfile
|
||||
|
||||
lint-pr-title:
|
||||
needs: node-modules
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
name: Verify PR title
|
||||
uses: ./.github/workflows/lint-pr.yml
|
||||
secrets: inherit
|
||||
|
||||
lint-format:
|
||||
timeout-minutes: 20
|
||||
needs: node-modules
|
||||
@@ -168,42 +175,19 @@ jobs:
|
||||
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
|
||||
preview_tools: ${{ env.PREVIEW_TOOLS }}
|
||||
|
||||
# console-e2e:
|
||||
# needs: build-sources
|
||||
# name: '(CI) console python'
|
||||
# uses: ./.github/workflows/console-test-run.yml
|
||||
# secrets: inherit
|
||||
# if: ${{ contains(fromJSON(needs.build-sources.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
|
||||
# with:
|
||||
# github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
check-e2e-needed:
|
||||
runs-on: ubuntu-latest
|
||||
console-e2e:
|
||||
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' && ${{ contains(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 }}"
|
||||
name: '(CI) console python'
|
||||
uses: ./.github/workflows/console-test-run.yml
|
||||
secrets: inherit
|
||||
if: ${{ contains(fromJSON(needs.build-sources.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
|
||||
with:
|
||||
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
cypress:
|
||||
needs: [build-sources, check-e2e-needed]
|
||||
needs: build-sources
|
||||
name: '(CI) cypress'
|
||||
if: ${{ needs.check-e2e-needed.outputs.run-tests == 'true' }}
|
||||
# if: ${{ needs.build-sources.outputs.projects-e2e != '[]' }}
|
||||
uses: ./.github/workflows/cypress-run.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
|
||||
@@ -6,37 +6,23 @@ on:
|
||||
github-sha:
|
||||
required: true
|
||||
type: string
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
console-test-branch:
|
||||
type: choice
|
||||
description: 'main: v0.72.14, develop: v0.73.0-preview7'
|
||||
options:
|
||||
- main
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
name: run-tests
|
||||
runs-on: 8-cores
|
||||
runs-on: console-test
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
#----------------------------------------------
|
||||
# check-out frontend-monorepo
|
||||
#----------------------------------------------
|
||||
- name: Checkout frontend-monorepo
|
||||
- name: Checkout console test repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.github-sha || github.sha }}
|
||||
ref: ${{ inputs.github-sha }}
|
||||
#----------------------------------------------
|
||||
# cache node modules
|
||||
#----------------------------------------------
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: yarn
|
||||
|
||||
- name: Cache node modules
|
||||
id: cache
|
||||
uses: actions/cache@v3
|
||||
@@ -79,42 +65,32 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: vegaprotocol/console-test
|
||||
ref: ${{ inputs.console-test-branch }}
|
||||
path: './console-test'
|
||||
|
||||
- name: Load console test envs
|
||||
id: console-test-env
|
||||
uses: falti/dotenv-action@v1.0.4
|
||||
with:
|
||||
path: './console-test/.env.${{ inputs.console-test-branch }}'
|
||||
export-variables: true
|
||||
keys-case: upper
|
||||
log-variables: true
|
||||
|
||||
#----------------------------------------------
|
||||
# install dependencies if cache does not exist
|
||||
#----------------------------------------------
|
||||
- name: Install dependencies
|
||||
working-directory: ./console-test
|
||||
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
|
||||
run: poetry install --no-interaction --no-root
|
||||
#----------------------------------------------
|
||||
# install vega binaries
|
||||
#----------------------------------------------
|
||||
- name: Install vega binaries
|
||||
working-directory: ./console-test
|
||||
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
|
||||
run: poetry run python -m vega_sim.tools.load_binaries --force
|
||||
#----------------------------------------------
|
||||
# install playwright
|
||||
#----------------------------------------------
|
||||
- name: install playwright
|
||||
run: poetry run playwright install --with-deps chromium
|
||||
run: poetry run playwright install
|
||||
working-directory: ./console-test
|
||||
#----------------------------------------------
|
||||
# run tests
|
||||
#----------------------------------------------
|
||||
- name: Run tests
|
||||
working-directory: ./console-test
|
||||
run: poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
|
||||
run: poetry run pytest -v -s --numprocesses 2 --dist loadfile --durations=20
|
||||
- name: Check files
|
||||
run: |
|
||||
ls -al .
|
||||
@@ -129,13 +105,3 @@ jobs:
|
||||
name: playwright-trace
|
||||
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
|
||||
|
||||
@@ -13,35 +13,13 @@ on:
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
runner-choice:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
runner: ${{ steps.step.outputs.runner }}
|
||||
steps:
|
||||
- name: Check branch
|
||||
id: step
|
||||
run: |
|
||||
if [ '${{ github.base_ref }}' == 'main' ]; then
|
||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
||||
elif [[ '${{ github.base_ref }}' == 'develop' && '${{ github.ref_name }}' == 'main' ]]; then
|
||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
||||
elif [[ '${{ github.event_name }}' == 'push' && ${{ contains(github.ref_name, 'release/mainnet') }} ]]; then
|
||||
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "runner=self-hosted-runner" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Print runner
|
||||
run: echo ${{ steps.step.outputs.runner }}
|
||||
|
||||
e2e:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
project: ${{ fromJSON(inputs.projects) }}
|
||||
name: ${{ matrix.project }}
|
||||
needs: runner-choice
|
||||
runs-on: ${{ needs.runner-choice.outputs.runner }}
|
||||
runs-on: self-hosted-runner
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
# Checks if skip cache was requested
|
||||
@@ -85,7 +63,6 @@ jobs:
|
||||
- name: Run Vegacapsule network and Vega wallet
|
||||
id: setup-vega
|
||||
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
|
||||
timeout-minutes: 10
|
||||
|
||||
######
|
||||
## Run some tests
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
name: Verify PR title
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- reopened
|
||||
- synchronize
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lint_pr:
|
||||
@@ -16,16 +11,21 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version-file: '.nvmrc'
|
||||
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
|
||||
cache: yarn
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
rm package.json
|
||||
npm install --no-save @commitlint/cli @commitlint/config-conventional @commitlint/config-nx-scopes nx
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
|
||||
|
||||
- name: Check PR title
|
||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
||||
|
||||
@@ -30,18 +30,12 @@ jobs:
|
||||
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
|
||||
echo IS_S3_RELEASE=false >> $GITHUB_ENV
|
||||
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
|
||||
echo IS_MAIN_IMAGE=false >> $GITHUB_ENV
|
||||
|
||||
- name: Is dev image
|
||||
if: ${{ github.ref_name == 'develop' && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||
if: ${{ contains(github.ref, 'develop') && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||
run: |
|
||||
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is main image
|
||||
if: ${{ github.ref_name == 'main' && github.event_name == 'push' && matrix.app == 'trading' }}
|
||||
run: |
|
||||
echo IS_MAIN_IMAGE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is PR
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
@@ -63,7 +57,7 @@ jobs:
|
||||
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
- name: Is S3 Release
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' && github.ref_name != 'main'}}
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' }}
|
||||
run: |
|
||||
echo IS_S3_RELEASE=true >> $GITHUB_ENV
|
||||
|
||||
@@ -87,7 +81,7 @@ jobs:
|
||||
|
||||
- name: Log in to the Container registry (docker hub)
|
||||
uses: docker/login-action@v2
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -161,10 +155,10 @@ jobs:
|
||||
- name: Sanity check docker image
|
||||
run: |
|
||||
echo "Check ipfs-hash"
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash'
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash > ${{ matrix.app }}-ipfs-hash
|
||||
echo "List html directory"
|
||||
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /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)
|
||||
uses: docker/build-push-action@v3
|
||||
@@ -185,7 +179,7 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
continue-on-error: true
|
||||
id: dockerhub-push
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
|
||||
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
@@ -195,7 +189,7 @@ jobs:
|
||||
ENV_NAME=${{ env.ENV_NAME }}
|
||||
tags: |
|
||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || 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)
|
||||
uses: docker/build-push-action@v3
|
||||
@@ -222,7 +216,7 @@ jobs:
|
||||
ENV_NAME=${{ env.ENV_NAME }}
|
||||
tags: |
|
||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || 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
|
||||
- name: Publish dist to s3
|
||||
@@ -335,9 +329,7 @@ jobs:
|
||||
fi
|
||||
|
||||
# create commit
|
||||
if ! git diff --cached --exit-code; then
|
||||
commit_msg="Automated hash update from ${{ github.ref }}"
|
||||
git commit -m "$commit_msg"
|
||||
git push -u origin "main"
|
||||
fi
|
||||
commit_msg="Automated hash update from ${{ github.ref }}"
|
||||
git commit -m "$commit_msg"
|
||||
git push -u origin "main"
|
||||
)
|
||||
|
||||
@@ -113,20 +113,6 @@ In order to run a container on port 3000:
|
||||
docker run -p 3000:80 [TAG]
|
||||
```
|
||||
|
||||
On top of that there are two possible scenarios for running docker image - using nginx server (default) of ipfs daemon.
|
||||
|
||||
to run ipfs on port 3000:
|
||||
|
||||
```bash
|
||||
docker run -p 3000:80 [TAG] /run-ipfs.sh
|
||||
```
|
||||
|
||||
to run nginx on port 3000:
|
||||
|
||||
```bash
|
||||
docker run -p 3000:80 [TAG]
|
||||
```
|
||||
|
||||
## Build instructions
|
||||
|
||||
The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of Console either for the web, or ready for pinning on IPFS.
|
||||
@@ -164,7 +150,7 @@ 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:
|
||||
|
||||
```bash
|
||||
docker build -f docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
||||
docker build --dockerfile docker/node-outside-docker.Dockerfile . --tag=[TAG]
|
||||
```
|
||||
|
||||
### Verifying ipfs-hash of existing current application version
|
||||
|
||||
@@ -4,7 +4,7 @@ import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
|
||||
import { useRef, useLayoutEffect } from 'react';
|
||||
import { BREAKPOINT_MD } from '../../config/breakpoints';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import type {
|
||||
VegaICellRendererParams,
|
||||
VegaValueGetterParams,
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
|
||||
import { VoteProgress } from '@vegaprotocol/proposals';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import type {
|
||||
VegaICellRendererParams,
|
||||
VegaValueFormatterParams,
|
||||
@@ -33,7 +33,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
||||
const { params } = useNetworkParams([
|
||||
NetworkParams.governance_proposal_market_requiredMajority,
|
||||
]);
|
||||
const tokenLink = useLinks(DApp.Governance);
|
||||
const tokenLink = useLinks(DApp.Token);
|
||||
const requiredMajorityPercentage = useMemo(() => {
|
||||
const requiredMajority =
|
||||
params?.governance_proposal_market_requiredMajority ?? 1;
|
||||
@@ -105,7 +105,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
||||
? new BigNumber(0)
|
||||
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full pt-2 uppercase">
|
||||
<div className="uppercase flex h-full items-center justify-center pt-2">
|
||||
<VoteProgress
|
||||
threshold={requiredMajorityPercentage}
|
||||
progress={yesPercentage}
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ export const BundleSigners = ({
|
||||
tx,
|
||||
id,
|
||||
}: BundleSignersProps) => {
|
||||
const tokenLink = useLinks(DApp.Governance);
|
||||
const tokenLink = useLinks(DApp.Token);
|
||||
|
||||
const bridgeFunction: BridgeFunction =
|
||||
tx?.changes?.erc20 && 'contractAddress' in tx.changes.erc20
|
||||
|
||||
@@ -8,9 +8,7 @@ import { useScrollToLocation } from '../../../hooks/scroll-to-location';
|
||||
import filter from 'recursive-key-filter';
|
||||
|
||||
const Oracles = () => {
|
||||
const { data, loading, error } = useExplorerOracleSpecsQuery({
|
||||
errorPolicy: 'ignore',
|
||||
});
|
||||
const { data, loading, error } = useExplorerOracleSpecsQuery();
|
||||
|
||||
useDocumentTitle(['Oracles']);
|
||||
useScrollToLocation();
|
||||
|
||||
@@ -139,7 +139,7 @@ export const ValidatorsPage = () => {
|
||||
const [vegaDialog, setVegaDialog] = useState<boolean>(false);
|
||||
const [tmDialog, setTmDialog] = useState<boolean>(false);
|
||||
|
||||
const tokenLink = useLinks(DApp.Governance);
|
||||
const tokenLink = useLinks(DApp.Token);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -212,7 +212,7 @@ context(
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
cy.get(`[row-id="${0}"]`)
|
||||
.first()
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.should('have.text', '3,002.00')
|
||||
@@ -222,7 +222,7 @@ context(
|
||||
.and('be.visible');
|
||||
});
|
||||
cy.get(`[row-id="${1}"]`)
|
||||
.first()
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.scrollIntoView()
|
||||
|
||||
@@ -8,7 +8,6 @@ NX_FAIRGROUND=false
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","STAGNET1":"https://governance.stagnet1.vega.rocks","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ NX_VEGA_REST_URL=https://api.vega.community/api/v2/
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||
|
||||
@@ -15,7 +15,6 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
|
||||
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||
|
||||
@@ -6,11 +6,6 @@ import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
||||
import { ProposalDocument } from './__generated__/Proposal';
|
||||
|
||||
jest.mock('@vegaprotocol/data-provider', () => ({
|
||||
...jest.requireActual('@vegaprotocol/data-provider'),
|
||||
useDataProvider: jest.fn(() => ({ data: [], loading: false })),
|
||||
}));
|
||||
|
||||
jest.mock('../components/proposal', () => ({
|
||||
Proposal: () => <div data-testid="proposal" />,
|
||||
}));
|
||||
|
||||
+4
-10
@@ -1,4 +1,4 @@
|
||||
import { useMemo, useEffect, useState, useCallback, useRef } from 'react';
|
||||
import { useMemo, useEffect, useState, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AsyncRenderer, Pagination } from '@vegaprotocol/ui-toolkit';
|
||||
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
@@ -86,18 +86,12 @@ export const EpochIndividualRewards = ({
|
||||
[epochId, page, refetch, delegationsPagination, pubKey]
|
||||
);
|
||||
|
||||
const prevEpochIdRef = useRef<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (prevEpochIdRef.current === null) {
|
||||
prevEpochIdRef.current = epochId;
|
||||
} else if (epochId !== prevEpochIdRef.current) {
|
||||
// When the epoch changes, we want to refetch the data to update the current page
|
||||
// when the epoch changes, we want to refetch the data to update the current page
|
||||
if (data) {
|
||||
refetchData();
|
||||
}
|
||||
|
||||
prevEpochIdRef.current = epochId;
|
||||
}, [epochId, refetchData]);
|
||||
}, [epochId, data, refetchData]);
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
|
||||
+5
-5
@@ -3,7 +3,7 @@ import { forwardRef, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Button, Icon } from '@vegaprotocol/ui-toolkit';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||
import { BigNumber } from '../../../../lib/bignumber';
|
||||
import {
|
||||
@@ -85,17 +85,17 @@ const TopThirdCellRenderer = (
|
||||
}}
|
||||
className="grid grid-cols-[60px_1fr] w-full h-full py-4 px-0 text-sm text-white text-center overflow-scroll"
|
||||
>
|
||||
<div className="px-3 text-xs text-left">
|
||||
<div className="text-xs text-left px-3">
|
||||
{params?.data?.rankingDisplay}
|
||||
</div>
|
||||
<div className="px-3 whitespace-normal">
|
||||
<div className="whitespace-normal px-3">
|
||||
<div className="mb-4">
|
||||
<Button
|
||||
data-testid="show-all-validators"
|
||||
rightIcon={
|
||||
<Icon
|
||||
name="arrow-right"
|
||||
className="mr-2 align-text-top fill-current"
|
||||
className="fill-current mr-2 align-text-top"
|
||||
/>
|
||||
}
|
||||
className="inline-flex items-center"
|
||||
@@ -103,7 +103,7 @@ const TopThirdCellRenderer = (
|
||||
{t('Reveal top validators')}
|
||||
</Button>
|
||||
</div>
|
||||
<p className="mb-0 font-semibold text-white">
|
||||
<p className="font-semibold text-white mb-0">
|
||||
{t(
|
||||
'Validators with too great a stake share will have the staking rewards for their delegators penalised.'
|
||||
)}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { forwardRef, useMemo, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||
import { BigNumber } from '../../../../lib/bignumber';
|
||||
import {
|
||||
|
||||
@@ -104,7 +104,7 @@ describe('deposit actions', { tags: '@smoke' }, () => {
|
||||
cy.visit('/#/markets/market-1');
|
||||
});
|
||||
|
||||
it.skip('Deposit to trade is visible', () => {
|
||||
it('Deposit to trade is visible', () => {
|
||||
cy.getByTestId('Collateral').click();
|
||||
cy.get('[row-id="asset-id"]').contains('tEURO').should('be.visible');
|
||||
cy.contains('[data-testid="deposit"]', 'Deposit').should('be.visible');
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
import { MarketTradingModeMapping } from '@vegaprotocol/types';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import compact from 'lodash/compact';
|
||||
|
||||
const accordionContent = 'accordion-content';
|
||||
const blockExplorerLink = 'block-explorer-link';
|
||||
const dialogClose = 'dialog-close';
|
||||
const dialogContent = 'dialog-content';
|
||||
const externalLink = 'external-link';
|
||||
const githubLink = 'github-link';
|
||||
const liquidityLink = 'view-liquidity-link';
|
||||
const marketInfoBtn = 'Info';
|
||||
const marketTitle = 'accordion-title';
|
||||
const providerName = 'provider-name';
|
||||
const row = 'key-value-table-row';
|
||||
const verifiedProofs = 'verified-proofs';
|
||||
|
||||
describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
});
|
||||
|
||||
before(() => {
|
||||
cy.setOnBoardingViewed();
|
||||
cy.mockTradingPage(MarketState.STATE_ACTIVE);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(marketInfoBtn).click();
|
||||
cy.wait('@MarketInfo');
|
||||
});
|
||||
|
||||
it('current fees displayed', () => {
|
||||
// 6002-MDET-101
|
||||
cy.getByTestId(marketTitle).contains('Current fees').click();
|
||||
validateMarketDataRow(0, 'Maker Fee', '0.02%');
|
||||
validateMarketDataRow(1, 'Infrastructure Fee', '0.05%');
|
||||
validateMarketDataRow(2, 'Liquidity Fee', '1.00%');
|
||||
validateMarketDataRow(3, 'Total Fees', '1.07%');
|
||||
});
|
||||
|
||||
it('market price', () => {
|
||||
// 6002-MDET-102
|
||||
cy.getByTestId(marketTitle).contains('Market price').click();
|
||||
validateMarketDataRow(0, 'Mark Price', '46,126.90058');
|
||||
validateMarketDataRow(1, 'Best Bid Price', '44,126.90058 ');
|
||||
validateMarketDataRow(2, 'Best Offer Price', '48,126.90058 ');
|
||||
validateMarketDataRow(3, 'Quote Unit', 'BTC');
|
||||
});
|
||||
|
||||
it('market volume displayed', () => {
|
||||
// 6002-MDET-103
|
||||
cy.getByTestId(marketTitle).contains('Market volume').click();
|
||||
validateMarketDataRow(1, 'Open Interest', '-');
|
||||
validateMarketDataRow(2, 'Best Bid Volume', '1');
|
||||
validateMarketDataRow(3, 'Best Offer Volume', '3');
|
||||
validateMarketDataRow(4, 'Best Static Bid Volume', '2');
|
||||
validateMarketDataRow(5, 'Best Static Offer Volume', '4');
|
||||
});
|
||||
|
||||
it('insurance pool displayed', () => {
|
||||
// 6002-MDET-104
|
||||
cy.getByTestId(marketTitle).contains('Insurance pool').click();
|
||||
validateMarketDataRow(0, 'Balance', '0');
|
||||
});
|
||||
|
||||
it('key details displayed', () => {
|
||||
// 6002-MDET-201
|
||||
cy.getByTestId(marketTitle).contains('Key details').click();
|
||||
|
||||
const rows: [string, string][] = compact([
|
||||
['Name', 'BTCUSD Monthly (30 Jun 2022)'],
|
||||
['Market ID', 'market-0'],
|
||||
Cypress.env('NX_SUCCESSOR_MARKETS') && ['Parent Market ID', 'PARENT-A'],
|
||||
Cypress.env('NX_SUCCESSOR_MARKETS') && [
|
||||
'Insurance Pool Fraction',
|
||||
'0.75',
|
||||
],
|
||||
['Trading Mode', MarketTradingModeMapping.TRADING_MODE_CONTINUOUS],
|
||||
['Market Decimal Places', '5'],
|
||||
['Position Decimal Places', '0'],
|
||||
['Settlement Asset Decimal Places', '5'],
|
||||
]);
|
||||
|
||||
for (const rowNumber in rows) {
|
||||
const [name, value] = rows[rowNumber];
|
||||
validateMarketDataRow(Number(rowNumber), name, value);
|
||||
}
|
||||
});
|
||||
|
||||
it('instrument displayed', () => {
|
||||
// 6002-MDET-202
|
||||
cy.getByTestId(marketTitle).contains('Instrument').click();
|
||||
|
||||
validateMarketDataRow(0, 'Market Name', 'BTCUSD Monthly (30 Jun 2022)');
|
||||
validateMarketDataRow(1, 'Code', 'BTCUSD.MF21');
|
||||
validateMarketDataRow(2, 'Product Type', 'Future');
|
||||
validateMarketDataRow(3, 'Quote Name', 'BTC');
|
||||
});
|
||||
|
||||
it('oracle displayed', () => {
|
||||
// 6002-MDET-203
|
||||
cy.getByTestId(marketTitle).contains('Oracle').click();
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId(providerName)
|
||||
.and('contain', 'Another oracle');
|
||||
|
||||
cy.getByTestId(providerName).should('be.visible').click();
|
||||
cy.getByTestId(dialogContent)
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.getByTestId(blockExplorerLink).contains('Block explorer');
|
||||
cy.getByTestId(githubLink).contains('Oracle repository');
|
||||
});
|
||||
cy.getByTestId(dialogClose).click();
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId(verifiedProofs)
|
||||
.and('contain', '1');
|
||||
});
|
||||
|
||||
it('settlement asset displayed', () => {
|
||||
// 6002-MDET-206
|
||||
cy.getByTestId(marketTitle).contains('Settlement asset').click();
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, 'prompt').returns('DISABLED WINDOW PROMPT');
|
||||
});
|
||||
validateMarketDataRow(0, 'ID', 'asset-id');
|
||||
validateMarketDataRow(1, 'Type', 'ERC20');
|
||||
validateMarketDataRow(2, 'Name', 'Euro');
|
||||
validateMarketDataRow(3, 'Symbol', 'tEURO');
|
||||
validateMarketDataRow(4, 'Decimals', '5');
|
||||
validateMarketDataRow(5, 'Quantum', '1');
|
||||
validateMarketDataRow(6, 'Status', 'Enabled');
|
||||
validateMarketDataRow(7, 'Contract address', '0x0158…78a4');
|
||||
validateMarketDataRow(8, 'Withdrawal threshold', '0.0005');
|
||||
validateMarketDataRow(9, 'Lifetime limit', '1,230');
|
||||
validateMarketDataRow(10, 'Infrastructure fee account balance', '0.00001');
|
||||
validateMarketDataRow(11, 'Global reward pool account balance', '0.00002');
|
||||
});
|
||||
|
||||
it('metadata displayed', () => {
|
||||
// 6002-MDET-207
|
||||
cy.getByTestId(marketTitle).contains('Metadata').click();
|
||||
|
||||
validateMarketDataRow(0, 'Formerly', '076BB86A5AA41E3E');
|
||||
validateMarketDataRow(1, 'Base', 'BTC');
|
||||
validateMarketDataRow(2, 'Quote', 'USD');
|
||||
validateMarketDataRow(3, 'Class', 'fx/crypto');
|
||||
validateMarketDataRow(4, 'Sector', 'crypto');
|
||||
});
|
||||
|
||||
it('risk model displayed', () => {
|
||||
// 6002-MDET-208
|
||||
cy.getByTestId(marketTitle).contains('Risk model').click();
|
||||
validateMarketDataRow(0, 'Tau', '0.0001140771161');
|
||||
validateMarketDataRow(1, 'Risk Aversion Parameter', '0.01');
|
||||
});
|
||||
|
||||
it('risk parameters displayed', () => {
|
||||
// 6002-MDET-209
|
||||
cy.getByTestId(marketTitle).contains('Risk parameters').click();
|
||||
validateMarketDataRow(0, 'R', '0.016');
|
||||
validateMarketDataRow(1, 'Sigma', '0.3');
|
||||
});
|
||||
|
||||
it('risk factors displayed', () => {
|
||||
// 6002-MDET-210
|
||||
cy.getByTestId(marketTitle).contains('Risk factors').click();
|
||||
|
||||
validateMarketDataRow(0, 'Short', '0.008571790367285281');
|
||||
validateMarketDataRow(1, 'Long', '0.008508132993273576');
|
||||
});
|
||||
|
||||
it('price monitoring bounds displayed', () => {
|
||||
// 6002-MDET-211
|
||||
cy.getByTestId(marketTitle).contains('Price monitoring bounds 1').click();
|
||||
cy.get('p.col-span-1').contains('99.99999% probability price bounds');
|
||||
cy.get('p.col-span-1').contains('Within 43,200 seconds');
|
||||
validateMarketDataRow(0, 'Highest Price', '7.97323 ');
|
||||
validateMarketDataRow(1, 'Lowest Price', '6.54701 ');
|
||||
});
|
||||
|
||||
it('liquidity monitoring parameters displayed', () => {
|
||||
// 6002-MDET-212
|
||||
cy.getByTestId(marketTitle)
|
||||
.contains('Liquidity monitoring parameters')
|
||||
.click();
|
||||
|
||||
validateMarketDataRow(0, 'Triggering Ratio', '0.7');
|
||||
validateMarketDataRow(1, 'Time Window', '3,600');
|
||||
validateMarketDataRow(2, 'Scaling Factor', '10');
|
||||
});
|
||||
|
||||
it('liquidity displayed', () => {
|
||||
// 6002-MDET-213
|
||||
cy.getByTestId(marketTitle)
|
||||
.contains(/Liquidity(?! m)/)
|
||||
.click();
|
||||
|
||||
validateMarketDataRow(0, 'Target Stake', '10.00 tBTC');
|
||||
validateMarketDataRow(1, 'Supplied Stake', '0.01 tBTC');
|
||||
validateMarketDataRow(2, 'Market Value Proxy', '20.00 tBTC');
|
||||
cy.getByTestId(liquidityLink).should(
|
||||
'have.text',
|
||||
'View liquidity provision table'
|
||||
);
|
||||
});
|
||||
|
||||
it('liquidity price range displayed', () => {
|
||||
// 6002-MDET-214
|
||||
cy.getByTestId(marketTitle).contains('Liquidity price range').click();
|
||||
|
||||
validateMarketDataRow(0, 'Liquidity Price Range', '2.00% of mid price');
|
||||
validateMarketDataRow(1, 'Lowest Price', '45,204.362 BTC');
|
||||
validateMarketDataRow(2, 'Highest Price', '47,049.438 BTC');
|
||||
});
|
||||
|
||||
it('proposal displayed', () => {
|
||||
// 6002-MDET-301
|
||||
cy.getByTestId(marketTitle).contains('Proposal').click();
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
.first()
|
||||
.should('have.text', 'View governance proposal')
|
||||
.and('have.attr', 'href')
|
||||
.and('contain', '/proposals/market-0');
|
||||
cy.getByTestId(accordionContent)
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
.eq(1)
|
||||
.should('have.text', 'Propose a change to market')
|
||||
.and('have.attr', 'href')
|
||||
.and('contain', '/proposals/propose/update-market');
|
||||
});
|
||||
|
||||
afterEach('close toggle', () => {
|
||||
cy.get('[data-state="open"]').then((tab) => {
|
||||
if (tab) tab.find('button').trigger('click');
|
||||
});
|
||||
});
|
||||
|
||||
function validateMarketDataRow(
|
||||
rowNumber: number,
|
||||
name: string,
|
||||
value: string
|
||||
) {
|
||||
cy.getByTestId(row)
|
||||
.eq(rowNumber)
|
||||
.within(() => {
|
||||
cy.get('dt').should('contain.text', name);
|
||||
cy.get('dd').should('contain.text', value);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -24,7 +24,9 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.getByTestId('deal-ticket-fee-margin-required').click();
|
||||
cy.getByTestId('deal-ticket-fee-margin-required').within(() => {
|
||||
cy.get('button').click();
|
||||
});
|
||||
});
|
||||
|
||||
describe('limit order', () => {
|
||||
@@ -109,7 +111,6 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
'Total margin available100.01 tDAI'
|
||||
);
|
||||
});
|
||||
cy.getByTestId('deal-ticket-fee-margin-required').click();
|
||||
});
|
||||
|
||||
it('must have current margin allocation', () => {
|
||||
@@ -119,7 +120,6 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
'Current margin allocation'
|
||||
);
|
||||
});
|
||||
cy.getByTestId('deal-ticket-fee-margin-required').click();
|
||||
});
|
||||
|
||||
it('should open usage breakdown dialog when clicked on current margin allocation', () => {
|
||||
@@ -128,7 +128,6 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
});
|
||||
cy.getByTestId('usage-breakdown').should('exist');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
cy.getByTestId('deal-ticket-fee-margin-required').click();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
testOrderAmendment,
|
||||
} from '../support/order-validation';
|
||||
|
||||
const orderSymbol = 'instrument-code';
|
||||
const orderSymbol = 'market.tradableInstrument.instrument.code';
|
||||
const orderSize = 'size';
|
||||
const orderType = 'type';
|
||||
const orderStatus = 'status';
|
||||
@@ -229,7 +229,10 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
|
||||
status: Schema.OrderStatus.STATUS_FILLED,
|
||||
});
|
||||
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Filled');
|
||||
cy.get(`[col-id="${orderSymbol}"]`).contains('[title="Future"]', 'Futr');
|
||||
cy.get('[col-id="market.tradableInstrument.instrument.code"]').contains(
|
||||
'[title="Future"]',
|
||||
'Futr'
|
||||
);
|
||||
});
|
||||
|
||||
it('must see a rejected order', () => {
|
||||
|
||||
@@ -86,8 +86,8 @@ describe('trades', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('copy price to deal ticket form', () => {
|
||||
cy.getByTestId('Order').click();
|
||||
// 6005-THIS-007
|
||||
cy.getByTestId('order-type-Limit').click();
|
||||
cy.get(colIdPrice).last().should('be.visible').click();
|
||||
cy.getByTestId('order-price').should('have.value', '171.16898');
|
||||
});
|
||||
|
||||
@@ -10,10 +10,10 @@ const dialogContent = 'dialog-content';
|
||||
describe('connect vega wallet', { tags: '@smoke', testIsolation: true }, () => {
|
||||
beforeEach(() => {
|
||||
// Using portfolio page as it requires vega wallet connection
|
||||
cy.visit('/#/portfolio');
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setOnBoardingViewed();
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
|
||||
});
|
||||
|
||||
|
||||
+1
-3
@@ -12,19 +12,17 @@ NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ICEBERG_ORDERS=true
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
NX_METAMASK_SNAPS=true
|
||||
NX_METAMASK_SNAPS=false
|
||||
|
||||
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
|
||||
|
||||
@@ -16,7 +16,10 @@ NX_VEGA_CONSOLE_URL=https://console.vega.xyz
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-mainnet/codfcglpplgmmlokgilfkpcjnmkbfiel
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
|
||||
|
||||
# TAG name of the current app version - TODO: bump to the latest upon release
|
||||
NX_APP_VERSION=v0.21.1-core-0.72.14
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
|
||||
@@ -16,7 +16,7 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
|
||||
@@ -17,7 +17,6 @@ NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
|
||||
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
|
||||
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
|
||||
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
|
||||
@@ -1,58 +1,18 @@
|
||||
import { DepositContainer } from '@vegaprotocol/deposits';
|
||||
import { GetStarted } from '../../components/welcome-dialog';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { GetStartedCheckList } from '../../components/welcome-dialog';
|
||||
import {
|
||||
useGetOnboardingStep,
|
||||
useOnboardingStore,
|
||||
OnboardingStep,
|
||||
} from '../../components/welcome-dialog/use-get-onboarding-step';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export const Deposit = () => {
|
||||
return (
|
||||
<div className="max-w-[600px] px-4 py-8 mx-auto lg:px-8">
|
||||
<h1 className="mb-6 text-4xl uppercase xl:text-5xl font-alpha calt">
|
||||
{t('Deposit')}
|
||||
</h1>
|
||||
<div className="flex flex-col gap-6">
|
||||
<DepositContainer />
|
||||
<DepositGetStarted />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const DepositGetStarted = () => {
|
||||
const onboardingDismissed = useOnboardingStore((store) => store.dismissed);
|
||||
const dismiss = useOnboardingStore((store) => store.dismiss);
|
||||
const step = useGetOnboardingStep();
|
||||
const wrapperClasses = classNames(
|
||||
'flex flex-col py-4 px-6 gap-4 rounded',
|
||||
'bg-vega-blue-300 dark:bg-vega-blue-700',
|
||||
'border border-vega-blue-350 dark:border-vega-blue-650'
|
||||
);
|
||||
|
||||
// Dont show unless still onboarding
|
||||
if (onboardingDismissed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="pt-6 border-t border-default">
|
||||
<div className={wrapperClasses}>
|
||||
<h3 className="text-lg">{t('Get started')}</h3>
|
||||
<GetStartedCheckList />
|
||||
{step > OnboardingStep.ONBOARDING_DEPOSIT_STEP && (
|
||||
<TradingAnchorButton
|
||||
href={Links[Routes.HOME]()}
|
||||
onClick={() => dismiss()}
|
||||
intent={Intent.Info}
|
||||
>
|
||||
{t('Start trading')}
|
||||
</TradingAnchorButton>
|
||||
)}
|
||||
<div className="py-16 px-8 flex w-full justify-center">
|
||||
<div className="lg:min-w-[700px] min-w-[300px] max-w-[700px]">
|
||||
<h1 className="text-4xl xl:text-5xl uppercase font-alpha calt">
|
||||
{t('Deposit')}
|
||||
</h1>
|
||||
<div className="mt-10">
|
||||
<DepositContainer />
|
||||
<GetStarted />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { marketsWithDataProvider } from '@vegaprotocol/markets';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import { useTopTradedMarkets } from '../../lib/hooks/use-top-traded-markets';
|
||||
|
||||
// The home pages only purpose is to redirect to the users last market,
|
||||
// the top traded if they are new, or fall back to the list of markets.
|
||||
// Thats why we just render a loader here
|
||||
export const Home = () => {
|
||||
const navigate = useNavigate();
|
||||
const { data } = useTopTradedMarkets();
|
||||
// The default market selected in the platform behind the overlay
|
||||
// should be the oldest market that is currently trading in continuous mode(i.e. not in auction).
|
||||
const { data, error, loading } = useDataProvider({
|
||||
dataProvider: marketsWithDataProvider,
|
||||
variables: undefined,
|
||||
});
|
||||
const update = useGlobalStore((store) => store.update);
|
||||
const marketId = useGlobalStore((store) => store.marketId);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -28,11 +32,12 @@ export const Home = () => {
|
||||
navigate(Links[Routes.MARKETS]());
|
||||
}
|
||||
}
|
||||
}, [marketId, data, navigate]);
|
||||
}, [marketId, data, navigate, update]);
|
||||
|
||||
return (
|
||||
<Splash>
|
||||
<Loader />
|
||||
</Splash>
|
||||
<AsyncRenderer data={data} loading={loading} error={error}>
|
||||
{/* Render a loading and error state but we will redirect if markets are found */}
|
||||
{null}
|
||||
</AsyncRenderer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -11,7 +11,6 @@ import { TradePanels } from './trade-panels';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { ViewType, useSidebar } from '../../components/sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
const calculatePrice = (markPrice?: string, decimalPlaces?: number) => {
|
||||
return markPrice && decimalPlaces
|
||||
@@ -59,9 +58,7 @@ const TitleUpdater = ({
|
||||
export const MarketPage = () => {
|
||||
const { marketId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const { setViews, getView } = useSidebar();
|
||||
const view = getView(currentRouteId);
|
||||
const { init, view, setView } = useSidebar();
|
||||
const { screenSize } = useScreenDimensions();
|
||||
const largeScreen = ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize);
|
||||
const update = useGlobalStore((store) => store.update);
|
||||
@@ -72,14 +69,15 @@ export const MarketPage = () => {
|
||||
useEffect(() => {
|
||||
if (data?.id && data.id !== lastMarketId) {
|
||||
update({ marketId: data.id });
|
||||
// make sidebar open on market id change
|
||||
setView({ type: ViewType.Order });
|
||||
}
|
||||
}, [update, lastMarketId, data?.id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (largeScreen && view === undefined) {
|
||||
setViews({ type: ViewType.Order }, currentRouteId);
|
||||
// make sidebar open on deal ticket by default
|
||||
if (view === null) {
|
||||
setView({ type: ViewType.Order });
|
||||
}
|
||||
}, [setViews, view, currentRouteId, largeScreen]);
|
||||
}, [update, lastMarketId, data?.id, setView, init, view]);
|
||||
|
||||
const tradeView = useMemo(() => {
|
||||
if (largeScreen) {
|
||||
|
||||
@@ -56,7 +56,6 @@ const MainGrid = memo(
|
||||
<Tabs storageKey="console-trade-grid-main-left">
|
||||
<Tab
|
||||
id="chart"
|
||||
overflowHidden
|
||||
name={t('Chart')}
|
||||
menu={<TradingViews.candles.menu />}
|
||||
>
|
||||
@@ -73,7 +72,7 @@ const MainGrid = memo(
|
||||
</ResizableGridPanel>
|
||||
<ResizableGridPanel
|
||||
minSize={200}
|
||||
preferredSize={sizesMiddle[1] || 275}
|
||||
preferredSize={sizesMiddle[1] || 300}
|
||||
>
|
||||
<TradeGridChild>
|
||||
<Tabs storageKey="console-trade-grid-main-right">
|
||||
@@ -128,7 +127,7 @@ const MainGrid = memo(
|
||||
</Tab>
|
||||
) : null}
|
||||
<Tab id="fills" name={t('Fills')}>
|
||||
<TradingViews.fills.component />
|
||||
<TradingViews.fills.component marketId={marketId} />
|
||||
</Tab>
|
||||
<Tab
|
||||
id="accounts"
|
||||
@@ -181,7 +180,7 @@ const TradeGridChild = ({ children }: TradeGridChildProps) => {
|
||||
{({ width, height }) => (
|
||||
<div
|
||||
style={{ width, height }}
|
||||
className="border rounded-sm border-default"
|
||||
className="border border-default rounded-sm"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@ import type {
|
||||
VegaICellRendererParams,
|
||||
VegaValueFormatterParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { AgGrid, COL_DEFS } from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid, COL_DEFS } from '@vegaprotocol/datagrid';
|
||||
import { useMemo } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { ProductType } from '@vegaprotocol/types';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { TypedDataAgGrid } from '@vegaprotocol/datagrid';
|
||||
import { AgGrid, PriceFlashCell } from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid, PriceFlashCell } from '@vegaprotocol/datagrid';
|
||||
import type { MarketMaybeWithData } from '@vegaprotocol/markets';
|
||||
import { useColumnDefs } from './use-column-defs';
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ export const MarketsPage = () => {
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
|
||||
const governanceLink = useLinks(DApp.Governance);
|
||||
const externalLink = governanceLink(TOKEN_NEW_MARKET_PROPOSAL);
|
||||
const tokenLink = useLinks(DApp.Token);
|
||||
const externalLink = tokenLink(TOKEN_NEW_MARKET_PROPOSAL);
|
||||
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy(['Markets']));
|
||||
|
||||
@@ -23,7 +23,6 @@ import { ViewType, useSidebar } from '../../components/sidebar';
|
||||
import { AccountsMenu } from '../../components/accounts-menu';
|
||||
import { DepositsMenu } from '../../components/deposits-menu';
|
||||
import { WithdrawalsMenu } from '../../components/withdrawals-menu';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
const WithdrawalsIndicator = () => {
|
||||
const { ready } = useIncompleteWithdrawals();
|
||||
@@ -38,10 +37,7 @@ const WithdrawalsIndicator = () => {
|
||||
};
|
||||
|
||||
export const Portfolio = () => {
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const { getView, setViews } = useSidebar();
|
||||
const view = getView(currentRouteId);
|
||||
|
||||
const { init, view, setView } = useSidebar();
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
@@ -52,10 +48,10 @@ export const Portfolio = () => {
|
||||
|
||||
// Make transfer sidebar open by default
|
||||
useEffect(() => {
|
||||
if (view === undefined) {
|
||||
setViews({ type: ViewType.Transfer }, currentRouteId);
|
||||
if (init && view === null) {
|
||||
setView({ type: ViewType.Transfer });
|
||||
}
|
||||
}, [view, setViews, currentRouteId]);
|
||||
}, [init, view, setView]);
|
||||
|
||||
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' });
|
||||
const wrapperClasses = 'p-0.5 h-full max-h-full flex flex-col';
|
||||
|
||||
@@ -12,7 +12,6 @@ import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
export const AccountsContainer = ({
|
||||
pinnedAsset,
|
||||
@@ -22,8 +21,7 @@ export const AccountsContainer = ({
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
|
||||
const gridStore = useAccountStore((store) => store.gridStore);
|
||||
const updateGridStore = useAccountStore((store) => store.updateGridStore);
|
||||
@@ -51,13 +49,13 @@ export const AccountsContainer = ({
|
||||
partyId={pubKey}
|
||||
onClickAsset={onClickAsset}
|
||||
onClickWithdraw={(assetId) => {
|
||||
setViews({ type: ViewType.Withdraw, assetId }, currentRouteId);
|
||||
setView({ type: ViewType.Withdraw, assetId });
|
||||
}}
|
||||
onClickDeposit={(assetId) => {
|
||||
setViews({ type: ViewType.Deposit, assetId }, currentRouteId);
|
||||
setView({ type: ViewType.Deposit, assetId });
|
||||
}}
|
||||
onClickTransfer={(assetId) => {
|
||||
setViews({ type: ViewType.Transfer, assetId }, currentRouteId);
|
||||
setView({ type: ViewType.Transfer, assetId });
|
||||
}}
|
||||
onMarketClick={onMarketClick}
|
||||
isReadOnly={isReadOnly}
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
export const AccountsMenu = () => {
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TradingButton
|
||||
size="extra-small"
|
||||
data-testid="open-transfer"
|
||||
onClick={() => setViews({ type: ViewType.Transfer }, currentRouteId)}
|
||||
onClick={() => setView({ type: ViewType.Transfer })}
|
||||
>
|
||||
{t('Transfer')}
|
||||
</TradingButton>
|
||||
<TradingButton
|
||||
size="extra-small"
|
||||
onClick={() => setViews({ type: ViewType.Deposit }, currentRouteId)}
|
||||
onClick={() => setView({ type: ViewType.Deposit })}
|
||||
>
|
||||
{t('Deposit')}
|
||||
</TradingButton>
|
||||
|
||||
@@ -9,11 +9,5 @@ export const AnnouncementBanner = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Banner
|
||||
app="console"
|
||||
configUrl={ANNOUNCEMENTS_CONFIG_URL}
|
||||
background="url('/banner-bg.jpg')"
|
||||
/>
|
||||
);
|
||||
return <Banner app="console" configUrl={ANNOUNCEMENTS_CONFIG_URL} />;
|
||||
};
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './announcement-banner';
|
||||
export * from './upgrade-banner';
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { gt, prerelease } from 'semver';
|
||||
import {
|
||||
ReleasesFeed,
|
||||
useEnvironment,
|
||||
useReleases,
|
||||
Networks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
CopyWithTooltip,
|
||||
ExternalLink,
|
||||
Intent,
|
||||
NotificationBanner,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
// v0.20.12-core-0.71.4 -> v0.20.12
|
||||
// we need to strip the "core" suffix in order to determine whether a release
|
||||
// is a pre-release (candidate); example: v.0.21.0-beta.1-core-0.71.4
|
||||
const parseTagName = (tagName: string) => tagName.replace(/-core-[\d.]+$/i, '');
|
||||
|
||||
type UpgradeBannerProps = {
|
||||
showVersionChange: boolean;
|
||||
};
|
||||
export const UpgradeBanner = ({ showVersionChange }: UpgradeBannerProps) => {
|
||||
const [visible, setVisible] = useState(true);
|
||||
const { data } = useReleases(ReleasesFeed.FrontEnd);
|
||||
const { APP_VERSION, VEGA_ENV, VEGA_NETWORKS } = useEnvironment();
|
||||
|
||||
const CANONICAL_URL = VEGA_NETWORKS[VEGA_ENV] || 'https://console.vega.xyz';
|
||||
|
||||
const newest = useMemo(() => {
|
||||
if (!APP_VERSION || !data) return undefined;
|
||||
const newer = data.filter((r) => gt(r.tagName, APP_VERSION));
|
||||
const valid =
|
||||
// filter pre-releases on mainnet
|
||||
VEGA_ENV === Networks.MAINNET
|
||||
? newer?.filter((r) => !prerelease(parseTagName(r.tagName)))
|
||||
: newer;
|
||||
return valid.sort((a, b) => (gt(a.tagName, b.tagName) ? -1 : 1))[0];
|
||||
}, [APP_VERSION, VEGA_ENV, data]);
|
||||
|
||||
if (!visible || !newest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<NotificationBanner
|
||||
intent={Intent.Warning}
|
||||
onClose={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="uppercase mb-1">
|
||||
<ExternalLink href={CANONICAL_URL}>
|
||||
{t('Upgrade to the latest version of Console')}
|
||||
</ExternalLink>
|
||||
</div>
|
||||
<div data-testid="bookmark-message">
|
||||
<a
|
||||
className="underline"
|
||||
href={newest.htmlUrl}
|
||||
rel="noreferrer nofollow noopener"
|
||||
target="_blank"
|
||||
>
|
||||
{t("View what's changed")}
|
||||
</a>{' '}
|
||||
{t(' or bookmark')}{' '}
|
||||
<a className="underline" href={CANONICAL_URL}>
|
||||
{t('console.vega.xyz')}
|
||||
</a>{' '}
|
||||
<CopyWithTooltip text={CANONICAL_URL}>
|
||||
<button title={t('Copy %s', CANONICAL_URL)}>
|
||||
<span className="sr-only">{t('Copy %s', CANONICAL_URL)}</span>
|
||||
<VegaIcon size={14} name={VegaIconNames.COPY} />
|
||||
</button>
|
||||
</CopyWithTooltip>{' '}
|
||||
{'to always see the latest version.'}
|
||||
</div>
|
||||
</NotificationBanner>
|
||||
);
|
||||
};
|
||||
@@ -1 +1,2 @@
|
||||
export const THROTTLE_UPDATE_TIME = 500;
|
||||
export const ONBOARDING_VIEWED_KEY = 'vega_onboarding_viewed';
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
export const DepositsMenu = () => {
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
|
||||
return (
|
||||
<TradingButton
|
||||
size="extra-small"
|
||||
onClick={() => setViews({ type: ViewType.Deposit }, currentRouteId)}
|
||||
onClick={() => setView({ type: ViewType.Deposit })}
|
||||
data-testid="deposit-button"
|
||||
>
|
||||
{t('Deposit')}
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { DataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
|
||||
export const FillsContainer = () => {
|
||||
export const FillsContainer = ({ marketId }: { marketId?: string }) => {
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const { pubKey } = useVegaWallet();
|
||||
|
||||
@@ -31,6 +31,7 @@ export const FillsContainer = () => {
|
||||
return (
|
||||
<FillsManager
|
||||
partyId={pubKey}
|
||||
marketId={marketId}
|
||||
onMarketClick={onMarketClick}
|
||||
gridProps={gridStoreCallbacks}
|
||||
/>
|
||||
|
||||
@@ -53,7 +53,7 @@ export const HeaderStat = ({
|
||||
<div data-testid="item-header" id={id}>
|
||||
{heading}
|
||||
</div>
|
||||
<Tooltip description={description} underline>
|
||||
<Tooltip description={description}>
|
||||
<div
|
||||
data-testid="item-value"
|
||||
aria-labelledby={id}
|
||||
|
||||
@@ -4,19 +4,16 @@ import classNames from 'classnames';
|
||||
import { Routes as AppRoutes } from '../../pages/client-router';
|
||||
import { MarketHeader } from '../market-header';
|
||||
import { LiquidityHeader } from '../liquidity-header';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
export const LayoutWithSidebar = () => {
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const views = useSidebar((store) => store.views);
|
||||
const sidebarView = views[currentRouteId] || null;
|
||||
const sidebarView = useSidebar((store) => store.view);
|
||||
const sidebarOpen = sidebarView !== null;
|
||||
|
||||
const gridClasses = classNames(
|
||||
'h-full relative z-0 grid',
|
||||
'grid-rows-[min-content_1fr_40px]',
|
||||
'lg:grid-rows-[min-content_1fr]',
|
||||
'lg:grid-cols-[1fr_280px_40px]',
|
||||
'xxxl:grid-cols-[1fr_320px_40px]'
|
||||
'lg:grid-cols-[1fr_350px_40px]'
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -29,7 +29,7 @@ export const MarketSuccessorProposalBanner = ({
|
||||
?.successorConfiguration?.parentMarketId === marketId
|
||||
) ?? [];
|
||||
const [visible, setVisible] = useState(true);
|
||||
const tokenLink = useLinks(DApp.Governance);
|
||||
const tokenLink = useLinks(DApp.Token);
|
||||
if (visible && successors.length) {
|
||||
return (
|
||||
<NotificationBanner
|
||||
|
||||
@@ -186,7 +186,7 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
|
||||
</NavbarLink>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<NavbarLinkExternal to={useLinks(DApp.Governance)()}>
|
||||
<NavbarLinkExternal to={useLinks(DApp.Token)()}>
|
||||
{t('Governance')}
|
||||
</NavbarLinkExternal>
|
||||
</NavbarItem>
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { OrderbookManager } from '@vegaprotocol/market-depth';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useDealTicketFormValues } from '@vegaprotocol/deal-ticket';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
export const OrderbookContainer = ({ marketId }: { marketId: string }) => {
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const update = useDealTicketFormValues((state) => state.updateAll);
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
return (
|
||||
<OrderbookManager
|
||||
marketId={marketId}
|
||||
onClick={(values) => {
|
||||
update(marketId, values);
|
||||
setViews({ type: ViewType.Order }, currentRouteId);
|
||||
setView({ type: ViewType.Order });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -28,20 +28,14 @@ export interface OrderContainerProps {
|
||||
filter?: Filter;
|
||||
}
|
||||
|
||||
const AUTO_SIZE_COLUMNS = ['instrument-code'];
|
||||
|
||||
export const OrdersContainer = ({ filter }: OrderContainerProps) => {
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const onOrderTypeClick = useMarketLiquidityClickHandler();
|
||||
const { gridState, updateGridState } = useOrderListGridState(filter);
|
||||
const gridStoreCallbacks = useDataGridEvents(
|
||||
gridState,
|
||||
(newState) => {
|
||||
updateGridState(filter, newState);
|
||||
},
|
||||
AUTO_SIZE_COLUMNS
|
||||
);
|
||||
const gridStoreCallbacks = useDataGridEvents(gridState, (newState) => {
|
||||
updateGridState(filter, newState);
|
||||
});
|
||||
|
||||
if (!pubKey) {
|
||||
return <Splash>{t('Please connect Vega wallet')}</Splash>;
|
||||
|
||||
@@ -10,8 +10,6 @@ import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
|
||||
const AUTO_SIZE_COLUMNS = ['marketCode'];
|
||||
|
||||
export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => {
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const { pubKey, pubKeys, isReadOnly } = useVegaWallet();
|
||||
@@ -19,11 +17,7 @@ export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => {
|
||||
const showClosed = usePositionsStore((store) => store.showClosedMarkets);
|
||||
const gridStore = usePositionsStore((store) => store.gridStore);
|
||||
const updateGridStore = usePositionsStore((store) => store.updateGridStore);
|
||||
const gridStoreCallbacks = useDataGridEvents(
|
||||
gridStore,
|
||||
updateGridStore,
|
||||
AUTO_SIZE_COLUMNS
|
||||
);
|
||||
const gridStoreCallbacks = useDataGridEvents(gridStore, updateGridStore);
|
||||
|
||||
if (!pubKey) {
|
||||
return (
|
||||
|
||||
@@ -11,7 +11,6 @@ import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
||||
import { VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import { Routes as AppRoutes } from '../../pages/client-router';
|
||||
|
||||
jest.mock('../node-health', () => ({
|
||||
NodeHealthContainer: () => <span data-testid="node-health" />,
|
||||
@@ -116,11 +115,7 @@ describe('SidebarContent', () => {
|
||||
<VegaWalletContext.Provider value={walletContext}>
|
||||
<MemoryRouter initialEntries={['/markets/ABC']}>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/markets/:marketId"
|
||||
id={AppRoutes.MARKET}
|
||||
element={<SidebarContent />}
|
||||
/>
|
||||
<Route path="/markets/:marketId" element={<SidebarContent />} />
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
</VegaWalletContext.Provider>
|
||||
@@ -129,17 +124,13 @@ describe('SidebarContent', () => {
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
|
||||
act(() => {
|
||||
useSidebar.setState({
|
||||
views: { [AppRoutes.MARKET]: { type: ViewType.Transfer } },
|
||||
});
|
||||
useSidebar.setState({ view: { type: ViewType.Transfer } });
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('transfer')).toBeInTheDocument();
|
||||
|
||||
act(() => {
|
||||
useSidebar.setState({
|
||||
views: { [AppRoutes.MARKET]: { type: ViewType.Deposit } },
|
||||
});
|
||||
useSidebar.setState({ view: { type: ViewType.Deposit } });
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('deposit')).toBeInTheDocument();
|
||||
@@ -150,36 +141,26 @@ describe('SidebarContent', () => {
|
||||
<VegaWalletContext.Provider value={walletContext}>
|
||||
<MemoryRouter initialEntries={['/portfolio']}>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/portfolio"
|
||||
id={AppRoutes.PORTFOLIO}
|
||||
element={<SidebarContent />}
|
||||
/>
|
||||
<Route path="/portfolio" element={<SidebarContent />} />
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
</VegaWalletContext.Provider>
|
||||
);
|
||||
|
||||
act(() => {
|
||||
useSidebar.setState({
|
||||
views: { [AppRoutes.PORTFOLIO]: { type: ViewType.Order } },
|
||||
});
|
||||
useSidebar.setState({ view: { type: ViewType.Order } });
|
||||
});
|
||||
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
|
||||
act(() => {
|
||||
useSidebar.setState({
|
||||
views: { [AppRoutes.PORTFOLIO]: { type: ViewType.Settings } },
|
||||
});
|
||||
useSidebar.setState({ view: { type: ViewType.Settings } });
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('settings')).toBeInTheDocument();
|
||||
|
||||
act(() => {
|
||||
useSidebar.setState({
|
||||
views: { [AppRoutes.PORTFOLIO]: { type: ViewType.Info } },
|
||||
});
|
||||
useSidebar.setState({ view: { type: ViewType.Info } });
|
||||
});
|
||||
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
@@ -197,7 +178,6 @@ describe('SidebarButton', () => {
|
||||
tooltip="INFO"
|
||||
onClick={onClick}
|
||||
view={view}
|
||||
routeId="current-route-id"
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@@ -14,9 +14,8 @@ import { Settings } from '../settings';
|
||||
import { Tooltip } from '../../components/tooltip';
|
||||
import { WithdrawContainer } from '../withdraw-container';
|
||||
import { Routes as AppRoutes } from '../../pages/client-router';
|
||||
import { useVegaWallet, useViewAsDialog } from '@vegaprotocol/wallet';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { GetStarted } from '../welcome-dialog';
|
||||
import { useVegaWallet, useViewAsDialog } from '@vegaprotocol/wallet';
|
||||
|
||||
export enum ViewType {
|
||||
Order = 'Order',
|
||||
@@ -52,31 +51,27 @@ type SidebarView =
|
||||
};
|
||||
|
||||
export const Sidebar = () => {
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const navClasses = 'flex lg:flex-col items-center gap-2 lg:gap-4 p-1';
|
||||
const setViewAsDialogOpen = useViewAsDialog((state) => state.setOpen);
|
||||
const { pubKeys } = useVegaWallet();
|
||||
return (
|
||||
<div className="flex h-full p-1 lg:flex-col gap-2" data-testid="sidebar">
|
||||
<div className="flex lg:flex-col gap-2 h-full p-1" data-testid="sidebar">
|
||||
<nav className={navClasses}>
|
||||
{/* sidebar options that always show */}
|
||||
<SidebarButton
|
||||
view={ViewType.Deposit}
|
||||
icon={VegaIconNames.DEPOSIT}
|
||||
tooltip={t('Deposit')}
|
||||
routeId={currentRouteId}
|
||||
/>
|
||||
<SidebarButton
|
||||
view={ViewType.Withdraw}
|
||||
icon={VegaIconNames.WITHDRAW}
|
||||
tooltip={t('Withdraw')}
|
||||
routeId={currentRouteId}
|
||||
/>
|
||||
<SidebarButton
|
||||
view={ViewType.Transfer}
|
||||
icon={VegaIconNames.TRANSFER}
|
||||
tooltip={t('Transfer')}
|
||||
routeId={currentRouteId}
|
||||
/>
|
||||
{/* buttons for specific routes */}
|
||||
<Routes>
|
||||
@@ -99,13 +94,11 @@ export const Sidebar = () => {
|
||||
view={ViewType.Order}
|
||||
icon={VegaIconNames.TICKET}
|
||||
tooltip={t('Order')}
|
||||
routeId={currentRouteId}
|
||||
/>
|
||||
<SidebarButton
|
||||
view={ViewType.Info}
|
||||
icon={VegaIconNames.BREAKDOWN}
|
||||
tooltip={t('Market specification')}
|
||||
routeId={currentRouteId}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
@@ -121,13 +114,12 @@ export const Sidebar = () => {
|
||||
icon={VegaIconNames.EYE}
|
||||
tooltip={t('View as party')}
|
||||
disabled={Boolean(pubKeys)}
|
||||
routeId={currentRouteId}
|
||||
/>
|
||||
|
||||
<SidebarButton
|
||||
view={ViewType.Settings}
|
||||
icon={VegaIconNames.COG}
|
||||
tooltip={t('Settings')}
|
||||
routeId={currentRouteId}
|
||||
/>
|
||||
<NodeHealthContainer />
|
||||
</nav>
|
||||
@@ -141,25 +133,23 @@ export const SidebarButton = ({
|
||||
tooltip,
|
||||
disabled = false,
|
||||
onClick,
|
||||
routeId,
|
||||
}: {
|
||||
view?: ViewType;
|
||||
icon: VegaIconNames;
|
||||
tooltip: string;
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
routeId: string;
|
||||
}) => {
|
||||
const { setViews, getView } = useSidebar((store) => ({
|
||||
setViews: store.setViews,
|
||||
getView: store.getView,
|
||||
const { currView, setView } = useSidebar((store) => ({
|
||||
currView: store.view,
|
||||
setView: store.setView,
|
||||
}));
|
||||
const currView = getView(routeId);
|
||||
|
||||
const onSelect = (view: SidebarView['type']) => {
|
||||
if (view === currView?.type) {
|
||||
setViews(null, routeId);
|
||||
setView(null);
|
||||
} else {
|
||||
setViews({ type: view }, routeId);
|
||||
setView({ type: view });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -197,7 +187,7 @@ export const SidebarButton = ({
|
||||
const SidebarDivider = () => {
|
||||
return (
|
||||
<div
|
||||
className="w-px h-4 bg-vega-clight-600 dark:bg-vega-cdark-600 lg:w-4 lg:h-px"
|
||||
className="bg-vega-clight-600 dark:bg-vega-cdark-600 w-px h-4 lg:w-4 lg:h-px"
|
||||
role="separator"
|
||||
/>
|
||||
);
|
||||
@@ -205,10 +195,8 @@ const SidebarDivider = () => {
|
||||
|
||||
export const SidebarContent = () => {
|
||||
const params = useParams();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const { view, setView } = useSidebar();
|
||||
|
||||
const { setViews, getView } = useSidebar();
|
||||
const view = getView(currentRouteId);
|
||||
if (!view) return null;
|
||||
|
||||
if (view.type === ViewType.Order) {
|
||||
@@ -218,7 +206,7 @@ export const SidebarContent = () => {
|
||||
<DealTicketContainer
|
||||
marketId={params.marketId}
|
||||
onDeposit={(assetId) =>
|
||||
setViews({ type: ViewType.Deposit, assetId }, currentRouteId)
|
||||
setView({ type: ViewType.Deposit, assetId })
|
||||
}
|
||||
/>
|
||||
<GetStarted />
|
||||
@@ -245,6 +233,7 @@ export const SidebarContent = () => {
|
||||
return (
|
||||
<ContentWrapper title={t('Deposit')}>
|
||||
<DepositContainer assetId={view.assetId} />
|
||||
<GetStarted />
|
||||
</ContentWrapper>
|
||||
);
|
||||
}
|
||||
@@ -253,6 +242,7 @@ export const SidebarContent = () => {
|
||||
return (
|
||||
<ContentWrapper title={t('Withdraw')}>
|
||||
<WithdrawContainer assetId={view.assetId} />
|
||||
<GetStarted />
|
||||
</ContentWrapper>
|
||||
);
|
||||
}
|
||||
@@ -261,6 +251,7 @@ export const SidebarContent = () => {
|
||||
return (
|
||||
<ContentWrapper title={t('Transfer')}>
|
||||
<TransferContainer assetId={view.assetId} />
|
||||
<GetStarted />
|
||||
</ContentWrapper>
|
||||
);
|
||||
}
|
||||
@@ -285,7 +276,7 @@ const ContentWrapper = ({
|
||||
}) => {
|
||||
return (
|
||||
<TinyScroll
|
||||
className="h-full py-4 pl-3 pr-4 overflow-auto"
|
||||
className="h-full overflow-auto py-4 pl-3 pr-4"
|
||||
// panes have p-1, since sidebar is on the right make pl less to account for additional pane space
|
||||
data-testid="sidebar-content"
|
||||
>
|
||||
@@ -297,21 +288,25 @@ const ContentWrapper = ({
|
||||
|
||||
/** If rendered will close sidebar */
|
||||
const CloseSidebar = () => {
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
useEffect(() => {
|
||||
setViews(null, currentRouteId);
|
||||
}, [setViews, currentRouteId]);
|
||||
setView(null);
|
||||
}, [setView]);
|
||||
return null;
|
||||
};
|
||||
|
||||
export const useSidebar = create<{
|
||||
views: { [key: string]: SidebarView | null };
|
||||
setViews: (view: SidebarView | null, routeId: string) => void;
|
||||
getView: (routeId: string) => SidebarView | null | undefined;
|
||||
}>()((set, get) => ({
|
||||
views: {},
|
||||
setViews: (x, routeId) =>
|
||||
set(({ views }) => ({ views: { ...views, [routeId]: x } })),
|
||||
getView: (routeId) => get().views[routeId],
|
||||
init: boolean;
|
||||
view: SidebarView | null;
|
||||
setView: (view: SidebarView | null) => void;
|
||||
}>()((set) => ({
|
||||
init: true,
|
||||
view: null,
|
||||
setView: (x) =>
|
||||
set(() => {
|
||||
if (x == null) {
|
||||
return { view: null, init: false };
|
||||
}
|
||||
return { view: x, init: false };
|
||||
}),
|
||||
}));
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { Telemetry } from './telemetry';
|
||||
@@ -1,69 +0,0 @@
|
||||
import type { Toast } from '@vegaprotocol/ui-toolkit';
|
||||
import { Intent, useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTelemetryApproval } from '../../lib/hooks/use-telemetry-approval';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { TelemetryApproval } from './telemetry-approval';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useOnboardingStore } from '../welcome-dialog/use-get-onboarding-step';
|
||||
|
||||
const TELEMETRY_APPROVAL_TOAST_ID = 'telemetry_tost_id';
|
||||
|
||||
export const Telemetry = () => {
|
||||
const onboardingDissmissed = useOnboardingStore((store) => store.dismissed);
|
||||
const [telemetryValue, setTelemetryValue, isTelemetryNeeded, closeTelemetry] =
|
||||
useTelemetryApproval();
|
||||
|
||||
const [setToast, hasToast, removeToast] = useToasts((store) => [
|
||||
store.setToast,
|
||||
store.hasToast,
|
||||
store.remove,
|
||||
]);
|
||||
|
||||
const onApprovalClose = useCallback(() => {
|
||||
closeTelemetry();
|
||||
removeToast(TELEMETRY_APPROVAL_TOAST_ID);
|
||||
}, [closeTelemetry, removeToast]);
|
||||
|
||||
const setTelemetryApprovalAndClose = useCallback(
|
||||
(value: string) => {
|
||||
setTelemetryValue(value);
|
||||
onApprovalClose();
|
||||
},
|
||||
[onApprovalClose, setTelemetryValue]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isTelemetryNeeded && onboardingDissmissed) {
|
||||
const toast: Toast = {
|
||||
id: TELEMETRY_APPROVAL_TOAST_ID,
|
||||
intent: Intent.Primary,
|
||||
content: (
|
||||
<>
|
||||
<h3 className="mb-1 text-sm uppercase">
|
||||
{t('Improve vega console')}
|
||||
</h3>
|
||||
<TelemetryApproval
|
||||
telemetryValue={telemetryValue}
|
||||
setTelemetryValue={setTelemetryApprovalAndClose}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
onClose: onApprovalClose,
|
||||
};
|
||||
if (!hasToast(TELEMETRY_APPROVAL_TOAST_ID)) {
|
||||
setToast(toast);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}, [
|
||||
telemetryValue,
|
||||
isTelemetryNeeded,
|
||||
onboardingDissmissed,
|
||||
setToast,
|
||||
hasToast,
|
||||
onApprovalClose,
|
||||
setTelemetryApprovalAndClose,
|
||||
]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -11,10 +11,6 @@ jest.mock('@vegaprotocol/wallet', () => ({
|
||||
useVegaWalletDialogStore: () => mockUpdateDialogOpen,
|
||||
}));
|
||||
|
||||
jest.mock('../../lib/hooks/use-get-current-route-id', () => ({
|
||||
useGetCurrentRouteId: jest.fn().mockReturnValue('current-route-id'),
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
@@ -22,15 +22,13 @@ import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import { useCopyTimeout } from '@vegaprotocol/react-helpers';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import classNames from 'classnames';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
export const VegaWalletConnectButton = () => {
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
);
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
const {
|
||||
pubKey,
|
||||
pubKeys,
|
||||
@@ -97,7 +95,7 @@ export const VegaWalletConnectButton = () => {
|
||||
<TradingDropdownItem
|
||||
data-testid="wallet-transfer"
|
||||
onClick={() => {
|
||||
setViews({ type: ViewType.Transfer }, currentRouteId);
|
||||
setView({ type: ViewType.Transfer });
|
||||
setDropdownOpen(false);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -10,7 +10,6 @@ import { useVegaWallet, type PubKey } from '@vegaprotocol/wallet';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
export const VegaWalletMenu = ({
|
||||
setMenu,
|
||||
@@ -18,8 +17,7 @@ export const VegaWalletMenu = ({
|
||||
setMenu: (open: 'nav' | 'wallet' | null) => void;
|
||||
}) => {
|
||||
const { pubKey, pubKeys, selectPubKey, disconnect } = useVegaWallet();
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
|
||||
const activeKey = useMemo(() => {
|
||||
return pubKeys?.find((pk) => pk.publicKey === pubKey);
|
||||
@@ -48,7 +46,7 @@ export const VegaWalletMenu = ({
|
||||
<div className="flex flex-col gap-2 m-4">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setViews({ type: ViewType.Transfer }, currentRouteId);
|
||||
setView({ type: ViewType.Transfer });
|
||||
setMenu(null);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -2,8 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
|
||||
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import { GetStarted } from './get-started';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { useOnboardingStore } from './use-get-onboarding-step';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
let mockStep = 1;
|
||||
jest.mock('./use-get-onboarding-step', () => ({
|
||||
@@ -45,15 +44,13 @@ describe('GetStarted', () => {
|
||||
globalThis.window.vega = undefined as unknown as Vega;
|
||||
});
|
||||
|
||||
it('renders nothing if dismissed', () => {
|
||||
useOnboardingStore.setState({ dismissed: true });
|
||||
it('renders nothing if connected', () => {
|
||||
mockStep = 0;
|
||||
const { container } = renderComponent({ pubKey: 'my-pubkey' });
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('steps should be ticked', () => {
|
||||
useOnboardingStore.setState({ dismissed: false });
|
||||
const navigatorGetter: jest.SpyInstance = jest.spyOn(
|
||||
window.navigator,
|
||||
'userAgent',
|
||||
@@ -75,7 +72,7 @@ describe('GetStarted', () => {
|
||||
</MemoryRouter>
|
||||
);
|
||||
checkTicks(screen.getAllByRole('listitem'));
|
||||
expect(screen.getByRole('link', { name: 'Deposit' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Deposit' })).toBeInTheDocument();
|
||||
|
||||
mockStep = 4;
|
||||
rerender(
|
||||
@@ -87,11 +84,9 @@ describe('GetStarted', () => {
|
||||
);
|
||||
checkTicks(screen.getAllByRole('listitem'));
|
||||
expect(
|
||||
screen.getByRole('link', { name: 'Ready to trade' })
|
||||
screen.getByRole('button', { name: 'Ready to trade' })
|
||||
).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole('link', { name: 'Ready to trade' }));
|
||||
|
||||
mockStep = 5;
|
||||
rerender(
|
||||
<MemoryRouter>
|
||||
|
||||
@@ -3,113 +3,89 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
ExternalLink,
|
||||
Intent,
|
||||
TradingAnchorButton,
|
||||
TradingButton,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import { useLocalStorage } from '@vegaprotocol/react-helpers';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
OnboardingStep,
|
||||
useGetOnboardingStep,
|
||||
useOnboardingStore,
|
||||
} from './use-get-onboarding-step';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import { useSidebar, ViewType } from '../sidebar';
|
||||
import * as constants from '../constants';
|
||||
import { useOnboardingStore } from './welcome-dialog';
|
||||
|
||||
interface Props {
|
||||
lead?: string;
|
||||
}
|
||||
|
||||
const GetStartedButton = ({ step }: { step: OnboardingStep }) => {
|
||||
const dismiss = useOnboardingStore((store) => store.dismiss);
|
||||
const setDialogOpen = useOnboardingStore((store) => store.setDialogOpen);
|
||||
const marketId = useGlobalStore((store) => store.marketId);
|
||||
const setWalletDialogOpen = useOnboardingStore(
|
||||
(store) => store.setWalletDialogOpen
|
||||
const navigate = useNavigate();
|
||||
const [, setOnboardingViewed] = useLocalStorage(
|
||||
constants.ONBOARDING_VIEWED_KEY
|
||||
);
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
|
||||
const buttonProps = {
|
||||
size: 'small' as const,
|
||||
'data-testid': 'get-started-button',
|
||||
intent: Intent.Info,
|
||||
const dismiss = useOnboardingStore((store) => store.dismiss);
|
||||
const marketId = useGlobalStore((store) => store.marketId);
|
||||
const link = marketId ? Links[Routes.MARKET](marketId) : Links[Routes.HOME]();
|
||||
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
);
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
let buttonText = t('Get started');
|
||||
let onClickHandle = () => {
|
||||
openVegaWalletDialog();
|
||||
};
|
||||
|
||||
if (step <= OnboardingStep.ONBOARDING_CONNECT_STEP) {
|
||||
return (
|
||||
<TradingButton {...buttonProps} onClick={() => setWalletDialogOpen(true)}>
|
||||
{t('Connect')}
|
||||
</TradingButton>
|
||||
);
|
||||
buttonText = t('Connect');
|
||||
} else if (step === OnboardingStep.ONBOARDING_DEPOSIT_STEP) {
|
||||
return (
|
||||
<TradingAnchorButton
|
||||
{...buttonProps}
|
||||
href={Links[Routes.DEPOSIT]()}
|
||||
onClick={() => setDialogOpen(false)}
|
||||
>
|
||||
{t('Deposit')}
|
||||
</TradingAnchorButton>
|
||||
);
|
||||
} else if (step >= OnboardingStep.ONBOARDING_ORDER_STEP) {
|
||||
return (
|
||||
<TradingAnchorButton
|
||||
{...buttonProps}
|
||||
href={marketId ? Links[Routes.MARKET](marketId) : Links[Routes.HOME]()}
|
||||
onClick={() => {
|
||||
setViews({ type: ViewType.Order }, Routes.MARKET);
|
||||
dismiss();
|
||||
}}
|
||||
>
|
||||
{t('Ready to trade')}
|
||||
</TradingAnchorButton>
|
||||
);
|
||||
buttonText = t('Deposit');
|
||||
onClickHandle = () => {
|
||||
navigate(link);
|
||||
setView({ type: ViewType.Deposit });
|
||||
dismiss();
|
||||
};
|
||||
} else if (step === OnboardingStep.ONBOARDING_ORDER_STEP) {
|
||||
buttonText = t('Ready to trade');
|
||||
onClickHandle = () => {
|
||||
navigate(link);
|
||||
setView({ type: ViewType.Order });
|
||||
setOnboardingViewed('true');
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<TradingButton {...buttonProps} onClick={() => setWalletDialogOpen(true)}>
|
||||
{t('Get started')}
|
||||
<TradingButton
|
||||
onClick={onClickHandle}
|
||||
size="small"
|
||||
data-testid="get-started-button"
|
||||
intent={Intent.Info}
|
||||
>
|
||||
{buttonText}
|
||||
</TradingButton>
|
||||
);
|
||||
};
|
||||
|
||||
export const GetStartedCheckList = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const currentStep = useGetOnboardingStep();
|
||||
return (
|
||||
<ul className="list-none">
|
||||
<Step
|
||||
step={1}
|
||||
text={t('Connect')}
|
||||
complete={Boolean(
|
||||
currentStep > OnboardingStep.ONBOARDING_CONNECT_STEP || pubKey
|
||||
)}
|
||||
/>
|
||||
<Step
|
||||
step={2}
|
||||
text={t('Deposit funds')}
|
||||
complete={currentStep > OnboardingStep.ONBOARDING_DEPOSIT_STEP}
|
||||
/>
|
||||
<Step
|
||||
step={3}
|
||||
text={t('Open a position')}
|
||||
complete={currentStep > OnboardingStep.ONBOARDING_ORDER_STEP}
|
||||
/>
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export const GetStarted = ({ lead }: Props) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { VEGA_ENV, VEGA_NETWORKS } = useEnvironment();
|
||||
const CANONICAL_URL = VEGA_NETWORKS[VEGA_ENV] || 'https://console.vega.xyz';
|
||||
const [onBoardingViewed] = useLocalStorage(constants.ONBOARDING_VIEWED_KEY);
|
||||
const currentStep = useGetOnboardingStep();
|
||||
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
);
|
||||
const currentStep = useGetOnboardingStep();
|
||||
const dismissed = useOnboardingStore((store) => store.dismissed);
|
||||
|
||||
const getStartedNeeded =
|
||||
onBoardingViewed !== 'true' &&
|
||||
currentStep &&
|
||||
currentStep < OnboardingStep.ONBOARDING_COMPLETE_STEP;
|
||||
|
||||
const wrapperClasses = classNames(
|
||||
'flex flex-col py-4 px-6 gap-4 rounded',
|
||||
@@ -118,13 +94,31 @@ export const GetStarted = ({ lead }: Props) => {
|
||||
{ 'mt-8': !lead }
|
||||
);
|
||||
|
||||
if (!dismissed) {
|
||||
if (getStartedNeeded) {
|
||||
return (
|
||||
<div className={wrapperClasses} data-testid="get-started-banner">
|
||||
{lead && <h2>{lead}</h2>}
|
||||
<h3 className="text-lg">{t('Get started')}</h3>
|
||||
<div>
|
||||
<GetStartedCheckList />
|
||||
<ul className="list-none">
|
||||
<Step
|
||||
step={1}
|
||||
text={t('Connect')}
|
||||
complete={Boolean(
|
||||
currentStep > OnboardingStep.ONBOARDING_CONNECT_STEP || pubKey
|
||||
)}
|
||||
/>
|
||||
<Step
|
||||
step={2}
|
||||
text={t('Deposit funds')}
|
||||
complete={currentStep > OnboardingStep.ONBOARDING_DEPOSIT_STEP}
|
||||
/>
|
||||
<Step
|
||||
step={3}
|
||||
text={t('Open a position')}
|
||||
complete={currentStep > OnboardingStep.ONBOARDING_ORDER_STEP}
|
||||
/>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<GetStartedButton step={currentStep} />
|
||||
@@ -132,7 +126,7 @@ export const GetStarted = ({ lead }: Props) => {
|
||||
{VEGA_ENV === Networks.MAINNET && (
|
||||
<p className="text-sm">
|
||||
{t('Experiment for free with virtual assets on')}{' '}
|
||||
<ExternalLink href={VEGA_NETWORKS.TESTNET}>
|
||||
<ExternalLink href={CANONICAL_URL}>
|
||||
{t('Fairground Testnet')}
|
||||
</ExternalLink>
|
||||
</p>
|
||||
@@ -140,7 +134,7 @@ export const GetStarted = ({ lead }: Props) => {
|
||||
{VEGA_ENV === Networks.TESTNET && (
|
||||
<p className="text-sm">
|
||||
{t('Ready to trade with real funds?')}{' '}
|
||||
<ExternalLink href={VEGA_NETWORKS.MAINNET}>
|
||||
<ExternalLink href={CANONICAL_URL}>
|
||||
{t('Switch to Mainnet')}
|
||||
</ExternalLink>
|
||||
</p>
|
||||
|
||||
@@ -41,7 +41,7 @@ export const ProposedMarkets = () => {
|
||||
proposal.terms.change.instrument.code,
|
||||
}));
|
||||
|
||||
const tokenLink = useLinks(DApp.Governance);
|
||||
const tokenLink = useLinks(DApp.Token);
|
||||
return useMemo(
|
||||
() => (
|
||||
<div className="mt-7 pt-8 border-t border-default">
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { depositsProvider } from '@vegaprotocol/deposits';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
@@ -9,33 +7,6 @@ import { aggregatedAccountsDataProvider } from '@vegaprotocol/accounts';
|
||||
import { positionsDataProvider } from '@vegaprotocol/positions';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
|
||||
const ONBOARDING_STORAGE_KEY = 'vega_onboarding';
|
||||
export const useOnboardingStore = create<{
|
||||
dialogOpen: boolean;
|
||||
walletDialogOpen: boolean;
|
||||
dismissed: boolean;
|
||||
dismiss: () => void;
|
||||
setDialogOpen: (isOpen: boolean) => void;
|
||||
setWalletDialogOpen: (isOpen: boolean) => void;
|
||||
}>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
dialogOpen: true,
|
||||
walletDialogOpen: false,
|
||||
dismissed: false,
|
||||
dismiss: () => set({ dismissed: true }),
|
||||
setDialogOpen: (isOpen) => set({ dialogOpen: isOpen }),
|
||||
setWalletDialogOpen: (isOpen) => set({ walletDialogOpen: isOpen }),
|
||||
}),
|
||||
{
|
||||
name: ONBOARDING_STORAGE_KEY,
|
||||
partialize: (state) => ({
|
||||
dismissed: state.dismissed,
|
||||
}),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
export enum OnboardingStep {
|
||||
ONBOARDING_UNKNOWN_STEP,
|
||||
ONBOARDING_WALLET_STEP,
|
||||
|
||||
@@ -1,24 +1,40 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { GetStarted } from './get-started';
|
||||
import { TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useTopTradedMarkets } from '../../lib/hooks/use-top-traded-markets';
|
||||
import { useOnboardingStore } from './use-get-onboarding-step';
|
||||
import { useOnboardingStore } from './welcome-dialog';
|
||||
import { useMarketList } from '@vegaprotocol/markets';
|
||||
import { isMarketActive } from '../../lib/utils';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { priceChangePercentage } from '@vegaprotocol/utils';
|
||||
|
||||
export const WelcomeDialogContent = () => {
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
const setOnboardingDialog = useOnboardingStore(
|
||||
(store) => store.setDialogOpen
|
||||
|
||||
const dismiss = useOnboardingStore((store) => store.dismiss);
|
||||
const navigate = useNavigate();
|
||||
const { data } = useMarketList();
|
||||
const markets = orderBy(
|
||||
data?.filter((m) => isMarketActive(m.state)) || [],
|
||||
[
|
||||
(m) => {
|
||||
if (!m.candles?.length) return 0;
|
||||
return Number(priceChangePercentage(m.candles.map((c) => c.close)));
|
||||
},
|
||||
],
|
||||
['desc']
|
||||
);
|
||||
|
||||
const { data } = useTopTradedMarkets();
|
||||
const marketId = data && data[0]?.id;
|
||||
const link = marketId
|
||||
? Links[Routes.MARKET](marketId)
|
||||
: Links[Routes.MARKETS]();
|
||||
|
||||
const explore = () => {
|
||||
const marketId = markets?.[0].id ?? '';
|
||||
const link = marketId
|
||||
? Links[Routes.MARKET](marketId)
|
||||
: Links[Routes.MARKETS]();
|
||||
navigate(link);
|
||||
dismiss();
|
||||
};
|
||||
const lead =
|
||||
VEGA_ENV === Networks.MAINNET
|
||||
? t('Start trading on the worlds most advanced decentralised exchange.')
|
||||
@@ -27,7 +43,7 @@ export const WelcomeDialogContent = () => {
|
||||
);
|
||||
return (
|
||||
<div className="flex flex-col sm:flex-row gap-8">
|
||||
<div className="flex flex-col justify-between pt-3 sm:w-1/2">
|
||||
<div className="sm:w-1/2 flex flex-col justify-between pt-3">
|
||||
<ul className="ml-0">
|
||||
<ListItemContent
|
||||
icon={<NonCustodialIcon />}
|
||||
@@ -49,16 +65,15 @@ export const WelcomeDialogContent = () => {
|
||||
)}
|
||||
/>
|
||||
</ul>
|
||||
<TradingAnchorButton
|
||||
href={link}
|
||||
onClick={() => setOnboardingDialog(false)}
|
||||
<TradingButton
|
||||
onClick={explore}
|
||||
className="block w-full"
|
||||
data-testid="browse-markets-button"
|
||||
>
|
||||
{t('Explore')}
|
||||
</TradingAnchorButton>
|
||||
</TradingButton>
|
||||
</div>
|
||||
<div className="flex sm:w-1/2 grow">
|
||||
<div className="sm:w-1/2 flex grow">
|
||||
<GetStarted lead={lead} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,10 +90,10 @@ const ListItemContent = ({
|
||||
text: string;
|
||||
}) => {
|
||||
return (
|
||||
<li className="flex my-4 gap-3">
|
||||
<div className="pt-1 shrink-0">{icon}</div>
|
||||
<li className="my-4 flex gap-3">
|
||||
<div className="shrink-0 pt-1">{icon}</div>
|
||||
<div>
|
||||
<h3 className="mb-2 text-lg leading-snug">{title}</h3>
|
||||
<h3 className="text-lg leading-snug mb-2">{title}</h3>
|
||||
<p className="text-sm text-secondary">{text}</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -1,38 +1,115 @@
|
||||
import { Dialog, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import type { Toast } from '@vegaprotocol/ui-toolkit';
|
||||
import { Dialog, Intent, useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { useLocalStorage } from '@vegaprotocol/react-helpers';
|
||||
import { WelcomeDialogContent } from './welcome-dialog-content';
|
||||
import { useOnboardingStore } from './use-get-onboarding-step';
|
||||
import { VegaConnectDialog } from '@vegaprotocol/wallet';
|
||||
import { Connectors } from '../../lib/vega-connectors';
|
||||
import { RiskMessage } from './risk-message';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import {
|
||||
useGetOnboardingStep,
|
||||
OnboardingStep,
|
||||
} from './use-get-onboarding-step';
|
||||
import * as constants from '../constants';
|
||||
import { TelemetryApproval } from './telemetry-approval';
|
||||
import { useTelemetryApproval } from '../../lib/hooks/use-telemetry-approval';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const ONBOARDING_STORAGE_KEY = 'vega_onboarding_dismiss_store';
|
||||
export const useOnboardingStore = create<{
|
||||
dismissed: boolean;
|
||||
dismiss: () => void;
|
||||
}>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
dismissed: false,
|
||||
dismiss: () => set(() => ({ dismissed: true })),
|
||||
}),
|
||||
{
|
||||
name: ONBOARDING_STORAGE_KEY,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const TELEMETRY_APPROVAL_TOAST_ID = 'telemetry_tost_id';
|
||||
export const WelcomeDialog = () => {
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
const dismissed = useOnboardingStore((store) => store.dismissed);
|
||||
const dialogOpen = useOnboardingStore((store) => store.dialogOpen);
|
||||
const navigate = useNavigate();
|
||||
const [telemetryValue, setTelemetryValue, isTelemetryNeeded, closeTelemetry] =
|
||||
useTelemetryApproval();
|
||||
const [onBoardingViewed] = useLocalStorage(constants.ONBOARDING_VIEWED_KEY);
|
||||
const dismiss = useOnboardingStore((store) => store.dismiss);
|
||||
const walletDialogOpen = useOnboardingStore(
|
||||
(store) => store.walletDialogOpen
|
||||
);
|
||||
const setWalletDialogOpen = useOnboardingStore(
|
||||
(store) => store.setWalletDialogOpen
|
||||
const dismissed = useOnboardingStore((store) => store.dismissed);
|
||||
const currentStep = useGetOnboardingStep();
|
||||
const isTelemetryPopupNeeded =
|
||||
isTelemetryNeeded &&
|
||||
(onBoardingViewed === 'true' ||
|
||||
currentStep > OnboardingStep.ONBOARDING_ORDER_STEP);
|
||||
|
||||
const isOnboardingDialogNeeded =
|
||||
onBoardingViewed !== 'true' &&
|
||||
currentStep &&
|
||||
currentStep < OnboardingStep.ONBOARDING_COMPLETE_STEP &&
|
||||
!dismissed;
|
||||
const marketId = useGlobalStore((store) => store.marketId);
|
||||
|
||||
const onClose = () => {
|
||||
if (isTelemetryPopupNeeded) {
|
||||
closeTelemetry();
|
||||
} else {
|
||||
const link = marketId
|
||||
? Links[Routes.MARKET](marketId)
|
||||
: Links[Routes.HOME]();
|
||||
navigate(link);
|
||||
dismiss();
|
||||
}
|
||||
};
|
||||
|
||||
const [setToast, hasToast, removeToast] = useToasts((store) => [
|
||||
store.setToast,
|
||||
store.hasToast,
|
||||
store.remove,
|
||||
]);
|
||||
const onApprovalClose = useCallback(() => {
|
||||
closeTelemetry();
|
||||
removeToast(TELEMETRY_APPROVAL_TOAST_ID);
|
||||
}, [removeToast, closeTelemetry]);
|
||||
|
||||
const setTelemetryApprovalAndClose = useCallback(
|
||||
(value: string) => {
|
||||
setTelemetryValue(value);
|
||||
onApprovalClose();
|
||||
},
|
||||
[setTelemetryValue, onApprovalClose]
|
||||
);
|
||||
|
||||
const content = walletDialogOpen ? (
|
||||
<VegaConnectDialog
|
||||
connectors={Connectors}
|
||||
riskMessage={<RiskMessage />}
|
||||
onClose={() => setWalletDialogOpen(false)}
|
||||
contentOnly
|
||||
/>
|
||||
) : (
|
||||
<WelcomeDialogContent />
|
||||
);
|
||||
if (isTelemetryPopupNeeded) {
|
||||
const toast: Toast = {
|
||||
id: TELEMETRY_APPROVAL_TOAST_ID,
|
||||
intent: Intent.Primary,
|
||||
content: (
|
||||
<>
|
||||
<h3 className="mb-1 text-sm uppercase">
|
||||
{t('Improve vega console')}
|
||||
</h3>
|
||||
<TelemetryApproval
|
||||
telemetryValue={telemetryValue}
|
||||
setTelemetryValue={setTelemetryApprovalAndClose}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
onClose: onApprovalClose,
|
||||
};
|
||||
if (!hasToast(TELEMETRY_APPROVAL_TOAST_ID)) {
|
||||
setToast(toast);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const onClose = walletDialogOpen ? () => setWalletDialogOpen(false) : dismiss;
|
||||
|
||||
const title = walletDialogOpen ? null : (
|
||||
const title = (
|
||||
<span className="font-alpha calt" data-testid="welcome-title">
|
||||
{t('Console')}{' '}
|
||||
<span className="text-vega-clight-100 dark:text-vega-cdark-100">
|
||||
@@ -41,16 +118,16 @@ export const WelcomeDialog = () => {
|
||||
</span>
|
||||
);
|
||||
|
||||
return (
|
||||
return isOnboardingDialogNeeded ? (
|
||||
<Dialog
|
||||
open={dismissed ? false : dialogOpen}
|
||||
open
|
||||
title={title}
|
||||
size="medium"
|
||||
onChange={onClose}
|
||||
intent={Intent.None}
|
||||
dataTestId="welcome-dialog"
|
||||
>
|
||||
{content}
|
||||
<WelcomeDialogContent />
|
||||
</Dialog>
|
||||
);
|
||||
) : null;
|
||||
};
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
|
||||
export const WithdrawalsMenu = () => {
|
||||
const setViews = useSidebar((store) => store.setViews);
|
||||
const currentRouteId = useGetCurrentRouteId();
|
||||
const setView = useSidebar((store) => store.setView);
|
||||
|
||||
return (
|
||||
<TradingButton
|
||||
size="extra-small"
|
||||
onClick={() => setViews({ type: ViewType.Withdraw }, currentRouteId)}
|
||||
onClick={() => setView({ type: ViewType.Withdraw })}
|
||||
data-testid="withdraw-dialog-button"
|
||||
>
|
||||
{t('Make withdrawal')}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { routerConfig } from '../../pages/client-router';
|
||||
import { matchRoutes, useLocation } from 'react-router-dom';
|
||||
|
||||
export const useGetCurrentRouteId = () => {
|
||||
const location = useLocation();
|
||||
const currentRoute = matchRoutes(routerConfig, location);
|
||||
const lastRoute = currentRoute?.pop();
|
||||
if (lastRoute) {
|
||||
const {
|
||||
route: { id },
|
||||
} = lastRoute;
|
||||
return id || '';
|
||||
}
|
||||
return '';
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { calcTradedFactor, useMarketList } from '@vegaprotocol/markets';
|
||||
import { isMarketActive } from '../utils';
|
||||
|
||||
export const useTopTradedMarkets = () => {
|
||||
const { data, loading, error } = useMarketList();
|
||||
|
||||
const activeMarkets = data?.filter((m) => isMarketActive(m.state));
|
||||
const marketsByTopTraded = data
|
||||
? orderBy(activeMarkets, (m) => calcTradedFactor(m), 'desc')
|
||||
: undefined;
|
||||
return { data: marketsByTopTraded, loading, error };
|
||||
};
|
||||
@@ -38,7 +38,7 @@ import { AppLoader, DynamicLoader } from '../components/app-loader';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { activeOrdersProvider } from '@vegaprotocol/orders';
|
||||
import { useTelemetryApproval } from '../lib/hooks/use-telemetry-approval';
|
||||
import { AnnouncementBanner } from '../components/banner';
|
||||
import { AnnouncementBanner, UpgradeBanner } from '../components/banner';
|
||||
import { Navbar } from '../components/navbar';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
@@ -49,7 +49,6 @@ import {
|
||||
import { ViewingBanner } from '../components/viewing-banner';
|
||||
import { NavHeader } from '../components/navbar/nav-header';
|
||||
import { Routes as AppRoutes } from './client-router';
|
||||
import { Telemetry } from '../components/telemetry';
|
||||
|
||||
const DEFAULT_TITLE = t('Welcome to Vega trading!');
|
||||
|
||||
@@ -115,6 +114,7 @@ function AppBody({ Component }: AppProps) {
|
||||
/>
|
||||
<ProtocolUpgradeInProgressNotification />
|
||||
<ViewingBanner />
|
||||
<UpgradeBanner showVersionChange={true} />
|
||||
</div>
|
||||
<div data-testid={`pathname-${location.pathname}`}>
|
||||
<Component />
|
||||
@@ -125,7 +125,6 @@ function AppBody({ Component }: AppProps) {
|
||||
<InitializeHandlers />
|
||||
<MaybeConnectEagerly />
|
||||
<PartyData />
|
||||
<Telemetry />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,24 +4,33 @@ export default function Document() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
{/*
|
||||
{/*
|
||||
meta tags
|
||||
- next advised against using _document for this, so they exist in our
|
||||
- next advised against using _document for this, so they exist in our
|
||||
- single page index.page.tsx
|
||||
*/}
|
||||
|
||||
{/* preload fonts */}
|
||||
{/* icons */}
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
href="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
content="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
|
||||
{/* fonts */}
|
||||
<link
|
||||
rel="preload"
|
||||
href="/AlphaLyrae-Medium.woff2"
|
||||
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
/>
|
||||
|
||||
{/* icons */}
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link rel="apple-touch-icon" content="/favicon.ico" />
|
||||
|
||||
{/* styles */}
|
||||
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
|
||||
{/* eslint-disable-next-line @next/next/no-css-tags */}
|
||||
<link rel="stylesheet" href="/preloader.css" media="all" />
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ export const Links: ConsoleLinks = {
|
||||
[Routes.DEPOSIT]: () => Routes.DEPOSIT,
|
||||
};
|
||||
|
||||
export const routerConfig: RouteObject[] = [
|
||||
const routerConfig: RouteObject[] = [
|
||||
{
|
||||
path: '/*',
|
||||
element: <LayoutWithSidebar />,
|
||||
@@ -68,7 +68,6 @@ export const routerConfig: RouteObject[] = [
|
||||
{
|
||||
index: true,
|
||||
element: <LazyHome />,
|
||||
id: Routes.HOME,
|
||||
},
|
||||
{
|
||||
path: 'markets',
|
||||
@@ -77,19 +76,16 @@ export const routerConfig: RouteObject[] = [
|
||||
{
|
||||
path: 'all',
|
||||
element: <LazyMarkets />,
|
||||
id: Routes.MARKETS,
|
||||
},
|
||||
{
|
||||
path: ':marketId',
|
||||
element: <LazyMarket />,
|
||||
id: Routes.MARKET,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'portfolio',
|
||||
element: <LazyPortfolio />,
|
||||
id: Routes.PORTFOLIO,
|
||||
},
|
||||
{
|
||||
path: 'liquidity',
|
||||
@@ -98,7 +94,6 @@ export const routerConfig: RouteObject[] = [
|
||||
{
|
||||
path: ':marketId',
|
||||
element: <LazyLiquidity />,
|
||||
id: Routes.LIQUIDITY,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -19,11 +19,17 @@ export default function Index() {
|
||||
<meta name="og:url" content="https://console.vega.xyz/" />
|
||||
<meta name="og:title" content="Vega Protocol - Console" />
|
||||
<meta name="og:site_name" content="Vega Protocol - Console" />
|
||||
<meta name="og:image" content="./favicon.ico" />
|
||||
<meta name="twitter:card" content="./favicon.ico" />
|
||||
<meta name="og:image" content="https://static.vega.xyz/favicon.ico" />
|
||||
<meta
|
||||
name="twitter:card"
|
||||
content="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<meta name="twitter:title" content="Vega Protocol - Console" />
|
||||
<meta name="twitter:description" content="Vega Protocol - Console" />
|
||||
<meta name="twitter:image" content="./favicon.ico" />
|
||||
<meta
|
||||
name="twitter:image"
|
||||
content="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<meta name="twitter:image:alt" content="VEGA logo" />
|
||||
<meta name="twitter:site" content="@vegaprotocol" />
|
||||
</Head>
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
@import 'ag-grid-community/styles/ag-grid.css';
|
||||
@import 'ag-grid-community/styles/ag-theme-balham.css';
|
||||
|
||||
/** Load AlphaLyrae font */
|
||||
@font-face {
|
||||
font-family: AlphaLyrae;
|
||||
src: url('/AlphaLyrae-Medium.woff2') format('woff2'),
|
||||
url('/AlphaLyrae-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -90,7 +83,8 @@ html [data-theme='light'] {
|
||||
--pennant-color-volume-sell: theme(colors.market.red.DEFAULT);
|
||||
|
||||
/* reduce space between candles */
|
||||
--pennant-candlestick-inner-padding: 0.25;
|
||||
--pennant-candlestick-inner-padding: 0.175;
|
||||
--pennant-candlestick-stroke-width: 0.5;
|
||||
}
|
||||
|
||||
html [data-theme='light'] {
|
||||
@@ -110,8 +104,8 @@ html [data-theme='light'] {
|
||||
--pennant-color-depth-sell-fill: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-depth-sell-stroke: theme(colors.market.red.650);
|
||||
|
||||
--pennant-color-volume-buy: theme(colors.market.green.DEFAULT);
|
||||
--pennant-color-volume-sell: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-volume-buy: theme(colors.market.green.300);
|
||||
--pennant-color-volume-sell: theme(colors.market.red.300);
|
||||
}
|
||||
|
||||
html [data-theme='dark'] {
|
||||
@@ -132,7 +126,7 @@ html [data-theme='dark'] {
|
||||
--pennant-color-depth-sell-stroke: theme(colors.market.red.DEFAULT);
|
||||
|
||||
--pennant-color-volume-buy: theme(colors.market.green.600);
|
||||
--pennant-color-volume-sell: theme(colors.market.red.DEFAULT);
|
||||
--pennant-color-volume-sell: theme(colors.market.red.650);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,22 +162,11 @@ html [data-theme='dark'] {
|
||||
@apply font-normal font-alpha;
|
||||
}
|
||||
|
||||
.ag-theme-balham,
|
||||
.ag-theme-balham-dark {
|
||||
--ag-grid-size: 2px; /* Used for compactness */
|
||||
--ag-row-height: 36px;
|
||||
--ag-header-height: 28px;
|
||||
}
|
||||
|
||||
@media (min-width: theme(screens.xxl)) {
|
||||
.ag-theme-balham,
|
||||
.ag-theme-balham-dark {
|
||||
--ag-header-height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Light variables */
|
||||
.ag-theme-balham {
|
||||
--ag-grid-size: 2px; /* Used for compactness */
|
||||
--ag-row-height: 36px;
|
||||
--ag-header-height: 36px;
|
||||
--ag-background-color: theme(colors.white);
|
||||
--ag-border-color: theme(colors.vega.clight.600);
|
||||
--ag-header-background-color: theme(colors.vega.clight.700);
|
||||
@@ -196,6 +179,9 @@ html [data-theme='dark'] {
|
||||
|
||||
/* Dark variables */
|
||||
.ag-theme-balham-dark {
|
||||
--ag-grid-size: 2px; /* Used for compactness */
|
||||
--ag-row-height: 36px;
|
||||
--ag-header-height: 36px;
|
||||
--ag-background-color: theme(colors.vega.cdark.900);
|
||||
--ag-border-color: theme(colors.vega.cdark.600);
|
||||
--ag-header-background-color: theme(colors.vega.cdark.700);
|
||||
@@ -205,7 +191,6 @@ html [data-theme='dark'] {
|
||||
--ag-row-hover-color: theme(colors.vega.cdark.800);
|
||||
--ag-modal-overlay-background-color: rgb(9 11 16 / 50%);
|
||||
}
|
||||
|
||||
.ag-theme-balham-dark .ag-row.no-hover,
|
||||
.ag-theme-balham-dark .ag-row.no-hover:hover,
|
||||
.ag-theme-balham .ag-row.no-hover,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 101 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.2 KiB |
@@ -20,7 +20,6 @@ RUN sh docker/docker-build.sh
|
||||
FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
|
||||
# configuration of system
|
||||
EXPOSE 80
|
||||
COPY docker/run-ipfs.sh /run-ipfs.sh
|
||||
# Copy dist
|
||||
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
RUN rm -rf /usr/share/nginx/html/*
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
|
||||
EXPOSE 80
|
||||
COPY docker/run-ipfs.sh /run-ipfs.sh
|
||||
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
RUN rm -rf /usr/share/nginx/html/*
|
||||
COPY ./dist-result/ /usr/share/nginx/html/
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
ipfs config profile apply server
|
||||
ipfs config --json Addresses.Gateway '"/ip4/127.0.0.1/tcp/80"'
|
||||
ipfs daemon
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
VegaIconNames,
|
||||
TooltipCellComponent,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import type {
|
||||
IGetRowsParams,
|
||||
IRowNode,
|
||||
|
||||
@@ -13,7 +13,7 @@ import type {
|
||||
VegaICellRendererParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { ProgressBarCell } from '@vegaprotocol/datagrid';
|
||||
import { AgGrid, PriceCell } from '@vegaprotocol/datagrid';
|
||||
import { AgGridLazy as AgGrid, PriceCell } from '@vegaprotocol/datagrid';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
import { accountValuesComparator } from './accounts-table';
|
||||
import { MarginHealthChart } from './margin-health-chart';
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
export type AnnouncementBannerProps = {
|
||||
app: AppNameType;
|
||||
configUrl: string;
|
||||
background?: string;
|
||||
};
|
||||
|
||||
// run only if below the allowed maximum delay ~24.8 days (https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value)
|
||||
@@ -37,7 +36,6 @@ const doesEndInTheFuture = (now: Date, data: Announcement) => {
|
||||
export const AnnouncementBanner = ({
|
||||
app,
|
||||
configUrl,
|
||||
background,
|
||||
}: AnnouncementBannerProps) => {
|
||||
const [isVisible, setVisible] = useState(false);
|
||||
const { data, reload } = useAnnouncement(app, configUrl);
|
||||
@@ -81,10 +79,10 @@ export const AnnouncementBanner = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Banner className="relative px-10" background={background}>
|
||||
<Banner className="relative px-10">
|
||||
<div
|
||||
data-testid="app-announcement"
|
||||
className="relative flex justify-center text-lg text-center text-white font-alpha gap-2"
|
||||
className="relative font-alpha flex gap-2 justify-center text-center text-lg text-white"
|
||||
>
|
||||
<span>{data.text}</span>{' '}
|
||||
{data.urlText && data.url && (
|
||||
@@ -92,7 +90,7 @@ export const AnnouncementBanner = ({
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
className="absolute top-0 right-0 flex items-center justify-center w-10 h-full p-4 text-white"
|
||||
className="absolute right-0 top-0 p-4 w-10 h-full flex items-center justify-center text-white"
|
||||
data-testid="app-announcement-close"
|
||||
onClick={() => {
|
||||
setVisible(false);
|
||||
|
||||
@@ -8,16 +8,13 @@ import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
STUDY_SIZE,
|
||||
useCandlesChartSettings,
|
||||
} from './use-candles-chart-settings';
|
||||
import { useCandlesChartSettings } from './use-candles-chart-settings';
|
||||
|
||||
export type CandlesChartContainerProps = {
|
||||
marketId: string;
|
||||
};
|
||||
|
||||
const CANDLES_TO_WIDTH_FACTOR = 0.2;
|
||||
const CANDLES_TO_WIDTH_FACTOR = 0.15;
|
||||
|
||||
export const CandlesChartContainer = ({
|
||||
marketId,
|
||||
@@ -52,34 +49,33 @@ export const CandlesChartContainer = ({
|
||||
|
||||
return (
|
||||
<AutoSizer>
|
||||
{({ width, height }) => {
|
||||
const candlesCount = Math.floor(width * CANDLES_TO_WIDTH_FACTOR);
|
||||
return (
|
||||
<div style={{ width, height }}>
|
||||
<CandlestickChart
|
||||
dataSource={dataSource}
|
||||
options={{
|
||||
chartType,
|
||||
overlays,
|
||||
studies,
|
||||
notEnoughDataText: (
|
||||
<span className="text-xs text-center">{t('No data')}</span>
|
||||
),
|
||||
initialNumCandlesToDisplay: candlesCount,
|
||||
studySize: STUDY_SIZE,
|
||||
studySizes,
|
||||
}}
|
||||
interval={interval}
|
||||
theme={theme}
|
||||
onOptionsChanged={(options) => {
|
||||
setStudies(options.studies);
|
||||
setOverlays(options.overlays);
|
||||
}}
|
||||
onPaneChanged={handlePaneChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
{({ width, height }) => (
|
||||
<div style={{ width, height }}>
|
||||
<CandlestickChart
|
||||
dataSource={dataSource}
|
||||
options={{
|
||||
chartType,
|
||||
overlays,
|
||||
studies,
|
||||
notEnoughDataText: (
|
||||
<span className="text-xs text-center">{t('No data')}</span>
|
||||
),
|
||||
initialNumCandlesToDisplay: Math.floor(
|
||||
width * CANDLES_TO_WIDTH_FACTOR
|
||||
),
|
||||
studySize: 150, // default size
|
||||
studySizes,
|
||||
}}
|
||||
interval={interval}
|
||||
theme={theme}
|
||||
onOptionsChanged={(options) => {
|
||||
setStudies(options.studies);
|
||||
setOverlays(options.overlays);
|
||||
}}
|
||||
onPaneChanged={handlePaneChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</AutoSizer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ interface StoredSettings {
|
||||
studySizes: StudySizes;
|
||||
}
|
||||
|
||||
export const STUDY_SIZE = 90;
|
||||
export const STUDY_SIZE = 100;
|
||||
const STUDY_ORDER: Study[] = [
|
||||
Study.FORCE_INDEX,
|
||||
Study.RELATIVE_STRENGTH_INDEX,
|
||||
|
||||
@@ -61,15 +61,10 @@ export function addVegaWalletConnect() {
|
||||
});
|
||||
}
|
||||
|
||||
const onboardingViewedState = { state: { dismissed: true }, version: 0 };
|
||||
|
||||
export function addSetVegaWallet() {
|
||||
Cypress.Commands.add('setVegaWallet', () => {
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem(
|
||||
'vega_onboarding',
|
||||
JSON.stringify(onboardingViewedState)
|
||||
);
|
||||
win.localStorage.setItem('vega_onboarding_viewed', 'true');
|
||||
win.localStorage.setItem('vega_telemetry_approval', 'false');
|
||||
win.localStorage.setItem('vega_telemetry_viewed', 'true');
|
||||
win.localStorage.setItem(
|
||||
@@ -87,10 +82,7 @@ export function addSetVegaWallet() {
|
||||
export function addSetOnBoardingViewed() {
|
||||
Cypress.Commands.add('setOnBoardingViewed', () => {
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem(
|
||||
'vega_onboarding',
|
||||
JSON.stringify(onboardingViewedState)
|
||||
);
|
||||
win.localStorage.setItem('vega_onboarding_viewed', 'true');
|
||||
win.localStorage.setItem('vega_telemetry_approval', 'false');
|
||||
win.localStorage.setItem('vega_telemetry_viewed', 'true');
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from './lib/ag-grid/ag-grid';
|
||||
export * from './lib/ag-grid/ag-grid-lazy';
|
||||
|
||||
export * from './lib/column-definitions';
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { forwardRef, lazy } from 'react';
|
||||
import type { AgGridReactProps, AgGridReact } from 'ag-grid-react';
|
||||
|
||||
type Props = AgGridReactProps & {
|
||||
style?: React.CSSProperties;
|
||||
gridRef?: React.Ref<AgGridReact>;
|
||||
};
|
||||
|
||||
export const AgGridLazyInternal = lazy(() =>
|
||||
import('./ag-grid-lazy-themed').then((module) => ({
|
||||
default: module.AgGridThemed,
|
||||
}))
|
||||
);
|
||||
|
||||
export const AgGridLazy = forwardRef<AgGridReact, Props>((props, ref) => (
|
||||
<AgGridLazyInternal {...props} gridRef={ref} />
|
||||
));
|
||||
@@ -1,12 +0,0 @@
|
||||
import { forwardRef } from 'react';
|
||||
import type { AgGridReactProps, AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridThemed } from './ag-grid-themed';
|
||||
|
||||
type Props = AgGridReactProps & {
|
||||
style?: React.CSSProperties;
|
||||
gridRef?: React.Ref<AgGridReact>;
|
||||
};
|
||||
|
||||
export const AgGrid = forwardRef<AgGridReact, Props>((props, ref) => (
|
||||
<AgGridThemed {...props} gridRef={ref} />
|
||||
));
|
||||
@@ -1,6 +1,9 @@
|
||||
import { act, render, waitFor } from '@testing-library/react';
|
||||
import { useDataGridEvents } from './use-datagrid-events';
|
||||
import { AgGridThemed } from './ag-grid/ag-grid-themed';
|
||||
import {
|
||||
useDataGridEvents,
|
||||
GRID_EVENT_DEBOUNCE_TIME,
|
||||
} from './use-datagrid-events';
|
||||
import { AgGridThemed } from './ag-grid/ag-grid-lazy-themed';
|
||||
import type { MutableRefObject } from 'react';
|
||||
import { useRef } from 'react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
@@ -16,29 +19,25 @@ const gridProps = {
|
||||
],
|
||||
style: { width: 500, height: 300 },
|
||||
};
|
||||
const GRID_EVENT_DEBOUNCE_TIME = 300;
|
||||
let gridRef: MutableRefObject<AgGridReact | null>;
|
||||
function TestComponent({
|
||||
hookParams,
|
||||
}: {
|
||||
hookParams: Parameters<typeof useDataGridEvents>;
|
||||
}) {
|
||||
const hookCallbacks = useDataGridEvents(...hookParams);
|
||||
gridRef = useRef<AgGridReact | null>(null);
|
||||
return <AgGridThemed gridRef={gridRef} {...gridProps} {...hookCallbacks} />;
|
||||
}
|
||||
|
||||
// Not using render hook so I can pass event callbacks
|
||||
// to a rendered grid
|
||||
function setup(...args: Parameters<typeof useDataGridEvents>) {
|
||||
return render(<TestComponent hookParams={args} />);
|
||||
let gridRef;
|
||||
|
||||
function TestComponent() {
|
||||
const hookCallbacks = useDataGridEvents(...args);
|
||||
gridRef = useRef<AgGridReact | null>(null);
|
||||
return <AgGridThemed gridRef={gridRef} {...gridProps} {...hookCallbacks} />;
|
||||
}
|
||||
render(<TestComponent />);
|
||||
return gridRef as unknown as MutableRefObject<AgGridReact>;
|
||||
}
|
||||
|
||||
describe('useDataGridEvents', () => {
|
||||
const originalWarn = console.warn;
|
||||
|
||||
beforeAll(() => {
|
||||
gridRef = undefined;
|
||||
jest.useFakeTimers();
|
||||
|
||||
// disabling some ag grid warnings that are caused by test setup only
|
||||
@@ -57,15 +56,15 @@ describe('useDataGridEvents', () => {
|
||||
columnState: undefined,
|
||||
};
|
||||
|
||||
setup(initialState, callback);
|
||||
const result = setup(initialState, callback);
|
||||
|
||||
// column state was not updated, so the default width provided by the
|
||||
// col def should be set
|
||||
expect(gridRef.current?.columnApi.getColumnState()[0].width).toEqual(
|
||||
expect(result.current.columnApi.getColumnState()[0].width).toEqual(
|
||||
gridProps.columnDefs[0].width
|
||||
);
|
||||
// no filters set
|
||||
expect(gridRef.current?.api.getFilterModel()).toEqual({});
|
||||
expect(result.current.api.getFilterModel()).toEqual({});
|
||||
|
||||
// Set filter
|
||||
const idFilter = {
|
||||
@@ -74,7 +73,7 @@ describe('useDataGridEvents', () => {
|
||||
type: 'equals',
|
||||
};
|
||||
await act(async () => {
|
||||
gridRef.current?.api.setFilterModel({
|
||||
result.current.api.setFilterModel({
|
||||
id: idFilter,
|
||||
});
|
||||
});
|
||||
@@ -90,7 +89,7 @@ describe('useDataGridEvents', () => {
|
||||
},
|
||||
});
|
||||
callback.mockClear();
|
||||
expect(gridRef.current?.api.getFilterModel()['id']).toEqual(idFilter);
|
||||
expect(result.current.api.getFilterModel()['id']).toEqual(idFilter);
|
||||
});
|
||||
|
||||
it('applies grid state on ready', async () => {
|
||||
@@ -107,11 +106,11 @@ describe('useDataGridEvents', () => {
|
||||
columnState: [colState],
|
||||
};
|
||||
|
||||
setup(initialState, jest.fn());
|
||||
const result = setup(initialState, jest.fn());
|
||||
|
||||
await waitFor(() => {
|
||||
expect(gridRef.current?.api.getFilterModel()['id']).toEqual(idFilter);
|
||||
expect(gridRef.current?.columnApi.getColumnState()[0]).toEqual(
|
||||
expect(result.current.api.getFilterModel()['id']).toEqual(idFilter);
|
||||
expect(result.current.columnApi.getColumnState()[0]).toEqual(
|
||||
expect.objectContaining(colState)
|
||||
);
|
||||
});
|
||||
@@ -124,13 +123,13 @@ describe('useDataGridEvents', () => {
|
||||
columnState: undefined,
|
||||
};
|
||||
|
||||
setup(initialState, callback);
|
||||
const result = setup(initialState, callback);
|
||||
|
||||
const newWidth = 400;
|
||||
|
||||
// Set col width multiple times
|
||||
await act(async () => {
|
||||
gridRef.current?.columnApi.setColumnWidth('id', newWidth);
|
||||
result.current.columnApi.setColumnWidth('id', newWidth);
|
||||
});
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
@@ -141,23 +140,4 @@ describe('useDataGridEvents', () => {
|
||||
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('columns for autosizing should be handle', () => {
|
||||
const callback = jest.fn();
|
||||
const initialState = {
|
||||
filterModel: undefined,
|
||||
columnState: undefined,
|
||||
};
|
||||
|
||||
const { rerender } = setup(initialState, callback, ['id']);
|
||||
jest.spyOn(gridRef.current?.columnApi, 'autoSizeColumns');
|
||||
rerender(<TestComponent hookParams={[initialState, callback, ['id']]} />);
|
||||
act(() => {
|
||||
gridRef.current?.api.setRowData([{ id: 'test-id' }]);
|
||||
jest.advanceTimersByTime(GRID_EVENT_DEBOUNCE_TIME);
|
||||
});
|
||||
expect(gridRef.current?.columnApi.autoSizeColumns).toHaveBeenCalledWith([
|
||||
'id',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,6 @@ import type {
|
||||
FilterChangedEvent,
|
||||
FirstDataRenderedEvent,
|
||||
SortChangedEvent,
|
||||
GridReadyEvent,
|
||||
} from 'ag-grid-community';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
@@ -18,8 +17,7 @@ type State = {
|
||||
|
||||
export const useDataGridEvents = (
|
||||
state: State,
|
||||
callback: (data: State) => void,
|
||||
autoSizeColumns?: string[]
|
||||
callback: (data: State) => void
|
||||
) => {
|
||||
/**
|
||||
* Callback for filter events
|
||||
@@ -80,7 +78,7 @@ export const useDataGridEvents = (
|
||||
* State only applied if found, otherwise columns sized to fit available space
|
||||
*/
|
||||
const onGridReady = useCallback(
|
||||
({ api, columnApi }: GridReadyEvent) => {
|
||||
({ api, columnApi }: FirstDataRenderedEvent) => {
|
||||
if (!api || !columnApi) return;
|
||||
|
||||
if (state.columnState) {
|
||||
@@ -99,16 +97,6 @@ export const useDataGridEvents = (
|
||||
[state]
|
||||
);
|
||||
|
||||
const onFirstDataRendered = useCallback(
|
||||
({ columnApi }: FirstDataRenderedEvent) => {
|
||||
if (!columnApi) return;
|
||||
if (!state?.columnState && autoSizeColumns?.length) {
|
||||
columnApi.autoSizeColumns(autoSizeColumns);
|
||||
}
|
||||
},
|
||||
[state, autoSizeColumns]
|
||||
);
|
||||
|
||||
return {
|
||||
onGridReady,
|
||||
// these events don't use the 'finished' flag
|
||||
@@ -118,6 +106,5 @@ export const useDataGridEvents = (
|
||||
// these trigger a lot so this callback uses the 'finished' flag
|
||||
onColumnMoved: onDebouncedColumnChange,
|
||||
onColumnResized: onDebouncedColumnChange,
|
||||
onFirstDataRendered,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -12,7 +12,6 @@ import { formatRange, formatValue } from '@vegaprotocol/utils';
|
||||
import { marketMarginDataProvider } from '@vegaprotocol/accounts';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
import {
|
||||
MARGIN_DIFF_TOOLTIP_TEXT,
|
||||
@@ -38,16 +37,14 @@ export interface DealTicketFeeDetailsProps {
|
||||
assetSymbol: string;
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
market: Market;
|
||||
isMarketInAuction?: boolean;
|
||||
}
|
||||
|
||||
export const DealTicketFeeDetails = ({
|
||||
assetSymbol,
|
||||
order,
|
||||
market,
|
||||
isMarketInAuction,
|
||||
}: DealTicketFeeDetailsProps) => {
|
||||
const feeEstimate = useEstimateFees(order, isMarketInAuction);
|
||||
const feeEstimate = useEstimateFees(order);
|
||||
const { settlementAsset: asset } =
|
||||
market.tradableInstrument.instrument.product;
|
||||
const { decimals: assetDecimals, quantum } = asset;
|
||||
@@ -67,7 +64,7 @@ export const DealTicketFeeDetails = ({
|
||||
<>
|
||||
<span>
|
||||
{t(
|
||||
`An estimate of the most you would be expected to pay in fees, in the market's settlement asset ${assetSymbol}. Fees estimated are "taker" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.`
|
||||
`An estimate of the most you would be expected to pay in fees, in the market's settlement asset ${assetSymbol}.`
|
||||
)}
|
||||
</span>
|
||||
<FeesBreakdown
|
||||
@@ -90,7 +87,6 @@ export interface DealTicketMarginDetailsProps {
|
||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
assetSymbol: string;
|
||||
positionEstimate: EstimatePositionQuery['estimatePosition'];
|
||||
side: Schema.Side;
|
||||
}
|
||||
|
||||
export const DealTicketMarginDetails = ({
|
||||
@@ -100,7 +96,6 @@ export const DealTicketMarginDetails = ({
|
||||
market,
|
||||
onMarketClick,
|
||||
positionEstimate,
|
||||
side,
|
||||
}: DealTicketMarginDetailsProps) => {
|
||||
const [breakdownDialog, setBreakdownDialog] = useState(false);
|
||||
const { pubKey: partyId } = useVegaWallet();
|
||||
@@ -170,7 +165,10 @@ export const DealTicketMarginDetails = ({
|
||||
: '0',
|
||||
assetDecimals
|
||||
)}
|
||||
formattedValue={formatValue(
|
||||
formattedValue={formatRange(
|
||||
deductionFromCollateralBestCase > 0
|
||||
? deductionFromCollateralBestCase.toString()
|
||||
: '0',
|
||||
deductionFromCollateralWorstCase > 0
|
||||
? deductionFromCollateralWorstCase.toString()
|
||||
: '0',
|
||||
@@ -189,7 +187,8 @@ export const DealTicketMarginDetails = ({
|
||||
marginEstimate?.worstCase.initialLevel,
|
||||
assetDecimals
|
||||
)}
|
||||
formattedValue={formatValue(
|
||||
formattedValue={formatRange(
|
||||
marginEstimate?.bestCase.initialLevel,
|
||||
marginEstimate?.worstCase.initialLevel,
|
||||
assetDecimals,
|
||||
quantum
|
||||
@@ -201,7 +200,6 @@ export const DealTicketMarginDetails = ({
|
||||
}
|
||||
|
||||
let liquidationPriceEstimate = emptyValue;
|
||||
let liquidationPriceEstimateRange = emptyValue;
|
||||
|
||||
if (liquidationEstimate) {
|
||||
const liquidationEstimateBestCaseIncludingBuyOrders = BigInt(
|
||||
@@ -211,7 +209,8 @@ export const DealTicketMarginDetails = ({
|
||||
liquidationEstimate.bestCase.including_sell_orders.replace(/\..*/, '')
|
||||
);
|
||||
const liquidationEstimateBestCase =
|
||||
side === Schema.Side.SIDE_BUY
|
||||
liquidationEstimateBestCaseIncludingBuyOrders >
|
||||
liquidationEstimateBestCaseIncludingSellOrders
|
||||
? liquidationEstimateBestCaseIncludingBuyOrders
|
||||
: liquidationEstimateBestCaseIncludingSellOrders;
|
||||
|
||||
@@ -222,19 +221,14 @@ export const DealTicketMarginDetails = ({
|
||||
liquidationEstimate.worstCase.including_sell_orders.replace(/\..*/, '')
|
||||
);
|
||||
const liquidationEstimateWorstCase =
|
||||
side === Schema.Side.SIDE_BUY
|
||||
liquidationEstimateWorstCaseIncludingBuyOrders >
|
||||
liquidationEstimateWorstCaseIncludingSellOrders
|
||||
? liquidationEstimateWorstCaseIncludingBuyOrders
|
||||
: liquidationEstimateWorstCaseIncludingSellOrders;
|
||||
|
||||
// The estimate order query API gives us the liquidation price in formatted by asset decimals.
|
||||
// We need to calculate it with asset decimals, but display it with market decimals precision until the API changes.
|
||||
liquidationPriceEstimate = formatValue(
|
||||
liquidationEstimateWorstCase.toString(),
|
||||
assetDecimals,
|
||||
undefined,
|
||||
market.decimalPlaces
|
||||
);
|
||||
liquidationPriceEstimateRange = formatRange(
|
||||
liquidationPriceEstimate = formatRange(
|
||||
(liquidationEstimateBestCase < liquidationEstimateWorstCase
|
||||
? liquidationEstimateBestCase
|
||||
: liquidationEstimateWorstCase
|
||||
@@ -290,9 +284,11 @@ export const DealTicketMarginDetails = ({
|
||||
assetDecimals
|
||||
) ?? '-'
|
||||
}
|
||||
noUnderline
|
||||
>
|
||||
<div className="font-mono text-right">
|
||||
{formatValue(
|
||||
{formatRange(
|
||||
marginRequiredBestCase,
|
||||
marginRequiredWorstCase,
|
||||
assetDecimals,
|
||||
quantum
|
||||
@@ -350,7 +346,7 @@ export const DealTicketMarginDetails = ({
|
||||
{projectedMargin}
|
||||
<KeyValue
|
||||
label={t('Liquidation')}
|
||||
value={liquidationPriceEstimateRange}
|
||||
value={liquidationPriceEstimate}
|
||||
formattedValue={liquidationPriceEstimate}
|
||||
symbol={quoteName}
|
||||
labelDescription={LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT}
|
||||
|
||||
@@ -26,7 +26,10 @@ import {
|
||||
Pill,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
import { useOpenVolume } from '@vegaprotocol/positions';
|
||||
import {
|
||||
useEstimatePositionQuery,
|
||||
useOpenVolume,
|
||||
} from '@vegaprotocol/positions';
|
||||
import {
|
||||
toBigNum,
|
||||
removeDecimal,
|
||||
@@ -36,7 +39,7 @@ import {
|
||||
formatValue,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { activeOrdersProvider } from '@vegaprotocol/orders';
|
||||
import { getDerivedPrice, isMarketInAuction } from '@vegaprotocol/markets';
|
||||
import { getDerivedPrice } from '@vegaprotocol/markets';
|
||||
import {
|
||||
validateExpiration,
|
||||
validateMarketState,
|
||||
@@ -60,14 +63,13 @@ import {
|
||||
useAccountBalance,
|
||||
} from '@vegaprotocol/accounts';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import type { OrderFormValues } from '../../hooks';
|
||||
import {
|
||||
DealTicketType,
|
||||
dealTicketTypeToOrderType,
|
||||
isStopOrderType,
|
||||
useDealTicketFormValues,
|
||||
usePositionEstimate,
|
||||
} from '../../hooks';
|
||||
} from '../../hooks/use-form-values';
|
||||
import type { OrderFormValues } from '../../hooks/use-form-values';
|
||||
import { useDealTicketFormValues } from '../../hooks/use-form-values';
|
||||
import { DealTicketSizeIceberg } from './deal-ticket-size-iceberg';
|
||||
import noop from 'lodash/noop';
|
||||
import { isNonPersistentOrder } from '../../utils/time-in-force-persistance';
|
||||
@@ -182,7 +184,6 @@ export const DealTicket = ({
|
||||
const iceberg = watch('iceberg');
|
||||
const peakSize = watch('peakSize');
|
||||
const expiresAt = watch('expiresAt');
|
||||
const postOnly = watch('postOnly');
|
||||
|
||||
useEffect(() => {
|
||||
const size = storedFormValues?.[dealTicketType]?.size;
|
||||
@@ -212,7 +213,6 @@ export const DealTicket = ({
|
||||
size: rawSize,
|
||||
timeInForce,
|
||||
type,
|
||||
postOnly,
|
||||
},
|
||||
market.id,
|
||||
market.decimalPlaces,
|
||||
@@ -221,7 +221,8 @@ export const DealTicket = ({
|
||||
|
||||
const price =
|
||||
normalizedOrder &&
|
||||
getDerivedPrice(normalizedOrder, marketPrice ?? undefined);
|
||||
marketPrice &&
|
||||
getDerivedPrice(normalizedOrder, marketPrice);
|
||||
|
||||
const notionalSize = getNotionalSize(
|
||||
price,
|
||||
@@ -252,14 +253,16 @@ export const DealTicket = ({
|
||||
side: normalizedOrder.side,
|
||||
});
|
||||
}
|
||||
|
||||
const positionEstimate = usePositionEstimate({
|
||||
marketId: market.id,
|
||||
openVolume,
|
||||
orders,
|
||||
collateralAvailable:
|
||||
marginAccountBalance || generalAccountBalance ? balance : undefined,
|
||||
const { data: positionEstimate } = useEstimatePositionQuery({
|
||||
variables: {
|
||||
marketId: market.id,
|
||||
openVolume,
|
||||
orders,
|
||||
collateralAvailable:
|
||||
marginAccountBalance || generalAccountBalance ? balance : undefined,
|
||||
},
|
||||
skip: !normalizedOrder,
|
||||
fetchPolicy: 'no-cache',
|
||||
});
|
||||
|
||||
const assetSymbol =
|
||||
@@ -475,7 +478,6 @@ export const DealTicket = ({
|
||||
}
|
||||
assetSymbol={assetSymbol}
|
||||
market={market}
|
||||
isMarketInAuction={isMarketInAuction(marketData.marketTradingMode)}
|
||||
/>
|
||||
</div>
|
||||
<Controller
|
||||
@@ -678,7 +680,6 @@ export const DealTicket = ({
|
||||
)}
|
||||
</Button>
|
||||
<DealTicketMarginDetails
|
||||
side={normalizedOrder.side}
|
||||
onMarketClick={onMarketClick}
|
||||
assetSymbol={assetSymbol}
|
||||
marginAccountBalance={marginAccountBalance}
|
||||
|
||||
@@ -47,7 +47,7 @@ export const KeyValue = ({
|
||||
<Tooltip description={labelDescription}>
|
||||
<div className="text-muted">{label}</div>
|
||||
</Tooltip>
|
||||
<Tooltip description={`${value ?? '-'} ${symbol || ''}`}>
|
||||
<Tooltip description={`${value ?? '-'} ${symbol || ''}`} noUnderline>
|
||||
{valueElement}
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from './__generated__/EstimateOrder';
|
||||
export * from './use-estimate-fees';
|
||||
export * from './use-form-values';
|
||||
export * from './use-position-estimate';
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useEstimateFees } from './use-estimate-fees';
|
||||
import { Side, OrderTimeInForce, OrderType } from '@vegaprotocol/types';
|
||||
|
||||
import type { EstimateFeesQuery } from './__generated__/EstimateOrder';
|
||||
|
||||
const data: EstimateFeesQuery = {
|
||||
estimateFees: {
|
||||
totalFeeAmount: '12',
|
||||
fees: {
|
||||
infrastructureFee: '2',
|
||||
liquidityFee: '4',
|
||||
makerFee: '6',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mockUseEstimateFeesQuery = jest.fn((...args) => ({
|
||||
data,
|
||||
}));
|
||||
|
||||
jest.mock('./__generated__/EstimateOrder', () => ({
|
||||
...jest.requireActual('@vegaprotocol/data-provider'),
|
||||
useEstimateFeesQuery: jest.fn((...args) => mockUseEstimateFeesQuery(...args)),
|
||||
}));
|
||||
|
||||
jest.mock('@vegaprotocol/wallet', () => ({
|
||||
useVegaWallet: () => ({ pubKey: 'pubKey' }),
|
||||
}));
|
||||
|
||||
describe('useEstimateFees', () => {
|
||||
it('returns 0 as estimated values if order is postOnly', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useEstimateFees({
|
||||
marketId: 'marketId',
|
||||
side: Side.SIDE_BUY,
|
||||
size: '1',
|
||||
price: '1',
|
||||
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
type: OrderType.TYPE_LIMIT,
|
||||
postOnly: true,
|
||||
})
|
||||
);
|
||||
expect(result.current).toEqual({
|
||||
totalFeeAmount: '0',
|
||||
fees: {
|
||||
infrastructureFee: '0',
|
||||
liquidityFee: '0',
|
||||
makerFee: '0',
|
||||
},
|
||||
});
|
||||
expect(mockUseEstimateFeesQuery.mock.lastCall?.[0].skip).toBeTruthy();
|
||||
});
|
||||
|
||||
it('divide values by 2 if market is in auction', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useEstimateFees(
|
||||
{
|
||||
marketId: 'marketId',
|
||||
side: Side.SIDE_BUY,
|
||||
size: '1',
|
||||
price: '1',
|
||||
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
type: OrderType.TYPE_LIMIT,
|
||||
},
|
||||
true
|
||||
)
|
||||
);
|
||||
expect(result.current).toEqual({
|
||||
totalFeeAmount: '6',
|
||||
fees: {
|
||||
infrastructureFee: '1',
|
||||
liquidityFee: '2',
|
||||
makerFee: '3',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user