Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a580f93bff | ||
|
|
b90db00710 | ||
|
|
98c9d34ad3 | ||
|
|
525a2af021 | ||
|
|
43ae1961eb | ||
|
|
783f897ee7 |
@@ -125,7 +125,7 @@ jobs:
|
||||
#----------------------------------------------
|
||||
- name: Run tests
|
||||
working-directory: ./console-test
|
||||
run: poetry run pytest -s --numprocesses auto --dist loadfile
|
||||
run: poetry run pytest -s --numprocesses auto
|
||||
- name: Check files
|
||||
run: |
|
||||
ls -al .
|
||||
|
||||
@@ -41,7 +41,7 @@ export const TxDetailsIssueSignatures = ({
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
const cmd: Command = txData.command.issueSignatures;
|
||||
const cmd: Command = txData.command;
|
||||
const k = cmd.kind ? kind[cmd.kind] : null;
|
||||
|
||||
return (
|
||||
|
||||
@@ -48,11 +48,9 @@ query ExplorerPartyAssets($partyId: ID!) {
|
||||
}
|
||||
stakingSummary {
|
||||
currentStakeAvailable
|
||||
linkings(pagination: { last: 100 }) {
|
||||
linkings(pagination: { first: 100 }) {
|
||||
edges {
|
||||
node {
|
||||
type
|
||||
status
|
||||
amount
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export type ExplorerPartyAssetsQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string, linkings: { __typename?: 'StakesConnection', edges?: Array<{ __typename?: 'StakeLinkingEdge', node: { __typename?: 'StakeLinking', type: Types.StakeLinkingType, status: Types.StakeLinkingStatus, amount: string } } | null> | null } }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null } } | null> | null } | null } }> } | null };
|
||||
export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string, linkings: { __typename?: 'StakesConnection', edges?: Array<{ __typename?: 'StakeLinkingEdge', node: { __typename?: 'StakeLinking', amount: string } } | null> | null } }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null } } | null> | null } | null } }> } | null };
|
||||
|
||||
export const ExplorerPartyAssetsAccountsFragmentDoc = gql`
|
||||
fragment ExplorerPartyAssetsAccounts on AccountBalance {
|
||||
@@ -64,11 +64,9 @@ export const ExplorerPartyAssetsDocument = gql`
|
||||
}
|
||||
stakingSummary {
|
||||
currentStakeAvailable
|
||||
linkings(pagination: {last: 100}) {
|
||||
linkings(pagination: {first: 100}) {
|
||||
edges {
|
||||
node {
|
||||
type
|
||||
status
|
||||
amount
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,15 +42,9 @@ export const PartyBlockStake = ({
|
||||
linkedLength && linkedLength > 0
|
||||
? p?.stakingSummary?.linkings?.edges
|
||||
?.reduce((total, e) => {
|
||||
const accumulator = new BigNumber(total);
|
||||
const diff = new BigNumber(e?.node.amount || 0);
|
||||
if (e?.node.type === 'TYPE_LINK') {
|
||||
return accumulator.plus(diff);
|
||||
} else if (e?.node.type === 'TYPE_UNLINK') {
|
||||
return accumulator.minus(diff);
|
||||
} else {
|
||||
return accumulator;
|
||||
}
|
||||
return new BigNumber(total).plus(
|
||||
new BigNumber(e?.node.amount || 0)
|
||||
);
|
||||
}, new BigNumber(0))
|
||||
.toString()
|
||||
: '0';
|
||||
|
||||
@@ -220,7 +220,6 @@ describe(
|
||||
cy.getByTestId(changeVoteButton).should('be.visible').click();
|
||||
voteForProposal('for');
|
||||
// 3001-VOTE-064
|
||||
cy.getByTestId('user-voted-yes').should('exist');
|
||||
getProposalInformationFromTable('Tokens for proposal')
|
||||
.should('have.text', (1).toFixed(2))
|
||||
.and('be.visible');
|
||||
@@ -361,34 +360,6 @@ describe(
|
||||
stakingPageDisassociateAllTokens();
|
||||
});
|
||||
|
||||
it('Error message should be displayed if error returned from wallet when voting', function () {
|
||||
const errorMsg =
|
||||
'Application error: party has already submitted the maximum number of transactions of this type per epoch (3)';
|
||||
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
cy.intercept('POST', '/api/v2/requests', {
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: 2001,
|
||||
message: 'Application error',
|
||||
data: 'party has already submitted the maximum number of transactions of this type per epoch (3)',
|
||||
},
|
||||
id: '-PK5EGmErnjLhAmzMeclC',
|
||||
});
|
||||
cy.contains('Vote breakdown').should('be.visible', { timeout: 10000 });
|
||||
cy.getByTestId('vote-buttons').contains('for').click();
|
||||
cy.getByTestId('dialog-title').should(
|
||||
'have.text',
|
||||
'Transaction failed'
|
||||
);
|
||||
cy.getByTestId('Error').should('have.text', errorMsg);
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to see successor market details with new and updated values', function () {
|
||||
cy.createMarket();
|
||||
cy.reload();
|
||||
|
||||
@@ -119,7 +119,6 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
// 0006-NETW-001 0006-NETW-002
|
||||
it('should display network data', function () {
|
||||
cy.getByTestId('git-network-data')
|
||||
.should('contain.text', 'Reading network data from')
|
||||
@@ -131,37 +130,6 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
// 0006-NETW-003 0006-NETW-008 0006-NETW-009 0006-NETW-010 0006-NETW-012 0006-NETW-013 0006-NETW-017 0006-NETW-018 0006-NETW-019 0006-NETW-020
|
||||
it('should have option to switch to different network node', function () {
|
||||
cy.getByTestId('git-network-data').within(() => {
|
||||
cy.getByTestId('link').click();
|
||||
});
|
||||
cy.getByTestId('node-row').within(() => {
|
||||
cy.getByTestId('node-url-0')
|
||||
.parent()
|
||||
.should('have.text', 'http://localhost:3008/graphql');
|
||||
cy.getByTestId('response-time-cell')
|
||||
.invoke('text')
|
||||
.should('not.be.empty')
|
||||
.and('not.eq', 'Checking');
|
||||
cy.getByTestId('block-height-cell')
|
||||
.invoke('text')
|
||||
.should('not.be.empty')
|
||||
.then((currentBlockHeight) => {
|
||||
// Check that block height updates automatically
|
||||
cy.getByTestId('block-height-cell')
|
||||
.invoke('text')
|
||||
.should('not.eq', currentBlockHeight);
|
||||
});
|
||||
cy.getByTestId('subscription-cell').should('have.text', 'Yes');
|
||||
});
|
||||
cy.getByTestId('connect').should('be.disabled');
|
||||
cy.getByTestId('node-url-custom').click();
|
||||
cy.get('input').should('exist');
|
||||
cy.getByTestId('connect').should('be.disabled');
|
||||
cy.getByTestId('icon-cross').click();
|
||||
});
|
||||
|
||||
it('should display eth data', function () {
|
||||
cy.getByTestId('git-eth-data')
|
||||
.should('contain.text', 'Reading Ethereum data from')
|
||||
@@ -170,7 +138,6 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
// 0006-NETW-011
|
||||
it('should contain link for known issues on Github', function () {
|
||||
cy.getByTestId('git-info').within(() => {
|
||||
cy.contains('Known issues and feedback on')
|
||||
|
||||
@@ -182,7 +182,7 @@ export function clickOnValidatorFromList(
|
||||
} else {
|
||||
cy.get(`[row-id="${validatorNumber}"]`)
|
||||
.should('be.visible')
|
||||
.first()
|
||||
.find(stakeValidatorListName)
|
||||
.as('validatorOnList');
|
||||
cy.get('@validatorOnList').click();
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ export const Proposal = ({
|
||||
mostRecentlyEnactedAssociatedMarketProposal,
|
||||
}: ProposalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { submit, Dialog, finalizedVote, transaction } = useVoteSubmit();
|
||||
const { submit, Dialog, finalizedVote } = useVoteSubmit();
|
||||
const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote);
|
||||
|
||||
if (!proposal) {
|
||||
@@ -215,7 +215,6 @@ export const Proposal = ({
|
||||
}
|
||||
submit={submit}
|
||||
dialog={Dialog}
|
||||
transaction={transaction}
|
||||
voteState={voteState}
|
||||
voteDatetime={voteDatetime}
|
||||
/>
|
||||
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { VoteTransactionDialog } from './vote-transaction-dialog';
|
||||
import { VoteState } from './use-user-vote';
|
||||
import { VegaTxStatus } from '@vegaprotocol/wallet';
|
||||
|
||||
describe('VoteTransactionDialog', () => {
|
||||
const mockTransactionDialog = jest.fn(({ title, content }) => (
|
||||
<div>
|
||||
<div>{title}</div>
|
||||
<div>{content?.Complete}</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
it('renders without crashing', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Yes}
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('vote-transaction-dialog')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders with txRequested title when voteState is Requested', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Requested}
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('txRequested')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders with votePending title when voteState is Pending', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Pending}
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('votePending')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders with no title when voteState is neither Requested nor Pending', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Yes} // or any other state other than Requested or Pending
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.queryByText('txRequested')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('votePending')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders custom error message when voteState is Failed and error message exists', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Failed}
|
||||
transaction={{
|
||||
error: { message: 'Custom error test message', name: 'blah' },
|
||||
txHash: null,
|
||||
signature: null,
|
||||
status: VegaTxStatus.Error,
|
||||
dialogOpen: false,
|
||||
}}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('Custom error test message')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders default error message when voteState is failed and no error message exists on the tx', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Failed}
|
||||
transaction={{
|
||||
error: null,
|
||||
txHash: null,
|
||||
signature: null,
|
||||
status: VegaTxStatus.Error,
|
||||
dialogOpen: false,
|
||||
}}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('voteError')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders default ui (i.e. not error) when not in a failed state', () => {
|
||||
render(
|
||||
<VoteTransactionDialog
|
||||
voteState={VoteState.Yes}
|
||||
transaction={null}
|
||||
TransactionDialog={mockTransactionDialog}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.queryByText('voteError')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { VoteButtons } from './vote-buttons';
|
||||
import { VoteState } from './use-user-vote';
|
||||
@@ -24,7 +24,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -48,7 +47,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -83,7 +81,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -108,7 +105,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(0)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -136,7 +132,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(1)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -164,7 +159,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(10)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
@@ -189,7 +183,6 @@ describe('Vote buttons', () => {
|
||||
currentStakeAvailable={new BigNumber(10)}
|
||||
dialog={() => <div>Blah</div>}
|
||||
submit={() => Promise.resolve()}
|
||||
transaction={null}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
|
||||
@@ -17,7 +17,7 @@ import { VoteState } from './use-user-vote';
|
||||
import { ProposalMinRequirements, ProposalUserAction } from '../shared';
|
||||
import { VoteTransactionDialog } from './vote-transaction-dialog';
|
||||
import { useVoteButtonsQuery } from './__generated__/Stake';
|
||||
import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet';
|
||||
import type { DialogProps } from '@vegaprotocol/wallet';
|
||||
|
||||
interface VoteButtonsContainerProps {
|
||||
voteState: VoteState | null;
|
||||
@@ -27,7 +27,6 @@ interface VoteButtonsContainerProps {
|
||||
minVoterBalance: string | null | undefined;
|
||||
spamProtectionMinTokens: string | null | undefined;
|
||||
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
|
||||
transaction: VegaTxState | null;
|
||||
dialog: (props: DialogProps) => JSX.Element;
|
||||
className?: string;
|
||||
}
|
||||
@@ -68,7 +67,6 @@ export const VoteButtons = ({
|
||||
minVoterBalance,
|
||||
spamProtectionMinTokens,
|
||||
submit,
|
||||
transaction,
|
||||
dialog: Dialog,
|
||||
}: VoteButtonsProps) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -210,11 +208,7 @@ export const VoteButtons = ({
|
||||
</p>
|
||||
)
|
||||
)}
|
||||
<VoteTransactionDialog
|
||||
voteState={voteState}
|
||||
transaction={transaction}
|
||||
TransactionDialog={Dialog}
|
||||
/>
|
||||
<VoteTransactionDialog voteState={voteState} TransactionDialog={Dialog} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@ import { VoteButtonsContainer } from './vote-buttons';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { ProposalType } from '../proposal/proposal';
|
||||
import type { VoteValue } from '@vegaprotocol/types';
|
||||
import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet';
|
||||
import type { DialogProps } from '@vegaprotocol/wallet';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { VoteState } from './use-user-vote';
|
||||
@@ -22,7 +22,6 @@ interface VoteDetailsProps {
|
||||
minVoterBalance: string | null | undefined;
|
||||
spamProtectionMinTokens: string | null | undefined;
|
||||
proposalType: ProposalType | null;
|
||||
transaction: VegaTxState | null;
|
||||
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
|
||||
dialog: (props: DialogProps) => JSX.Element;
|
||||
voteState: VoteState | null;
|
||||
@@ -35,7 +34,6 @@ export const VoteDetails = ({
|
||||
spamProtectionMinTokens,
|
||||
proposalType,
|
||||
submit,
|
||||
transaction,
|
||||
dialog,
|
||||
voteState,
|
||||
voteDatetime,
|
||||
@@ -230,7 +228,6 @@ export const VoteDetails = ({
|
||||
spamProtectionMinTokens={spamProtectionMinTokens}
|
||||
className="flex"
|
||||
submit={submit}
|
||||
transaction={transaction}
|
||||
dialog={dialog}
|
||||
/>
|
||||
)
|
||||
|
||||
+2
-6
@@ -1,10 +1,9 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { VoteState } from './use-user-vote';
|
||||
import type { DialogProps, VegaTxState } from '@vegaprotocol/wallet';
|
||||
import type { DialogProps } from '@vegaprotocol/wallet';
|
||||
|
||||
interface VoteTransactionDialogProps {
|
||||
voteState: VoteState;
|
||||
transaction: VegaTxState | null;
|
||||
TransactionDialog: (props: DialogProps) => JSX.Element;
|
||||
}
|
||||
|
||||
@@ -21,15 +20,12 @@ const dialogTitle = (voteState: VoteState): string | undefined => {
|
||||
|
||||
export const VoteTransactionDialog = ({
|
||||
voteState,
|
||||
transaction,
|
||||
TransactionDialog,
|
||||
}: VoteTransactionDialogProps) => {
|
||||
// Render a custom message if the voting fails otherwise
|
||||
// pass undefined so that the default vega transaction dialog UI gets used
|
||||
const customMessage =
|
||||
voteState === VoteState.Failed ? (
|
||||
<p>{transaction?.error?.message || t('voteError')}</p>
|
||||
) : undefined;
|
||||
voteState === VoteState.Failed ? <p>{t('voteError')}</p> : undefined;
|
||||
|
||||
return (
|
||||
<div data-testid="vote-transaction-dialog">
|
||||
|
||||
@@ -259,12 +259,6 @@ describe('Closed markets', { tags: '@smoke' }, () => {
|
||||
.find('[data-testid="market-code"]')
|
||||
.should('have.text', settledMarket.tradableInstrument.instrument.code);
|
||||
|
||||
// 6001-MARK-071
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[title="Future"]')
|
||||
.should('have.text', 'Futr');
|
||||
|
||||
// 6001-MARK-002
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
|
||||
@@ -69,12 +69,6 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
||||
.find(colInstrumentCode)
|
||||
.should('have.text', 'SOLUSD');
|
||||
|
||||
// 6001-MARK-073
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[title="Future"]')
|
||||
.should('have.text', 'Futr');
|
||||
|
||||
// 6001-MARK-036
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
import {
|
||||
AuctionTrigger,
|
||||
MarketState,
|
||||
MarketTradingMode,
|
||||
} from '@vegaprotocol/types';
|
||||
|
||||
describe('markets selector', { tags: '@smoke' }, () => {
|
||||
const list = 'market-selector-list';
|
||||
const searchInput = 'search-term';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.window().then((window) => {
|
||||
window.localStorage.setItem('marketId', 'market-1');
|
||||
});
|
||||
cy.setOnBoardingViewed();
|
||||
cy.mockTradingPage(
|
||||
MarketState.STATE_ACTIVE,
|
||||
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
||||
);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
|
||||
cy.wait('@Markets');
|
||||
cy.wait('@MarketsData');
|
||||
});
|
||||
|
||||
// 6001-MARK-066
|
||||
it('can open popover to view markets', () => {
|
||||
cy.getByTestId('market-selector').should('not.exist');
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
cy.getByTestId('market-selector').should('be.visible');
|
||||
});
|
||||
|
||||
// need function keyword as we need 'this' to access market data
|
||||
it('displays data as expected', () => {
|
||||
// TODO: load data from mocks in. Using alias and wrap intermittently fails
|
||||
const data = [
|
||||
{
|
||||
code: 'SOLUSD',
|
||||
markPrice: '84.41',
|
||||
vol: '0.00',
|
||||
productType: 'Futr',
|
||||
},
|
||||
{
|
||||
code: 'ETHBTC.QM21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
productType: 'Futr',
|
||||
},
|
||||
{
|
||||
code: 'BTCUSD.MF21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
productType: 'Futr',
|
||||
},
|
||||
{
|
||||
code: 'AAPL.MF21',
|
||||
markPrice: '46,126.90058',
|
||||
vol: '0.00',
|
||||
productType: 'Futr',
|
||||
},
|
||||
];
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
cy.getByTestId(list)
|
||||
.find('a')
|
||||
.each((item, i) => {
|
||||
const market = data[i];
|
||||
// 6001-MARK-021
|
||||
// 6001-MARK-022
|
||||
expect(item.find('h3').text()).equals(
|
||||
`${market.code} ${market.productType}`
|
||||
);
|
||||
expect(
|
||||
item.find('[data-testid="market-selector-volume"]').text()
|
||||
).contains(market.vol);
|
||||
// 6001-MARK-024
|
||||
expect(
|
||||
item.find('[data-testid="market-selector-price"]').text()
|
||||
).contains(market.markPrice);
|
||||
// 6001-MARK-025
|
||||
expect(item.find('[data-testid="sparkline-svg"]')).to.not.exist;
|
||||
});
|
||||
});
|
||||
|
||||
it('can use the filter options', () => {
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
|
||||
// 6001-MARK-027
|
||||
// product type
|
||||
cy.getByTestId('product-Spot').click();
|
||||
cy.getByTestId(list).contains('Spot markets coming soon.');
|
||||
cy.getByTestId('product-Perpetual').click();
|
||||
cy.getByTestId(list).contains('Perpetual markets coming soon.');
|
||||
cy.getByTestId('product-Future').click();
|
||||
cy.getByTestId(list).find('a').should('have.length', 4);
|
||||
|
||||
// 6001-MARK-029
|
||||
cy.getByTestId(searchInput).clear().type('btc');
|
||||
cy.getByTestId(list).find('a').should('have.length', 2);
|
||||
cy.getByTestId(list).find('a').eq(1).contains('BTCUSD.MF21');
|
||||
cy.getByTestId(list).find('a').eq(0).contains('ETHBTC.QM21');
|
||||
|
||||
cy.getByTestId(searchInput).clear();
|
||||
cy.getByTestId(list).find('a').should('have.length', 4);
|
||||
});
|
||||
|
||||
it('can sort by by top gaining and top losing market', () => {
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
|
||||
// 6001-MARK-030
|
||||
// 6001-MARK-031
|
||||
// 6001-MARK-032
|
||||
// 6001-MARK-033
|
||||
cy.getByTestId(' sort-trigger').click();
|
||||
cy.getByTestId('sort-item-Gained')
|
||||
.contains('Top gaining')
|
||||
.should('be.visible');
|
||||
cy.getByTestId('sort-item-Lost')
|
||||
.contains('Top losing')
|
||||
.should('be.visible');
|
||||
cy.getByTestId('sort-item-New')
|
||||
.contains('New markets')
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
it('can filter by settlement asset', () => {
|
||||
cy.getByTestId('header-title').should('be.visible').click();
|
||||
|
||||
// 6001-MARK-028
|
||||
cy.getByTestId('asset-trigger').click();
|
||||
cy.getByTestId('asset-id-asset-3').contains('tBTC').click();
|
||||
cy.getByTestId(list).find('a').should('have.length', 1);
|
||||
cy.getByTestId(list).find('a').eq(0).contains('ETHBTC.QM21');
|
||||
});
|
||||
});
|
||||
@@ -45,12 +45,6 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
|
||||
.find('[col-id="description"]')
|
||||
.should('have.text', 'ETHUSD');
|
||||
|
||||
// 6001-MARK-074
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[title="Future"]')
|
||||
.should('have.text', 'Futr');
|
||||
|
||||
// 6001-MARK-051
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
describe('Settings page', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setOnBoardingViewed();
|
||||
cy.visit('/');
|
||||
|
||||
// Only click if not already active otherwise sidebar will close
|
||||
cy.get('[data-testid="sidebar-content"]').then(($sidebarContent) => {
|
||||
if ($sidebarContent.find('h2').text() !== 'Settings') {
|
||||
cy.get('[data-testid="sidebar"] [data-testid="Settings"]').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('telemetry checkbox should work well', () => {
|
||||
const telemetrySwitch = '#switch-settings-telemetry-switch';
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked');
|
||||
cy.get(telemetrySwitch).click();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'checked');
|
||||
cy.reload();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'checked');
|
||||
cy.get(telemetrySwitch).click();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked');
|
||||
cy.reload();
|
||||
cy.get(telemetrySwitch).should('have.attr', 'data-state', 'unchecked');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,186 @@
|
||||
interface ItemInfoType {
|
||||
name: string;
|
||||
infoText: string;
|
||||
}
|
||||
|
||||
type CheckMenuItemsFnType = (
|
||||
triggerSelector: string,
|
||||
validTexts: string[],
|
||||
clickItem?: string
|
||||
) => void;
|
||||
type CheckMenuItemCheckboxFnType = (
|
||||
buttonText: string,
|
||||
items: ItemInfoType[]
|
||||
) => void;
|
||||
|
||||
const menuItemRadio = 'div[role="menuitemradio"]';
|
||||
const menuItemCheckbox = 'div[role="menuitemcheckbox"]';
|
||||
const button = 'button';
|
||||
const indicatorInfo = '.indicator-info-wrapper';
|
||||
|
||||
const checkMenuItems: CheckMenuItemsFnType = (
|
||||
triggerSelector,
|
||||
validTexts,
|
||||
clickItem
|
||||
) => {
|
||||
cy.get(triggerSelector).click();
|
||||
|
||||
cy.get(menuItemRadio)
|
||||
.should('have.length', validTexts.length)
|
||||
.each(($el, index) => {
|
||||
const text = $el.text().trim();
|
||||
expect(text).to.equal(validTexts[index]);
|
||||
});
|
||||
|
||||
if (clickItem) {
|
||||
cy.contains(menuItemRadio, clickItem).click();
|
||||
cy.get(triggerSelector).click();
|
||||
cy.get(`${menuItemRadio}[data-state="checked"]`)
|
||||
.invoke('text')
|
||||
.then((text: string) => {
|
||||
expect(text.trim()).to.equal(clickItem);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const checkMenuItemCheckbox: CheckMenuItemCheckboxFnType = (
|
||||
buttonText,
|
||||
items
|
||||
) => {
|
||||
items.forEach((item) => {
|
||||
cy.contains(button, buttonText).click();
|
||||
cy.contains(menuItemCheckbox, item.name).click();
|
||||
});
|
||||
|
||||
cy.contains(button, buttonText).click();
|
||||
cy.get(menuItemCheckbox)
|
||||
.should('have.length', items.length)
|
||||
.each(($el, index) => {
|
||||
const text = $el.text();
|
||||
expect(text).to.equal(items[index].name);
|
||||
});
|
||||
|
||||
items.forEach((item, index) => {
|
||||
cy.get(indicatorInfo)
|
||||
.eq(index + 1)
|
||||
.invoke('text')
|
||||
.should('eq', item.infoText);
|
||||
});
|
||||
|
||||
cy.contains(button, buttonText).click({ force: true });
|
||||
};
|
||||
|
||||
function getButtonSelectorByText(text: string): string {
|
||||
return `${button}[aria-haspopup="menu"]:contains(${text})`;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setOnBoardingViewed();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
describe(
|
||||
'chart display options',
|
||||
{ tags: '@smoke', testIsolation: true },
|
||||
() => {
|
||||
it('change time interval', () => {
|
||||
// 6004-CHAR-001
|
||||
checkMenuItems(
|
||||
getButtonSelectorByText('Interval:'),
|
||||
['1m', '5m', '15m', '1H', '6H', '1D'],
|
||||
'1m'
|
||||
);
|
||||
});
|
||||
|
||||
it('change display type', () => {
|
||||
// 6004-CHAR-002
|
||||
// 6004-CHAR-003
|
||||
checkMenuItems(
|
||||
'[aria-label$="chart icon"]',
|
||||
['Mountain', 'Candlestick', 'Line', 'OHLC'],
|
||||
'Mountain'
|
||||
);
|
||||
});
|
||||
|
||||
it('Overlays', () => {
|
||||
// 6004-CHAR-004
|
||||
// 6004-CHAR-008
|
||||
// 6004-CHAR-009
|
||||
// 6004-CHAR-034
|
||||
// 6004-CHAR-037
|
||||
// 6004-CHAR-039
|
||||
// 6004-CHAR-041
|
||||
|
||||
const overlayInfo: ItemInfoType[] = [
|
||||
{
|
||||
name: 'Bollinger bands',
|
||||
infoText: 'Bollinger: Upper 174.78590Lower 173.38014',
|
||||
},
|
||||
{
|
||||
name: 'Envelope',
|
||||
infoText: 'Envelope: Upper 191.29000Lower 156.51000',
|
||||
},
|
||||
{ name: 'EMA', infoText: 'EMA: 174.06793' },
|
||||
{ name: 'Moving average', infoText: 'Moving average: 174.08302' },
|
||||
{
|
||||
name: 'Price monitoring bounds',
|
||||
infoText:
|
||||
'Price Monitoring Bounds 1: Min 162.56291Max 182.96869Reference 172.47489',
|
||||
},
|
||||
];
|
||||
|
||||
checkMenuItemCheckbox('Overlays', overlayInfo);
|
||||
});
|
||||
|
||||
it('Studies', () => {
|
||||
// 6004-CHAR-005
|
||||
// 6004-CHAR-006
|
||||
// 6004-CHAR-007
|
||||
// 6004-CHAR-042
|
||||
// 6004-CHAR-045
|
||||
// 6004-CHAR-047
|
||||
// 6004-CHAR-049
|
||||
// 6004-CHAR-051
|
||||
const studyInfo: ItemInfoType[] = [
|
||||
{
|
||||
name: 'Eldar-ray',
|
||||
infoText: 'Eldar-ray: Bull -0.08376Bear -0.58376',
|
||||
},
|
||||
{ name: 'Force index', infoText: 'Force index: 987.48858' },
|
||||
{ name: 'MACD', infoText: 'MACD: S -0.06420D 0.00359MACD -0.06062' },
|
||||
{ name: 'RSI', infoText: 'RSI: 47.08648' },
|
||||
{ name: 'Volume', infoText: 'Volume: 55,000' },
|
||||
];
|
||||
cy.get(indicatorInfo).eq(1).realHover();
|
||||
cy.get('.chart__wrapper [data-testid="split-view-view"]')
|
||||
.last()
|
||||
.find('[role="button"][title="Close"]')
|
||||
.click({ force: true });
|
||||
cy.get(indicatorInfo).should('have.length', 1);
|
||||
|
||||
checkMenuItemCheckbox('Studies', studyInfo);
|
||||
});
|
||||
|
||||
it('price details', () => {
|
||||
// 6004-CHAR-010
|
||||
const expectedDateRegex = new RegExp(
|
||||
/^\d{2}:\d{2} \d{2} [A-Za-z]{3} \d{4}$/
|
||||
);
|
||||
const expectedOhlc = `O 173.60000H 174.00000L 173.50000C 173.90000Change −0.60000(−0.34%)`;
|
||||
cy.get(indicatorInfo)
|
||||
.eq(0)
|
||||
.invoke('text')
|
||||
.then((text) => {
|
||||
const actualDate = text.slice(0, -67);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(actualDate);
|
||||
const actualOhlc = text.slice(-67);
|
||||
assert.isTrue(expectedDateRegex.test(actualDate));
|
||||
assert.strictEqual(actualOhlc, expectedOhlc);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -3,7 +3,7 @@ import { testOrderSubmission } from '../support/order-validation';
|
||||
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||
import { createOrder } from '../support/create-order';
|
||||
|
||||
describe.skip('must submit order', { tags: '@smoke' }, () => {
|
||||
describe('must submit order', { tags: '@smoke' }, () => {
|
||||
// 7002-SORD-039
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
|
||||
@@ -54,15 +54,6 @@ describe('deal ticket basics', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId(toggleLimit).next('input').should('be.checked');
|
||||
cy.getByTestId(orderPriceField).should('have.value', '101');
|
||||
});
|
||||
|
||||
it('sidebar should be open after reload', () => {
|
||||
cy.mockTradingPage();
|
||||
cy.getByTestId('deal-ticket-form').should('be.visible');
|
||||
cy.getByTestId('Order').click();
|
||||
cy.getByTestId('deal-ticket-form').should('not.exist');
|
||||
cy.reload();
|
||||
cy.getByTestId('deal-ticket-form').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
describe(
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import {
|
||||
accountsQuery,
|
||||
amendGeneralAccountBalance,
|
||||
amendMarginAccountBalance,
|
||||
} from '@vegaprotocol/mock';
|
||||
|
||||
describe.skip(
|
||||
'account validation',
|
||||
{ tags: '@regression', testIsolation: true },
|
||||
() => {
|
||||
describe('zero balance error', () => {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
let accounts = accountsQuery();
|
||||
accounts = amendMarginAccountBalance(accounts, 'market-0', '1000');
|
||||
accounts = amendGeneralAccountBalance(accounts, 'market-0', '0');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('should show an error if your balance is zero', () => {
|
||||
const accounts = accountsQuery();
|
||||
amendMarginAccountBalance(accounts, 'market-0', '0');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
// 7002-SORD-060
|
||||
cy.getByTestId('place-order').should('be.enabled');
|
||||
// 7002-SORD-003
|
||||
cy.getByTestId('deal-ticket-error-message-zero-balance').should(
|
||||
'have.text',
|
||||
'You need ' +
|
||||
'tDAI' +
|
||||
' in your wallet to trade in this market. See all your collateral.Make a deposit'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-deposit-dialog-button').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('not enough balance warning', () => {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
let accounts = accountsQuery();
|
||||
accounts = amendMarginAccountBalance(accounts, 'market-0', '1000');
|
||||
accounts = amendGeneralAccountBalance(accounts, 'market-0', '1');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
|
||||
cy.get('[data-testid="deal-ticket-form"]').then(($form) => {
|
||||
if (!$form.length) {
|
||||
cy.getByTestId('Order').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should display info and button for deposit', () => {
|
||||
// 7002-SORD-003
|
||||
|
||||
// warning should show immediately
|
||||
cy.getByTestId('deal-ticket-warning-margin').should(
|
||||
'contain.text',
|
||||
'You may not have enough margin available to open this position'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-warning-margin').should(
|
||||
'contain.text',
|
||||
'You may not have enough margin available to open this position. 5.00 tDAI is currently required. You have only 0.01001 tDAI available.'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-deposit-dialog-button').click();
|
||||
cy.getByTestId('sidebar-content')
|
||||
.find('h2')
|
||||
.eq(0)
|
||||
.should('have.text', 'Deposit');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||
import { createOrder } from '../support/create-order';
|
||||
|
||||
describe.skip(
|
||||
describe(
|
||||
'account validation',
|
||||
{ tags: '@regression', testIsolation: true },
|
||||
() => {
|
||||
|
||||
@@ -222,17 +222,12 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
|
||||
|
||||
it('must see a filled order', () => {
|
||||
// 7002-SORD-046
|
||||
// 7003-MORD-020
|
||||
// NOT COVERED: Must be able to see/link to all trades that were created from this order
|
||||
updateOrder({
|
||||
id: orderId,
|
||||
status: Schema.OrderStatus.STATUS_FILLED,
|
||||
});
|
||||
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Filled');
|
||||
cy.get('[col-id="market.tradableInstrument.instrument.code"]').contains(
|
||||
'[title="Future"]',
|
||||
'Futr'
|
||||
);
|
||||
});
|
||||
|
||||
it('must see a rejected order', () => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/markets';
|
||||
import {
|
||||
TradingInput,
|
||||
Input,
|
||||
TinyScroll,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
@@ -57,7 +57,7 @@ export const MarketSelector = ({
|
||||
/>
|
||||
<div className="text-sm grid grid-cols-[2fr_1fr_1fr] gap-1 ">
|
||||
<div className="flex-1">
|
||||
<TradingInput
|
||||
<Input
|
||||
onChange={(e) =>
|
||||
setFilter((curr) => ({ ...curr, searchTerm: e.target.value }))
|
||||
}
|
||||
|
||||
@@ -14,9 +14,12 @@ import { Settings } from '../settings';
|
||||
import { Tooltip } from '../../components/tooltip';
|
||||
import { WithdrawContainer } from '../withdraw-container';
|
||||
import { Routes as AppRoutes } from '../../pages/client-router';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { GetStarted } from '../welcome-dialog';
|
||||
import { useVegaWallet, useViewAsDialog } from '@vegaprotocol/wallet';
|
||||
|
||||
const STORAGE_KEY = 'vega_sidebar_store';
|
||||
|
||||
export enum ViewType {
|
||||
Order = 'Order',
|
||||
Info = 'Info',
|
||||
@@ -299,14 +302,22 @@ export const useSidebar = create<{
|
||||
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 };
|
||||
}>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
init: true,
|
||||
view: null,
|
||||
setView: (x) =>
|
||||
set(() => {
|
||||
if (x == null) {
|
||||
return { view: null, init: false };
|
||||
}
|
||||
|
||||
return { view: x, init: false };
|
||||
}),
|
||||
}),
|
||||
}));
|
||||
{
|
||||
name: STORAGE_KEY,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TradingCheckbox } from '@vegaprotocol/ui-toolkit';
|
||||
import { Checkbox } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useTelemetryApproval } from '../../lib/hooks/use-telemetry-approval';
|
||||
|
||||
@@ -7,7 +7,7 @@ export const TelemetryApproval = ({ helpText }: { helpText: string }) => {
|
||||
return (
|
||||
<div className="flex flex-col py-3">
|
||||
<div className="mr-4" role="form">
|
||||
<TradingCheckbox
|
||||
<Checkbox
|
||||
label={<span className="text-lg pl-1">{t('Share usage data')}</span>}
|
||||
checked={isApproved}
|
||||
name="telemetry-approval"
|
||||
|
||||
@@ -1,10 +1,40 @@
|
||||
import { Head, Html, Main, NextScript } from 'next/document';
|
||||
import { Html, Head, Main, NextScript } from 'next/document';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<>
|
||||
<Html>
|
||||
<Head>
|
||||
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta charSet="utf-8" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
href="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="Vega Protocol - VEGA Console" />
|
||||
<meta name="og:type" content="website" />
|
||||
<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="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="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<meta name="twitter:image:alt" content="VEGA logo" />
|
||||
<meta name="twitter:site" content="@vegaprotocol" />
|
||||
|
||||
<meta name="description" content="Vega Protocol - Console" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
content="https://static.vega.xyz/favicon.ico"
|
||||
@@ -15,6 +45,8 @@ export default function Document() {
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
/>
|
||||
{/* eslint-disable-next-line @next/next/no-css-tags */}
|
||||
<link rel="stylesheet" href="/preloader.css" media="all" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
@@ -22,12 +54,10 @@ export default function Document() {
|
||||
/>
|
||||
<script src="/theme-setter.js" type="text/javascript" async />
|
||||
</Head>
|
||||
<Html>
|
||||
<body className="bg-white dark:bg-vega-cdark-900 text-default font-alpha">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
</>
|
||||
<body className="bg-white dark:bg-vega-cdark-900 text-default font-alpha">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import Head from 'next/head';
|
||||
import { ClientRouter } from './client-router';
|
||||
|
||||
/**
|
||||
@@ -7,60 +6,5 @@ import { ClientRouter } from './client-router';
|
||||
* have to serve a static site via next export
|
||||
*/
|
||||
export default function Index() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta charSet="utf-8" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
href="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="Vega Protocol - VEGA Console" />
|
||||
<meta name="og:type" content="website" />
|
||||
<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="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="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<meta name="twitter:image:alt" content="VEGA logo" />
|
||||
<meta name="twitter:site" content="@vegaprotocol" />
|
||||
|
||||
<meta name="description" content="Vega Protocol - Console" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
content="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
/>
|
||||
{/* eslint-disable-next-line @next/next/no-css-tags */}
|
||||
<link rel="stylesheet" href="/preloader.css" media="all" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
href="https://static.vega.xyz/favicon.ico"
|
||||
/>
|
||||
<script src="/theme-setter.js" type="text/javascript" async />
|
||||
</Head>
|
||||
<ClientRouter />
|
||||
</>
|
||||
);
|
||||
return <ClientRouter />;
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ import {
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
Button,
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
TradingInputError,
|
||||
TradingRichSelect,
|
||||
TradingSelect,
|
||||
FormGroup,
|
||||
Input,
|
||||
InputError,
|
||||
RichSelect,
|
||||
Select,
|
||||
Tooltip,
|
||||
TradingCheckbox,
|
||||
Checkbox,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { Transfer } from '@vegaprotocol/wallet';
|
||||
import { normalizeTransfer } from '@vegaprotocol/wallet';
|
||||
@@ -130,16 +130,12 @@ export const TransferForm = ({
|
||||
className="text-sm"
|
||||
data-testid="transfer-form"
|
||||
>
|
||||
<TradingFormGroup label="Vega key" labelFor="to-address">
|
||||
<FormGroup label="Vega key" labelFor="to-address">
|
||||
<AddressField
|
||||
pubKeys={pubKeys}
|
||||
onChange={() => setValue('toAddress', '')}
|
||||
select={
|
||||
<TradingSelect
|
||||
{...register('toAddress')}
|
||||
id="to-address"
|
||||
defaultValue=""
|
||||
>
|
||||
<Select {...register('toAddress')} id="to-address" defaultValue="">
|
||||
<option value="" disabled={true}>
|
||||
{t('Please select')}
|
||||
</option>
|
||||
@@ -151,10 +147,10 @@ export const TransferForm = ({
|
||||
{pk}
|
||||
</option>
|
||||
))}
|
||||
</TradingSelect>
|
||||
</Select>
|
||||
}
|
||||
input={
|
||||
<TradingInput
|
||||
<Input
|
||||
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus={true} // focus input immediately after is shown
|
||||
id="to-address"
|
||||
@@ -175,12 +171,12 @@ export const TransferForm = ({
|
||||
}
|
||||
/>
|
||||
{errors.toAddress?.message && (
|
||||
<TradingInputError forInput="to-address">
|
||||
<InputError forInput="to-address">
|
||||
{errors.toAddress.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
<TradingFormGroup label="Asset" labelFor="asset">
|
||||
</FormGroup>
|
||||
<FormGroup label="Asset" labelFor="asset">
|
||||
<Controller
|
||||
control={control}
|
||||
name="asset"
|
||||
@@ -190,7 +186,7 @@ export const TransferForm = ({
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TradingRichSelect
|
||||
<RichSelect
|
||||
data-testid="select-asset"
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
@@ -212,17 +208,15 @@ export const TransferForm = ({
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</TradingRichSelect>
|
||||
</RichSelect>
|
||||
)}
|
||||
/>
|
||||
{errors.asset?.message && (
|
||||
<TradingInputError forInput="asset">
|
||||
{errors.asset.message}
|
||||
</TradingInputError>
|
||||
<InputError forInput="asset">{errors.asset.message}</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
<TradingFormGroup label="Amount" labelFor="amount">
|
||||
<TradingInput
|
||||
</FormGroup>
|
||||
<FormGroup label="Amount" labelFor="amount">
|
||||
<Input
|
||||
id="amount"
|
||||
autoComplete="off"
|
||||
appendElement={
|
||||
@@ -245,13 +239,11 @@ export const TransferForm = ({
|
||||
})}
|
||||
/>
|
||||
{errors.amount?.message && (
|
||||
<TradingInputError forInput="amount">
|
||||
{errors.amount.message}
|
||||
</TradingInputError>
|
||||
<InputError forInput="amount">{errors.amount.message}</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
<div className="mb-4">
|
||||
<TradingCheckbox
|
||||
<Checkbox
|
||||
name="include-transfer-fee"
|
||||
disabled={!transferAmount}
|
||||
label={
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
{
|
||||
"name": "@vegaprotocol/announcements",
|
||||
"version": "0.0.2",
|
||||
"peerDependencies": {
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
}
|
||||
"version": "0.0.2"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TradingOption } from '@vegaprotocol/ui-toolkit';
|
||||
import { Option } from '@vegaprotocol/ui-toolkit';
|
||||
import type { AssetFieldsFragment } from './__generated__/Asset';
|
||||
import classNames from 'classnames';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
@@ -28,7 +28,7 @@ export const Balance = ({
|
||||
|
||||
export const AssetOption = ({ asset, balance }: AssetOptionProps) => {
|
||||
return (
|
||||
<TradingOption key={asset.id} value={asset.id}>
|
||||
<Option key={asset.id} value={asset.id}>
|
||||
<div className="flex flex-col items-start">
|
||||
<div className="flex flex-row align-baseline gap-2">
|
||||
<span>{asset.name}</span>{' '}
|
||||
@@ -49,6 +49,6 @@ export const AssetOption = ({ asset, balance }: AssetOptionProps) => {
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</TradingOption>
|
||||
</Option>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from 'date-fns';
|
||||
import { formatForInput } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TradingInputError } from '@vegaprotocol/ui-toolkit';
|
||||
import { InputError } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
const defaultValue: Schema.DateRange = {};
|
||||
export interface DateRangeFilterProps extends IFilterParams {
|
||||
@@ -195,7 +195,7 @@ export const DateRangeFilter = forwardRef(
|
||||
}, [value, props]);
|
||||
|
||||
const notification = useMemo(() => {
|
||||
const not = error ? <TradingInputError>{error}</TradingInputError> : null;
|
||||
const not = error ? <InputError>{error}</InputError> : null;
|
||||
return (
|
||||
<div className="ag-filter-apply-panel flex min-h-[2rem]">{not}</div>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
TradingInputError,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { FormGroup, Input, InputError } from '@vegaprotocol/ui-toolkit';
|
||||
import { toDecimal, validateAmount } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { DealTicketAmountProps } from './deal-ticket-amount';
|
||||
@@ -26,17 +22,17 @@ export const DealTicketLimitAmount = ({
|
||||
const renderError = () => {
|
||||
if (sizeError) {
|
||||
return (
|
||||
<TradingInputError testId="deal-ticket-error-message-size-limit">
|
||||
<InputError testId="deal-ticket-error-message-size-limit">
|
||||
{sizeError}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
);
|
||||
}
|
||||
|
||||
if (priceError) {
|
||||
return (
|
||||
<TradingInputError testId="deal-ticket-error-message-price-limit">
|
||||
<InputError testId="deal-ticket-error-message-price-limit">
|
||||
{priceError}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,7 +43,7 @@ export const DealTicketLimitAmount = ({
|
||||
<div className="mb-2">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex-1">
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
label={t('Size')}
|
||||
labelFor="input-order-size-limit"
|
||||
className="!mb-0"
|
||||
@@ -63,8 +59,8 @@ export const DealTicketLimitAmount = ({
|
||||
},
|
||||
validate: validateAmount(sizeStep, 'Size'),
|
||||
}}
|
||||
render={({ field, fieldState }) => (
|
||||
<TradingInput
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
id="input-order-size-limit"
|
||||
className="w-full"
|
||||
type="number"
|
||||
@@ -72,16 +68,15 @@ export const DealTicketLimitAmount = ({
|
||||
min={sizeStep}
|
||||
data-testid="order-size"
|
||||
onWheel={(e) => e.currentTarget.blur()}
|
||||
hasError={!!fieldState.error}
|
||||
{...field}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
</div>
|
||||
<div className="pt-5 leading-10">@</div>
|
||||
<div className="pt-7 leading-10">@</div>
|
||||
<div className="flex-1">
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
labelFor="input-price-quote"
|
||||
label={t(`Price (${quoteName})`)}
|
||||
labelAlign="right"
|
||||
@@ -98,20 +93,19 @@ export const DealTicketLimitAmount = ({
|
||||
},
|
||||
validate: validateAmount(priceStep, 'Price'),
|
||||
}}
|
||||
render={({ field, fieldState }) => (
|
||||
<TradingInput
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
id="input-price-quote"
|
||||
className="w-full"
|
||||
type="number"
|
||||
step={priceStep}
|
||||
data-testid="order-price"
|
||||
onWheel={(e) => e.currentTarget.blur()}
|
||||
hasError={!!fieldState.error}
|
||||
{...field}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
</div>
|
||||
</div>
|
||||
{renderError()}
|
||||
|
||||
@@ -4,11 +4,7 @@ import {
|
||||
validateAmount,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
TradingInput,
|
||||
TradingInputError,
|
||||
Tooltip,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { Input, InputError, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { isMarketInAuction } from '@vegaprotocol/markets';
|
||||
import type { DealTicketAmountProps } from './deal-ticket-amount';
|
||||
import { Controller } from 'react-hook-form';
|
||||
@@ -37,7 +33,7 @@ export const DealTicketMarketAmount = ({
|
||||
<div className="mb-2">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex-1">
|
||||
<div className="mb-2 text-xs">{t('Size')}</div>
|
||||
<div className="mb-2 text-sm">{t('Size')}</div>
|
||||
<Controller
|
||||
name="size"
|
||||
control={control}
|
||||
@@ -49,8 +45,8 @@ export const DealTicketMarketAmount = ({
|
||||
},
|
||||
validate: validateAmount(sizeStep, 'Size'),
|
||||
}}
|
||||
render={({ field, fieldState }) => (
|
||||
<TradingInput
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
id="input-order-size-market"
|
||||
className="w-full"
|
||||
type="number"
|
||||
@@ -58,13 +54,12 @@ export const DealTicketMarketAmount = ({
|
||||
min={sizeStep}
|
||||
onWheel={(e) => e.currentTarget.blur()}
|
||||
data-testid="order-size"
|
||||
hasError={!!fieldState.error}
|
||||
{...field}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="pt-5 leading-10">@</div>
|
||||
<div className="pt-7 leading-10">@</div>
|
||||
<div className="flex-1 text-sm text-right">
|
||||
{inAuction && (
|
||||
<Tooltip
|
||||
@@ -77,7 +72,7 @@ export const DealTicketMarketAmount = ({
|
||||
)}
|
||||
<div
|
||||
data-testid="last-price"
|
||||
className={classNames('leading-10', { 'pt-5': !inAuction })}
|
||||
className={classNames('leading-10', { 'pt-7': !inAuction })}
|
||||
>
|
||||
{priceFormatted && quoteName ? (
|
||||
<>
|
||||
@@ -90,12 +85,12 @@ export const DealTicketMarketAmount = ({
|
||||
</div>
|
||||
</div>
|
||||
{sizeError && (
|
||||
<TradingInputError
|
||||
<InputError
|
||||
intent="danger"
|
||||
testId="deal-ticket-error-message-size-market"
|
||||
>
|
||||
{sizeError}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,9 +4,9 @@ import type { OrderFormValues } from '../../hooks/use-form-values';
|
||||
import { toDecimal, validateAmount } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
TradingInputError,
|
||||
FormGroup,
|
||||
Input,
|
||||
InputError,
|
||||
Tooltip,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
@@ -32,9 +32,9 @@ export const DealTicketSizeIceberg = ({
|
||||
const renderPeakSizeError = () => {
|
||||
if (peakSizeError) {
|
||||
return (
|
||||
<TradingInputError testId="deal-ticket-peak-error-message-size-limit">
|
||||
<InputError testId="deal-ticket-peak-error-message-size-limit">
|
||||
{peakSizeError}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,9 +44,9 @@ export const DealTicketSizeIceberg = ({
|
||||
const renderMinimumSizeError = () => {
|
||||
if (minimumVisibleSizeError) {
|
||||
return (
|
||||
<TradingInputError testId="deal-ticket-minimum-error-message-size-limit">
|
||||
<InputError testId="deal-ticket-minimum-error-message-size-limit">
|
||||
{minimumVisibleSizeError}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export const DealTicketSizeIceberg = ({
|
||||
<div className="mb-2">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex-1">
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
label={
|
||||
<Tooltip
|
||||
description={
|
||||
@@ -93,7 +93,7 @@ export const DealTicketSizeIceberg = ({
|
||||
validate: validateAmount(sizeStep, 'peakSize'),
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TradingInput
|
||||
<Input
|
||||
id="input-order-peak-size"
|
||||
className="w-full"
|
||||
type="number"
|
||||
@@ -106,14 +106,14 @@ export const DealTicketSizeIceberg = ({
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
</div>
|
||||
<div className="flex-0 items-center">
|
||||
<div className="flex"></div>
|
||||
<div className="flex"></div>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
label={
|
||||
<Tooltip
|
||||
description={
|
||||
@@ -151,7 +151,7 @@ export const DealTicketSizeIceberg = ({
|
||||
validate: validateAmount(sizeStep, 'minimumVisibleSize'),
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TradingInput
|
||||
<Input
|
||||
id="input-order-minimum-size"
|
||||
className="w-full"
|
||||
type="number"
|
||||
@@ -164,7 +164,7 @@ export const DealTicketSizeIceberg = ({
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
</div>
|
||||
</div>
|
||||
{renderPeakSizeError()}
|
||||
|
||||
@@ -10,13 +10,13 @@ import {
|
||||
import { useForm, Controller, useController } from 'react-hook-form';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
TradingRadio,
|
||||
TradingRadioGroup,
|
||||
TradingInput,
|
||||
TradingCheckbox,
|
||||
TradingFormGroup,
|
||||
TradingInputError,
|
||||
TradingSelect,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Input,
|
||||
Checkbox,
|
||||
FormGroup,
|
||||
InputError,
|
||||
Select,
|
||||
Tooltip,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { getDerivedPrice, type Market } from '@vegaprotocol/markets';
|
||||
@@ -187,9 +187,9 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
}}
|
||||
/>
|
||||
{errors.type && (
|
||||
<TradingInputError testId="stop-order-error-message-type">
|
||||
<InputError testId="stop-order-error-message-type">
|
||||
{errors.type.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
|
||||
<Controller
|
||||
@@ -199,21 +199,21 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
<SideSelector value={field.value} onValueChange={field.onChange} />
|
||||
)}
|
||||
/>
|
||||
<TradingFormGroup label={t('Trigger')} compact={true} labelFor="">
|
||||
<FormGroup label={t('Trigger')} compact={true} labelFor="">
|
||||
<Controller
|
||||
name="triggerDirection"
|
||||
control={control}
|
||||
render={({ field }) => {
|
||||
const { onChange, value } = field;
|
||||
return (
|
||||
<TradingRadioGroup
|
||||
<RadioGroup
|
||||
name="triggerDirection"
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
orientation="horizontal"
|
||||
className="mb-2"
|
||||
>
|
||||
<TradingRadio
|
||||
<Radio
|
||||
value={
|
||||
Schema.StopOrderTriggerDirection
|
||||
.TRIGGER_DIRECTION_RISES_ABOVE
|
||||
@@ -221,7 +221,7 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
id="triggerDirection-risesAbove"
|
||||
label={'Rises above'}
|
||||
/>
|
||||
<TradingRadio
|
||||
<Radio
|
||||
value={
|
||||
Schema.StopOrderTriggerDirection
|
||||
.TRIGGER_DIRECTION_FALLS_BELOW
|
||||
@@ -229,7 +229,7 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
id="triggerDirection-fallsBelow"
|
||||
label={'Falls below'}
|
||||
/>
|
||||
</TradingRadioGroup>
|
||||
</RadioGroup>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -246,17 +246,16 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
validate: validateAmount(priceStep, 'Price'),
|
||||
}}
|
||||
control={control}
|
||||
render={({ field, fieldState }) => {
|
||||
render={({ field }) => {
|
||||
const { value, ...props } = field;
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<TradingInput
|
||||
<Input
|
||||
data-testid="triggerPrice"
|
||||
type="number"
|
||||
step={priceStep}
|
||||
appendElement={asset.symbol}
|
||||
value={value || ''}
|
||||
hasError={!!fieldState.error}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
@@ -264,9 +263,9 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
}}
|
||||
/>
|
||||
{errors.triggerPrice && (
|
||||
<TradingInputError testId="stop-order-error-message-trigger-price">
|
||||
<InputError testId="stop-order-error-message-trigger-price">
|
||||
{errors.triggerPrice.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -295,17 +294,16 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
'Trailing percentage offset'
|
||||
),
|
||||
}}
|
||||
render={({ field, fieldState }) => {
|
||||
render={({ field }) => {
|
||||
const { value, ...props } = field;
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<TradingInput
|
||||
<Input
|
||||
type="number"
|
||||
step={trailingPercentOffsetStep}
|
||||
appendElement="%"
|
||||
data-testid="triggerTrailingPercentOffset"
|
||||
value={value || ''}
|
||||
hasError={!!fieldState.error}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
@@ -313,9 +311,9 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
}}
|
||||
/>
|
||||
{errors.triggerTrailingPercentOffset && (
|
||||
<TradingInputError testId="stop-order-error-message-trigger-trailing-percent-offset">
|
||||
<InputError testId="stop-order-error-message-trigger-trailing-percent-offset">
|
||||
{errors.triggerTrailingPercentOffset.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -326,29 +324,25 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
render={({ field }) => {
|
||||
const { onChange, value } = field;
|
||||
return (
|
||||
<TradingRadioGroup
|
||||
<RadioGroup
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
orientation="horizontal"
|
||||
>
|
||||
<TradingRadio
|
||||
value="price"
|
||||
id="triggerType-price"
|
||||
label={'Price'}
|
||||
/>
|
||||
<TradingRadio
|
||||
<Radio value="price" id="triggerType-price" label={'Price'} />
|
||||
<Radio
|
||||
value="trailingPercentOffset"
|
||||
id="triggerType-trailingPercentOffset"
|
||||
label={'Trailing Percent Offset'}
|
||||
/>
|
||||
</TradingRadioGroup>
|
||||
</RadioGroup>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
<div className="mb-2">
|
||||
<div className="flex items-start gap-4">
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
labelFor="input-price-quote"
|
||||
label={t(`Size`)}
|
||||
className="!mb-0 flex-1"
|
||||
@@ -364,10 +358,10 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
},
|
||||
validate: validateAmount(sizeStep, 'Size'),
|
||||
}}
|
||||
render={({ field, fieldState }) => {
|
||||
render={({ field }) => {
|
||||
const { value, ...props } = field;
|
||||
return (
|
||||
<TradingInput
|
||||
<Input
|
||||
id="order-size"
|
||||
className="w-full"
|
||||
type="number"
|
||||
@@ -376,17 +370,16 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
onWheel={(e) => e.currentTarget.blur()}
|
||||
data-testid="order-size"
|
||||
value={value || ''}
|
||||
hasError={!!fieldState.error}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
<div className="pt-5 leading-10">@</div>
|
||||
</FormGroup>
|
||||
<div className="pt-7 leading-10">@</div>
|
||||
<div className="flex-1">
|
||||
{type === Schema.OrderType.TYPE_LIMIT ? (
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
labelFor="input-price-quote"
|
||||
label={t(`Price (${quoteName})`)}
|
||||
labelAlign="right"
|
||||
@@ -404,10 +397,10 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
},
|
||||
validate: validateAmount(priceStep, 'Price'),
|
||||
}}
|
||||
render={({ field, fieldState }) => {
|
||||
render={({ field }) => {
|
||||
const { value, ...props } = field;
|
||||
return (
|
||||
<TradingInput
|
||||
<Input
|
||||
id="input-price-quote"
|
||||
className="w-full"
|
||||
type="number"
|
||||
@@ -415,16 +408,15 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
data-testid="order-price"
|
||||
onWheel={(e) => e.currentTarget.blur()}
|
||||
value={value || ''}
|
||||
hasError={!!fieldState.error}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
) : (
|
||||
<div
|
||||
className="text-sm text-right pt-5 leading-10"
|
||||
className="text-sm text-right pt-7 leading-10"
|
||||
data-testid="price"
|
||||
>
|
||||
{priceFormatted && quoteName
|
||||
@@ -435,21 +427,21 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
</div>
|
||||
</div>
|
||||
{errors.size && (
|
||||
<TradingInputError testId="stop-order-error-message-size">
|
||||
<InputError testId="stop-order-error-message-size">
|
||||
{errors.size.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
|
||||
{!errors.size &&
|
||||
errors.price &&
|
||||
type === Schema.OrderType.TYPE_LIMIT && (
|
||||
<TradingInputError testId="stop-order-error-message-price">
|
||||
<InputError testId="stop-order-error-message-price">
|
||||
{errors.price.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</div>
|
||||
<div className="mb-2">
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
label={t('Time in force')}
|
||||
labelFor="select-time-in-force"
|
||||
compact={true}
|
||||
@@ -457,12 +449,11 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
<Controller
|
||||
name="timeInForce"
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TradingSelect
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
id="select-time-in-force"
|
||||
className="w-full"
|
||||
data-testid="order-tif"
|
||||
hasError={!!fieldState.error}
|
||||
{...field}
|
||||
>
|
||||
<option
|
||||
@@ -477,14 +468,14 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
>
|
||||
{timeInForceLabel(Schema.OrderTimeInForce.TIME_IN_FORCE_FOK)}
|
||||
</option>
|
||||
</TradingSelect>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
{errors.timeInForce && (
|
||||
<TradingInputError testId="stop-error-message-tif">
|
||||
<InputError testId="stop-error-message-tif">
|
||||
{errors.timeInForce.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-2 pb-2 justify-between">
|
||||
@@ -494,29 +485,29 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
render={({ field }) => {
|
||||
const { onChange: onCheckedChange, value } = field;
|
||||
return (
|
||||
<TradingCheckbox
|
||||
<Checkbox
|
||||
onCheckedChange={onCheckedChange}
|
||||
checked={value}
|
||||
name="expire"
|
||||
label={t('Expire')}
|
||||
label={<span className="text-xs">{t('Expire')}</span>}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<TradingCheckbox
|
||||
<Checkbox
|
||||
name="reduce-only"
|
||||
checked={true}
|
||||
disabled={true}
|
||||
label={
|
||||
<Tooltip description={<span>{t(REDUCE_ONLY_TOOLTIP)}</span>}>
|
||||
<>{t('Reduce only')}</>
|
||||
<span className="text-xs">{t('Reduce only')}</span>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{expire && (
|
||||
<>
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
label={t('Strategy')}
|
||||
labelFor="expiryStrategy"
|
||||
compact={true}
|
||||
@@ -526,26 +517,26 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
|
||||
control={control}
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<TradingRadioGroup orientation="horizontal" {...field}>
|
||||
<TradingRadio
|
||||
<RadioGroup orientation="horizontal" {...field}>
|
||||
<Radio
|
||||
value={
|
||||
Schema.StopOrderExpiryStrategy.EXPIRY_STRATEGY_SUBMIT
|
||||
}
|
||||
id="expiryStrategy-submit"
|
||||
label={'Submit'}
|
||||
/>
|
||||
<TradingRadio
|
||||
<Radio
|
||||
value={
|
||||
Schema.StopOrderExpiryStrategy.EXPIRY_STRATEGY_CANCELS
|
||||
}
|
||||
id="expiryStrategy-cancel"
|
||||
label={'Cancel'}
|
||||
/>
|
||||
</TradingRadioGroup>
|
||||
</RadioGroup>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
<div className="mb-2">
|
||||
<Controller
|
||||
name="expiresAt"
|
||||
|
||||
@@ -17,8 +17,8 @@ import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { mapFormValuesToOrderSubmission } from '../../utils/map-form-values-to-submission';
|
||||
import {
|
||||
TradingCheckbox,
|
||||
TradingInputError,
|
||||
Checkbox,
|
||||
InputError,
|
||||
Intent,
|
||||
Notification,
|
||||
Tooltip,
|
||||
@@ -417,7 +417,7 @@ export const DealTicket = ({
|
||||
name="postOnly"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<TradingCheckbox
|
||||
<Checkbox
|
||||
name="post-only"
|
||||
checked={!disablePostOnlyCheckbox && field.value}
|
||||
disabled={disablePostOnlyCheckbox}
|
||||
@@ -449,7 +449,7 @@ export const DealTicket = ({
|
||||
name="reduceOnly"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<TradingCheckbox
|
||||
<Checkbox
|
||||
name="reduce-only"
|
||||
checked={!disableReduceOnlyCheckbox && field.value}
|
||||
disabled={disableReduceOnlyCheckbox}
|
||||
@@ -483,7 +483,7 @@ export const DealTicket = ({
|
||||
name="iceberg"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<TradingCheckbox
|
||||
<Checkbox
|
||||
name="iceberg"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
@@ -572,11 +572,11 @@ export const NoWalletWarning = ({
|
||||
if (isReadOnly) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<TradingInputError testId="deal-ticket-error-message-summary">
|
||||
<InputError testId="deal-ticket-error-message-summary">
|
||||
{
|
||||
'You need to connect your own wallet to start trading on this market'
|
||||
}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -613,9 +613,9 @@ const SummaryMessage = memo(
|
||||
if (error?.message) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<TradingInputError testId="deal-ticket-error-message-summary">
|
||||
<InputError testId="deal-ticket-error-message-summary">
|
||||
{error?.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
TradingInputError,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { FormGroup, Input, InputError } from '@vegaprotocol/ui-toolkit';
|
||||
import { formatForInput } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useRef } from 'react';
|
||||
@@ -23,25 +19,24 @@ export const ExpirySelector = ({
|
||||
const dateFormatted = formatForInput(date);
|
||||
const minDate = formatForInput(date);
|
||||
return (
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
label={t('Expiry time/date')}
|
||||
labelFor="expiration"
|
||||
compact={true}
|
||||
>
|
||||
<TradingInput
|
||||
<Input
|
||||
data-testid="date-picker-field"
|
||||
id="expiration"
|
||||
type="datetime-local"
|
||||
value={dateFormatted}
|
||||
onChange={(e) => onSelect(e.target.value)}
|
||||
min={minDate}
|
||||
hasError={!!errorMessage}
|
||||
/>
|
||||
{errorMessage && (
|
||||
<TradingInputError testId="deal-ticket-error-message-expiry">
|
||||
<InputError testId="deal-ticket-error-message-expiry">
|
||||
{errorMessage}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
TradingFormGroup,
|
||||
TradingInputError,
|
||||
TradingSelect,
|
||||
FormGroup,
|
||||
InputError,
|
||||
Select,
|
||||
Tooltip,
|
||||
SimpleGrid,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
@@ -90,12 +90,12 @@ export const TimeInForceSelector = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
label={t('Time in force')}
|
||||
labelFor="select-time-in-force"
|
||||
compact={true}
|
||||
>
|
||||
<TradingSelect
|
||||
<Select
|
||||
id="select-time-in-force"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
@@ -103,19 +103,18 @@ export const TimeInForceSelector = ({
|
||||
}}
|
||||
className="w-full"
|
||||
data-testid="order-tif"
|
||||
hasError={!!errorMessage}
|
||||
>
|
||||
{options.map(([key, value]) => (
|
||||
<option key={key} value={value}>
|
||||
{timeInForceLabel(value)}
|
||||
</option>
|
||||
))}
|
||||
</TradingSelect>
|
||||
</Select>
|
||||
{errorMessage && (
|
||||
<TradingInputError testId="deal-ticket-error-message-tif">
|
||||
<InputError testId="deal-ticket-error-message-tif">
|
||||
{renderError(errorMessage)}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
TradingInputError,
|
||||
InputError,
|
||||
SimpleGrid,
|
||||
Tooltip,
|
||||
TradingDropdown,
|
||||
@@ -178,9 +178,9 @@ export const TypeSelector = ({
|
||||
value={value}
|
||||
/>
|
||||
{errorMessage && (
|
||||
<TradingInputError testId="deal-ticket-error-message-type">
|
||||
<InputError testId="deal-ticket-error-message-type">
|
||||
{renderError(errorMessage as MarketModeValidationType)}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -14,14 +14,14 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import { useLocalStorage } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
Button,
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
TradingInputError,
|
||||
TradingRichSelect,
|
||||
FormGroup,
|
||||
Input,
|
||||
InputError,
|
||||
RichSelect,
|
||||
Notification,
|
||||
Intent,
|
||||
ButtonLink,
|
||||
TradingSelect,
|
||||
Select,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
@@ -151,7 +151,7 @@ export const DepositForm = ({
|
||||
noValidate={true}
|
||||
data-testid="deposit-form"
|
||||
>
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
label={t('From (Ethereum address)')}
|
||||
labelFor="ethereum-address"
|
||||
>
|
||||
@@ -197,17 +197,15 @@ export const DepositForm = ({
|
||||
}}
|
||||
/>
|
||||
{errors.from?.message && (
|
||||
<TradingInputError intent="danger">
|
||||
{errors.from.message}
|
||||
</TradingInputError>
|
||||
<InputError intent="danger">{errors.from.message}</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
<TradingFormGroup label={t('To (Vega key)')} labelFor="to">
|
||||
</FormGroup>
|
||||
<FormGroup label={t('To (Vega key)')} labelFor="to">
|
||||
<AddressField
|
||||
pubKeys={pubKeys}
|
||||
onChange={() => setValue('to', '')}
|
||||
select={
|
||||
<TradingSelect {...register('to')} id="to" defaultValue="">
|
||||
<Select {...register('to')} id="to" defaultValue="">
|
||||
<option value="" disabled>
|
||||
{t('Please select')}
|
||||
</option>
|
||||
@@ -217,10 +215,10 @@ export const DepositForm = ({
|
||||
{pk}
|
||||
</option>
|
||||
))}
|
||||
</TradingSelect>
|
||||
</Select>
|
||||
}
|
||||
input={
|
||||
<TradingInput
|
||||
<Input
|
||||
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus={true} // focus input immediately after is shown
|
||||
id="to"
|
||||
@@ -235,12 +233,12 @@ export const DepositForm = ({
|
||||
}
|
||||
/>
|
||||
{errors.to?.message && (
|
||||
<TradingInputError intent="danger" forInput="to">
|
||||
<InputError intent="danger" forInput="to">
|
||||
{errors.to.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
<TradingFormGroup label={t('Asset')} labelFor="asset">
|
||||
</FormGroup>
|
||||
<FormGroup label={t('Asset')} labelFor="asset">
|
||||
<Controller
|
||||
control={control}
|
||||
name="asset"
|
||||
@@ -250,7 +248,7 @@ export const DepositForm = ({
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TradingRichSelect
|
||||
<RichSelect
|
||||
data-testid="select-asset"
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
@@ -273,13 +271,13 @@ export const DepositForm = ({
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</TradingRichSelect>
|
||||
</RichSelect>
|
||||
)}
|
||||
/>
|
||||
{errors.asset?.message && (
|
||||
<TradingInputError intent="danger" forInput="asset">
|
||||
<InputError intent="danger" forInput="asset">
|
||||
{errors.asset.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
{isActive && isFaucetable && selectedAsset && (
|
||||
<UseButton onClick={submitFaucet}>
|
||||
@@ -298,7 +296,7 @@ export const DepositForm = ({
|
||||
{t('View asset details')}
|
||||
</button>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
<FaucetNotification
|
||||
isActive={isActive}
|
||||
selectedAsset={selectedAsset}
|
||||
@@ -310,8 +308,8 @@ export const DepositForm = ({
|
||||
</div>
|
||||
)}
|
||||
{approved && (
|
||||
<TradingFormGroup label={t('Amount')} labelFor="amount">
|
||||
<TradingInput
|
||||
<FormGroup label={t('Amount')} labelFor="amount">
|
||||
<Input
|
||||
type="number"
|
||||
autoComplete="off"
|
||||
id="amount"
|
||||
@@ -376,9 +374,9 @@ export const DepositForm = ({
|
||||
})}
|
||||
/>
|
||||
{errors.amount?.message && (
|
||||
<TradingInputError intent="danger" forInput="amount">
|
||||
<InputError intent="danger" forInput="amount">
|
||||
{errors.amount.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
{selectedAsset && balances && (
|
||||
<UseButton
|
||||
@@ -392,7 +390,7 @@ export const DepositForm = ({
|
||||
{t('Use maximum')}
|
||||
</UseButton>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
)}
|
||||
<ApproveNotification
|
||||
isActive={isActive}
|
||||
|
||||
@@ -4,10 +4,10 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
Button,
|
||||
ButtonLink,
|
||||
TradingInput,
|
||||
Input,
|
||||
Loader,
|
||||
TradingRadio,
|
||||
TradingRadioGroup,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '../../hooks';
|
||||
import { CUSTOM_NODE_KEY } from '../../types';
|
||||
@@ -76,7 +76,7 @@ export const NodeSwitcher = ({ closeDialog }: { closeDialog: () => void }) => {
|
||||
`This app will only work on ${VEGA_ENV}. Select a node to connect to.`
|
||||
)}
|
||||
</p>
|
||||
<TradingRadioGroup
|
||||
<RadioGroup
|
||||
value={nodeRadio}
|
||||
onChange={(value) => setNodeRadio(value)}
|
||||
>
|
||||
@@ -112,7 +112,7 @@ export const NodeSwitcher = ({ closeDialog }: { closeDialog: () => void }) => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</TradingRadioGroup>
|
||||
</RadioGroup>
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
fill={true}
|
||||
@@ -161,7 +161,7 @@ const CustomRowWrapper = ({
|
||||
<LayoutRow dataTestId="custom-row">
|
||||
<div className="flex w-full mb-2">
|
||||
{nodes.length > 0 && (
|
||||
<TradingRadio
|
||||
<Radio
|
||||
id="node-url-custom"
|
||||
value={CUSTOM_NODE_KEY}
|
||||
label={nodeRadio === CUSTOM_NODE_KEY ? '' : t('Other')}
|
||||
@@ -172,7 +172,7 @@ const CustomRowWrapper = ({
|
||||
data-testid="custom-node"
|
||||
className="flex items-center w-full gap-2"
|
||||
>
|
||||
<TradingInput
|
||||
<Input
|
||||
placeholder="https://"
|
||||
value={inputText}
|
||||
hasError={Boolean(error)}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ApolloError } from '@apollo/client';
|
||||
import { useHeaderStore } from '@vegaprotocol/apollo-client';
|
||||
import { isValidUrl } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { TradingRadio } from '@vegaprotocol/ui-toolkit';
|
||||
import { Radio } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CUSTOM_NODE_KEY } from '../../types';
|
||||
import {
|
||||
@@ -138,7 +138,7 @@ export const RowData = ({
|
||||
<>
|
||||
{id !== CUSTOM_NODE_KEY && (
|
||||
<div className="break-all" data-testid="node">
|
||||
<TradingRadio id={`node-url-${id}`} value={url} label={url} />
|
||||
<Radio id={`node-url-${id}`} value={url} label={url} />
|
||||
</div>
|
||||
)}
|
||||
<LayoutCell
|
||||
|
||||
@@ -128,9 +128,6 @@ fragment StopOrderFields on StopOrder {
|
||||
updatedAt
|
||||
partyId
|
||||
marketId
|
||||
order {
|
||||
...OrderFields
|
||||
}
|
||||
trigger {
|
||||
... on StopOrderPrice {
|
||||
price
|
||||
|
||||
+33
-37
@@ -34,51 +34,22 @@ export type OrdersUpdateSubscription = { __typename?: 'Subscription', orders?: A
|
||||
|
||||
export type OrderSubmissionFieldsFragment = { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null };
|
||||
|
||||
export type StopOrderFieldsFragment = { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, order?: { __typename?: 'Order', id: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, postOnly?: boolean | null, reduceOnly?: boolean | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, icebergOrder?: { __typename: 'IcebergOrder', peakSize: string, minimumVisibleSize: string, reservedRemaining: string } | null } | null, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } };
|
||||
export type StopOrderFieldsFragment = { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } };
|
||||
|
||||
export type StopOrdersQueryVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type StopOrdersQuery = { __typename?: 'Query', stopOrders?: { __typename?: 'StopOrderConnection', edges?: Array<{ __typename?: 'StopOrderEdge', node?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, order?: { __typename?: 'Order', id: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, postOnly?: boolean | null, reduceOnly?: boolean | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, icebergOrder?: { __typename: 'IcebergOrder', peakSize: string, minimumVisibleSize: string, reservedRemaining: string } | null } | null, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null }> | null } | null };
|
||||
export type StopOrdersQuery = { __typename?: 'Query', stopOrders?: { __typename?: 'StopOrderConnection', edges?: Array<{ __typename?: 'StopOrderEdge', node?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null }> | null } | null };
|
||||
|
||||
export type StopOrderByIdQueryVariables = Types.Exact<{
|
||||
stopOrderId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type StopOrderByIdQuery = { __typename?: 'Query', stopOrder?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, order?: { __typename?: 'Order', id: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, postOnly?: boolean | null, reduceOnly?: boolean | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, icebergOrder?: { __typename: 'IcebergOrder', peakSize: string, minimumVisibleSize: string, reservedRemaining: string } | null } | null, trigger: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string }, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null };
|
||||
export type StopOrderByIdQuery = { __typename?: 'Query', stopOrder?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null };
|
||||
|
||||
export const OrderUpdateFieldsFragmentDoc = gql`
|
||||
fragment OrderUpdateFields on OrderUpdate {
|
||||
id
|
||||
marketId
|
||||
type
|
||||
side
|
||||
size
|
||||
status
|
||||
rejectionReason
|
||||
price
|
||||
timeInForce
|
||||
remaining
|
||||
expiresAt
|
||||
createdAt
|
||||
updatedAt
|
||||
liquidityProvisionId
|
||||
peggedOrder {
|
||||
__typename
|
||||
reference
|
||||
offset
|
||||
}
|
||||
icebergOrder {
|
||||
__typename
|
||||
peakSize
|
||||
minimumVisibleSize
|
||||
reservedRemaining
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const OrderFieldsFragmentDoc = gql`
|
||||
fragment OrderFields on Order {
|
||||
id
|
||||
@@ -114,6 +85,35 @@ export const OrderFieldsFragmentDoc = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const OrderUpdateFieldsFragmentDoc = gql`
|
||||
fragment OrderUpdateFields on OrderUpdate {
|
||||
id
|
||||
marketId
|
||||
type
|
||||
side
|
||||
size
|
||||
status
|
||||
rejectionReason
|
||||
price
|
||||
timeInForce
|
||||
remaining
|
||||
expiresAt
|
||||
createdAt
|
||||
updatedAt
|
||||
liquidityProvisionId
|
||||
peggedOrder {
|
||||
__typename
|
||||
reference
|
||||
offset
|
||||
}
|
||||
icebergOrder {
|
||||
__typename
|
||||
peakSize
|
||||
minimumVisibleSize
|
||||
reservedRemaining
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const OrderSubmissionFieldsFragmentDoc = gql`
|
||||
fragment OrderSubmissionFields on OrderSubmission {
|
||||
marketId
|
||||
@@ -144,9 +144,6 @@ export const StopOrderFieldsFragmentDoc = gql`
|
||||
updatedAt
|
||||
partyId
|
||||
marketId
|
||||
order {
|
||||
...OrderFields
|
||||
}
|
||||
trigger {
|
||||
... on StopOrderPrice {
|
||||
price
|
||||
@@ -159,8 +156,7 @@ export const StopOrderFieldsFragmentDoc = gql`
|
||||
...OrderSubmissionFields
|
||||
}
|
||||
}
|
||||
${OrderFieldsFragmentDoc}
|
||||
${OrderSubmissionFieldsFragmentDoc}`;
|
||||
${OrderSubmissionFieldsFragmentDoc}`;
|
||||
export const OrderByIdDocument = gql`
|
||||
query OrderById($orderId: ID!) {
|
||||
orderByID(id: $orderId) {
|
||||
|
||||
@@ -9,9 +9,9 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import { Size } from '@vegaprotocol/datagrid';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
TradingInputError,
|
||||
FormGroup,
|
||||
Input,
|
||||
InputError,
|
||||
Button,
|
||||
Dialog,
|
||||
Icon,
|
||||
@@ -102,12 +102,8 @@ export const OrderEditDialog = ({
|
||||
noValidate
|
||||
>
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<TradingFormGroup
|
||||
label={t('Price')}
|
||||
labelFor="limitPrice"
|
||||
className="grow"
|
||||
>
|
||||
<TradingInput
|
||||
<FormGroup label={t('Price')} labelFor="limitPrice" className="grow">
|
||||
<Input
|
||||
type="number"
|
||||
step={step}
|
||||
{...register('limitPrice', {
|
||||
@@ -123,13 +119,13 @@ export const OrderEditDialog = ({
|
||||
id="limitPrice"
|
||||
/>
|
||||
{errors.limitPrice?.message && (
|
||||
<TradingInputError intent="danger">
|
||||
<InputError intent="danger">
|
||||
{errors.limitPrice.message}
|
||||
</TradingInputError>
|
||||
</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
<TradingFormGroup label={t('Size')} labelFor="size" className="grow">
|
||||
<TradingInput
|
||||
</FormGroup>
|
||||
<FormGroup label={t('Size')} labelFor="size" className="grow">
|
||||
<Input
|
||||
type="number"
|
||||
step={stepSize}
|
||||
{...register('size', {
|
||||
@@ -143,11 +139,9 @@ export const OrderEditDialog = ({
|
||||
id="size"
|
||||
/>
|
||||
{errors.size?.message && (
|
||||
<TradingInputError intent="danger">
|
||||
{errors.size.message}
|
||||
</TradingInputError>
|
||||
<InputError intent="danger">{errors.size.message}</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
</div>
|
||||
<Button variant="primary" size="md" type="submit">
|
||||
{t('Update')}
|
||||
|
||||
@@ -296,7 +296,7 @@ export const OrderListTable = memo<
|
||||
</ButtonLink>
|
||||
</>
|
||||
)}
|
||||
<ActionsDropdown data-testid="order-actions-content">
|
||||
<ActionsDropdown data-testid="market-actions-content">
|
||||
<TradingDropdownCopyItem
|
||||
value={data.id}
|
||||
text={t('Copy order ID')}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { StopOrdersTable } from '../stop-orders-table/stop-orders-table';
|
||||
import type { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/wallet';
|
||||
import type { StopOrder } from '../order-data-provider/stop-orders-data-provider';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { stopOrdersWithMarketProvider } from '../order-data-provider/stop-orders-data-provider';
|
||||
import { OrderViewDialog } from '../order-list/order-view-dialog';
|
||||
import type { Order } from '../order-data-provider';
|
||||
|
||||
export interface StopOrdersManagerProps {
|
||||
partyId: string;
|
||||
@@ -25,7 +23,6 @@ export const StopOrdersManager = ({
|
||||
gridProps,
|
||||
}: StopOrdersManagerProps) => {
|
||||
const create = useVegaTransactionStore((state) => state.create);
|
||||
const [viewOrder, setViewOrder] = useState<Order | null>(null);
|
||||
const variables = { partyId };
|
||||
|
||||
const { data, error, reload } = useDataProvider({
|
||||
@@ -56,25 +53,14 @@ export const StopOrdersManager = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StopOrdersTable
|
||||
rowData={data}
|
||||
onCancel={cancel}
|
||||
onView={setViewOrder}
|
||||
onMarketClick={onMarketClick}
|
||||
isReadOnly={isReadOnly}
|
||||
suppressAutoSize
|
||||
overlayNoRowsTemplate={error ? error.message : t('No stop orders')}
|
||||
{...gridProps}
|
||||
/>
|
||||
{viewOrder && (
|
||||
<OrderViewDialog
|
||||
isOpen={Boolean(viewOrder)}
|
||||
order={viewOrder}
|
||||
onChange={() => setViewOrder(null)}
|
||||
onMarketClick={onMarketClick}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<StopOrdersTable
|
||||
rowData={data}
|
||||
onCancel={cancel}
|
||||
onMarketClick={onMarketClick}
|
||||
isReadOnly={isReadOnly}
|
||||
suppressAutoSize
|
||||
overlayNoRowsTemplate={error ? error.message : t('No stop orders')}
|
||||
{...gridProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { PartialDeep } from 'type-fest';
|
||||
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import {
|
||||
StopOrdersTable,
|
||||
type StopOrdersTableProps,
|
||||
@@ -28,7 +27,6 @@ jest.mock('@vegaprotocol/utils', () => ({
|
||||
}));
|
||||
|
||||
const defaultProps: StopOrdersTableProps = {
|
||||
onView: jest.fn(),
|
||||
rowData: [],
|
||||
onCancel: jest.fn(),
|
||||
isReadOnly: false,
|
||||
@@ -106,7 +104,6 @@ const rowData = [
|
||||
generateStopOrder({
|
||||
id: 'stop-order-6',
|
||||
status: Schema.StopOrderStatus.STATUS_TRIGGERED,
|
||||
order: { id: 'order-id' },
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -237,37 +234,4 @@ describe('StopOrdersTable', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('shows actions dropdown only for triggered stop orders', async () => {
|
||||
await act(async () => {
|
||||
render(generateJsx({ rowData }));
|
||||
});
|
||||
const dropdownMenuButtons = screen.getAllByTestId('dropdown-menu');
|
||||
expect(dropdownMenuButtons).toHaveLength(1);
|
||||
dropdownMenuButtons.forEach((dropdownMenuButton) => {
|
||||
const id = dropdownMenuButton
|
||||
.closest('[role="row"]')
|
||||
?.getAttribute('row-id');
|
||||
expect(rowData.find((row) => row.id === id)?.status).toEqual(
|
||||
Schema.StopOrderStatus.STATUS_TRIGGERED
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('action dropdown has copy and view order actions', async () => {
|
||||
const onView = jest.fn();
|
||||
const user = userEvent.setup();
|
||||
await act(async () => {
|
||||
render(generateJsx({ rowData, onView }));
|
||||
});
|
||||
const dropdownMenuButtons = screen.getByTestId('dropdown-menu');
|
||||
dropdownMenuButtons.click();
|
||||
await user.click(dropdownMenuButtons as HTMLButtonElement);
|
||||
const menuItems = screen.getAllByRole('menuitem');
|
||||
expect(menuItems).toHaveLength(2);
|
||||
expect(menuItems[0]).toHaveTextContent('Copy order ID');
|
||||
expect(menuItems[1]).toHaveTextContent('View order details');
|
||||
menuItems[1].click();
|
||||
expect(onView).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,14 +7,7 @@ import {
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
ActionsDropdown,
|
||||
ButtonLink,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
DropdownMenuItem,
|
||||
TradingDropdownCopyItem,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ForwardedRef } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import {
|
||||
@@ -35,7 +28,6 @@ import type {
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { StopOrder } from '../order-data-provider/stop-orders-data-provider';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
import type { Order } from '../order-data-provider';
|
||||
|
||||
const defaultColDef = {
|
||||
resizable: true,
|
||||
@@ -46,13 +38,12 @@ const defaultColDef = {
|
||||
export type StopOrdersTableProps = TypedDataAgGrid<StopOrder> & {
|
||||
onCancel: (order: StopOrder) => void;
|
||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
onView: (order: Order) => void;
|
||||
isReadOnly: boolean;
|
||||
};
|
||||
|
||||
export const StopOrdersTable = memo<
|
||||
StopOrdersTableProps & { ref?: ForwardedRef<AgGridReact> }
|
||||
>(({ onCancel, onView, onMarketClick, ...props }: StopOrdersTableProps) => {
|
||||
>(({ onCancel, onMarketClick, ...props }: StopOrdersTableProps) => {
|
||||
const showAllActions = !props.isReadOnly;
|
||||
const columnDefs: ColDef[] = useMemo(
|
||||
() => [
|
||||
@@ -245,32 +236,12 @@ export const StopOrdersTable = memo<
|
||||
{t('Cancel')}
|
||||
</ButtonLink>
|
||||
)}
|
||||
{data.status === Schema.StopOrderStatus.STATUS_TRIGGERED &&
|
||||
data.order && (
|
||||
<ActionsDropdown data-testid="stop-order-actions-content">
|
||||
<TradingDropdownCopyItem
|
||||
value={data.order.id}
|
||||
text={t('Copy order ID')}
|
||||
/>
|
||||
<DropdownMenuItem
|
||||
key={'view-order'}
|
||||
data-testid="view-order"
|
||||
onClick={() =>
|
||||
data.order &&
|
||||
onView({ ...data.order, market: data.market })
|
||||
}
|
||||
>
|
||||
<VegaIcon name={VegaIconNames.INFO} size={16} />
|
||||
{t('View order details')}
|
||||
</DropdownMenuItem>
|
||||
</ActionsDropdown>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
[onCancel, onMarketClick, onView, props.isReadOnly, showAllActions]
|
||||
[onCancel, onMarketClick, props.isReadOnly, showAllActions]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -17,17 +17,4 @@ export const proposalsDataProvider = makeDataProvider<
|
||||
never,
|
||||
never,
|
||||
ProposalsListQueryVariables
|
||||
>({
|
||||
query: ProposalsListDocument,
|
||||
getData,
|
||||
/**
|
||||
* Ignores errors for not found settlement asset for NewMarket proposals.
|
||||
*
|
||||
* It can happen that a NewMarket proposal is incomplete and does not contain
|
||||
* `futureProduct` details. This guard protects against that.
|
||||
*
|
||||
* GQL Path: `terms.change.instrument.futureProduct.settlementAsset`
|
||||
*/
|
||||
errorPolicyGuard: (errors) =>
|
||||
errors.every((e) => e.message.match(/failed to get asset for ID/)),
|
||||
});
|
||||
>({ query: ProposalsListDocument, getData });
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
{
|
||||
"name": "@vegaprotocol/react-helpers",
|
||||
"version": "0.2.5",
|
||||
"peerDependencies": {
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
}
|
||||
"version": "0.2.5"
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ module.exports = {
|
||||
900: '#F9FAFA',
|
||||
},
|
||||
},
|
||||
danger: '#EC003C',
|
||||
danger: '#FF077F',
|
||||
warning: '#FF8700',
|
||||
success: '#00F780',
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"name": "@vegaprotocol/types",
|
||||
"version": "0.0.5"
|
||||
"version": "0.0.4"
|
||||
}
|
||||
|
||||
Generated
+1
-3
@@ -4364,8 +4364,6 @@ export type StopOrder = {
|
||||
marketId: Scalars['ID'];
|
||||
/** If OCO (one-cancels-other) order, the ID of the associated order. */
|
||||
ocoLinkId?: Maybe<Scalars['ID']>;
|
||||
/** The order that was created when triggered. */
|
||||
order?: Maybe<Order>;
|
||||
/** Party that submitted the stop order. */
|
||||
partyId: Scalars['ID'];
|
||||
/** Status of the stop order */
|
||||
@@ -4373,7 +4371,7 @@ export type StopOrder = {
|
||||
/** Order to submit when the stop order is triggered. */
|
||||
submission: OrderSubmission;
|
||||
/** Price movement that will trigger the stop order */
|
||||
trigger: StopOrderTrigger;
|
||||
trigger?: Maybe<StopOrderTrigger>;
|
||||
/** Direction the price is moving to trigger the stop order. */
|
||||
triggerDirection: StopOrderTriggerDirection;
|
||||
/** Time the stop order was last updated. */
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
{
|
||||
"name": "@vegaprotocol/ui-toolkit",
|
||||
"version": "0.12.8",
|
||||
"peerDependencies": {
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
}
|
||||
"version": "0.12.7"
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ export * from './form-group';
|
||||
export * from './healthbar';
|
||||
export * from './icon';
|
||||
export * from './indicator';
|
||||
export * from './input';
|
||||
export * from './input-error';
|
||||
export * from './input';
|
||||
export * from './key-value-table';
|
||||
export * from './link';
|
||||
export * from './loader';
|
||||
@@ -48,18 +48,10 @@ export * from './tiny-scroll';
|
||||
export * from './toast';
|
||||
export * from './toggle';
|
||||
export * from './tooltip';
|
||||
export * from './trading-button';
|
||||
export * from './trading-dropdown';
|
||||
export * from './traffic-light';
|
||||
export * from './vega-icons';
|
||||
export * from './vega-logo';
|
||||
export * from './viewing-as-user';
|
||||
export * from './pill';
|
||||
|
||||
// Trading specific components
|
||||
export * from './trading-button';
|
||||
export * from './trading-checkbox';
|
||||
export * from './trading-dropdown';
|
||||
export * from './trading-form-group';
|
||||
export * from './trading-input-error';
|
||||
export * from './trading-input';
|
||||
export * from './trading-radio-group';
|
||||
export * from './trading-select';
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { TradingCheckbox } from './checkbox';
|
||||
|
||||
describe('Checkbox', () => {
|
||||
it('should render checkbox with label successfully', () => {
|
||||
render(<TradingCheckbox label="test" />);
|
||||
expect(screen.getByText('test')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render a checked checkbox if specified in state', () => {
|
||||
render(<TradingCheckbox label="label" checked={true} />);
|
||||
expect(screen.getByTestId(/icon-/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render an unchecked checkbox if specified in state', () => {
|
||||
render(<TradingCheckbox label="unchecked" checked={false} />);
|
||||
expect(screen.queryByTestId(/icon-/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render an indeterminate checkbox if specified in state', () => {
|
||||
render(<TradingCheckbox label="indeterminate" checked="indeterminate" />);
|
||||
expect(screen.getByTestId('indeterminate-icon')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('fires callback on change if provided', () => {
|
||||
const callback = jest.fn();
|
||||
|
||||
render(
|
||||
<TradingCheckbox
|
||||
name="test"
|
||||
label="onchange"
|
||||
onCheckedChange={callback}
|
||||
/>
|
||||
);
|
||||
|
||||
const checkbox = screen.getByText('onchange');
|
||||
fireEvent.click(checkbox);
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,38 +0,0 @@
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import type { TradingCheckboxProps } from './checkbox';
|
||||
import { TradingCheckbox } from './checkbox';
|
||||
|
||||
export default {
|
||||
component: TradingCheckbox,
|
||||
title: 'Checkbox',
|
||||
} as Meta<typeof TradingCheckbox>;
|
||||
|
||||
const Template: StoryFn<TradingCheckboxProps> = (args) => (
|
||||
<TradingCheckbox {...args} />
|
||||
);
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
name: 'default',
|
||||
label: 'Regular checkbox',
|
||||
};
|
||||
|
||||
export const Overflow = Template.bind({});
|
||||
Overflow.args = {
|
||||
name: 'overflow',
|
||||
label:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
|
||||
};
|
||||
|
||||
export const Disabled = Template.bind({});
|
||||
Disabled.args = {
|
||||
disabled: true,
|
||||
label: 'Disabled',
|
||||
};
|
||||
|
||||
export const Indeterminate = Template.bind({});
|
||||
Indeterminate.args = {
|
||||
name: 'default',
|
||||
checked: 'indeterminate',
|
||||
label: 'Indeterminate checkbox',
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
import { VegaIcon, VegaIconNames } from '../icon';
|
||||
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
type CheckedState = boolean | 'indeterminate';
|
||||
export interface TradingCheckboxProps {
|
||||
checked?: CheckedState;
|
||||
label?: ReactNode;
|
||||
name?: string;
|
||||
onCheckedChange?: (checked: CheckedState) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const TradingCheckbox = ({
|
||||
checked,
|
||||
label,
|
||||
name,
|
||||
onCheckedChange,
|
||||
disabled = false,
|
||||
}: TradingCheckboxProps) => {
|
||||
const rootClasses = classNames(
|
||||
'relative flex justify-center items-center w-3 h-3',
|
||||
'border rounded-sm overflow-hidden',
|
||||
'border-vega-clight-500 dark:border-vega-cdark-500',
|
||||
'aria-checked:border-vega-clight-400 dark:aria-checked:border-vega-cdark-400',
|
||||
'disabled:border-vega-clight-600 dark:disabled:border-vega-cdark-600',
|
||||
'bg-vega-clight-700 dark:bg-vega-cdark-700'
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex gap-1.5 items-center">
|
||||
<CheckboxPrimitive.Root
|
||||
name={name}
|
||||
id={name}
|
||||
className={rootClasses}
|
||||
checked={checked}
|
||||
onCheckedChange={onCheckedChange}
|
||||
disabled={disabled}
|
||||
data-testid={name}
|
||||
>
|
||||
<CheckboxPrimitive.CheckboxIndicator className="flex justify-center items-center w-3 h-3">
|
||||
{checked === 'indeterminate' ? (
|
||||
<span
|
||||
data-testid="indeterminate-icon"
|
||||
className="absolute w-[8px] h-[2px] bg-vega-clight-50 dark:bg-vega-cdark-50"
|
||||
/>
|
||||
) : (
|
||||
<VegaIcon name={VegaIconNames.TICK} size={10} />
|
||||
)}
|
||||
</CheckboxPrimitive.CheckboxIndicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
<label
|
||||
htmlFor={name}
|
||||
className={classNames('text-xs flex-1', {
|
||||
'text-vega-clight-200 dark:text-vega-cdark-200': disabled,
|
||||
})}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export * from './checkbox';
|
||||
@@ -1,23 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
import { TradingFormGroup } from './form-group';
|
||||
|
||||
describe('FormGroup', () => {
|
||||
it('should render label if given a label', () => {
|
||||
render(
|
||||
<TradingFormGroup label="label" labelFor="test">
|
||||
<input id="test"></input>
|
||||
</TradingFormGroup>
|
||||
);
|
||||
expect(screen.getByLabelText('label')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render children', () => {
|
||||
render(
|
||||
<TradingFormGroup label="label" labelFor="test">
|
||||
<input data-testid="foo" id="test"></input>
|
||||
</TradingFormGroup>
|
||||
);
|
||||
expect(screen.getByTestId('foo')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,53 +0,0 @@
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export interface TradingFormGroupProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
label: string | ReactNode; // For accessibility reasons this must always be set for screen readers. If you want it to not show, then use the hideLabel prop"
|
||||
labelFor: string; // Same as above
|
||||
hideLabel?: boolean;
|
||||
disabled?: boolean;
|
||||
labelDescription?: string;
|
||||
labelAlign?: 'left' | 'right';
|
||||
compact?: boolean;
|
||||
}
|
||||
|
||||
export const TradingFormGroup = ({
|
||||
children,
|
||||
className,
|
||||
label,
|
||||
labelFor,
|
||||
labelDescription,
|
||||
labelAlign = 'left',
|
||||
hideLabel = false,
|
||||
compact = false,
|
||||
disabled = false,
|
||||
}: TradingFormGroupProps) => {
|
||||
const wrapperClasses = classNames(
|
||||
'relative',
|
||||
{
|
||||
'mb-2': compact,
|
||||
'mb-4': !compact,
|
||||
},
|
||||
className
|
||||
);
|
||||
const labelClasses = classNames('block mb-2 text-xs', {
|
||||
'text-right': labelAlign === 'right',
|
||||
'sr-only': hideLabel,
|
||||
'text-muted': disabled,
|
||||
});
|
||||
return (
|
||||
<div data-testid="form-group" className={wrapperClasses}>
|
||||
{label && (
|
||||
<label htmlFor={labelFor} className={labelClasses}>
|
||||
{label}
|
||||
{labelDescription && (
|
||||
<div className="font-light mt-1">{labelDescription}</div>
|
||||
)}
|
||||
</label>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,47 +0,0 @@
|
||||
import type { StoryFn, Meta } from '@storybook/react';
|
||||
import { TradingInput } from '../trading-input';
|
||||
import type { TradingFormGroupProps } from './form-group';
|
||||
import { TradingFormGroup } from './form-group';
|
||||
export default {
|
||||
component: TradingFormGroup,
|
||||
title: 'FormGroup',
|
||||
argTypes: {
|
||||
label: {
|
||||
type: 'string',
|
||||
},
|
||||
labelFor: {
|
||||
type: 'string',
|
||||
},
|
||||
labelDescription: {
|
||||
type: 'string',
|
||||
},
|
||||
className: {
|
||||
type: 'string',
|
||||
},
|
||||
hasError: {
|
||||
type: 'boolean',
|
||||
},
|
||||
disabled: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
const Template: StoryFn<TradingFormGroupProps> = (args) => (
|
||||
<TradingFormGroup {...args}>
|
||||
<TradingInput id="labelFor" />
|
||||
</TradingFormGroup>
|
||||
);
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
label: 'Label',
|
||||
labelFor: 'labelFor',
|
||||
};
|
||||
|
||||
export const WithLabelDescription = Template.bind({});
|
||||
WithLabelDescription.args = {
|
||||
label: 'Label',
|
||||
labelFor: 'labelFor',
|
||||
labelDescription: 'Description text',
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export * from './form-group';
|
||||
@@ -1 +0,0 @@
|
||||
export * from './input-error';
|
||||
@@ -1,10 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { TradingInputError } from './input-error';
|
||||
|
||||
describe('InputError', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<TradingInputError />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
import type { StoryFn, Meta } from '@storybook/react';
|
||||
import { TradingInputError } from './input-error';
|
||||
|
||||
export default {
|
||||
component: TradingInputError,
|
||||
title: 'InputError',
|
||||
} as Meta;
|
||||
|
||||
const Template: StoryFn = (args) => <TradingInputError {...args} />;
|
||||
|
||||
export const Danger = Template.bind({});
|
||||
Danger.args = {
|
||||
children: 'An error that might have happened',
|
||||
};
|
||||
|
||||
export const Warning = Template.bind({});
|
||||
Warning.args = {
|
||||
intent: 'warning',
|
||||
children: 'Something that might be an issue',
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
import classNames from 'classnames';
|
||||
import type { HTMLAttributes } from 'react';
|
||||
|
||||
interface TradingInputErrorProps extends HTMLAttributes<HTMLDivElement> {
|
||||
children?: React.ReactNode;
|
||||
intent?: 'danger' | 'warning';
|
||||
forInput?: string;
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
export const TradingInputError = ({
|
||||
intent = 'danger',
|
||||
children,
|
||||
forInput,
|
||||
testId,
|
||||
className,
|
||||
...props
|
||||
}: TradingInputErrorProps) => {
|
||||
const effectiveClassName = classNames(
|
||||
'text-xs flex items-center first-letter:uppercase',
|
||||
'mt-2',
|
||||
{
|
||||
'border-danger': intent === 'danger',
|
||||
'border-warning': intent === 'warning',
|
||||
},
|
||||
{
|
||||
'text-warning': intent === 'warning',
|
||||
'text-danger': intent === 'danger',
|
||||
}
|
||||
);
|
||||
return (
|
||||
<div
|
||||
data-testid={testId || 'input-error-text'}
|
||||
aria-describedby={forInput}
|
||||
className={classNames(effectiveClassName, className)}
|
||||
{...props}
|
||||
role="alert"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export * from './input';
|
||||
@@ -1,10 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { TradingInput } from './input';
|
||||
|
||||
describe('Input', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<TradingInput />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
import type { StoryFn, Meta } from '@storybook/react';
|
||||
import { TradingInput } from './input';
|
||||
import { FormGroup } from '../form-group';
|
||||
export default {
|
||||
component: TradingInput,
|
||||
title: 'Input',
|
||||
} as Meta;
|
||||
|
||||
const Template: StoryFn = (args) => (
|
||||
<FormGroup label="Hello" labelFor={args.id}>
|
||||
<TradingInput value="I type words" {...args} />
|
||||
</FormGroup>
|
||||
);
|
||||
|
||||
const customElementPlaceholder = (
|
||||
<span
|
||||
style={{
|
||||
fontFamily: 'monospace',
|
||||
backgroundColor: 'grey',
|
||||
padding: '4px',
|
||||
}}
|
||||
>
|
||||
Ω
|
||||
</span>
|
||||
);
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
id: 'input-default',
|
||||
};
|
||||
|
||||
export const WithError = Template.bind({});
|
||||
WithError.args = {
|
||||
hasError: true,
|
||||
id: 'input-has-error',
|
||||
};
|
||||
|
||||
export const Disabled = Template.bind({});
|
||||
Disabled.args = {
|
||||
disabled: true,
|
||||
id: 'input-disabled',
|
||||
};
|
||||
|
||||
export const TypeDate = Template.bind({});
|
||||
TypeDate.args = {
|
||||
type: 'date',
|
||||
id: 'input-date',
|
||||
};
|
||||
|
||||
export const TypeDateTime = Template.bind({});
|
||||
TypeDateTime.args = {
|
||||
type: 'datetime-local',
|
||||
id: 'input-datetime-local',
|
||||
min: '2022-09-05T11:29:17',
|
||||
max: '2023-09-05T10:29:49',
|
||||
};
|
||||
|
||||
export const IconPrepend = Template.bind({});
|
||||
IconPrepend.args = {
|
||||
prependIconName: 'search',
|
||||
id: 'input-icon-prepend',
|
||||
};
|
||||
|
||||
export const IconAppend = Template.bind({});
|
||||
IconAppend.args = {
|
||||
value: 'I type words and even more words',
|
||||
appendIconName: 'search',
|
||||
id: 'input-icon-append',
|
||||
};
|
||||
|
||||
export const ElementPrepend = Template.bind({});
|
||||
ElementPrepend.args = {
|
||||
value: '<- custom element',
|
||||
prependElement: customElementPlaceholder,
|
||||
id: 'input-element-prepend',
|
||||
};
|
||||
|
||||
export const ElementAppend = Template.bind({});
|
||||
ElementAppend.args = {
|
||||
value: 'custom element ->',
|
||||
appendElement: customElementPlaceholder,
|
||||
id: 'input-element-append',
|
||||
};
|
||||
@@ -1,174 +0,0 @@
|
||||
import type { InputHTMLAttributes, ReactNode } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import type { IconName } from '../icon';
|
||||
import { Icon } from '../icon';
|
||||
import { defaultFormElement } from '../../utils/shared';
|
||||
|
||||
type InputRootProps = InputHTMLAttributes<HTMLInputElement> & {
|
||||
hasError?: boolean;
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
type NoPrepend = {
|
||||
prependIconName?: never;
|
||||
prependIconDescription?: string;
|
||||
prependElement?: never;
|
||||
};
|
||||
|
||||
type NoAppend = {
|
||||
appendIconName?: never;
|
||||
appendIconDescription?: string;
|
||||
appendElement?: never;
|
||||
};
|
||||
|
||||
type InputPrepend = NoAppend &
|
||||
(
|
||||
| NoPrepend
|
||||
| {
|
||||
prependIconName: IconName;
|
||||
prependIconDescription?: string;
|
||||
prependElement?: never;
|
||||
}
|
||||
| {
|
||||
prependIconName?: never;
|
||||
prependIconDescription?: never;
|
||||
prependElement: ReactNode;
|
||||
}
|
||||
);
|
||||
|
||||
type InputAppend = NoPrepend &
|
||||
(
|
||||
| NoAppend
|
||||
| {
|
||||
appendIconName: IconName;
|
||||
appendIconDescription?: string;
|
||||
appendElement?: never;
|
||||
}
|
||||
| {
|
||||
appendIconName?: never;
|
||||
appendIconDescription?: never;
|
||||
appendElement: ReactNode;
|
||||
}
|
||||
);
|
||||
|
||||
type AffixProps = InputPrepend | InputAppend;
|
||||
|
||||
export type TradingInputProps = InputRootProps & AffixProps;
|
||||
|
||||
export const tradingInputStyle = ({
|
||||
style,
|
||||
disabled,
|
||||
}: {
|
||||
style?: React.CSSProperties;
|
||||
disabled?: boolean;
|
||||
}) =>
|
||||
disabled
|
||||
? {
|
||||
...style,
|
||||
backgroundImage:
|
||||
'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAAXNSR0IArs4c6QAAACNJREFUGFdjtLS0/M8ABcePH2eEsRlJl4BpBdHIuuFmEi0BABqjEQVjx/LTAAAAAElFTkSuQmCC)',
|
||||
}
|
||||
: style;
|
||||
|
||||
const getAffixElement = ({
|
||||
prependElement,
|
||||
prependIconName,
|
||||
prependIconDescription,
|
||||
appendElement,
|
||||
appendIconName,
|
||||
appendIconDescription,
|
||||
}: Pick<TradingInputProps, keyof AffixProps>) => {
|
||||
const position = prependIconName || prependElement ? 'pre' : 'post';
|
||||
|
||||
const className = classNames(
|
||||
['fill-black dark:fill-white', 'absolute', 'z-10'],
|
||||
{
|
||||
'left-3': position === 'pre',
|
||||
'right-3': position === 'post',
|
||||
}
|
||||
);
|
||||
|
||||
const element = prependElement || appendElement;
|
||||
const iconName = prependIconName || appendIconName;
|
||||
const iconDescription = prependIconDescription || appendIconDescription;
|
||||
|
||||
if (element) {
|
||||
return <div className={className}>{element}</div>;
|
||||
}
|
||||
|
||||
if (iconName) {
|
||||
return (
|
||||
<Icon
|
||||
name={iconName}
|
||||
className={className}
|
||||
aria-label={iconDescription}
|
||||
aria-hidden={!iconDescription}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const TradingInput = forwardRef<HTMLInputElement, TradingInputProps>(
|
||||
(
|
||||
{
|
||||
prependIconName,
|
||||
prependIconDescription,
|
||||
appendIconName,
|
||||
appendIconDescription,
|
||||
prependElement,
|
||||
appendElement,
|
||||
className,
|
||||
hasError,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const hasPrepended = !!(prependIconName || prependElement);
|
||||
const hasAppended = !!(appendIconName || appendElement);
|
||||
|
||||
const inputClassName = classNames(
|
||||
'appearance-none dark:color-scheme-dark px-3 h-8',
|
||||
className,
|
||||
{
|
||||
'pl-9': hasPrepended,
|
||||
'pr-9': hasAppended,
|
||||
}
|
||||
);
|
||||
|
||||
const input = (
|
||||
<input
|
||||
{...props}
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
defaultFormElement(hasError, props.disabled),
|
||||
inputClassName
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
const element = getAffixElement({
|
||||
prependIconName,
|
||||
prependIconDescription,
|
||||
appendIconName,
|
||||
appendIconDescription,
|
||||
prependElement,
|
||||
appendElement,
|
||||
});
|
||||
|
||||
if (element) {
|
||||
return (
|
||||
<div className="flex items-center relative">
|
||||
{hasPrepended && element}
|
||||
{input}
|
||||
{hasAppended && element}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
);
|
||||
@@ -1 +0,0 @@
|
||||
export * from './radio-group';
|
||||
@@ -1,22 +0,0 @@
|
||||
import type { StoryFn, Meta } from '@storybook/react';
|
||||
import type { TradingRadioGroupProps } from './radio-group';
|
||||
import { TradingRadioGroup, TradingRadio } from './radio-group';
|
||||
|
||||
export default {
|
||||
component: TradingRadioGroup,
|
||||
title: 'RadioGroup',
|
||||
} as Meta;
|
||||
|
||||
const Template: StoryFn<TradingRadioGroupProps> = (args) => (
|
||||
<TradingRadioGroup {...args}>
|
||||
<TradingRadio id="item-1" value="1" label="Item 1" />
|
||||
<TradingRadio id="item-2" value="2" label="Item 2" />
|
||||
<TradingRadio id="item-3" value="3" label="Disabled item" disabled={true} />
|
||||
</TradingRadioGroup>
|
||||
);
|
||||
|
||||
export const Vertical = Template.bind({});
|
||||
export const Horizontal = Template.bind({});
|
||||
Horizontal.args = {
|
||||
orientation: 'horizontal',
|
||||
};
|
||||
@@ -1,99 +0,0 @@
|
||||
import { forwardRef } from 'react';
|
||||
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export interface TradingRadioGroupProps {
|
||||
name?: string;
|
||||
children: ReactNode;
|
||||
defaultValue?: string;
|
||||
value?: string;
|
||||
orientation?: 'horizontal' | 'vertical';
|
||||
onChange?: (value: string) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const TradingRadioGroup = forwardRef<
|
||||
HTMLDivElement,
|
||||
TradingRadioGroupProps
|
||||
>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
name,
|
||||
value,
|
||||
orientation = 'vertical',
|
||||
onChange,
|
||||
className,
|
||||
}: TradingRadioGroupProps,
|
||||
ref
|
||||
) => {
|
||||
const groupClasses = classNames(
|
||||
'flex text-sm',
|
||||
{
|
||||
'flex-col gap-2': orientation === 'vertical',
|
||||
'flex-row gap-4': orientation === 'horizontal',
|
||||
},
|
||||
className
|
||||
);
|
||||
return (
|
||||
<RadioGroupPrimitive.Root
|
||||
ref={ref}
|
||||
name={name}
|
||||
value={value}
|
||||
onValueChange={onChange}
|
||||
orientation={orientation}
|
||||
className={groupClasses}
|
||||
>
|
||||
{children}
|
||||
</RadioGroupPrimitive.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
interface RadioProps {
|
||||
id: string;
|
||||
value: string;
|
||||
label: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const TradingRadio = ({ id, value, label, disabled }: RadioProps) => {
|
||||
const wrapperClasses = classNames('flex items-center gap-1.5 text-xs');
|
||||
const itemClasses = classNames(
|
||||
'flex justify-center items-center',
|
||||
'w-3 h-3 rounded-full border',
|
||||
'border-vega-clight-500 dark:border-vega-cdark-500',
|
||||
'aria-checked:border-vega-clight-400 dark:aria-checked:border-vega-cdark-400',
|
||||
'disabled:border-vega-clight-600 dark:disabled:border-vega-cdark-600',
|
||||
'bg-vega-clight-700 dark:bg-vega-cdark-700'
|
||||
);
|
||||
const indicatorClasses = classNames(
|
||||
'block w-2.5 h-2.5 border-2 rounded-full',
|
||||
'bg-vega-clight-50 dark:bg-vega-cdark-50',
|
||||
'border-vega-clight-700 dark:border-vega-cdark-700'
|
||||
);
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
<RadioGroupPrimitive.Item
|
||||
value={value}
|
||||
className={itemClasses}
|
||||
id={id}
|
||||
data-testid={id}
|
||||
disabled={disabled}
|
||||
>
|
||||
<RadioGroupPrimitive.Indicator className={indicatorClasses} />
|
||||
</RadioGroupPrimitive.Item>
|
||||
<label
|
||||
htmlFor={id}
|
||||
className={
|
||||
disabled
|
||||
? 'text-vega-clight-200 dark:text-vega-cdark-200'
|
||||
: 'cursor-pointer'
|
||||
}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export * from './select';
|
||||
@@ -1,37 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { TradingRichSelect, TradingSelect, TradingOption } from './select';
|
||||
|
||||
describe('Select', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<TradingSelect />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('RichSelect', () => {
|
||||
it('should render select element with placeholder when no value is pre-selected', async () => {
|
||||
const { findByTestId } = render(
|
||||
<TradingRichSelect placeholder={'Select'}>
|
||||
<TradingOption value={'1'}>1</TradingOption>
|
||||
<TradingOption value={'2'}>2</TradingOption>
|
||||
</TradingRichSelect>
|
||||
);
|
||||
const btn = (await findByTestId(
|
||||
'rich-select-trigger'
|
||||
)) as HTMLButtonElement;
|
||||
expect(btn.textContent).toEqual('Select');
|
||||
});
|
||||
|
||||
it('should render select element with pre-selected value', async () => {
|
||||
const { findByTestId } = render(
|
||||
<TradingRichSelect placeholder={'Select'} value={'1'}>
|
||||
<TradingOption value={'1'}>1</TradingOption>
|
||||
<TradingOption value={'2'}>2</TradingOption>
|
||||
</TradingRichSelect>
|
||||
);
|
||||
const btn = (await findByTestId(
|
||||
'rich-select-trigger'
|
||||
)) as HTMLButtonElement;
|
||||
expect(btn.textContent).toEqual('1');
|
||||
});
|
||||
});
|
||||
@@ -1,92 +0,0 @@
|
||||
import type { StoryFn, Meta } from '@storybook/react';
|
||||
import { TradingOption, TradingSelect, TradingRichSelect } from './select';
|
||||
import { FormGroup } from '../form-group';
|
||||
|
||||
export default {
|
||||
component: TradingSelect,
|
||||
title: 'Select',
|
||||
} as Meta;
|
||||
|
||||
const Template: StoryFn = (args) => (
|
||||
<FormGroup label="Select an option" labelFor={args.id}>
|
||||
<TradingSelect {...args}>
|
||||
<option value="Option 1">Option 1</option>
|
||||
<option value="Option 2">Option 2</option>
|
||||
<option value="Option 3">Option 3</option>
|
||||
</TradingSelect>
|
||||
</FormGroup>
|
||||
);
|
||||
|
||||
const RichSelectTemplate: StoryFn = ({ placeholder, ...props }) => (
|
||||
<FormGroup label="Select an option" labelFor={props.id}>
|
||||
<TradingRichSelect placeholder={placeholder} {...props} />
|
||||
</FormGroup>
|
||||
);
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
id: 'select-default',
|
||||
};
|
||||
|
||||
export const WithError = Template.bind({});
|
||||
WithError.args = {
|
||||
id: 'select-has-error',
|
||||
hasError: true,
|
||||
};
|
||||
|
||||
export const Disabled = Template.bind({});
|
||||
Disabled.args = {
|
||||
id: 'select-disabled',
|
||||
disabled: true,
|
||||
};
|
||||
|
||||
export const RichDefaultSelect = RichSelectTemplate.bind({});
|
||||
RichDefaultSelect.args = {
|
||||
id: 'rich',
|
||||
name: 'rich',
|
||||
placeholder: 'Select an option',
|
||||
onValueChange: (v: string) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(v);
|
||||
},
|
||||
children: (
|
||||
<>
|
||||
<TradingOption value="1">
|
||||
<div className="flex flex-col justify-start items-start">
|
||||
<span>Option One</span>
|
||||
<span className="text-xs">First option</span>
|
||||
</div>
|
||||
</TradingOption>
|
||||
<TradingOption value="2">
|
||||
<div className="flex flex-col justify-start items-start">
|
||||
<span>Option Two</span>
|
||||
<span className="text-xs">Second option</span>
|
||||
</div>
|
||||
</TradingOption>
|
||||
<TradingOption value="3">
|
||||
<div className="flex flex-col justify-start items-start">
|
||||
<span>Option Three</span>
|
||||
<span className="text-xs">Third option</span>
|
||||
</div>
|
||||
</TradingOption>
|
||||
<TradingOption value="4">
|
||||
<div className="flex flex-col justify-start items-start">
|
||||
<span>Option Four</span>
|
||||
<span className="text-xs">Fourth option</span>
|
||||
</div>
|
||||
</TradingOption>
|
||||
<TradingOption value="5">
|
||||
<div className="flex flex-col justify-start items-start">
|
||||
<span>Option Five</span>
|
||||
<span className="text-xs">Fifth option</span>
|
||||
</div>
|
||||
</TradingOption>
|
||||
<TradingOption value="6">
|
||||
<div className="flex flex-col justify-start items-start">
|
||||
<span>Option Six</span>
|
||||
<span className="text-xs">Sixth option</span>
|
||||
</div>
|
||||
</TradingOption>
|
||||
</>
|
||||
),
|
||||
};
|
||||
@@ -1,129 +0,0 @@
|
||||
import type { Ref, SelectHTMLAttributes } from 'react';
|
||||
import { useRef } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Icon } from '..';
|
||||
import { defaultSelectElement } from '../../utils/shared';
|
||||
import * as SelectPrimitive from '@radix-ui/react-select';
|
||||
|
||||
export interface TradingSelectProps
|
||||
extends SelectHTMLAttributes<HTMLSelectElement> {
|
||||
hasError?: boolean;
|
||||
className?: string;
|
||||
value?: string | number;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const TradingSelect = forwardRef<HTMLSelectElement, TradingSelectProps>(
|
||||
({ className, hasError, ...props }, ref) => (
|
||||
<div className="flex items-center relative">
|
||||
<select
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={classNames(
|
||||
defaultSelectElement(hasError, props.disabled),
|
||||
className,
|
||||
'appearance-none rounded-md'
|
||||
)}
|
||||
/>
|
||||
<Icon
|
||||
name="chevron-down"
|
||||
className="absolute right-4 z-10 pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
|
||||
export type TradingRichSelectProps = React.ComponentProps<
|
||||
typeof SelectPrimitive.Root
|
||||
> & {
|
||||
placeholder: string;
|
||||
hasError?: boolean;
|
||||
id?: string;
|
||||
'data-testid'?: string;
|
||||
};
|
||||
export const TradingRichSelect = forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
TradingRichSelectProps
|
||||
>(({ id, children, placeholder, hasError, ...props }, forwardedRef) => {
|
||||
const containerRef = useRef<HTMLDivElement>();
|
||||
const contentRef = useRef<HTMLDivElement>();
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef as Ref<HTMLDivElement>}
|
||||
className="flex items-center relative"
|
||||
>
|
||||
<SelectPrimitive.Root {...props} defaultOpen={false}>
|
||||
<SelectPrimitive.Trigger
|
||||
data-testid={props['data-testid'] || 'rich-select-trigger'}
|
||||
className={classNames(
|
||||
defaultSelectElement(hasError, props.disabled),
|
||||
'rounded-md pl-2 pr-11',
|
||||
'max-w-full overflow-hidden break-all'
|
||||
)}
|
||||
id={id}
|
||||
ref={forwardedRef}
|
||||
>
|
||||
<SelectPrimitive.Value placeholder={placeholder} />
|
||||
<SelectPrimitive.Icon className={classNames('absolute right-4')}>
|
||||
<Icon name="chevron-down" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
<SelectPrimitive.Portal container={containerRef.current}>
|
||||
<SelectPrimitive.Content
|
||||
ref={contentRef as Ref<HTMLDivElement>}
|
||||
className={classNames(
|
||||
'relative',
|
||||
'z-20',
|
||||
'bg-white dark:bg-black',
|
||||
'border border-neutral-500 focus:border-black dark:focus:border-white rounded',
|
||||
'overflow-hidden',
|
||||
'shadow-lg'
|
||||
)}
|
||||
position={'item-aligned'}
|
||||
side={'bottom'}
|
||||
align={'center'}
|
||||
>
|
||||
<SelectPrimitive.ScrollUpButton className="flex items-center justify-center py-1 absolute w-full h-6 z-20 bg-gradient-to-t from-transparent to-neutral-50 dark:to-neutral-900">
|
||||
<Icon name="chevron-up" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
<SelectPrimitive.Viewport>{children}</SelectPrimitive.Viewport>
|
||||
<SelectPrimitive.ScrollDownButton className="flex items-center justify-center py-1 absolute bottom-0 w-full h-6 z-20 bg-gradient-to-b from-transparent to-neutral-50 dark:to-neutral-900">
|
||||
<Icon name="chevron-down" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
</SelectPrimitive.Root>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const TradingOption = forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentProps<typeof SelectPrimitive.Item>
|
||||
>(({ children, className, ...props }, forwardedRef) => (
|
||||
<SelectPrimitive.Item
|
||||
data-testid="rich-select-option"
|
||||
className={classNames(
|
||||
'relative',
|
||||
'text-black dark:text-white',
|
||||
'cursor-pointer outline-none',
|
||||
'hover:bg-neutral-100 dark:hover:bg-neutral-800',
|
||||
'focus:bg-neutral-100 dark:focus:bg-neutral-800',
|
||||
'pl-2 py-2',
|
||||
'pr-12',
|
||||
'w-full',
|
||||
'text-sm',
|
||||
'data-selected:bg-vega-yellow dark:data-selected:text-black dark:data-selected:bg-vega-yellow',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={forwardedRef}
|
||||
>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
<SelectPrimitive.ItemIndicator className="absolute right-4 top-[50%] translate-y-[-50%]">
|
||||
<Icon name="tick" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</SelectPrimitive.Item>
|
||||
));
|
||||
@@ -1,20 +1,18 @@
|
||||
import classnames from 'classnames';
|
||||
|
||||
export const defaultSelectElement = (hasError?: boolean, disabled?: boolean) =>
|
||||
classnames(defaultFormElement(hasError, disabled), 'pr-10 min-h-8 py-1');
|
||||
export const defaultSelectElement = (hasError?: boolean) =>
|
||||
classnames(defaultFormElement(hasError), 'pr-10 dark:bg-black');
|
||||
|
||||
export const defaultFormElement = (hasError?: boolean, disabled?: boolean) =>
|
||||
export const defaultFormElement = (hasError?: boolean) =>
|
||||
classnames(
|
||||
'flex items-center w-full text-sm',
|
||||
'p-2 rounded whitespace-nowrap text-ellipsis overflow-hidden',
|
||||
'bg-transparent',
|
||||
'border',
|
||||
'focus:border-vega-clight-400 dark:focus:border-vega-cdark-400',
|
||||
'focus:border-vega-light-300 dark:focus:border-vega-dark-300',
|
||||
'disabled:opacity-60',
|
||||
{
|
||||
'bg-vega-clight-700 dark:bg-vega-cdark-700': !disabled && !hasError,
|
||||
'bg-transparent': disabled || hasError,
|
||||
'border-vega-clight-600 dark:border-vega-cdark-600': disabled,
|
||||
'border-vega-red-500': !disabled && hasError,
|
||||
'border-vega-clight-500 dark:border-vega-cdark-500':
|
||||
!disabled && !hasError,
|
||||
'border-vega-pink text-vega-pink': hasError,
|
||||
'border-vega-light-200 dark:border-vega-dark-200': !hasError,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@vegaprotocol/utils",
|
||||
"version": "0.0.8",
|
||||
"version": "0.0.7",
|
||||
"type": "commonjs"
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ import classNames from 'classnames';
|
||||
import { create } from 'zustand';
|
||||
import {
|
||||
Dialog,
|
||||
FormGroup,
|
||||
Input,
|
||||
Intent,
|
||||
Pill,
|
||||
TradingButton,
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
@@ -421,17 +421,17 @@ const CustomUrlInput = ({
|
||||
<VegaIcon name={VegaIconNames.ARROW_LEFT} /> {t('Go back')}
|
||||
</button>
|
||||
</div>
|
||||
<TradingFormGroup
|
||||
<FormGroup
|
||||
labelFor="wallet-url"
|
||||
label={t('Custom wallet location')}
|
||||
hideLabel
|
||||
>
|
||||
<TradingInput
|
||||
<Input
|
||||
value={walletUrl}
|
||||
onChange={(e) => setWalletUrl(e.target.value)}
|
||||
name="wallet-url"
|
||||
/>
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
<ConnectionOption
|
||||
disabled={!isDesktopWalletRunning}
|
||||
type="jsonRpc"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
TradingInputError,
|
||||
FormGroup,
|
||||
Input,
|
||||
InputError,
|
||||
Intent,
|
||||
TradingButton,
|
||||
VegaIcon,
|
||||
@@ -60,8 +60,8 @@ export function ViewConnectorForm({
|
||||
'Browse from the perspective of another Vega user in read-only mode.'
|
||||
)}
|
||||
</p>
|
||||
<TradingFormGroup label={t('Vega Pubkey')} labelFor="address">
|
||||
<TradingInput
|
||||
<FormGroup label={t('Vega Pubkey')} labelFor="address">
|
||||
<Input
|
||||
{...register('address', {
|
||||
required: t('Required'),
|
||||
validate: validatePubkey,
|
||||
@@ -71,11 +71,9 @@ export function ViewConnectorForm({
|
||||
type="text"
|
||||
/>
|
||||
{errors.address?.message && (
|
||||
<TradingInputError intent="danger">
|
||||
{errors.address.message}
|
||||
</TradingInputError>
|
||||
<InputError intent="danger">{errors.address.message}</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
<TradingButton
|
||||
data-testid="connect"
|
||||
intent={Intent.Info}
|
||||
|
||||
@@ -12,11 +12,11 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import { useLocalStorage } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
Button,
|
||||
TradingFormGroup,
|
||||
TradingInput,
|
||||
TradingInputError,
|
||||
FormGroup,
|
||||
Input,
|
||||
InputError,
|
||||
Notification,
|
||||
TradingRichSelect,
|
||||
RichSelect,
|
||||
ExternalLink,
|
||||
Intent,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
@@ -150,7 +150,7 @@ export const WithdrawForm = ({
|
||||
field: ControllerRenderProps<FormFields, 'asset'>;
|
||||
}) => {
|
||||
return (
|
||||
<TradingRichSelect
|
||||
<RichSelect
|
||||
data-testid="select-asset"
|
||||
id="asset"
|
||||
name="asset"
|
||||
@@ -170,7 +170,7 @@ export const WithdrawForm = ({
|
||||
balance={<AssetBalance asset={a} />}
|
||||
/>
|
||||
))}
|
||||
</TradingRichSelect>
|
||||
</RichSelect>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -193,7 +193,7 @@ export const WithdrawForm = ({
|
||||
noValidate={true}
|
||||
data-testid="withdraw-form"
|
||||
>
|
||||
<TradingFormGroup label={t('Asset')} labelFor="asset">
|
||||
<FormGroup label={t('Asset')} labelFor="asset">
|
||||
<Controller
|
||||
control={control}
|
||||
name="asset"
|
||||
@@ -205,12 +205,10 @@ export const WithdrawForm = ({
|
||||
render={renderAssetsSelector}
|
||||
/>
|
||||
{errors.asset?.message && (
|
||||
<TradingInputError intent="danger">
|
||||
{errors.asset.message}
|
||||
</TradingInputError>
|
||||
<InputError intent="danger">{errors.asset.message}</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
<TradingFormGroup
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={t('To (Ethereum address)')}
|
||||
labelFor="ethereum-address"
|
||||
>
|
||||
@@ -220,17 +218,15 @@ export const WithdrawForm = ({
|
||||
clearErrors('to');
|
||||
}}
|
||||
/>
|
||||
<TradingInput
|
||||
<Input
|
||||
id="ethereum-address"
|
||||
data-testid="eth-address-input"
|
||||
{...register('to', { validate: { required, ethereumAddress } })}
|
||||
/>
|
||||
{errors.to?.message && (
|
||||
<TradingInputError intent="danger">
|
||||
{errors.to.message}
|
||||
</TradingInputError>
|
||||
<InputError intent="danger">{errors.to.message}</InputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
{selectedAsset && threshold && (
|
||||
<div className="mb-4">
|
||||
<WithdrawLimits
|
||||
@@ -242,8 +238,8 @@ export const WithdrawForm = ({
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<TradingFormGroup label={t('Amount')} labelFor="amount">
|
||||
<TradingInput
|
||||
<FormGroup label={t('Amount')} labelFor="amount">
|
||||
<Input
|
||||
data-testid="amount-input"
|
||||
type="number"
|
||||
autoComplete="off"
|
||||
@@ -263,9 +259,7 @@ export const WithdrawForm = ({
|
||||
})}
|
||||
/>
|
||||
{errors.amount?.message && (
|
||||
<TradingInputError intent="danger">
|
||||
{errors.amount.message}
|
||||
</TradingInputError>
|
||||
<InputError intent="danger">{errors.amount.message}</InputError>
|
||||
)}
|
||||
{selectedAsset && (
|
||||
<UseButton
|
||||
@@ -288,7 +282,7 @@ export const WithdrawForm = ({
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
</FormGroup>
|
||||
<Button
|
||||
data-testid="submit-withdrawal"
|
||||
type="submit"
|
||||
|
||||
+1
-1
@@ -166,7 +166,7 @@
|
||||
"babel-jest": "29.4.3",
|
||||
"babel-loader": "8.1.0",
|
||||
"css-loader": "^6.4.0",
|
||||
"cypress": "12.17.0",
|
||||
"cypress": "^12.2.0",
|
||||
"cypress-mochawesome-reporter": "^3.3.0",
|
||||
"cypress-real-events": "^1.8.1",
|
||||
"dotenv": "^16.0.1",
|
||||
|
||||
@@ -53,6 +53,7 @@ for the a given Ethereum wallet/address/key:
|
||||
- **must** see how many tokens in each tranche are locked <a name="1005-VEST-025" href="#1005-VEST-025">1005-VEST-025</a>
|
||||
- **must** see how many tokens in each tranche are redeemable <a name="1005-VEST-026" href="#1005-VEST-026">1005-VEST-026</a>
|
||||
- **must** see an option to redeem from tranche <a name="1005-VEST-027" href="#1005-VEST-027">1005-VEST-027</a>
|
||||
- **must** be warned if amount that can be redeemed from that tranche is greater than the un-associated balance for that Eth key (because this will cause the redeem function to fail) <a name="1005-VEST-028" href="#1005-VEST-028">1005-VEST-028</a>
|
||||
- **should** see how many tokens I'd need to disassociate to be able to run the redeem function (this should be rounded up to avoid the transaction failing due to more tokens having unlocked since the user looked at the form)
|
||||
- **should** see link to [disassociate](1004-ASSO-associate.md)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
## Closed Markets
|
||||
|
||||
- **Must** see market's instrument code (<a name="6001-MARK-001" href="#6001-MARK-001">6001-MARK-001</a>)
|
||||
- **Must** see market's product type (<a name="6001-MARK-071" href="#6001-MARK-071">6001-MARK-071</a>)
|
||||
- **Must** see market's instrument name (sometimes labelled 'description') (<a name="6001-MARK-002" href="#6001-MARK-002">6001-MARK-002</a>)
|
||||
- **Must** see status (<a name="6001-MARK-003" href="#6001-MARK-003">6001-MARK-003</a>)
|
||||
- **Must** see the settlement date (<a name="6001-MARK-004" href="#6001-MARK-004">6001-MARK-004</a>)
|
||||
@@ -46,12 +45,10 @@
|
||||
- **Must** be able to close and open the market selector (<a name="6001-MARK-066" href="#6001-MARK-066">6001-MARK-066</a>)
|
||||
- **Must** must change color and have + or negative suffix of the price change and change color for the sparkline (<a name="6001-MARK-067" href="#6001-MARK-067">6001-MARK-067</a>)
|
||||
- **Must** be default tab "All" where there's no filtering by product. (<a name="6001-MARK-070" href="#6001-MARK-070">6001-MARK-070</a>)
|
||||
- If tab "All" is selected **Must** see product type (<a name="6001-MARK-072" href="#6001-MARK-072">6001-MARK-072</a>)
|
||||
|
||||
## All Markets
|
||||
|
||||
- **Must** see market's instrument code (<a name="6001-MARK-035" href="#6001-MARK-035">6001-MARK-035</a>)
|
||||
- **Must** see product type (<a name="6001-MARK-073" href="#6001-MARK-073">6001-MARK-073</a>)
|
||||
- **Must** see market's instrument name (sometimes labelled 'description') (<a name="6001-MARK-036" href="#6001-MARK-036">6001-MARK-036</a>)
|
||||
- **Must** see Trading mode (<a name="6001-MARK-037" href="#6001-MARK-037">6001-MARK-037</a>)
|
||||
- **Must** see status (<a name="6001-MARK-038" href="#6001-MARK-038">6001-MARK-038</a>)
|
||||
@@ -74,7 +71,6 @@
|
||||
## Proposed markets
|
||||
|
||||
- **Must** see market's instrument code (<a name="6001-MARK-049" href="#6001-MARK-049">6001-MARK-049</a>)
|
||||
- **Must** see product type (<a name="6001-MARK-074" href="#6001-MARK-074">6001-MARK-074</a>)
|
||||
- **Must** see market's instrument name (sometimes labelled 'description') (<a name="6001-MARK-050" href="#6001-MARK-050">6001-MARK-050</a>)
|
||||
- **Must** show the settlement asset (<a name="6001-MARK-051" href="#6001-MARK-051">6001-MARK-051</a>)
|
||||
- **Must** see state (<a name="6001-MARK-052" href="#6001-MARK-052">6001-MARK-052</a>)
|
||||
|
||||
@@ -13,31 +13,16 @@
|
||||
- **Must** show the asset symbol (<a name="7001-COLL-007" href="#7001-COLL-007">7001-COLL-007</a>)
|
||||
- **Must** provide a way to see the [full asset details](6501-ASSE-assets.md) (<a name="7001-COLL-008" href="#7001-COLL-008">7001-COLL-008</a>)
|
||||
- **Must** provide a way to see all accounts, their type, and their balance for a single asset (<a name="7001-COLL-009" href="#7001-COLL-009">7001-COLL-009</a>)
|
||||
- **Could** have default sort order (<a name="7001-COLL-010" href="#7001-COLL-010">7001-COLL-010</a>)
|
||||
- General
|
||||
- Margin
|
||||
- Bond
|
||||
- Fees - Maker
|
||||
- Fees - Liquidity
|
||||
- Rewards - Maker Paid
|
||||
- Rewards - Maker Received
|
||||
- Rewards - Liquidity Provision Received Fees
|
||||
- Rewards - Market Proposers
|
||||
|
||||
## Accounts breakdown
|
||||
|
||||
- **Must** be able to see a breakdown of accounts for a single asset (<a name="7001-COLL-013" href="#7001-COLL-013">7001-COLL-013</a>)
|
||||
- **Must** be able to see the total amount of the selected asset (<a name="7001-COLL-014" href="#7001-COLL-014">7001-COLL-014</a>)
|
||||
- **Must** be able to see market code of margin account (<a name="7001-COLL-015" href="#7001-COLL-015">7001-COLL-015</a>)
|
||||
- **Must** be able to see product type of the margin account's associated market (<a name="7001-COLL-016" href="#7001-COLL-016">7001-COLL-016</a>)
|
||||
- **Must** be able to see account type (<a name="7001-COLL-017" href="#7001-COLL-017">7001-COLL-017</a>)
|
||||
- **Must** be able to see account balance (<a name="7001-COLL-018" href="#7001-COLL-018">7001-COLL-018</a>)
|
||||
- **Must** be able to see what percentage of that assets total is used by a margin account (<a name="7001-COLL-019" href="#7001-COLL-019">7001-COLL-019</a>)
|
||||
- **Must** be able to see margin health if its a margin account (<a name="7001-COLL-020" href="#7001-COLL-020">7001-COLL-020</a>)
|
||||
|
||||
### Margin health
|
||||
|
||||
TODO
|
||||
- **Could** have default sort order (<a name="7001-COLL-010" href="#7001-COLL-010">7001-COLL-010</a>)
|
||||
- General
|
||||
- Margin
|
||||
- Bond
|
||||
- Fees - Maker
|
||||
- Fees - Liquidity
|
||||
- Rewards - Maker Paid
|
||||
- Rewards - Maker Received
|
||||
- Rewards - Liquidity Provision Received Fees
|
||||
- Rewards - Market Proposers
|
||||
|
||||
## Deal Ticket
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ When looking at a list of orders, I...
|
||||
|
||||
- **must** see what [market](9001-DATA-data_display.md#market) an order is related to (either code, ID or name, preferable name) (<a name="7003-MORD-002" href="#7003-MORD-002">7003-MORD-002</a>)
|
||||
- **should** see what the `status` is of the market (particularly if it is not "normal")
|
||||
- **must** see product type of market's instrument (<a name="7003-MORD-020" href="#7003-MORD-020">7003-MORD-020</a>)
|
||||
- **must** see the [size](9001-DATA-data_display.md#size) of the order (<a name="7003-MORD-003" href="#7003-MORD-003">7003-MORD-003</a>)
|
||||
- **must** see the [direction/side](9001-DATA-data_display.md#direction--side) (Long or Short) of the order (this can be implied with a + or negative suffix on the size, + for Long, - for short) (<a name="7003-MORD-004" href="#7003-MORD-004">7003-MORD-004</a>)
|
||||
- **must** see [order type](9001-DATA-data_display.md#order-type) (<a name="7003-MORD-005" href="#7003-MORD-005">7003-MORD-005</a>)
|
||||
|
||||
@@ -57,13 +57,9 @@ The quantum is a value that is used to define "The minimum economically meaningf
|
||||
## Market
|
||||
|
||||
Markets do not have names, technically it is the instrument within a market that has the name. Theoretically the same instrument can be traded in multiple markets. if/when this happens a user needs to be able to disambiguate between markets. Each market does have a unique ID, Note: this is a hash of the definition of the market when it was created.
|
||||
|
||||
Instruments have both a Name and Code, see [market framework](../protocol/0001-MKTF-market_framework.md) for how these are used. Generally the Code can save space once a user is familiar with the market. The Name is more descriptive and should be the default when discovering markets. It remains to be seen how the community will use these exactly.
|
||||
|
||||
Markets can have several statuses and it may be sensible when listing markets to highlight their status. e.g. if a market is usually in continuous trading mode, but is currently in an auction due to low liquidity. The market name field could be augmented to show the status (add an icon etc).
|
||||
|
||||
Near to instrument code or name its product type should be shown using the short name (Futr, Spot, Perp) or if space allows for it, then the long name may be used (Future, Spot, Perpetual).
|
||||
|
||||
## Public keys
|
||||
|
||||
> aka Party
|
||||
|
||||
@@ -2881,9 +2881,9 @@
|
||||
globby "^11.0.4"
|
||||
|
||||
"@cypress/request@^2.88.10":
|
||||
version "2.88.12"
|
||||
resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.12.tgz#ba4911431738494a85e93fb04498cb38bc55d590"
|
||||
integrity sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==
|
||||
version "2.88.10"
|
||||
resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce"
|
||||
integrity sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
@@ -2898,9 +2898,9 @@
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.10.3"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "^4.1.3"
|
||||
tough-cookie "~2.5.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^8.3.2"
|
||||
|
||||
@@ -8247,9 +8247,9 @@
|
||||
integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
|
||||
|
||||
"@types/node@^14.14.31":
|
||||
version "14.18.55"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.55.tgz#c60ad83c7d87c2d933cc4c1cb7d54d98ae50e460"
|
||||
integrity sha512-PiNZnJDie6lgSWfjWYcQ8KWrEHp0bGv1WgnQAUuaao/HpUBKNX+HXubScoMRdLXBuovbte0djGtsxiWScvlQUQ==
|
||||
version "14.18.32"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.32.tgz#8074f7106731f1a12ba993fe8bad86ee73905014"
|
||||
integrity sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow==
|
||||
|
||||
"@types/node@^16.0.0":
|
||||
version "16.18.37"
|
||||
@@ -12337,10 +12337,10 @@ cypress-real-events@^1.8.1:
|
||||
resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.8.1.tgz#d00c7fe93124bbe7c0f27296684838614d24a840"
|
||||
integrity sha512-8fFnA8EzS3EVbAmpSEUf3A8yZCmfU3IPOSGUDVFCdE1ke1gYL1A+gvXXV6HKUbTPRuvKKt2vpaMbUwYLpDRswQ==
|
||||
|
||||
cypress@12.17.0:
|
||||
version "12.17.0"
|
||||
resolved "https://registry.yarnpkg.com/cypress/-/cypress-12.17.0.tgz#3a907a41c4afbb44be7b84e822e4914d734a6bb0"
|
||||
integrity sha512-nq0ug8Zrjq/2khHU1PTNxg+3/n1oqtmAFCxwQhS6QzkQ4mR6RLitX+cGIOuIMfnEbDAtVub0hZh661FOA16JxA==
|
||||
cypress@^12.2.0:
|
||||
version "12.16.0"
|
||||
resolved "https://registry.yarnpkg.com/cypress/-/cypress-12.16.0.tgz#d0dcd0725a96497f4c60cf54742242259847924c"
|
||||
integrity sha512-mwv1YNe48hm0LVaPgofEhGCtLwNIQEjmj2dJXnAkY1b4n/NE9OtgPph4TyS+tOtYp5CKtRmDvBzWseUXQTjbTg==
|
||||
dependencies:
|
||||
"@cypress/request" "^2.88.10"
|
||||
"@cypress/xvfb" "^1.2.4"
|
||||
@@ -12379,7 +12379,7 @@ cypress@12.17.0:
|
||||
pretty-bytes "^5.6.0"
|
||||
proxy-from-env "1.0.0"
|
||||
request-progress "^3.0.0"
|
||||
semver "^7.5.3"
|
||||
semver "^7.3.2"
|
||||
supports-color "^8.1.1"
|
||||
tmp "~0.2.1"
|
||||
untildify "^4.0.0"
|
||||
@@ -20881,7 +20881,7 @@ prr@~1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
||||
integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==
|
||||
|
||||
psl@^1.1.33:
|
||||
psl@^1.1.28, psl@^1.1.33:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
|
||||
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
|
||||
@@ -20998,12 +20998,10 @@ qs@^6.10.3:
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
qs@~6.10.3:
|
||||
version "6.10.5"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.5.tgz#974715920a80ff6a262264acd2c7e6c2a53282b4"
|
||||
integrity sha512-O5RlPh0VFtR78y79rgcgKK4wbAI0C5zGVLztOIdpWX6ep368q5Hv6XRxDvXuZ9q3C6v+e3n8UfZZJw7IIG27eQ==
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
qs@~6.5.2:
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
|
||||
integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
|
||||
|
||||
query-string@6.13.5:
|
||||
version "6.13.5"
|
||||
@@ -22271,13 +22269,6 @@ semver@^7.5.1:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^7.5.3:
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@~7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
|
||||
@@ -23531,7 +23522,7 @@ toml@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee"
|
||||
integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==
|
||||
|
||||
tough-cookie@^4.1.2, tough-cookie@^4.1.3:
|
||||
tough-cookie@^4.1.2:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
|
||||
integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
|
||||
@@ -23541,6 +23532,14 @@ tough-cookie@^4.1.2, tough-cookie@^4.1.3:
|
||||
universalify "^0.2.0"
|
||||
url-parse "^1.5.3"
|
||||
|
||||
tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||
dependencies:
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tr46@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
|
||||
|
||||
Reference in New Issue
Block a user