Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/view-iceberg-orders

This commit is contained in:
Madalina Raicu
2023-07-06 11:17:50 +03:00
46 changed files with 530 additions and 567 deletions
+13
View File
@@ -0,0 +1,13 @@
# App configuration variables
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
NX_VEGA_ENV=MAINNET-MIRROR
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
+1
View File
@@ -32,6 +32,7 @@ yarn nx serve explorer
Example configurations are provided here:
- [Mainnet](./.env.mainnet)
- [Mainnet-mirror](./.env.mainnet-mirror)
- [Devnet](./.env.devnet)
- [Capsule](./.env.capsule)
- [Testnet](./.env.testnet)
+15
View File
@@ -0,0 +1,15 @@
# App configuration variables
NX_VEGA_ENV=MAINNET-MIRROR
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz","MAINNET-MIRROR":"https://governance.mainnet-mirror.vega.rocks","STAGNET1":"https://trading.stagnet1.vega.rocks"}'
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-mirror-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/
+1
View File
@@ -25,6 +25,7 @@ yarn nx serve governance
Example configurations are provided here:
- [Mainnet](./.env.mainnet)
- [Mainnet-mirror](./.env.mainnet-mirror)
- [Devnet](./.env.devnet)
- [Testnet](./.env.testnet)
@@ -91,46 +91,46 @@ query Proposal($proposalId: ID!) {
}
}
}
dataSourceSpecForTradingTermination {
sourceType {
... on DataSourceDefinitionInternal {
sourceType {
... on DataSourceSpecConfigurationTime {
conditions {
operator
value
}
}
}
}
... on DataSourceDefinitionExternal {
sourceType {
... on DataSourceSpecConfiguration {
signers {
signer {
... on PubKey {
key
}
... on ETHAddress {
address
}
}
}
filters {
key {
name
type
}
conditions {
operator
value
}
}
}
}
}
}
}
# dataSourceSpecForTradingTermination {
# sourceType {
# ... on DataSourceDefinitionInternal {
# sourceType {
# ... on DataSourceSpecConfigurationTime {
# conditions {
# operator
# value
# }
# }
# }
# }
# ... on DataSourceDefinitionExternal {
# sourceType {
# ... on DataSourceSpecConfiguration {
# signers {
# signer {
# ... on PubKey {
# key
# }
# ... on ETHAddress {
# address
# }
# }
# }
# filters {
# key {
# name
# type
# }
# conditions {
# operator
# value
# }
# }
# }
# }
# }
# }
# }
dataSourceSpecBinding {
settlementDataProperty
tradingTerminationProperty
@@ -203,46 +203,46 @@ query Proposal($proposalId: ID!) {
}
}
}
dataSourceSpecForTradingTermination {
sourceType {
... on DataSourceDefinitionInternal {
sourceType {
... on DataSourceSpecConfigurationTime {
conditions {
operator
value
}
}
}
}
... on DataSourceDefinitionExternal {
sourceType {
... on DataSourceSpecConfiguration {
signers {
signer {
... on PubKey {
key
}
... on ETHAddress {
address
}
}
}
filters {
key {
name
type
}
conditions {
operator
value
}
}
}
}
}
}
}
# dataSourceSpecForTradingTermination {
# sourceType {
# ... on DataSourceDefinitionInternal {
# sourceType {
# ... on DataSourceSpecConfigurationTime {
# conditions {
# operator
# value
# }
# }
# }
# }
# ... on DataSourceDefinitionExternal {
# sourceType {
# ... on DataSourceSpecConfiguration {
# signers {
# signer {
# ... on PubKey {
# key
# }
# ... on ETHAddress {
# address
# }
# }
# }
# filters {
# key {
# name
# type
# }
# conditions {
# operator
# value
# }
# }
# }
# }
# }
# }
# }
dataSourceSpecBinding {
settlementDataProperty
tradingTerminationProperty
File diff suppressed because one or more lines are too long
@@ -153,7 +153,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
cy.get(dropdownContent)
.find(dropdownContentItem)
.eq(2)
.should('have.text', 'View asset');
.should('have.text', 'View settlement asset details');
cy.getByTestId('market-actions-content').click();
});
+17
View File
@@ -0,0 +1,17 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_SENTRY_DSN=https://2ffce43721964aafa78277c50654ece4@o286262.ingest.sentry.io/6300613
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_ENV=MAINNET-MIRROR
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks
NX_VEGA_NETWORKS={\"MAINNET\":\"https://console.vega.xyz\",\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\",\"MAINNET-MIRROR\":\"https://trading.mainnet-mirror.vega.rocks\"}
NX_VEGA_TOKEN_URL=https://governance.mainnet-mirror.vega.rocks
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
# TAG name of the current app version - TODO: bump to the latest upon release
NX_APP_VERSION=v0.20.19-core-0.71.6
+1
View File
@@ -19,6 +19,7 @@ yarn nx serve explorer
Example configurations are provided here:
- [Mainnet](./.env.mainnet)
- [Mainnet-mirror](./.env.mainnet-mirror)
- [Devnet](./.env.devnet)
- [Testnet](./.env.testnet)
@@ -9,10 +9,7 @@ import { t } from '@vegaprotocol/i18n';
import { OracleBanner } from '@vegaprotocol/markets';
import type { Market } from '@vegaprotocol/markets';
import { Filter } from '@vegaprotocol/orders';
import {
usePaneLayout,
useScreenDimensions,
} from '@vegaprotocol/react-helpers';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import {
Tab,
LocalStoragePersistTabs as Tabs,
@@ -25,6 +22,7 @@ import { HeaderTitle } from '../../components/header';
import {
ResizableGrid,
ResizableGridPanel,
usePaneLayout,
} from '../../components/resizable-grid';
import { TradingViews } from './trade-views';
import { MarketSelector } from './market-selector';
+2 -2
View File
@@ -18,7 +18,7 @@ import type {
MarketMaybeWithData,
} from '@vegaprotocol/markets';
import {
MarketTableActions,
MarketActionsDropdown,
closedMarketsWithDataProvider,
} from '@vegaprotocol/markets';
import { useVegaWallet } from '@vegaprotocol/wallet';
@@ -291,7 +291,7 @@ const ClosedMarketsDataGrid = ({
cellRenderer: ({ data }: VegaICellRendererParams<Row>) => {
if (!data) return null;
return (
<MarketTableActions
<MarketActionsDropdown
marketId={data.id}
assetId={data.settlementAsset.id}
/>
@@ -24,7 +24,10 @@ import { PriceChart } from 'pennant';
import 'pennant/dist/style.css';
import type { Account } 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 type { Market } from '@vegaprotocol/markets';
@@ -68,7 +71,7 @@ export const AccountHistoryContainer = () => {
const { data: assets } = useAssetsDataProvider();
if (!pubKey) {
return <Splash>Connect wallet</Splash>;
return <Splash>{t('Connect wallet')}</Splash>;
}
return (
@@ -114,7 +117,15 @@ const AccountHistoryManager = ({
.sort((a, b) => a.name.localeCompare(b.name)),
[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]>(
DateRange.RANGE_1M
);
@@ -146,10 +157,10 @@ const AccountHistoryManager = ({
m.tradableInstrument.instrument.product.settlementAsset.id;
const newAsset = assets.find((item) => item.id === newAssetId);
if ((!asset || (assets && newAssetId !== asset.id)) && newAsset) {
setAsset(newAsset);
setAssetId(newAsset.id);
}
},
[asset, assets]
[asset, assets, setAssetId]
);
const variables = useMemo(
@@ -211,14 +222,14 @@ const AccountHistoryManager = ({
>
<DropdownMenuContent>
{assets.map((a) => (
<DropdownMenuItem key={a.id} onClick={() => setAsset(a)}>
<DropdownMenuItem key={a.id} onClick={() => setAssetId(a.id)}>
{a.symbol}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
);
}, [assets, asset]);
}, [asset, assets, setAssetId]);
const marketsMenu = useMemo(() => {
return accountType === Schema.AccountType.ACCOUNT_TYPE_MARGIN &&
markets?.length ? (
@@ -4,7 +4,6 @@ import { LayoutPriority } from 'allotment';
import { titlefy } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { useIncompleteWithdrawals } from '@vegaprotocol/withdraws';
import { usePaneLayout } from '@vegaprotocol/react-helpers';
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
import { usePageTitleStore } from '../../stores';
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
@@ -20,6 +19,7 @@ import { AccountHistoryContainer } from './account-history-container';
import {
ResizableGrid,
ResizableGridPanel,
usePaneLayout,
} from '../../components/resizable-grid';
const WithdrawalsIndicator = () => {
@@ -1 +1,2 @@
export * from './resizable-grid';
export * from './use-pane-layout';
@@ -1,11 +1,9 @@
import { ETHERSCAN_ADDRESS, useEtherscanLink } from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n';
import {
DropdownMenu,
DropdownMenuContent,
ActionsDropdown,
DropdownMenuCopyItem,
DropdownMenuItem,
DropdownMenuTrigger,
Link,
VegaIcon,
VegaIconNames,
@@ -29,75 +27,65 @@ export const AccountsActionsDropdown = ({
const etherscanLink = useEtherscanLink();
const openTransferDialog = useTransferDialog((store) => store.open);
const openAssetDialog = useAssetDetailsDialogStore((store) => store.open);
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
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>
<DropdownMenuItem
key={'deposit'}
data-testid="deposit"
onClick={onClickDeposit}
>
<VegaIcon name={VegaIconNames.DEPOSIT} size={16} />
{t('Deposit')}
<ActionsDropdown>
<DropdownMenuItem
key={'deposit'}
data-testid="deposit"
onClick={onClickDeposit}
>
<VegaIcon name={VegaIconNames.DEPOSIT} size={16} />
{t('Deposit')}
</DropdownMenuItem>
<DropdownMenuItem
key={'withdraw'}
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('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
key={'withdraw'}
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>
)}
</ActionsDropdown>
);
};
+2 -1
View File
@@ -13,6 +13,7 @@ import { accountsDataProvider } from './accounts-data-provider';
import { TransferForm } from './transfer-form';
import { useTransferDialog } from './transfer-dialog';
import { Lozenge } from '@vegaprotocol/ui-toolkit';
import sortBy from 'lodash/sortBy';
export const TransferContainer = ({ assetId }: { assetId?: string }) => {
const { pubKey, pubKeys } = useVegaWallet();
@@ -58,7 +59,7 @@ export const TransferContainer = ({ assetId }: { assetId?: string }) => {
<TransferForm
pubKey={pubKey}
pubKeys={pubKeys ? pubKeys?.map((pk) => pk.publicKey) : null}
assets={assets}
assets={sortBy(assets, 'name')}
assetId={assetId}
feeFactor={param}
submitTransfer={transfer}
+8 -8
View File
@@ -8,7 +8,7 @@ import {
import BigNumber from 'bignumber.js';
import { AddressField, TransferFee, TransferForm } from './transfer-form';
import { AccountType } from '@vegaprotocol/types';
import { formatNumber, removeDecimal } from '@vegaprotocol/utils';
import { addDecimal, formatNumber, removeDecimal } from '@vegaprotocol/utils';
describe('TransferForm', () => {
const submit = () => fireEvent.submit(screen.getByTestId('transfer-form'));
@@ -16,11 +16,11 @@ describe('TransferForm', () => {
const pubKey =
'70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680';
const asset = {
id: 'asset-0',
symbol: 'ASSET 0',
name: 'Asset 0',
id: 'eur',
symbol: '',
name: 'EUR',
decimals: 2,
balance: '1000',
balance: addDecimal(100000, 2), // 1000
};
const props = {
pubKey,
@@ -92,7 +92,7 @@ describe('TransferForm', () => {
expect(await screen.findByTestId('select-asset')).toHaveTextContent(
asset.name
);
expect(screen.getByTestId('asset-balance')).toHaveTextContent(
expect(await screen.findByTestId('asset-balance')).toHaveTextContent(
formatNumber(asset.balance, asset.decimals)
);
@@ -168,7 +168,7 @@ describe('TransferForm', () => {
expect(await screen.findByTestId('select-asset')).toHaveTextContent(
asset.name
);
expect(screen.getByTestId('asset-balance')).toHaveTextContent(
expect(await screen.findByTestId('asset-balance')).toHaveTextContent(
formatNumber(asset.balance, asset.decimals)
);
@@ -244,7 +244,7 @@ describe('TransferForm', () => {
expect(await screen.findByTestId('select-asset')).toHaveTextContent(
asset.name
);
expect(screen.getByTestId('asset-balance')).toHaveTextContent(
expect(await screen.findByTestId('asset-balance')).toHaveTextContent(
formatNumber(asset.balance, asset.decimals)
);
+12 -13
View File
@@ -12,7 +12,6 @@ import {
FormGroup,
Input,
InputError,
Option,
RichSelect,
Select,
Tooltip,
@@ -24,6 +23,7 @@ import BigNumber from 'bignumber.js';
import type { ReactNode } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { AssetOption, Balance } from '@vegaprotocol/assets';
interface FormFields {
toAddress: string;
@@ -193,21 +193,20 @@ export const TransferForm = ({
onValueChange={(value) => {
field.onChange(value);
}}
placeholder={t('Please select')}
placeholder={t('Please select an asset')}
value={field.value}
>
{assets.map((a) => (
<Option key={a.id} value={a.id}>
<div className="text-left" data-testid={`asset-${a.id}`}>
<div>{a.name}</div>
<div className="text-xs">
<span className="font-mono" data-testid="asset-balance">
{formatNumber(a.balance, a.decimals)}
</span>{' '}
<span>{a.symbol}</span>
</div>
</div>
</Option>
<AssetOption
key={a.id}
asset={a}
balance={
<Balance
balance={formatNumber(a.balance, a.decimals)}
symbol={a.symbol}
/>
}
/>
))}
</RichSelect>
)}
+9 -2
View File
@@ -1,6 +1,9 @@
import { useEffect, useState } from 'react';
import type { AppNameType, Announcement } from './schema';
import { useAnnouncement } from './hooks/use-announcement';
import {
useAnnouncement,
useDismissedAnnouncement,
} from './hooks/use-announcement';
import {
AnnouncementBanner as Banner,
ExternalLink,
@@ -36,6 +39,7 @@ export const AnnouncementBanner = ({
}: AnnouncementBannerProps) => {
const [isVisible, setVisible] = useState(false);
const { data, reload } = useAnnouncement(app, configUrl);
const [, setDismissed] = useDismissedAnnouncement();
useEffect(() => {
const now = new Date();
@@ -88,7 +92,10 @@ export const AnnouncementBanner = ({
<button
className="absolute right-0 top-0 p-4 w-10 h-full flex items-center justify-center text-white"
data-testid="app-announcement-close"
onClick={() => setVisible(false)}
onClick={() => {
setVisible(false);
setDismissed(data);
}}
>
<VegaIcon name={VegaIconNames.CROSS} size={24} />
</button>
@@ -1,6 +1,8 @@
import { useCallback, useEffect, useState } from 'react';
import type { AppNameType, Announcement } from '../schema';
import { AnnouncementsSchema } from '../schema';
import { sha256 } from 'ethers/lib/utils';
import { useLocalStorageSnapshot } from '@vegaprotocol/react-helpers';
const getData = async (name: AppNameType, url: string) => {
const now = new Date();
@@ -31,6 +33,22 @@ type State = {
error: null | string;
};
const checksum = (data: object) => sha256(Buffer.from(JSON.stringify(data)));
export const useDismissedAnnouncement = (): [
string | null | undefined,
(data: object) => void
] => {
const [dismissed, setDismissedInStorage] = useLocalStorageSnapshot(
'dismissed-announcement'
);
const setDismissed = useCallback(
(data: object) => setDismissedInStorage(checksum(data)),
[setDismissedInStorage]
);
return [dismissed, setDismissed];
};
export const useAnnouncement = (name: AppNameType, url: string) => {
const [state, setState] = useState<State>({
loading: true,
@@ -38,12 +56,14 @@ export const useAnnouncement = (name: AppNameType, url: string) => {
error: null,
});
const [dismissed] = useDismissedAnnouncement();
const fetchData = useCallback(() => {
let mounted = true;
getData(name, url)
.then((data) => {
if (mounted) {
if (mounted && dismissed !== checksum(data)) {
setState({
loading: false,
data,
@@ -64,7 +84,7 @@ export const useAnnouncement = (name: AppNameType, url: string) => {
return () => {
mounted = false;
};
}, [name, url, setState]);
}, [name, url, dismissed]);
useEffect(() => {
fetchData();
+5 -3
View File
@@ -5,7 +5,7 @@ import { t } from '@vegaprotocol/i18n';
import type { ReactNode } from 'react';
type AssetOptionProps = {
asset: AssetFieldsFragment;
asset: Pick<AssetFieldsFragment, 'id' | 'name' | 'symbol'>;
balance?: ReactNode;
};
@@ -17,11 +17,13 @@ export const Balance = ({
symbol: string;
}) =>
balance ? (
<div className="mt-1 font-alpha">
<div className="mt-1 font-alpha" data-testid="asset-balance">
{balance} {symbol}
</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) => {
@@ -1,13 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { act, render, screen } from '@testing-library/react';
import { act, render, renderHook, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { generateMarket, generateMarketData } from '../../test-helpers';
import { DealTicket } from './deal-ticket';
import * as Schema from '@vegaprotocol/types';
import { MockedProvider } from '@apollo/client/testing';
import { addDecimal } from '@vegaprotocol/utils';
import { useOrderStore } from '@vegaprotocol/orders';
import { useCreateOrderStore } from '@vegaprotocol/orders';
jest.mock('zustand');
jest.mock('./deal-ticket-fee-details', () => ({
@@ -30,6 +30,9 @@ function generateJsx() {
}
describe('DealTicket', () => {
const { result } = renderHook(() => useCreateOrderStore());
const useOrderStore = result.current;
beforeEach(() => {
localStorage.clear();
});
@@ -138,7 +141,6 @@ describe('DealTicket', () => {
reduceOnly: true,
postOnly: false,
};
useOrderStore.setState({
orders: {
[expectedOrder.marketId]: expectedOrder,
@@ -1,6 +1,6 @@
import omit from 'lodash/omit';
import { act, renderHook } from '@testing-library/react';
import { getDefaultOrder, useOrderStore } from '@vegaprotocol/orders';
import { getDefaultOrder, useCreateOrderStore } from '@vegaprotocol/orders';
import { useOrderForm } from './use-order-form';
jest.mock('zustand');
@@ -10,6 +10,8 @@ describe('useOrderForm', () => {
const setup = (marketId: string) => {
return renderHook(() => useOrderForm(marketId));
};
const { result } = renderHook(() => useCreateOrderStore());
const useOrderStore = result.current;
it('updates form fields when the order changes', async () => {
const order = getDefaultOrder(marketId);
+9 -27
View File
@@ -1,10 +1,6 @@
import {
DropdownMenu,
DropdownMenuContent,
ActionsDropdown,
DropdownMenuCopyItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
@@ -18,27 +14,13 @@ export const FillActionsDropdown = ({
sellOrderId: string;
}) => {
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
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={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>
<ActionsDropdown 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')}
/>
</ActionsDropdown>
);
};
@@ -9,7 +9,7 @@ import type {
MarketDepthUpdateSubscription,
PriceLevelFieldsFragment,
} from './__generated__/MarketDepth';
import { useOrderStore } from '@vegaprotocol/orders';
import { useCreateOrderStore } from '@vegaprotocol/orders';
export type OrderbookData = {
asks: PriceLevelFieldsFragment[];
@@ -50,8 +50,8 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
dataProvider: marketDataProvider,
variables,
});
const updateOrder = useOrderStore((store) => store.update);
const useOrderStoreRef = useCreateOrderStore();
const updateOrder = useOrderStoreRef((store) => store.update);
return (
<AsyncRenderer
@@ -1,18 +1,16 @@
import { t } from '@vegaprotocol/i18n';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuCopyItem,
Link,
VegaIcon,
VegaIconNames,
ActionsDropdown,
} from '@vegaprotocol/ui-toolkit';
import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
export const MarketTableActions = ({
export const MarketActionsDropdown = ({
marketId,
assetId,
}: {
@@ -21,39 +19,29 @@ export const MarketTableActions = ({
}) => {
const open = useAssetDetailsDialogStore((store) => store.open);
const linkCreator = useLinks(DApp.Explorer);
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
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"
<ActionsDropdown data-testid="market-actions-content">
<DropdownMenuCopyItem value={marketId} text={t('Copy Market ID')} />
<DropdownMenuItem>
<Link
href={linkCreator(EXPLORER_MARKET.replace(':id', marketId))}
target="_blank"
>
<VegaIcon name={VegaIconNames.KEBAB} />
</DropdownMenuTrigger>
}
>
<DropdownMenuContent data-testid="market-actions-content">
<DropdownMenuCopyItem value={marketId} text={t('Copy Market ID')} />
<DropdownMenuItem>
<Link
href={linkCreator(EXPLORER_MARKET.replace(':id', marketId))}
target="_blank"
>
<span className="flex gap-2">
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View on Explorer')}
</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem
onClick={(e) => {
open(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View asset')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<span className="flex gap-2">
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View on Explorer')}
</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem
onClick={(e) => {
open(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.INFO} size={16} />
{t('View settlement asset details')}
</DropdownMenuItem>
</ActionsDropdown>
);
};
@@ -12,7 +12,7 @@ import { addDecimalsFormatNumber, toBigNum } from '@vegaprotocol/utils';
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import type { MarketMaybeWithData } from '../../markets-provider';
import { MarketTableActions } from './market-table-actions';
import { MarketActionsDropdown } from './market-table-actions';
interface Props {
onMarketClick: (marketId: string, metaKey?: boolean) => void;
@@ -172,7 +172,7 @@ export const useColumnDefs = ({ onMarketClick }: Props) => {
}: VegaICellRendererParams<MarketMaybeWithData>) => {
if (!data) return null;
return (
<MarketTableActions
<MarketActionsDropdown
marketId={data.id}
assetId={
data.tradableInstrument.instrument.product.settlementAsset.id
@@ -1,28 +1,13 @@
import {
DropdownMenu,
DropdownMenuContent,
ActionsDropdown,
DropdownMenuCopyItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
export const OrderActionsDropdown = ({ id }: { id: string }) => {
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
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>
<ActionsDropdown data-testid="market-actions-content">
<DropdownMenuCopyItem value={id} text={t('Copy order ID')} />
</ActionsDropdown>
);
};
@@ -2,16 +2,17 @@ import {
getDefaultOrder,
STORAGE_KEY,
useOrder,
useOrderStore,
useCreateOrderStore,
} from './use-order-store';
import { act, renderHook } from '@testing-library/react';
import { OrderType } from '@vegaprotocol/types';
jest.mock('zustand');
describe('useOrderStore', () => {
describe('useCreateOrderStore', () => {
const setup = () => {
return renderHook(() => useOrderStore());
const { result } = renderHook(() => useCreateOrderStore());
return renderHook(() => result.current());
};
afterEach(() => {
@@ -1,6 +1,7 @@
import { OrderTimeInForce, Side } from '@vegaprotocol/types';
import { OrderType } from '@vegaprotocol/types';
import { useCallback, useEffect } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import type { StateCreator, UseBoundStore, Mutate, StoreApi } from 'zustand';
import { create } from 'zustand';
import { persist, subscribeWithSelector } from 'zustand/middleware';
@@ -31,58 +32,69 @@ interface Store {
export const STORAGE_KEY = 'vega_order_store';
export const useOrderStore = create<Store>()(
persist(
subscribeWithSelector((set) => ({
orders: {},
update: (marketId, order, persist = true) => {
set((state) => {
const curr = state.orders[marketId];
const defaultOrder = getDefaultOrder(marketId);
const orderStateCreator: StateCreator<Store> = (set) => ({
orders: {},
update: (marketId, order, persist = true) => {
set((state) => {
const curr = state.orders[marketId];
const defaultOrder = getDefaultOrder(marketId);
return {
orders: {
...state.orders,
[marketId]: {
...defaultOrder,
...curr,
...order,
persist,
},
},
};
});
},
});
let store: UseBoundStore<Mutate<StoreApi<Store>, []>> | null = null;
const getOrderStore = () => {
if (!store) {
store = create<Store>()(
persist(subscribeWithSelector(orderStateCreator), {
name: STORAGE_KEY,
partialize: (state) => {
// only store the order in localStorage if user has edited, this avoids
// bloating localStorage if a user just visits the page but does not
// edit the ticket
const partializedOrders: OrderMap = {};
for (const o in state.orders) {
const order = state.orders[o];
if (order && order.persist) {
partializedOrders[order.marketId] = order;
}
}
return {
orders: {
...state.orders,
[marketId]: {
...defaultOrder,
...curr,
...order,
persist,
},
},
...state,
orders: partializedOrders,
};
});
},
})),
{
name: STORAGE_KEY,
partialize: (state) => {
// only store the order in localStorage if user has edited, this avoids
// bloating localStorage if a user just visits the page but does not
// edit the ticket
const partializedOrders: OrderMap = {};
for (const o in state.orders) {
const order = state.orders[o];
if (order && order.persist) {
partializedOrders[order.marketId] = order;
}
}
},
})
);
}
return store as UseBoundStore<Mutate<StoreApi<Store>, []>>;
};
return {
...state,
orders: partializedOrders,
};
},
}
)
);
export const useCreateOrderStore = () => {
const useOrderStoreRef = useRef(getOrderStore());
return useOrderStoreRef.current;
};
/**
* Retrieves an order from the store for a market and
* creates one if it doesn't already exist
*/
export const useOrder = (marketId: string) => {
const [order, _update] = useOrderStore((store) => {
const useOrderStoreRef = useCreateOrderStore();
const [order, _update] = useOrderStoreRef((store) => {
return [store.orders[marketId], store.update];
});
@@ -1,37 +1,25 @@
import { t } from '@vegaprotocol/i18n';
import {
DropdownMenu,
DropdownMenuContent,
ActionsDropdown,
DropdownMenuItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
export const PositionTableActions = ({ assetId }: { assetId: string }) => {
export const PositionActionsDropdown = ({ assetId }: { assetId: string }) => {
const open = useAssetDetailsDialogStore((store) => store.open);
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
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">
<DropdownMenuItem
onClick={(e) => {
open(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View asset')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<ActionsDropdown data-testid="market-actions-content">
<DropdownMenuItem
onClick={(e) => {
open(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.INFO} size={16} />
{t('View settlement asset details')}
</DropdownMenuItem>
</ActionsDropdown>
);
};
+3 -2
View File
@@ -38,7 +38,7 @@ import type { Position } from './positions-data-providers';
import * as Schema from '@vegaprotocol/types';
import { PositionStatus, PositionStatusMapping } from '@vegaprotocol/types';
import { DocsLinks } from '@vegaprotocol/environment';
import { PositionTableActions } from './position-actions-dropdown';
import { PositionActionsDropdown } from './position-actions-dropdown';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { LiquidationPrice } from './liquidation-price';
@@ -264,6 +264,7 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
if (!data) return null;
return (
<ButtonLink
title={t('View settlement asset details')}
onClick={(e) => {
openAssetDetailsDialog(
data.assetId,
@@ -449,7 +450,7 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
</ButtonLink>
) : null}
{data?.assetId && (
<PositionTableActions assetId={data?.assetId} />
<PositionActionsDropdown assetId={data?.assetId} />
)}
</div>
);
@@ -1,39 +1,27 @@
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
Link,
ActionsDropdown,
} from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
export const ProposalActionsDropdown = ({ id }: { id: string }) => {
const linkCreator = useLinks(DApp.Token);
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
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"
<ActionsDropdown data-testid="market-actions-content">
<DropdownMenuItem>
<Link
href={linkCreator(TOKEN_PROPOSAL.replace(':id', id))}
target="_blank"
>
<VegaIcon name={VegaIconNames.KEBAB} />
</DropdownMenuTrigger>
}
>
<DropdownMenuContent data-testid="market-actions-content">
<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>
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View proposal')}
</Link>
</DropdownMenuItem>
</ActionsDropdown>
);
};
@@ -19,7 +19,7 @@ export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) =>
export const ProposalsList = () => {
const gridRef = useRef<AgGridReact | null>(null);
const { data, error } = useProposalsListQuery({
const { data } = useProposalsListQuery({
variables: {
proposalType: Types.ProposalType.TYPE_NEW_MARKET,
},
@@ -40,7 +40,7 @@ export const ProposalsList = () => {
defaultColDef={defaultColDef}
getRowId={({ data }) => data.id}
style={{ width: '100%', height: '100%' }}
overlayNoRowsTemplate={error ? error.message : t('No markets')}
overlayNoRowsTemplate={t('No markets')}
/>
</div>
);
@@ -37,11 +37,10 @@ const UpdateNetworkParameterToastContent = ({
<div>
<ToastHeading>{title}</ToastHeading>
<p className="italic">
'
{t(
`Update ${change.networkParameter.key} to ${change.networkParameter.value}`
)}
'
'{t('Update ')}
<span className="break-all">{change.networkParameter.key}</span>
{t(' to ')}
<span>{change.networkParameter.value}</span>'
</p>
{!isNaN(enactment) && (
<p>
-1
View File
@@ -11,5 +11,4 @@ export * from './use-theme-switcher';
export * from './use-storybook-theme-observer';
export * from './use-yesterday';
export * from './use-previous';
export * from './use-pane-layout';
export * from './use-copy-timeout';
+3 -2
View File
@@ -3,7 +3,7 @@ import type { AgGridReact } from 'ag-grid-react';
import { useRef } from 'react';
import { tradesWithMarketProvider } from './trades-data-provider';
import { TradesTable } from './trades-table';
import { useOrderStore } from '@vegaprotocol/orders';
import { useCreateOrderStore } from '@vegaprotocol/orders';
import { t } from '@vegaprotocol/i18n';
interface TradesContainerProps {
@@ -12,7 +12,8 @@ interface TradesContainerProps {
export const TradesContainer = ({ marketId }: TradesContainerProps) => {
const gridRef = useRef<AgGridReact | null>(null);
const updateOrder = useOrderStore((store) => store.update);
const useOrderStoreRef = useCreateOrderStore();
const updateOrder = useOrderStoreRef((store) => store.update);
const { data, error } = useDataProvider({
dataProvider: tradesWithMarketProvider,
@@ -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>
);
};
@@ -1 +1,2 @@
export * from './dropdown-menu';
export * from './actions-dropdown';
@@ -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>
);
};
@@ -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 { IconArrowRight } from './svg-icons/icon-arrow-right';
import { IconBreakdown } from './svg-icons/icon-breakdown';
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 { 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 {
ARROW_DOWN = 'arrow-down',
ARROW_RIGHT = 'arrow-right',
BREAKDOWN = 'breakdown',
CHEVRON_DOWN = 'chevron-down',
CHEVRON_UP = 'chevron-up',
COPY = 'copy',
CROSS = 'cross',
DEPOSIT = 'deposit',
WITHDRAW = 'withdraw',
EDIT = 'edit',
TRANSFER = 'transfer',
FORUM = 'forum',
GLOBE = 'globe',
INFO = 'info',
KEBAB = 'kebab',
LINKEDIN = 'linkedin',
TWITTER = 'twitter',
MOON = 'moon',
OPEN_EXTERNAL = 'open-external',
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',
TRANSFER = 'transfer',
TREND_UP = 'trend-up',
TWITTER = 'twitter',
WITHDRAW = 'withdraw',
}
export const VegaIconNameMap: Record<
VegaIconNames,
({ 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,
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,
deposit: IconDeposit,
edit: IconEdit,
forum: IconForum,
globe: IconGlobe,
info: IconInfo,
kebab: IconKebab,
linkedin: IconLinkedIn,
moon: IconMoon,
tick: IconTick,
transfer: IconTransfer,
twitter: IconTwitter,
withdraw: IconWithdraw,
};
@@ -48,24 +48,12 @@ export const RichSelect = forwardRef<
const containerRef = useRef<HTMLDivElement>();
const contentRef = useRef<HTMLDivElement>();
const setWidth = () => {
if (contentRef.current) {
contentRef.current.style.width = containerRef.current ? `450px` : 'auto';
}
};
return (
<div
ref={containerRef as Ref<HTMLDivElement>}
className="flex items-center relative"
>
<SelectPrimitive.Root
{...props}
onOpenChange={() => {
setWidth();
}}
defaultOpen={false}
>
<SelectPrimitive.Root {...props} defaultOpen={false}>
<SelectPrimitive.Trigger
data-testid={props['data-testid'] || 'rich-select-trigger'}
className={classNames(
@@ -85,9 +73,10 @@ export const RichSelect = forwardRef<
<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',
'border border-neutral-500 focus:border-black dark:focus:border-white rounded',
'overflow-hidden',
'shadow-lg'
)}
@@ -95,11 +84,11 @@ export const RichSelect = forwardRef<
side={'bottom'}
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" />
</SelectPrimitive.ScrollUpButton>
<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" />
</SelectPrimitive.ScrollDownButton>
</SelectPrimitive.Content>
+5 -2
View File
@@ -2,7 +2,7 @@ import { useAccountBalance } from '@vegaprotocol/accounts';
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
import { useBalancesStore } 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 { useEffect } from 'react';
@@ -23,7 +23,10 @@ export const AssetBalance = ({ asset }: { asset: AssetFieldsFragment }) => {
return (
<Balance
balance={getBalance(asset.id)?.balanceOnVega?.toString()}
balance={formatNumber(
getBalance(asset.id)?.balanceOnVega || 0,
accountDecimals || 0
)}
symbol={asset.symbol}
/>
);
+16 -30
View File
@@ -10,11 +10,9 @@ import {
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import {
ActionsDropdown,
ButtonLink,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
@@ -160,7 +158,7 @@ export type CompleteCellProps = {
};
export const CompleteCell = ({ data, complete }: CompleteCellProps) => {
const open = useWithdrawalApprovalDialog((state) => state.open);
const ref = useRef<HTMLDivElement>(null);
const ref = useRef<HTMLButtonElement>(null);
if (!data) {
return null;
@@ -176,32 +174,20 @@ export const CompleteCell = ({ data, complete }: CompleteCellProps) => {
{t('Complete withdrawal')}
</ButtonLink>
<DropdownMenu
trigger={
<DropdownMenuTrigger
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>
<DropdownMenuItem
key={'withdrawal-approval'}
data-testid="withdrawal-approval"
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>
<ActionsDropdown>
<DropdownMenuItem
key={'withdrawal-approval'}
data-testid="withdrawal-approval"
onClick={() => {
if (data.id) {
open(data.id, ref.current, false);
}
}}
>
<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />
{t('View withdrawal details')}
</DropdownMenuItem>
</ActionsDropdown>
</div>
);
};