chore(trading): dropdown alignments, account history default asset, transfer dialog asset selector (#4239)

This commit is contained in:
Art 2023-07-05 13:02:02 +02:00 committed by GitHub
parent fc8f12d6fc
commit f6fc4df1c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 286 additions and 333 deletions

View File

@ -153,7 +153,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
cy.get(dropdownContent) cy.get(dropdownContent)
.find(dropdownContentItem) .find(dropdownContentItem)
.eq(2) .eq(2)
.should('have.text', 'View asset'); .should('have.text', 'View settlement asset details');
cy.getByTestId('market-actions-content').click(); cy.getByTestId('market-actions-content').click();
}); });

View File

@ -18,7 +18,7 @@ import type {
MarketMaybeWithData, MarketMaybeWithData,
} from '@vegaprotocol/markets'; } from '@vegaprotocol/markets';
import { import {
MarketTableActions, MarketActionsDropdown,
closedMarketsWithDataProvider, closedMarketsWithDataProvider,
} from '@vegaprotocol/markets'; } from '@vegaprotocol/markets';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
@ -291,7 +291,7 @@ const ClosedMarketsDataGrid = ({
cellRenderer: ({ data }: VegaICellRendererParams<Row>) => { cellRenderer: ({ data }: VegaICellRendererParams<Row>) => {
if (!data) return null; if (!data) return null;
return ( return (
<MarketTableActions <MarketActionsDropdown
marketId={data.id} marketId={data.id}
assetId={data.settlementAsset.id} assetId={data.settlementAsset.id}
/> />

View File

@ -24,7 +24,10 @@ import { PriceChart } from 'pennant';
import 'pennant/dist/style.css'; import 'pennant/dist/style.css';
import type { Account } from '@vegaprotocol/accounts'; import type { Account } from '@vegaprotocol/accounts';
import { accountsDataProvider } from '@vegaprotocol/accounts'; import { accountsDataProvider } from '@vegaprotocol/accounts';
import { useThemeSwitcher } from '@vegaprotocol/react-helpers'; import {
useLocalStorageSnapshot,
useThemeSwitcher,
} from '@vegaprotocol/react-helpers';
import { useDataProvider } from '@vegaprotocol/data-provider'; import { useDataProvider } from '@vegaprotocol/data-provider';
import type { Market } from '@vegaprotocol/markets'; import type { Market } from '@vegaprotocol/markets';
@ -68,7 +71,7 @@ export const AccountHistoryContainer = () => {
const { data: assets } = useAssetsDataProvider(); const { data: assets } = useAssetsDataProvider();
if (!pubKey) { if (!pubKey) {
return <Splash>Connect wallet</Splash>; return <Splash>{t('Connect wallet')}</Splash>;
} }
return ( return (
@ -114,7 +117,15 @@ const AccountHistoryManager = ({
.sort((a, b) => a.name.localeCompare(b.name)), .sort((a, b) => a.name.localeCompare(b.name)),
[assetData, assetIds] [assetData, assetIds]
); );
const [asset, setAsset] = useState<AssetFieldsFragment>(assets[0]); const [assetId, setAssetId] = useLocalStorageSnapshot(
'account-history-active-asset-id'
);
const asset = useMemo(
() => assets.find((a) => a.id === assetId) || assets[0],
[assetId, assets]
);
const [range, setRange] = useState<typeof DateRange[keyof typeof DateRange]>( const [range, setRange] = useState<typeof DateRange[keyof typeof DateRange]>(
DateRange.RANGE_1M DateRange.RANGE_1M
); );
@ -146,10 +157,10 @@ const AccountHistoryManager = ({
m.tradableInstrument.instrument.product.settlementAsset.id; m.tradableInstrument.instrument.product.settlementAsset.id;
const newAsset = assets.find((item) => item.id === newAssetId); const newAsset = assets.find((item) => item.id === newAssetId);
if ((!asset || (assets && newAssetId !== asset.id)) && newAsset) { if ((!asset || (assets && newAssetId !== asset.id)) && newAsset) {
setAsset(newAsset); setAssetId(newAsset.id);
} }
}, },
[asset, assets] [asset, assets, setAssetId]
); );
const variables = useMemo( const variables = useMemo(
@ -211,14 +222,14 @@ const AccountHistoryManager = ({
> >
<DropdownMenuContent> <DropdownMenuContent>
{assets.map((a) => ( {assets.map((a) => (
<DropdownMenuItem key={a.id} onClick={() => setAsset(a)}> <DropdownMenuItem key={a.id} onClick={() => setAssetId(a.id)}>
{a.symbol} {a.symbol}
</DropdownMenuItem> </DropdownMenuItem>
))} ))}
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
); );
}, [assets, asset]); }, [asset, assets, setAssetId]);
const marketsMenu = useMemo(() => { const marketsMenu = useMemo(() => {
return accountType === Schema.AccountType.ACCOUNT_TYPE_MARGIN && return accountType === Schema.AccountType.ACCOUNT_TYPE_MARGIN &&
markets?.length ? ( markets?.length ? (

View File

@ -1,11 +1,9 @@
import { ETHERSCAN_ADDRESS, useEtherscanLink } from '@vegaprotocol/environment'; import { ETHERSCAN_ADDRESS, useEtherscanLink } from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { import {
DropdownMenu, ActionsDropdown,
DropdownMenuContent,
DropdownMenuCopyItem, DropdownMenuCopyItem,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger,
Link, Link,
VegaIcon, VegaIcon,
VegaIconNames, VegaIconNames,
@ -29,75 +27,65 @@ export const AccountsActionsDropdown = ({
const etherscanLink = useEtherscanLink(); const etherscanLink = useEtherscanLink();
const openTransferDialog = useTransferDialog((store) => store.open); const openTransferDialog = useTransferDialog((store) => store.open);
const openAssetDialog = useAssetDetailsDialogStore((store) => store.open); const openAssetDialog = useAssetDetailsDialogStore((store) => store.open);
return ( return (
<DropdownMenu <ActionsDropdown>
trigger={ <DropdownMenuItem
<DropdownMenuTrigger key={'deposit'}
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full" data-testid="deposit"
data-testid="dropdown-menu" onClick={onClickDeposit}
> >
<VegaIcon name={VegaIconNames.KEBAB} /> <VegaIcon name={VegaIconNames.DEPOSIT} size={16} />
</DropdownMenuTrigger> {t('Deposit')}
} </DropdownMenuItem>
> <DropdownMenuItem
<DropdownMenuContent> key={'withdraw'}
<DropdownMenuItem data-testid="withdraw"
key={'deposit'} onClick={onClickWithdraw}
data-testid="deposit" >
onClick={onClickDeposit} <VegaIcon name={VegaIconNames.WITHDRAW} size={16} />
> {t('Withdraw')}
<VegaIcon name={VegaIconNames.DEPOSIT} size={16} /> </DropdownMenuItem>
{t('Deposit')} <DropdownMenuItem
key={'transfer'}
data-testid="transfer"
onClick={() => openTransferDialog(true, assetId)}
>
<VegaIcon name={VegaIconNames.TRANSFER} size={16} />
{t('Transfer')}
</DropdownMenuItem>
<DropdownMenuItem
key={'breakdown'}
data-testid="breakdown"
onClick={onClickBreakdown}
>
<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />
{t('View usage breakdown')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={(e) => {
openAssetDialog(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.INFO} size={16} />
{t('View asset details')}
</DropdownMenuItem>
<DropdownMenuCopyItem value={assetId} text={t('Copy asset ID')} />
{assetContractAddress && (
<DropdownMenuItem>
<Link
href={etherscanLink(
ETHERSCAN_ADDRESS.replace(':hash', assetContractAddress)
)}
target="_blank"
>
<span className="flex gap-2">
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View on Etherscan')}
</span>
</Link>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem )}
key={'withdraw'} </ActionsDropdown>
data-testid="withdraw"
onClick={onClickWithdraw}
>
<VegaIcon name={VegaIconNames.WITHDRAW} size={16} />
{t('Withdraw')}
</DropdownMenuItem>
<DropdownMenuItem
key={'transfer'}
data-testid="transfer"
onClick={() => openTransferDialog(true, assetId)}
>
<VegaIcon name={VegaIconNames.TRANSFER} size={16} />
{t('Transfer')}
</DropdownMenuItem>
<DropdownMenuItem
key={'breakdown'}
data-testid="breakdown"
onClick={onClickBreakdown}
>
<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />
{t('Breakdown')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={(e) => {
openAssetDialog(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />
{t('View asset')}
</DropdownMenuItem>
<DropdownMenuCopyItem value={assetId} text={t('Copy asset ID')} />
{assetContractAddress && (
<DropdownMenuItem>
<Link
href={etherscanLink(
ETHERSCAN_ADDRESS.replace(':hash', assetContractAddress)
)}
target="_blank"
>
<span className="flex gap-2">
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View on Etherscan')}
</span>
</Link>
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenu>
); );
}; };

View File

@ -13,6 +13,7 @@ import { accountsDataProvider } from './accounts-data-provider';
import { TransferForm } from './transfer-form'; import { TransferForm } from './transfer-form';
import { useTransferDialog } from './transfer-dialog'; import { useTransferDialog } from './transfer-dialog';
import { Lozenge } from '@vegaprotocol/ui-toolkit'; import { Lozenge } from '@vegaprotocol/ui-toolkit';
import sortBy from 'lodash/sortBy';
export const TransferContainer = ({ assetId }: { assetId?: string }) => { export const TransferContainer = ({ assetId }: { assetId?: string }) => {
const { pubKey, pubKeys } = useVegaWallet(); const { pubKey, pubKeys } = useVegaWallet();
@ -58,7 +59,7 @@ export const TransferContainer = ({ assetId }: { assetId?: string }) => {
<TransferForm <TransferForm
pubKey={pubKey} pubKey={pubKey}
pubKeys={pubKeys ? pubKeys?.map((pk) => pk.publicKey) : null} pubKeys={pubKeys ? pubKeys?.map((pk) => pk.publicKey) : null}
assets={assets} assets={sortBy(assets, 'name')}
assetId={assetId} assetId={assetId}
feeFactor={param} feeFactor={param}
submitTransfer={transfer} submitTransfer={transfer}

View File

@ -8,7 +8,7 @@ import {
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { AddressField, TransferFee, TransferForm } from './transfer-form'; import { AddressField, TransferFee, TransferForm } from './transfer-form';
import { AccountType } from '@vegaprotocol/types'; import { AccountType } from '@vegaprotocol/types';
import { formatNumber, removeDecimal } from '@vegaprotocol/utils'; import { addDecimal, formatNumber, removeDecimal } from '@vegaprotocol/utils';
describe('TransferForm', () => { describe('TransferForm', () => {
const submit = () => fireEvent.submit(screen.getByTestId('transfer-form')); const submit = () => fireEvent.submit(screen.getByTestId('transfer-form'));
@ -16,11 +16,11 @@ describe('TransferForm', () => {
const pubKey = const pubKey =
'70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680'; '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680';
const asset = { const asset = {
id: 'asset-0', id: 'eur',
symbol: 'ASSET 0', symbol: '',
name: 'Asset 0', name: 'EUR',
decimals: 2, decimals: 2,
balance: '1000', balance: addDecimal(100000, 2), // 1000
}; };
const props = { const props = {
pubKey, pubKey,
@ -92,7 +92,7 @@ describe('TransferForm', () => {
expect(await screen.findByTestId('select-asset')).toHaveTextContent( expect(await screen.findByTestId('select-asset')).toHaveTextContent(
asset.name asset.name
); );
expect(screen.getByTestId('asset-balance')).toHaveTextContent( expect(await screen.findByTestId('asset-balance')).toHaveTextContent(
formatNumber(asset.balance, asset.decimals) formatNumber(asset.balance, asset.decimals)
); );
@ -168,7 +168,7 @@ describe('TransferForm', () => {
expect(await screen.findByTestId('select-asset')).toHaveTextContent( expect(await screen.findByTestId('select-asset')).toHaveTextContent(
asset.name asset.name
); );
expect(screen.getByTestId('asset-balance')).toHaveTextContent( expect(await screen.findByTestId('asset-balance')).toHaveTextContent(
formatNumber(asset.balance, asset.decimals) formatNumber(asset.balance, asset.decimals)
); );
@ -244,7 +244,7 @@ describe('TransferForm', () => {
expect(await screen.findByTestId('select-asset')).toHaveTextContent( expect(await screen.findByTestId('select-asset')).toHaveTextContent(
asset.name asset.name
); );
expect(screen.getByTestId('asset-balance')).toHaveTextContent( expect(await screen.findByTestId('asset-balance')).toHaveTextContent(
formatNumber(asset.balance, asset.decimals) formatNumber(asset.balance, asset.decimals)
); );

View File

@ -12,7 +12,6 @@ import {
FormGroup, FormGroup,
Input, Input,
InputError, InputError,
Option,
RichSelect, RichSelect,
Select, Select,
Tooltip, Tooltip,
@ -24,6 +23,7 @@ import BigNumber from 'bignumber.js';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { Controller, useForm } from 'react-hook-form'; import { Controller, useForm } from 'react-hook-form';
import { AssetOption, Balance } from '@vegaprotocol/assets';
interface FormFields { interface FormFields {
toAddress: string; toAddress: string;
@ -193,21 +193,20 @@ export const TransferForm = ({
onValueChange={(value) => { onValueChange={(value) => {
field.onChange(value); field.onChange(value);
}} }}
placeholder={t('Please select')} placeholder={t('Please select an asset')}
value={field.value} value={field.value}
> >
{assets.map((a) => ( {assets.map((a) => (
<Option key={a.id} value={a.id}> <AssetOption
<div className="text-left" data-testid={`asset-${a.id}`}> key={a.id}
<div>{a.name}</div> asset={a}
<div className="text-xs"> balance={
<span className="font-mono" data-testid="asset-balance"> <Balance
{formatNumber(a.balance, a.decimals)} balance={formatNumber(a.balance, a.decimals)}
</span>{' '} symbol={a.symbol}
<span>{a.symbol}</span> />
</div> }
</div> />
</Option>
))} ))}
</RichSelect> </RichSelect>
)} )}

View File

@ -5,7 +5,7 @@ import { t } from '@vegaprotocol/i18n';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
type AssetOptionProps = { type AssetOptionProps = {
asset: AssetFieldsFragment; asset: Pick<AssetFieldsFragment, 'id' | 'name' | 'symbol'>;
balance?: ReactNode; balance?: ReactNode;
}; };
@ -17,11 +17,13 @@ export const Balance = ({
symbol: string; symbol: string;
}) => }) =>
balance ? ( balance ? (
<div className="mt-1 font-alpha"> <div className="mt-1 font-alpha" data-testid="asset-balance">
{balance} {symbol} {balance} {symbol}
</div> </div>
) : ( ) : (
<div className="text-vega-orange-500">{t('Fetching balance…')}</div> <div className="text-vega-orange-500" data-testid="asset-balance">
{t('Fetching balance…')}
</div>
); );
export const AssetOption = ({ asset, balance }: AssetOptionProps) => { export const AssetOption = ({ asset, balance }: AssetOptionProps) => {

View File

@ -1,10 +1,6 @@
import { import {
DropdownMenu, ActionsDropdown,
DropdownMenuContent,
DropdownMenuCopyItem, DropdownMenuCopyItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
@ -18,27 +14,13 @@ export const FillActionsDropdown = ({
sellOrderId: string; sellOrderId: string;
}) => { }) => {
return ( return (
<DropdownMenu <ActionsDropdown data-testid="market-actions-content">
trigger={ <DropdownMenuCopyItem value={tradeId} text={t('Copy trade ID')} />
<DropdownMenuTrigger <DropdownMenuCopyItem value={buyOrderId} text={t('Copy buy order ID')} />
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full" <DropdownMenuCopyItem
data-testid="dropdown-menu" value={sellOrderId}
> text={t('Copy sell order ID')}
<VegaIcon name={VegaIconNames.KEBAB} /> />
</DropdownMenuTrigger> </ActionsDropdown>
}
>
<DropdownMenuContent data-testid="market-actions-content">
<DropdownMenuCopyItem value={tradeId} text={t('Copy trade ID')} />
<DropdownMenuCopyItem
value={buyOrderId}
text={t('Copy buy order ID')}
/>
<DropdownMenuCopyItem
value={sellOrderId}
text={t('Copy sell order ID')}
/>
</DropdownMenuContent>
</DropdownMenu>
); );
}; };

View File

@ -1,18 +1,16 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuCopyItem, DropdownMenuCopyItem,
Link, Link,
VegaIcon, VegaIcon,
VegaIconNames, VegaIconNames,
ActionsDropdown,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment'; import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
export const MarketTableActions = ({ export const MarketActionsDropdown = ({
marketId, marketId,
assetId, assetId,
}: { }: {
@ -21,39 +19,29 @@ export const MarketTableActions = ({
}) => { }) => {
const open = useAssetDetailsDialogStore((store) => store.open); const open = useAssetDetailsDialogStore((store) => store.open);
const linkCreator = useLinks(DApp.Explorer); const linkCreator = useLinks(DApp.Explorer);
return ( return (
<DropdownMenu <ActionsDropdown data-testid="market-actions-content">
trigger={ <DropdownMenuCopyItem value={marketId} text={t('Copy Market ID')} />
<DropdownMenuTrigger <DropdownMenuItem>
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full" <Link
data-testid="dropdown-menu" href={linkCreator(EXPLORER_MARKET.replace(':id', marketId))}
target="_blank"
> >
<VegaIcon name={VegaIconNames.KEBAB} /> <span className="flex gap-2">
</DropdownMenuTrigger> <VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
} {t('View on Explorer')}
> </span>
<DropdownMenuContent data-testid="market-actions-content"> </Link>
<DropdownMenuCopyItem value={marketId} text={t('Copy Market ID')} /> </DropdownMenuItem>
<DropdownMenuItem> <DropdownMenuItem
<Link onClick={(e) => {
href={linkCreator(EXPLORER_MARKET.replace(':id', marketId))} open(assetId, e.target as HTMLElement);
target="_blank" }}
> >
<span className="flex gap-2"> <VegaIcon name={VegaIconNames.INFO} size={16} />
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} /> {t('View settlement asset details')}
{t('View on Explorer')} </DropdownMenuItem>
</span> </ActionsDropdown>
</Link>
</DropdownMenuItem>
<DropdownMenuItem
onClick={(e) => {
open(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View asset')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
); );
}; };

View File

@ -12,7 +12,7 @@ import { addDecimalsFormatNumber, toBigNum } from '@vegaprotocol/utils';
import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import type { MarketMaybeWithData } from '../../markets-provider'; import type { MarketMaybeWithData } from '../../markets-provider';
import { MarketTableActions } from './market-table-actions'; import { MarketActionsDropdown } from './market-table-actions';
interface Props { interface Props {
onMarketClick: (marketId: string, metaKey?: boolean) => void; onMarketClick: (marketId: string, metaKey?: boolean) => void;
@ -172,7 +172,7 @@ export const useColumnDefs = ({ onMarketClick }: Props) => {
}: VegaICellRendererParams<MarketMaybeWithData>) => { }: VegaICellRendererParams<MarketMaybeWithData>) => {
if (!data) return null; if (!data) return null;
return ( return (
<MarketTableActions <MarketActionsDropdown
marketId={data.id} marketId={data.id}
assetId={ assetId={
data.tradableInstrument.instrument.product.settlementAsset.id data.tradableInstrument.instrument.product.settlementAsset.id

View File

@ -1,28 +1,13 @@
import { import {
DropdownMenu, ActionsDropdown,
DropdownMenuContent,
DropdownMenuCopyItem, DropdownMenuCopyItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
export const OrderActionsDropdown = ({ id }: { id: string }) => { export const OrderActionsDropdown = ({ id }: { id: string }) => {
return ( return (
<DropdownMenu <ActionsDropdown data-testid="market-actions-content">
trigger={ <DropdownMenuCopyItem value={id} text={t('Copy order ID')} />
<DropdownMenuTrigger </ActionsDropdown>
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full"
data-testid="dropdown-menu"
>
<VegaIcon name={VegaIconNames.KEBAB} />
</DropdownMenuTrigger>
}
>
<DropdownMenuContent data-testid="market-actions-content">
<DropdownMenuCopyItem value={id} text={t('Copy order ID')} />
</DropdownMenuContent>
</DropdownMenu>
); );
}; };

View File

@ -1,37 +1,25 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { import {
DropdownMenu, ActionsDropdown,
DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger,
VegaIcon, VegaIcon,
VegaIconNames, VegaIconNames,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
export const PositionTableActions = ({ assetId }: { assetId: string }) => { export const PositionActionsDropdown = ({ assetId }: { assetId: string }) => {
const open = useAssetDetailsDialogStore((store) => store.open); const open = useAssetDetailsDialogStore((store) => store.open);
return ( return (
<DropdownMenu <ActionsDropdown data-testid="market-actions-content">
trigger={ <DropdownMenuItem
<DropdownMenuTrigger onClick={(e) => {
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full" open(assetId, e.target as HTMLElement);
data-testid="dropdown-menu" }}
> >
<VegaIcon name={VegaIconNames.KEBAB} /> <VegaIcon name={VegaIconNames.INFO} size={16} />
</DropdownMenuTrigger> {t('View settlement asset details')}
} </DropdownMenuItem>
> </ActionsDropdown>
<DropdownMenuContent data-testid="market-actions-content">
<DropdownMenuItem
onClick={(e) => {
open(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View asset')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
); );
}; };

View File

@ -38,7 +38,7 @@ import type { Position } from './positions-data-providers';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import { PositionStatus, PositionStatusMapping } from '@vegaprotocol/types'; import { PositionStatus, PositionStatusMapping } from '@vegaprotocol/types';
import { DocsLinks } from '@vegaprotocol/environment'; import { DocsLinks } from '@vegaprotocol/environment';
import { PositionTableActions } from './position-actions-dropdown'; import { PositionActionsDropdown } from './position-actions-dropdown';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { LiquidationPrice } from './liquidation-price'; import { LiquidationPrice } from './liquidation-price';
@ -264,6 +264,7 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
if (!data) return null; if (!data) return null;
return ( return (
<ButtonLink <ButtonLink
title={t('View settlement asset details')}
onClick={(e) => { onClick={(e) => {
openAssetDetailsDialog( openAssetDetailsDialog(
data.assetId, data.assetId,
@ -449,7 +450,7 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
</ButtonLink> </ButtonLink>
) : null} ) : null}
{data?.assetId && ( {data?.assetId && (
<PositionTableActions assetId={data?.assetId} /> <PositionActionsDropdown assetId={data?.assetId} />
)} )}
</div> </div>
); );

View File

@ -1,39 +1,27 @@
import { import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger,
VegaIcon, VegaIcon,
VegaIconNames, VegaIconNames,
Link, Link,
ActionsDropdown,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment'; import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
export const ProposalActionsDropdown = ({ id }: { id: string }) => { export const ProposalActionsDropdown = ({ id }: { id: string }) => {
const linkCreator = useLinks(DApp.Token); const linkCreator = useLinks(DApp.Token);
return ( return (
<DropdownMenu <ActionsDropdown data-testid="market-actions-content">
trigger={ <DropdownMenuItem>
<DropdownMenuTrigger <Link
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full" href={linkCreator(TOKEN_PROPOSAL.replace(':id', id))}
data-testid="dropdown-menu" target="_blank"
> >
<VegaIcon name={VegaIconNames.KEBAB} /> <VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
</DropdownMenuTrigger> {t('View proposal')}
} </Link>
> </DropdownMenuItem>
<DropdownMenuContent data-testid="market-actions-content"> </ActionsDropdown>
<DropdownMenuItem>
<Link
href={linkCreator(TOKEN_PROPOSAL.replace(':id', id))}
target="_blank"
>
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View proposal')}
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
); );
}; };

View File

@ -0,0 +1,26 @@
import { VegaIcon, VegaIconNames } from '../icon';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
} from './dropdown-menu';
export const ActionsDropdownTrigger = () => {
return (
<DropdownMenuTrigger
className='hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 [&[aria-expanded="true"]]:bg-vega-light-200 dark:[&[aria-expanded="true"]]:bg-vega-dark-200 p-0.5 rounded-full'
data-testid="dropdown-menu"
>
<VegaIcon name={VegaIconNames.KEBAB} />
</DropdownMenuTrigger>
);
};
type ActionMenuContentProps = React.ComponentProps<typeof DropdownMenuContent>;
export const ActionsDropdown = (props: ActionMenuContentProps) => {
return (
<DropdownMenu trigger={<ActionsDropdownTrigger />}>
<DropdownMenuContent {...props}></DropdownMenuContent>
</DropdownMenu>
);
};

View File

@ -1 +1,2 @@
export * from './dropdown-menu'; export * from './dropdown-menu';
export * from './actions-dropdown';

View File

@ -0,0 +1,12 @@
export const IconInfo = ({ size = 14 }: { size: number }) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 14 14"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M7 0C3.13 0 0 3.13 0 7C0 10.87 3.13 14 7 14C10.87 14 14 10.87 14 7C14 3.13 10.87 0 7 0ZM7.75 10.75H6.25V5.75H7.75V10.75ZM7.75 4.75H6.25V3.25H7.75V4.75Z" />
</svg>
);
};

View File

@ -1,72 +1,75 @@
import { IconBreakdown } from './svg-icons/icon-breakdown';
import { IconCopy } from './svg-icons/icon-copy';
import { IconDeposit } from './svg-icons/icon-deposit';
import { IconWithdraw } from './svg-icons/icon-withdraw';
import { IconTransfer } from './svg-icons/icon-transfer';
import { IconEdit } from './svg-icons/icon-edit';
import { IconMoon } from './svg-icons/icon-moon';
import { IconGlobe } from './svg-icons/icon-globe';
import { IconLinkedIn } from './svg-icons/icon-linkedin';
import { IconTwitter } from './svg-icons/icon-twitter';
import { IconQuestionMark } from './svg-icons/icon-question-mark';
import { IconForum } from './svg-icons/icon-forum';
import { IconOpenExternal } from './svg-icons/icon-open-external';
import { IconArrowRight } from './svg-icons/icon-arrow-right';
import { IconChevronUp } from './svg-icons/icon-chevron-up';
import { IconTrendUp } from './svg-icons/icon-trend-up';
import { IconCross } from './svg-icons/icon-cross';
import { IconKebab } from './svg-icons/icon-kebab';
import { IconArrowDown } from './svg-icons/icon-arrow-down'; import { IconArrowDown } from './svg-icons/icon-arrow-down';
import { IconArrowRight } from './svg-icons/icon-arrow-right';
import { IconBreakdown } from './svg-icons/icon-breakdown';
import { IconChevronDown } from './svg-icons/icon-chevron-down'; import { IconChevronDown } from './svg-icons/icon-chevron-down';
import { IconChevronUp } from './svg-icons/icon-chevron-up';
import { IconCopy } from './svg-icons/icon-copy';
import { IconCross } from './svg-icons/icon-cross';
import { IconDeposit } from './svg-icons/icon-deposit';
import { IconEdit } from './svg-icons/icon-edit';
import { IconForum } from './svg-icons/icon-forum';
import { IconGlobe } from './svg-icons/icon-globe';
import { IconInfo } from './svg-icons/icon-info';
import { IconKebab } from './svg-icons/icon-kebab';
import { IconLinkedIn } from './svg-icons/icon-linkedin';
import { IconMoon } from './svg-icons/icon-moon';
import { IconOpenExternal } from './svg-icons/icon-open-external';
import { IconQuestionMark } from './svg-icons/icon-question-mark';
import { IconTick } from './svg-icons/icon-tick'; import { IconTick } from './svg-icons/icon-tick';
import { IconTransfer } from './svg-icons/icon-transfer';
import { IconTrendUp } from './svg-icons/icon-trend-up';
import { IconTwitter } from './svg-icons/icon-twitter';
import { IconWithdraw } from './svg-icons/icon-withdraw';
export enum VegaIconNames { export enum VegaIconNames {
ARROW_DOWN = 'arrow-down',
ARROW_RIGHT = 'arrow-right',
BREAKDOWN = 'breakdown', BREAKDOWN = 'breakdown',
CHEVRON_DOWN = 'chevron-down',
CHEVRON_UP = 'chevron-up',
COPY = 'copy', COPY = 'copy',
CROSS = 'cross',
DEPOSIT = 'deposit', DEPOSIT = 'deposit',
WITHDRAW = 'withdraw',
EDIT = 'edit', EDIT = 'edit',
TRANSFER = 'transfer',
FORUM = 'forum', FORUM = 'forum',
GLOBE = 'globe', GLOBE = 'globe',
INFO = 'info',
KEBAB = 'kebab',
LINKEDIN = 'linkedin', LINKEDIN = 'linkedin',
TWITTER = 'twitter',
MOON = 'moon', MOON = 'moon',
OPEN_EXTERNAL = 'open-external', OPEN_EXTERNAL = 'open-external',
QUESTION_MARK = 'question-mark', QUESTION_MARK = 'question-mark',
ARROW_RIGHT = 'arrow-right',
ARROW_DOWN = 'arrow-down',
CHEVRON_UP = 'chevron-up',
CHEVRON_DOWN = 'chevron-down',
TREND_UP = 'trend-up',
CROSS = 'cross',
KEBAB = 'kebab',
TICK = 'tick', TICK = 'tick',
TRANSFER = 'transfer',
TREND_UP = 'trend-up',
TWITTER = 'twitter',
WITHDRAW = 'withdraw',
} }
export const VegaIconNameMap: Record< export const VegaIconNameMap: Record<
VegaIconNames, VegaIconNames,
({ size }: { size: number }) => JSX.Element ({ size }: { size: number }) => JSX.Element
> = { > = {
'arrow-down': IconArrowDown,
'arrow-right': IconArrowRight,
'chevron-down': IconChevronDown,
'chevron-up': IconChevronUp,
'open-external': IconOpenExternal,
'question-mark': IconQuestionMark,
'trend-up': IconTrendUp,
breakdown: IconBreakdown, breakdown: IconBreakdown,
copy: IconCopy, copy: IconCopy,
deposit: IconDeposit,
withdraw: IconWithdraw,
transfer: IconTransfer,
edit: IconEdit,
moon: IconMoon,
globe: IconGlobe,
linkedin: IconLinkedIn,
twitter: IconTwitter,
'question-mark': IconQuestionMark,
forum: IconForum,
'open-external': IconOpenExternal,
'arrow-right': IconArrowRight,
'arrow-down': IconArrowDown,
'chevron-up': IconChevronUp,
'chevron-down': IconChevronDown,
'trend-up': IconTrendUp,
cross: IconCross, cross: IconCross,
deposit: IconDeposit,
edit: IconEdit,
forum: IconForum,
globe: IconGlobe,
info: IconInfo,
kebab: IconKebab, kebab: IconKebab,
linkedin: IconLinkedIn,
moon: IconMoon,
tick: IconTick, tick: IconTick,
transfer: IconTransfer,
twitter: IconTwitter,
withdraw: IconWithdraw,
}; };

View File

@ -48,24 +48,12 @@ export const RichSelect = forwardRef<
const containerRef = useRef<HTMLDivElement>(); const containerRef = useRef<HTMLDivElement>();
const contentRef = useRef<HTMLDivElement>(); const contentRef = useRef<HTMLDivElement>();
const setWidth = () => {
if (contentRef.current) {
contentRef.current.style.width = containerRef.current ? `450px` : 'auto';
}
};
return ( return (
<div <div
ref={containerRef as Ref<HTMLDivElement>} ref={containerRef as Ref<HTMLDivElement>}
className="flex items-center relative" className="flex items-center relative"
> >
<SelectPrimitive.Root <SelectPrimitive.Root {...props} defaultOpen={false}>
{...props}
onOpenChange={() => {
setWidth();
}}
defaultOpen={false}
>
<SelectPrimitive.Trigger <SelectPrimitive.Trigger
data-testid={props['data-testid'] || 'rich-select-trigger'} data-testid={props['data-testid'] || 'rich-select-trigger'}
className={classNames( className={classNames(
@ -85,9 +73,10 @@ export const RichSelect = forwardRef<
<SelectPrimitive.Content <SelectPrimitive.Content
ref={contentRef as Ref<HTMLDivElement>} ref={contentRef as Ref<HTMLDivElement>}
className={classNames( className={classNames(
'relative',
'z-20', 'z-20',
'bg-white dark:bg-black', 'bg-white dark:bg-black',
'border border-neutral-500 focus:border-black dark:focus:border-white', 'border border-neutral-500 focus:border-black dark:focus:border-white rounded',
'overflow-hidden', 'overflow-hidden',
'shadow-lg' 'shadow-lg'
)} )}
@ -95,11 +84,11 @@ export const RichSelect = forwardRef<
side={'bottom'} side={'bottom'}
align={'center'} align={'center'}
> >
<SelectPrimitive.ScrollUpButton className="flex items-center justify-center p-1 absolute w-full h-6 z-20 bg-gradient-to-t from-transparent to-neutral-50 dark:to-neutral-900"> <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" /> <Icon name="chevron-up" />
</SelectPrimitive.ScrollUpButton> </SelectPrimitive.ScrollUpButton>
<SelectPrimitive.Viewport>{children}</SelectPrimitive.Viewport> <SelectPrimitive.Viewport>{children}</SelectPrimitive.Viewport>
<SelectPrimitive.ScrollDownButton className="flex items-center justify-center p-1 absolute bottom-0 w-full h-6 z-20 bg-gradient-to-b from-transparent to-neutral-50 dark:to-neutral-900"> <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" /> <Icon name="chevron-down" />
</SelectPrimitive.ScrollDownButton> </SelectPrimitive.ScrollDownButton>
</SelectPrimitive.Content> </SelectPrimitive.Content>

View File

@ -2,7 +2,7 @@ import { useAccountBalance } from '@vegaprotocol/accounts';
import type { AssetFieldsFragment } from '@vegaprotocol/assets'; import type { AssetFieldsFragment } from '@vegaprotocol/assets';
import { useBalancesStore } from '@vegaprotocol/assets'; import { useBalancesStore } from '@vegaprotocol/assets';
import { Balance } from '@vegaprotocol/assets'; import { Balance } from '@vegaprotocol/assets';
import { addDecimal } from '@vegaprotocol/utils'; import { addDecimal, formatNumber } from '@vegaprotocol/utils';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { useEffect } from 'react'; import { useEffect } from 'react';
@ -23,7 +23,10 @@ export const AssetBalance = ({ asset }: { asset: AssetFieldsFragment }) => {
return ( return (
<Balance <Balance
balance={getBalance(asset.id)?.balanceOnVega?.toString()} balance={formatNumber(
getBalance(asset.id)?.balanceOnVega || 0,
accountDecimals || 0
)}
symbol={asset.symbol} symbol={asset.symbol}
/> />
); );

View File

@ -10,11 +10,9 @@ import {
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { import {
ActionsDropdown,
ButtonLink, ButtonLink,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger,
VegaIcon, VegaIcon,
VegaIconNames, VegaIconNames,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
@ -160,7 +158,7 @@ export type CompleteCellProps = {
}; };
export const CompleteCell = ({ data, complete }: CompleteCellProps) => { export const CompleteCell = ({ data, complete }: CompleteCellProps) => {
const open = useWithdrawalApprovalDialog((state) => state.open); const open = useWithdrawalApprovalDialog((state) => state.open);
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLButtonElement>(null);
if (!data) { if (!data) {
return null; return null;
@ -176,32 +174,20 @@ export const CompleteCell = ({ data, complete }: CompleteCellProps) => {
{t('Complete withdrawal')} {t('Complete withdrawal')}
</ButtonLink> </ButtonLink>
<DropdownMenu <ActionsDropdown>
trigger={ <DropdownMenuItem
<DropdownMenuTrigger key={'withdrawal-approval'}
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full" data-testid="withdrawal-approval"
data-testid="dropdown-menu" onClick={() => {
> if (data.id) {
<VegaIcon name={VegaIconNames.KEBAB} /> open(data.id, ref.current, false);
</DropdownMenuTrigger> }
} }}
> >
<DropdownMenuContent> <VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />
<DropdownMenuItem {t('View withdrawal details')}
key={'withdrawal-approval'} </DropdownMenuItem>
data-testid="withdrawal-approval" </ActionsDropdown>
ref={ref}
onClick={() => {
if (data.id) {
open(data.id, ref.current, false);
}
}}
>
<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />
{t('View withdrawal details')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div> </div>
); );
}; };