Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08f21eeee4 | ||
|
|
a6964bc3cf | ||
|
|
48a9998441 | ||
|
|
bd1bd94ee7 | ||
|
|
2fdebbd694 | ||
|
|
96af8035d0 | ||
|
|
051e3da366 | ||
|
|
af5e666d5e | ||
|
|
333a7d6206 | ||
|
|
cb6b988466 | ||
|
|
806ea74f7e | ||
|
|
8693f3bfd8 | ||
|
|
58c6652e29 | ||
|
|
e8adff25c4 | ||
|
|
3e594a783a | ||
|
|
1f7117075b | ||
|
|
4c850ecead | ||
|
|
19f8fa909e | ||
|
|
8214858685 | ||
|
|
868f8e21dc | ||
|
|
6ead84b57c | ||
|
|
3975477985 |
@@ -3,3 +3,7 @@ apps/**/node_modules/*
|
||||
tmp/*
|
||||
.dockerignore
|
||||
dockerfiles
|
||||
node_modules
|
||||
.git
|
||||
.github
|
||||
.vscode
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
name: Cypress Run
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
@@ -17,6 +18,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
project: ${{ fromJSON(inputs.projects) }}
|
||||
name: ${{ matrix.project }}
|
||||
runs-on: self-hosted-runner
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Cypress tests - PR
|
||||
name: PR Validations
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -20,14 +20,16 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check node version
|
||||
id: node-version
|
||||
run: |
|
||||
npmVersion=$(cat .nvmrc | head -n 1)
|
||||
echo ::set-output name=npmVersion::${npmVersion}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
|
||||
- name: Remove package.json & yarn.lock to avoid installing everything
|
||||
run: rm package.json yarn.lock
|
||||
|
||||
- name: Install nx
|
||||
run: yarn add nx
|
||||
with:
|
||||
node-version: ${{ steps.node-version.outputs.npmVersion }}
|
||||
|
||||
# Check SHAs
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
@@ -39,38 +41,51 @@ jobs:
|
||||
# See affected apps
|
||||
- name: See affected apps
|
||||
run: |
|
||||
nx_version=$(cat package.json | grep '"nx"' | cut -d ':' -f 2 | tr -d '",[:space:]')
|
||||
rm package.json yarn.lock
|
||||
yarn add nx@$nx_version
|
||||
affected=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)
|
||||
echo -n "Affected projects: $affected"
|
||||
projects=""
|
||||
if [[ $affected == *"governance"* ]]; then projects+='"governance-e2e" '; fi
|
||||
if [[ $affected == *"trading"* ]]; then projects+='"trading-e2e" '; fi
|
||||
if [[ $affected == *"explorer"* ]]; then projects+='"explorer-e2e" '; fi
|
||||
if [[ -z "$projects" ]]; then projects+='"governance-e2e" "trading-e2e" "explorer-e2e" '; fi
|
||||
projects=${projects%?}
|
||||
projects=[${projects// /,}]
|
||||
echo PROJECTS=$projects >> $GITHUB_ENV
|
||||
projects_e2e=""
|
||||
if [[ $affected == *"governance"* ]]; then projects_e2e+='"governance-e2e" '; fi
|
||||
if [[ $affected == *"trading"* ]]; then projects_e2e+='"trading-e2e" '; fi
|
||||
if [[ $affected == *"explorer"* ]]; then projects_e2e+='"explorer-e2e" '; fi
|
||||
if [[ -z "$projects_e2e" ]]; then projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '; fi
|
||||
projects_e2e=${projects_e2e%?}
|
||||
projects_e2e=[${projects_e2e// /,}]
|
||||
echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
|
||||
echo PROJECTS=$(echo $projects_e2e | sed 's|-e2e||g') >> $GITHUB_ENV
|
||||
|
||||
outputs:
|
||||
projects: ${{ env.PROJECTS }}
|
||||
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||
|
||||
run:
|
||||
run-cypress:
|
||||
needs: pr
|
||||
if: ${{ needs.pr.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/cypress-run.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
projects: ${{ needs.pr.outputs.projects }}
|
||||
projects: ${{ needs.pr.outputs.projects-e2e }}
|
||||
tags: '@smoke @regression'
|
||||
|
||||
run-docker-build:
|
||||
needs: pr
|
||||
if: ${{ needs.pr.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/publish-docker-containers.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
projects: ${{ needs.pr.outputs.projects }}
|
||||
|
||||
# Report single result at the end, to avoid mess with required checks in PR
|
||||
result:
|
||||
if: ${{ always() }}
|
||||
needs: run
|
||||
needs: run-cypress
|
||||
runs-on: ubuntu-latest
|
||||
name: Cypress result
|
||||
steps:
|
||||
- run: |
|
||||
result="${{ needs.run.result }}"
|
||||
result="${{ needs.run-cypress.result }}"
|
||||
if [[ $result == "success" || $result == "skipped" ]]; then
|
||||
exit 0
|
||||
else
|
||||
@@ -1,16 +1,19 @@
|
||||
name: Publish docker containers
|
||||
name: Docker build
|
||||
|
||||
'on':
|
||||
pull_request:
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
projects:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
master:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# to be replaced by nix: https://github.com/vegaprotocol/frontend-monorepo/blob/develop/tools/ipfs-deploy.js#L106-L108
|
||||
matrix:
|
||||
app: ${{ fromJson('["explorer"]') }}
|
||||
name: Build the ${{ matrix.app }} image
|
||||
app: ${{ fromJSON(inputs.projects) }}
|
||||
name: ${{ matrix.app }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
@@ -45,13 +48,10 @@ jobs:
|
||||
- name: Build and export to local Docker
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
file: dockerfiles/Dockerfile
|
||||
load: true
|
||||
build-args: |
|
||||
APP=${{ matrix.app }}
|
||||
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
|
||||
load: true
|
||||
tags: |
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||
|
||||
@@ -75,9 +75,7 @@ jobs:
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: dockerfiles/Dockerfile
|
||||
build-args: |
|
||||
APP=${{ matrix.app }}
|
||||
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
|
||||
@@ -85,5 +83,12 @@ jobs:
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:latest
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ steps.tags.outputs.version }}
|
||||
|
||||
- name: Add preview label
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
labels: ${{ matrix.app }}-preview
|
||||
number: ${{ github.event.number }}
|
||||
|
||||
- name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
|
||||
@@ -4,13 +4,15 @@ FROM --platform=amd64 node:${NODE_VERSION}-alpine3.16 as build
|
||||
WORKDIR /app
|
||||
# Argument to allow building of different apps
|
||||
ARG APP
|
||||
ENV PATH /app/node_modules/.bin:$PATH
|
||||
COPY package.json ./
|
||||
COPY yarn.lock ./
|
||||
RUN apk add --update --no-cache \
|
||||
python3 \
|
||||
make \
|
||||
gcc \
|
||||
g++
|
||||
COPY . ./
|
||||
RUN apk add python3 make gcc g++
|
||||
RUN yarn --network-timeout 100000 --pure-lockfile
|
||||
RUN yarn nx build ${APP} --network-timeout 100000 --pure-lockfile
|
||||
# work around for different build process in trading
|
||||
RUN sh ./docker-build.sh
|
||||
|
||||
# Server environment
|
||||
# if this fails you need to docker pull nginx:1.23-alpine and pin new SHA
|
||||
@@ -25,7 +27,7 @@ CMD ["/entrypoint.sh"]
|
||||
|
||||
# Copy dist
|
||||
WORKDIR /usr/share/nginx/html
|
||||
COPY --from=build /app/dist/apps/${APP} /usr/share/nginx/html
|
||||
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build /app/dist/apps/${APP} /usr/share/nginx/html
|
||||
COPY ./apps/${APP}/.env .env
|
||||
RUN ipfs init && echo "$(ipfs add -rQ .)" > ipfs-hash
|
||||
@@ -341,7 +341,7 @@ context(
|
||||
'Currently expected to pass'
|
||||
);
|
||||
getProposalInformationFromTable('Expected to pass')
|
||||
.contains('👍 by Token vote')
|
||||
.contains('👍 by token vote')
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
|
||||
@@ -221,8 +221,9 @@
|
||||
"votePending": "Casting vote",
|
||||
"voteError": "Something went wrong, and your vote was not seen by the network",
|
||||
"back": "back",
|
||||
"byTokenVote": "by Token vote",
|
||||
"byLiquidityVote": "by Liquidity vote",
|
||||
"byTokenVote": "by token vote",
|
||||
"byLiquidityVote": "by liquidity vote",
|
||||
"byLPVote": "by LP vote",
|
||||
"youDidNotVote": "Voting has ended. You did not vote",
|
||||
"voteState_Yes": "For",
|
||||
"voteState_No": "Against",
|
||||
|
||||
+2
-2
@@ -86,7 +86,7 @@ describe('Proposal Votes Table', () => {
|
||||
|
||||
it('displays if an update market proposal will pass by token vote', () => {
|
||||
renderComponent(updateMarketProposal, updateMarketProposalType);
|
||||
expect(screen.getByText('👍 by Token vote')).toBeInTheDocument();
|
||||
expect(screen.getByText('👍 by token vote')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays if an update market proposal will pass by LP vote', () => {
|
||||
@@ -110,6 +110,6 @@ describe('Proposal Votes Table', () => {
|
||||
}),
|
||||
updateMarketProposalType
|
||||
);
|
||||
expect(screen.getByText('👍 by Liquidity vote')).toBeInTheDocument();
|
||||
expect(screen.getByText('👍 by liquidity vote')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
+76
@@ -136,6 +136,82 @@ describe('Proposals list item details', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('Renders proposal state: Update market proposal - set to pass by LP vote', () => {
|
||||
renderComponent(
|
||||
generateProposal({
|
||||
state: ProposalState.STATE_OPEN,
|
||||
terms: {
|
||||
change: {
|
||||
__typename: 'UpdateMarket',
|
||||
},
|
||||
},
|
||||
votes: {
|
||||
yes: {
|
||||
...generateYesVotes(0),
|
||||
totalEquityLikeShareWeight: '1000',
|
||||
},
|
||||
no: {
|
||||
...generateNoVotes(0),
|
||||
totalEquityLikeShareWeight: '0',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
expect(screen.getByTestId('vote-status')).toHaveTextContent(
|
||||
'Set to pass by LP vote'
|
||||
);
|
||||
});
|
||||
|
||||
it('Renders proposal state: Update market proposal - set to pass by token vote', () => {
|
||||
renderComponent(
|
||||
generateProposal({
|
||||
state: ProposalState.STATE_OPEN,
|
||||
terms: {
|
||||
change: {
|
||||
__typename: 'UpdateMarket',
|
||||
},
|
||||
},
|
||||
votes: {
|
||||
yes: {
|
||||
...generateYesVotes(1000, 1000),
|
||||
totalEquityLikeShareWeight: '0',
|
||||
},
|
||||
no: {
|
||||
...generateNoVotes(0),
|
||||
totalEquityLikeShareWeight: '0',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
expect(screen.getByTestId('vote-status')).toHaveTextContent(
|
||||
'Set to pass by token vote'
|
||||
);
|
||||
});
|
||||
|
||||
it('Renders proposal state: Update market proposal - set to fail', () => {
|
||||
renderComponent(
|
||||
generateProposal({
|
||||
state: ProposalState.STATE_OPEN,
|
||||
terms: {
|
||||
change: {
|
||||
__typename: 'UpdateMarket',
|
||||
},
|
||||
},
|
||||
votes: {
|
||||
yes: {
|
||||
...generateYesVotes(0),
|
||||
totalEquityLikeShareWeight: '0',
|
||||
},
|
||||
no: {
|
||||
...generateNoVotes(0),
|
||||
totalEquityLikeShareWeight: '0',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
expect(screen.getByTestId('vote-status')).toHaveTextContent('Set to fail');
|
||||
});
|
||||
|
||||
it('Renders proposal state: Open - 5 minutes left to vote', () => {
|
||||
renderComponent(
|
||||
generateProposal({
|
||||
|
||||
+27
-4
@@ -41,12 +41,22 @@ export const ProposalsListItemDetails = ({
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
}) => {
|
||||
const state = proposal?.state;
|
||||
const { willPassByTokenVote, majorityMet, participationMet } =
|
||||
useVoteInformation({
|
||||
proposal,
|
||||
});
|
||||
const {
|
||||
willPassByTokenVote,
|
||||
willPassByLPVote,
|
||||
majorityMet,
|
||||
participationMet,
|
||||
} = useVoteInformation({
|
||||
proposal,
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const { voteState } = useUserVote(proposal?.id);
|
||||
const isUpdateMarket = proposal?.terms.change.__typename === 'UpdateMarket';
|
||||
const updateMarketWillPass = willPassByTokenVote || willPassByLPVote;
|
||||
const updateMarketVotePassMethod = willPassByTokenVote
|
||||
? t('byTokenVote')
|
||||
: t('byLPVote');
|
||||
|
||||
let proposalStatus: ReactNode;
|
||||
let voteDetails: ReactNode;
|
||||
let voteStatus: ReactNode;
|
||||
@@ -128,6 +138,19 @@ export const ProposalsListItemDetails = ({
|
||||
</>
|
||||
);
|
||||
voteStatus =
|
||||
(isUpdateMarket &&
|
||||
(updateMarketWillPass ? (
|
||||
<>
|
||||
{t('Set to')}{' '}
|
||||
<StatusPass>
|
||||
{t('pass')} {updateMarketVotePassMethod}
|
||||
</StatusPass>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{t('Set to')} <StatusFail>{t('fail')}</StatusFail>
|
||||
</>
|
||||
))) ||
|
||||
(!participationMet && <ParticipationNotReached />) ||
|
||||
(!majorityMet && <MajorityNotReached />) ||
|
||||
(willPassByTokenVote ? (
|
||||
|
||||
@@ -32,6 +32,7 @@ export const VoteDetails = ({
|
||||
totalTokensPercentage,
|
||||
participationMet,
|
||||
totalTokensVoted,
|
||||
totalLPTokensPercentage,
|
||||
noPercentage,
|
||||
noLPPercentage,
|
||||
yesPercentage,
|
||||
@@ -41,6 +42,8 @@ export const VoteDetails = ({
|
||||
requiredMajorityPercentage,
|
||||
requiredMajorityLPPercentage,
|
||||
requiredParticipation,
|
||||
requiredParticipationLP,
|
||||
participationLPMet,
|
||||
} = useVoteInformation({ proposal });
|
||||
|
||||
const { t } = useTranslation();
|
||||
@@ -101,6 +104,25 @@ export const VoteDetails = ({
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p className="mb-6">
|
||||
{t('participation')}
|
||||
{': '}
|
||||
{participationLPMet ? (
|
||||
<span className="text-vega-green mx-4">{t('met')}</span>
|
||||
) : (
|
||||
<span className="text-danger mx-4">{t('notMet')}</span>
|
||||
)}{' '}
|
||||
{formatNumber(totalLPTokensPercentage, defaultDecimals)}%
|
||||
<span className="ml-4">
|
||||
{requiredParticipationLP && (
|
||||
<>
|
||||
({formatNumber(requiredParticipationLP, defaultDecimals)}%{' '}
|
||||
{t('governanceRequired')})
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</p>
|
||||
</section>
|
||||
)}
|
||||
<section data-testid="votes-table">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -135,7 +135,7 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||
cy.getByTestId(toastContent).should(
|
||||
'contain.text',
|
||||
'Transfer completeYour transaction has been confirmed TransferTo 7f9cf0…c255351.00 tBTC'
|
||||
'Transfer completeYour transaction has been confirmed View in block explorerTransferTo 7f9cf0…c255351.00 tBTC'
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
});
|
||||
@@ -283,7 +283,7 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
});
|
||||
});
|
||||
// comment because of bug #2695
|
||||
it.skip('can edit order', function () {
|
||||
it('can edit order', function () {
|
||||
cy.getByTestId(ordersTab).click();
|
||||
cy.getByTestId('edit').first().should('be.visible').click();
|
||||
cy.getByTestId('dialog-title').should('contain.text', 'Edit order');
|
||||
@@ -422,7 +422,11 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.getByTestId(depositSubmit).click();
|
||||
cy.getByTestId('input-error-text').should(
|
||||
'contain.text',
|
||||
'Amount is above approved amount.Update approve amount'
|
||||
'Amount is above approved amount'
|
||||
);
|
||||
cy.getByTestId('reapprove-default').should(
|
||||
'contain.text',
|
||||
'Approve again to deposit more than'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -437,9 +441,11 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
cy.get(assetSelectField, txTimeout).select(vegaName, { force: true });
|
||||
cy.getByTestId('deposit-submit').click();
|
||||
cy.getByTestId('dialog-title').should('contain.text', 'Approve complete');
|
||||
cy.get('[data-testid="Return to deposit"]').click();
|
||||
cy.getByTestId('approve-submit').click();
|
||||
cy.getByTestId('approve-confirmed').should(
|
||||
'contain.text',
|
||||
'You can now make deposits in VEGA, up to a maximum of'
|
||||
);
|
||||
cy.get(amountField).clear().type('10000');
|
||||
cy.getByTestId('deposit-submit').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
@@ -447,7 +453,7 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
`Your transaction has been confirmed.`,
|
||||
{ matchCase: false }
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId(toastCloseBtn).click({ multiple: true });
|
||||
cy.getByTestId('Collateral').click();
|
||||
|
||||
cy.highlight('deposit verification');
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useCallback } from 'react';
|
||||
import { useMarketList } from '@vegaprotocol/market-list';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { Link as UILink } from '@vegaprotocol/ui-toolkit';
|
||||
import { Link as UILink, TinyScroll } from '@vegaprotocol/ui-toolkit';
|
||||
import type { OnCellClickHandler } from '../select-market';
|
||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
@@ -55,8 +55,8 @@ export const SelectMarketLandingTable = ({
|
||||
const showProposed = (markets?.length || 0) <= 5;
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="max-h-[60vh] overflow-x-auto"
|
||||
<TinyScroll
|
||||
className="max-h-[60vh] overflow-x-auto -mr-4 pr-4"
|
||||
data-testid="select-market-list"
|
||||
>
|
||||
<p className="text-neutral-500 dark:text-neutral-400 mb-4">
|
||||
@@ -78,7 +78,7 @@ export const SelectMarketLandingTable = ({
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</TinyScroll>
|
||||
<div className="mt-4 text-md">
|
||||
<Link
|
||||
to={Links[Routes.MARKETS]()}
|
||||
|
||||
@@ -103,7 +103,9 @@ const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
<>
|
||||
<ToastHeading>{t('Awaiting confirmation')}</ToastHeading>
|
||||
<p>{t('Please wait for your transaction to be confirmed.')}</p>
|
||||
{tx.txHash && <EtherscanLink tx={tx.txHash} />}
|
||||
{tx.txHash && (
|
||||
<EtherscanLink tx={tx.txHash}>{t('View on Etherscan')}</EtherscanLink>
|
||||
)}
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</>
|
||||
);
|
||||
@@ -131,7 +133,9 @@ const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
<>
|
||||
<ToastHeading>{t('Transaction confirmed')}</ToastHeading>
|
||||
<p>{t('Your transaction has been confirmed.')}</p>
|
||||
{tx.txHash && <EtherscanLink tx={tx.txHash} />}
|
||||
{tx.txHash && (
|
||||
<EtherscanLink tx={tx.txHash}>{t('View on Etherscan')}</EtherscanLink>
|
||||
)}
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</>
|
||||
);
|
||||
@@ -148,7 +152,9 @@ const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
{t('Your transaction has been completed.')}{' '}
|
||||
{isDeposit && t('Waiting for deposit confirmation.')}
|
||||
</p>
|
||||
{tx.txHash && <EtherscanLink tx={tx.txHash} />}
|
||||
{tx.txHash && (
|
||||
<EtherscanLink tx={tx.txHash}>{t('View on Etherscan')}</EtherscanLink>
|
||||
)}
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</>
|
||||
);
|
||||
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh -eux
|
||||
export PATH="/app/node_modules/.bin:$PATH"
|
||||
if [ "${APP}" = "trading" ]; then
|
||||
yarn nx export ${APP} --network-timeout 100000 --pure-lockfile
|
||||
mv /app/dist/apps/trading/exported/ /app/tmp
|
||||
rm -rf /app/dist/apps/trading
|
||||
mv /app/tmp /app/dist/apps/trading
|
||||
else
|
||||
yarn nx build ${APP} --network-timeout 100000 --pure-lockfile
|
||||
fi
|
||||
+5
-1
@@ -7,6 +7,10 @@ mkdir -p $(dirname $env_file)
|
||||
rm -rf $env_file || echo "no file to delete"
|
||||
touch $env_file
|
||||
|
||||
env_vars_file=/usr/share/nginx/html/.env
|
||||
sed -i '/^#/d' $env_vars_file # remove comment lines
|
||||
sed -i '/^$/d' $env_vars_file # remove empty lines
|
||||
|
||||
# Add assignment
|
||||
echo "window._env_ = {" >> $env_file
|
||||
|
||||
@@ -29,7 +33,7 @@ do
|
||||
if [ ! -z "$varname" ]; then
|
||||
echo " $varname: \"$value\"," >> $env_file
|
||||
fi
|
||||
done < /usr/share/nginx/html/.env
|
||||
done < $env_vars_file
|
||||
|
||||
echo "}" >> $env_file
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
InputError,
|
||||
Intent,
|
||||
Notification,
|
||||
TinyScroll,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
import {
|
||||
@@ -160,136 +161,140 @@ export const DealTicket = ({
|
||||
if (!order || !normalizedOrder) return null;
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={isReadOnly ? undefined : handleSubmit(onSubmit)}
|
||||
className="p-4"
|
||||
noValidate
|
||||
>
|
||||
<Controller
|
||||
name="type"
|
||||
control={control}
|
||||
rules={{
|
||||
validate: validateType(
|
||||
marketData.marketTradingMode,
|
||||
marketData.trigger
|
||||
),
|
||||
}}
|
||||
render={() => (
|
||||
<TypeSelector
|
||||
value={order.type}
|
||||
onSelect={(type) => {
|
||||
if (type === OrderType.TYPE_NETWORK) return;
|
||||
update({
|
||||
type,
|
||||
// when changing type also update the tif to what was last used of new type
|
||||
timeInForce: lastTIF[type] || order.timeInForce,
|
||||
expiresAt: undefined,
|
||||
});
|
||||
clearErrors('expiresAt');
|
||||
}}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
errorMessage={errors.type?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="side"
|
||||
control={control}
|
||||
render={() => (
|
||||
<SideSelector
|
||||
value={order.side}
|
||||
onSelect={(side) => {
|
||||
update({ side });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<DealTicketAmount
|
||||
control={control}
|
||||
orderType={order.type}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
sizeError={errors.size?.message}
|
||||
priceError={errors.price?.message}
|
||||
update={update}
|
||||
size={order.size}
|
||||
price={order.price}
|
||||
/>
|
||||
<Controller
|
||||
name="timeInForce"
|
||||
control={control}
|
||||
rules={{
|
||||
validate: validateTimeInForce(
|
||||
marketData.marketTradingMode,
|
||||
marketData.trigger
|
||||
),
|
||||
}}
|
||||
render={() => (
|
||||
<TimeInForceSelector
|
||||
value={order.timeInForce}
|
||||
orderType={order.type}
|
||||
onSelect={(timeInForce) => {
|
||||
update({ timeInForce });
|
||||
// Set tif value for the given order type, so that when switching
|
||||
// types we know the last used TIF for the given order type
|
||||
setLastTIF((curr) => ({
|
||||
...curr,
|
||||
[order.type]: timeInForce,
|
||||
expiresAt: undefined,
|
||||
}));
|
||||
clearErrors('expiresAt');
|
||||
}}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
errorMessage={errors.timeInForce?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{order.type === Schema.OrderType.TYPE_LIMIT &&
|
||||
order.timeInForce === Schema.OrderTimeInForce.TIME_IN_FORCE_GTT && (
|
||||
<Controller
|
||||
name="expiresAt"
|
||||
control={control}
|
||||
rules={{
|
||||
validate: validateExpiration,
|
||||
}}
|
||||
render={() => (
|
||||
<ExpirySelector
|
||||
value={order.expiresAt}
|
||||
onSelect={(expiresAt) =>
|
||||
update({
|
||||
expiresAt: expiresAt || undefined,
|
||||
})
|
||||
}
|
||||
errorMessage={errors.expiresAt?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<SummaryMessage
|
||||
errorMessage={errors.summary?.message}
|
||||
asset={asset}
|
||||
marketTradingMode={marketData.marketTradingMode}
|
||||
balance={balance}
|
||||
margin={totalMargin}
|
||||
isReadOnly={isReadOnly}
|
||||
pubKey={pubKey}
|
||||
onClickCollateral={onClickCollateral}
|
||||
/>
|
||||
<DealTicketButton
|
||||
disabled={Object.keys(errors).length >= 1 || isReadOnly}
|
||||
variant={order.side === Schema.Side.SIDE_BUY ? 'ternary' : 'secondary'}
|
||||
/>
|
||||
<DealTicketFeeDetails
|
||||
order={normalizedOrder}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
margin={margin}
|
||||
totalMargin={totalMargin}
|
||||
balance={marginAccountBalance}
|
||||
/>
|
||||
</form>
|
||||
<TinyScroll className="h-full overflow-auto">
|
||||
<form
|
||||
onSubmit={isReadOnly ? undefined : handleSubmit(onSubmit)}
|
||||
className="p-4"
|
||||
noValidate
|
||||
>
|
||||
<Controller
|
||||
name="type"
|
||||
control={control}
|
||||
rules={{
|
||||
validate: validateType(
|
||||
marketData.marketTradingMode,
|
||||
marketData.trigger
|
||||
),
|
||||
}}
|
||||
render={() => (
|
||||
<TypeSelector
|
||||
value={order.type}
|
||||
onSelect={(type) => {
|
||||
if (type === OrderType.TYPE_NETWORK) return;
|
||||
update({
|
||||
type,
|
||||
// when changing type also update the tif to what was last used of new type
|
||||
timeInForce: lastTIF[type] || order.timeInForce,
|
||||
expiresAt: undefined,
|
||||
});
|
||||
clearErrors('expiresAt');
|
||||
}}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
errorMessage={errors.type?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="side"
|
||||
control={control}
|
||||
render={() => (
|
||||
<SideSelector
|
||||
value={order.side}
|
||||
onSelect={(side) => {
|
||||
update({ side });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<DealTicketAmount
|
||||
control={control}
|
||||
orderType={order.type}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
sizeError={errors.size?.message}
|
||||
priceError={errors.price?.message}
|
||||
update={update}
|
||||
size={order.size}
|
||||
price={order.price}
|
||||
/>
|
||||
<Controller
|
||||
name="timeInForce"
|
||||
control={control}
|
||||
rules={{
|
||||
validate: validateTimeInForce(
|
||||
marketData.marketTradingMode,
|
||||
marketData.trigger
|
||||
),
|
||||
}}
|
||||
render={() => (
|
||||
<TimeInForceSelector
|
||||
value={order.timeInForce}
|
||||
orderType={order.type}
|
||||
onSelect={(timeInForce) => {
|
||||
update({ timeInForce });
|
||||
// Set tif value for the given order type, so that when switching
|
||||
// types we know the last used TIF for the given order type
|
||||
setLastTIF((curr) => ({
|
||||
...curr,
|
||||
[order.type]: timeInForce,
|
||||
expiresAt: undefined,
|
||||
}));
|
||||
clearErrors('expiresAt');
|
||||
}}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
errorMessage={errors.timeInForce?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{order.type === Schema.OrderType.TYPE_LIMIT &&
|
||||
order.timeInForce === Schema.OrderTimeInForce.TIME_IN_FORCE_GTT && (
|
||||
<Controller
|
||||
name="expiresAt"
|
||||
control={control}
|
||||
rules={{
|
||||
validate: validateExpiration,
|
||||
}}
|
||||
render={() => (
|
||||
<ExpirySelector
|
||||
value={order.expiresAt}
|
||||
onSelect={(expiresAt) =>
|
||||
update({
|
||||
expiresAt: expiresAt || undefined,
|
||||
})
|
||||
}
|
||||
errorMessage={errors.expiresAt?.message}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<SummaryMessage
|
||||
errorMessage={errors.summary?.message}
|
||||
asset={asset}
|
||||
marketTradingMode={marketData.marketTradingMode}
|
||||
balance={balance}
|
||||
margin={totalMargin}
|
||||
isReadOnly={isReadOnly}
|
||||
pubKey={pubKey}
|
||||
onClickCollateral={onClickCollateral}
|
||||
/>
|
||||
<DealTicketButton
|
||||
disabled={Object.keys(errors).length >= 1 || isReadOnly}
|
||||
variant={
|
||||
order.side === Schema.Side.SIDE_BUY ? 'ternary' : 'secondary'
|
||||
}
|
||||
/>
|
||||
<DealTicketFeeDetails
|
||||
order={normalizedOrder}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
margin={margin}
|
||||
totalMargin={totalMargin}
|
||||
balance={marginAccountBalance}
|
||||
/>
|
||||
</form>
|
||||
</TinyScroll>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ interface ApproveNotificationProps {
|
||||
balances: DepositBalances | null;
|
||||
amount: string;
|
||||
approveTxId: number | null;
|
||||
intent?: Intent;
|
||||
}
|
||||
|
||||
export const ApproveNotification = ({
|
||||
@@ -26,6 +27,7 @@ export const ApproveNotification = ({
|
||||
balances,
|
||||
approved,
|
||||
approveTxId,
|
||||
intent = Intent.Warning,
|
||||
}: ApproveNotificationProps) => {
|
||||
const tx = useEthTransactionStore((state) => {
|
||||
return state.transactions.find((t) => t?.id === approveTxId);
|
||||
@@ -46,7 +48,7 @@ export const ApproveNotification = ({
|
||||
const approvePrompt = (
|
||||
<div className="mb-4">
|
||||
<Notification
|
||||
intent={Intent.Warning}
|
||||
intent={intent}
|
||||
testId="approve-default"
|
||||
message={t(
|
||||
`Before you can make a deposit of your chosen asset, ${selectedAsset?.symbol}, you need to approve its use in your Ethereum wallet`
|
||||
@@ -63,7 +65,7 @@ export const ApproveNotification = ({
|
||||
const reApprovePrompt = (
|
||||
<div className="mb-4">
|
||||
<Notification
|
||||
intent={Intent.Warning}
|
||||
intent={intent}
|
||||
testId="reapprove-default"
|
||||
message={t(
|
||||
`Approve again to deposit more than ${formatNumber(
|
||||
|
||||
@@ -83,6 +83,8 @@ export const DepositForm = ({
|
||||
const openDialog = useWeb3ConnectStore((store) => store.open);
|
||||
const { isActive, account } = useWeb3React();
|
||||
const { pubKey, pubKeys: _pubKeys } = useVegaWallet();
|
||||
const [approveNotificationIntent, setApproveNotificationIntent] =
|
||||
useState<Intent>(Intent.Warning);
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
@@ -103,8 +105,10 @@ export const DepositForm = ({
|
||||
if (!selectedAsset || selectedAsset.source.__typename !== 'ERC20') {
|
||||
throw new Error('Invalid asset');
|
||||
}
|
||||
if (!approved) throw new Error('Deposits not approved');
|
||||
|
||||
if (!approved) {
|
||||
setApproveNotificationIntent(Intent.Danger);
|
||||
return;
|
||||
}
|
||||
submitDeposit({
|
||||
assetSource: selectedAsset.source.contractAddress,
|
||||
amount: fields.amount,
|
||||
@@ -219,7 +223,7 @@ export const DepositForm = ({
|
||||
{errors.asset.message}
|
||||
</InputError>
|
||||
)}
|
||||
{isFaucetable && selectedAsset && (
|
||||
{isActive && isFaucetable && selectedAsset && (
|
||||
<UseButton onClick={submitFaucet}>
|
||||
{t(`Get ${selectedAsset.symbol}`)}
|
||||
</UseButton>
|
||||
@@ -355,9 +359,13 @@ export const DepositForm = ({
|
||||
isActive={isActive}
|
||||
approveTxId={approveTxId}
|
||||
selectedAsset={selectedAsset}
|
||||
onApprove={submitApprove}
|
||||
onApprove={() => {
|
||||
submitApprove();
|
||||
setApproveNotificationIntent(Intent.Warning);
|
||||
}}
|
||||
balances={balances}
|
||||
approved={approved}
|
||||
intent={approveNotificationIntent}
|
||||
amount={amount}
|
||||
/>
|
||||
<FormButton approved={approved} selectedAsset={selectedAsset} />
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import styles from './orderbook.module.scss';
|
||||
import colors from 'tailwindcss/colors';
|
||||
import { useEffect, useRef, useState, useCallback, Fragment } from 'react';
|
||||
import classNames from 'classnames';
|
||||
@@ -14,7 +13,7 @@ import {
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { OrderbookRow } from './orderbook-row';
|
||||
import { createRow } from './orderbook-data';
|
||||
import { Checkbox, Icon, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { Checkbox, Icon, Splash, TinyScroll } from '@vegaprotocol/ui-toolkit';
|
||||
import type { OrderbookData, OrderbookRowData } from './orderbook-data';
|
||||
|
||||
interface OrderbookProps extends OrderbookData {
|
||||
@@ -547,8 +546,8 @@ export const Orderbook = ({
|
||||
{t('Cumulative vol')}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`h-full overflow-auto relative ${styles['scroll']}`}
|
||||
<TinyScroll
|
||||
className="h-full overflow-auto relative"
|
||||
onScroll={onScroll}
|
||||
ref={scrollElement}
|
||||
data-testid="scroll"
|
||||
@@ -580,7 +579,7 @@ export const Orderbook = ({
|
||||
testId={'best-static-offer-price'}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</TinyScroll>
|
||||
<div
|
||||
className="absolute bottom-0 grid grid-cols-4 gap-2 border-t border-default mt-2 z-10 bg-white dark:bg-black w-full"
|
||||
ref={footerElement}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
ExternalLink,
|
||||
Link as UILink,
|
||||
Splash,
|
||||
TinyScroll,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useMemo } from 'react';
|
||||
import { generatePath, Link } from 'react-router-dom';
|
||||
@@ -71,7 +72,9 @@ export const MarketInfoContainer = ({
|
||||
return (
|
||||
<AsyncRenderer data={data} loading={loading} error={error} reload={reload}>
|
||||
{data ? (
|
||||
<Info market={data} onSelect={(id) => onSelect?.(id)} />
|
||||
<TinyScroll className="h-full overflow-auto">
|
||||
<Info market={data} onSelect={(id) => onSelect?.(id)} />
|
||||
</TinyScroll>
|
||||
) : (
|
||||
<Splash>
|
||||
<p>{t('Could not load market')}</p>
|
||||
|
||||
@@ -40,6 +40,7 @@ export * from './tabs';
|
||||
export * from './text-area';
|
||||
export * from './theme-switcher';
|
||||
export * from './thumbs';
|
||||
export * from './tiny-scroll';
|
||||
export * from './toast';
|
||||
export * from './toggle';
|
||||
export * from './tooltip';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './tiny-scroll';
|
||||
@@ -0,0 +1,20 @@
|
||||
import styles from './tiny-scroll.module.scss';
|
||||
import { forwardRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { HTMLAttributes, ReactNode } from 'react';
|
||||
|
||||
export interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const TinyScroll = forwardRef<HTMLDivElement, Props>(
|
||||
({ children, className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={classNames(className, styles['scroll'])}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user