Feat/627 show asset details (#960)
* feat: show asset details (627) * feat: show asset details (627) fixed tests * feat: show asset details (627) pr suggestions * feat: show asset details (627) var name convention * feat: show asset details (627) merge confict, keys * feat: show asset details (627) Introduced zustand store for asset details dialog. * feat: show asset details (627) Made it prettier * fix: fixed lint error in accounts-table
This commit is contained in:
parent
bfe2dbeaae
commit
6211c87389
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@ -4,6 +4,7 @@
|
|||||||
"esbenp.prettier-vscode",
|
"esbenp.prettier-vscode",
|
||||||
"firsttris.vscode-jest-runner",
|
"firsttris.vscode-jest-runner",
|
||||||
"dbaeumer.vscode-eslint",
|
"dbaeumer.vscode-eslint",
|
||||||
"stevejpurves.cucumber"
|
"stevejpurves.cucumber",
|
||||||
|
"streetsidesoftware.code-spell-checker"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
16
.vscode/settings.json
vendored
Normal file
16
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"cSpell.language": "en-GB",
|
||||||
|
"cSpell.words": ["vegaprotocol"],
|
||||||
|
"workbench.colorCustomizations": {
|
||||||
|
"activityBar.background": "#000000",
|
||||||
|
"activityBar.foreground": "#ffffff",
|
||||||
|
"activityBar.inactiveForeground": "#474B0A", // vega-yellow-dark
|
||||||
|
"activityBar.activeBorder": "#DFFF0B", // vega-yellow
|
||||||
|
"titleBar.activeBackground": "#DFFF0B", // vega-yellow
|
||||||
|
"titleBar.activeForeground": "#000000",
|
||||||
|
"titleBar.inactiveBackground": "#474B0A", // vega-yellow-dark
|
||||||
|
"titleBar.inactiveForeground": "#000000",
|
||||||
|
"activityBarBadge.background": "#DFFF0B",
|
||||||
|
"activityBarBadge.foreground": "#000000" // vega-yellow
|
||||||
|
}
|
||||||
|
}
|
@ -14,9 +14,18 @@ import { AppLoader } from '../components/app-loader';
|
|||||||
import { VegaWalletConnectButton } from '../components/vega-wallet-connect-button';
|
import { VegaWalletConnectButton } from '../components/vega-wallet-connect-button';
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
import { useGlobalStore } from '../stores';
|
import { useGlobalStore } from '../stores';
|
||||||
|
import {
|
||||||
|
AssetDetailsDialog,
|
||||||
|
useAssetDetailsDialogStore,
|
||||||
|
} from '@vegaprotocol/market-list';
|
||||||
|
|
||||||
function AppBody({ Component, pageProps }: AppProps) {
|
function AppBody({ Component, pageProps }: AppProps) {
|
||||||
const store = useGlobalStore();
|
const store = useGlobalStore();
|
||||||
|
const {
|
||||||
|
isAssetDetailsDialogOpen,
|
||||||
|
assetDetailsDialogSymbol,
|
||||||
|
setAssetDetailsDialogOpen,
|
||||||
|
} = useAssetDetailsDialogStore();
|
||||||
const [theme, toggleTheme] = useThemeSwitcher();
|
const [theme, toggleTheme] = useThemeSwitcher();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -54,6 +63,11 @@ function AppBody({ Component, pageProps }: AppProps) {
|
|||||||
dialogOpen={store.vegaWalletManageDialog}
|
dialogOpen={store.vegaWalletManageDialog}
|
||||||
setDialogOpen={(open) => store.setVegaWalletManageDialog(open)}
|
setDialogOpen={(open) => store.setVegaWalletManageDialog(open)}
|
||||||
/>
|
/>
|
||||||
|
<AssetDetailsDialog
|
||||||
|
assetSymbol={assetDetailsDialogSymbol}
|
||||||
|
open={isAssetDetailsDialogOpen}
|
||||||
|
onChange={(open) => setAssetDetailsDialogOpen(open)}
|
||||||
|
/>
|
||||||
</AppLoader>
|
</AppLoader>
|
||||||
</div>
|
</div>
|
||||||
</ThemeContext.Provider>
|
</ThemeContext.Provider>
|
||||||
|
@ -26,10 +26,12 @@ import { useGlobalStore } from '../../stores';
|
|||||||
import { AccountsContainer } from '@vegaprotocol/accounts';
|
import { AccountsContainer } from '@vegaprotocol/accounts';
|
||||||
import { DepthChartContainer } from '@vegaprotocol/market-depth';
|
import { DepthChartContainer } from '@vegaprotocol/market-depth';
|
||||||
import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
|
import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
|
||||||
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/market-list';
|
||||||
import {
|
import {
|
||||||
Tab,
|
Tab,
|
||||||
Tabs,
|
Tabs,
|
||||||
PriceCellChange,
|
PriceCellChange,
|
||||||
|
Button,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
ResizablePanel,
|
ResizablePanel,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
@ -58,9 +60,13 @@ export const TradeMarketHeader = ({
|
|||||||
market,
|
market,
|
||||||
className,
|
className,
|
||||||
}: TradeMarketHeaderProps) => {
|
}: TradeMarketHeaderProps) => {
|
||||||
|
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
|
||||||
|
useAssetDetailsDialogStore();
|
||||||
const candlesClose: string[] = (market?.candles || [])
|
const candlesClose: string[] = (market?.candles || [])
|
||||||
.map((candle) => candle?.close)
|
.map((candle) => candle?.close)
|
||||||
.filter((c): c is CandleClose => c !== null);
|
.filter((c): c is CandleClose => c !== null);
|
||||||
|
const symbol =
|
||||||
|
market.tradableInstrument.instrument.product?.settlementAsset?.symbol;
|
||||||
const headerItemClassName = 'whitespace-nowrap flex flex-col ';
|
const headerItemClassName = 'whitespace-nowrap flex flex-col ';
|
||||||
const itemClassName =
|
const itemClassName =
|
||||||
'font-sans font-normal mb-0 text-black-60 dark:text-white-80 text-ui-small';
|
'font-sans font-normal mb-0 text-black-60 dark:text-white-80 text-ui-small';
|
||||||
@ -132,15 +138,20 @@ export const TradeMarketHeader = ({
|
|||||||
: '-'}
|
: '-'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{market.tradableInstrument.instrument.product?.settlementAsset
|
{symbol && (
|
||||||
?.symbol && (
|
|
||||||
<div className={headerItemClassName}>
|
<div className={headerItemClassName}>
|
||||||
<span className={itemClassName}>{t('Settlement asset')}</span>
|
<span className={itemClassName}>{t('Settlement asset')}</span>
|
||||||
<span data-testid="trading-mode" className={itemValueClassName}>
|
<span data-testid="trading-mode" className={itemValueClassName}>
|
||||||
{
|
<Button
|
||||||
market.tradableInstrument.instrument.product?.settlementAsset
|
variant="inline-link"
|
||||||
?.symbol
|
className="no-underline hover:underline"
|
||||||
}
|
onClick={() => {
|
||||||
|
setAssetDetailsDialogOpen(true);
|
||||||
|
setAssetDetailsDialogSymbol(symbol);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{symbol}
|
||||||
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import type { SetState } from 'zustand';
|
|
||||||
import create from 'zustand';
|
import create from 'zustand';
|
||||||
|
|
||||||
interface GlobalStore {
|
interface GlobalStore {
|
||||||
@ -14,7 +13,7 @@ interface GlobalStore {
|
|||||||
setMarketId: (marketId: string) => void;
|
setMarketId: (marketId: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useGlobalStore = create((set: SetState<GlobalStore>) => ({
|
export const useGlobalStore = create<GlobalStore>((set) => ({
|
||||||
vegaWalletConnectDialog: false,
|
vegaWalletConnectDialog: false,
|
||||||
setVegaWalletConnectDialog: (isOpen: boolean) => {
|
setVegaWalletConnectDialog: (isOpen: boolean) => {
|
||||||
set({ vegaWalletConnectDialog: isOpen });
|
set({ vegaWalletConnectDialog: isOpen });
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
import type { ColumnApi, ValueFormatterParams } from 'ag-grid-community';
|
import type {
|
||||||
|
ColumnApi,
|
||||||
|
GroupCellRendererParams,
|
||||||
|
ValueFormatterParams,
|
||||||
|
} from 'ag-grid-community';
|
||||||
import {
|
import {
|
||||||
PriceCell,
|
PriceCell,
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
@ -12,6 +16,7 @@ import { AgGridColumn } from 'ag-grid-react';
|
|||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import type { Accounts_party_accounts } from './__generated__/Accounts';
|
import type { Accounts_party_accounts } from './__generated__/Accounts';
|
||||||
import { getId } from './accounts-data-provider';
|
import { getId } from './accounts-data-provider';
|
||||||
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/market-list';
|
||||||
|
|
||||||
interface AccountsTableProps {
|
interface AccountsTableProps {
|
||||||
data: Accounts_party_accounts[] | null;
|
data: Accounts_party_accounts[] | null;
|
||||||
@ -85,6 +90,8 @@ const comparator = (
|
|||||||
|
|
||||||
export const AccountsTable = forwardRef<AgGridReact, AccountsTableProps>(
|
export const AccountsTable = forwardRef<AgGridReact, AccountsTableProps>(
|
||||||
({ data }, ref) => {
|
({ data }, ref) => {
|
||||||
|
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
|
||||||
|
useAssetDetailsDialogStore();
|
||||||
return (
|
return (
|
||||||
<AgGrid
|
<AgGrid
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{ width: '100%', height: '100%' }}
|
||||||
@ -117,6 +124,21 @@ export const AccountsTable = forwardRef<AgGridReact, AccountsTableProps>(
|
|||||||
sortable
|
sortable
|
||||||
sortingOrder={['asc', 'desc']}
|
sortingOrder={['asc', 'desc']}
|
||||||
comparator={comparator}
|
comparator={comparator}
|
||||||
|
cellRenderer={({ value }: GroupCellRendererParams) =>
|
||||||
|
value && value.length > 0 ? (
|
||||||
|
<button
|
||||||
|
className="hover:underline"
|
||||||
|
onClick={() => {
|
||||||
|
setAssetDetailsDialogOpen(true);
|
||||||
|
setAssetDetailsDialogSymbol(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Type')}
|
headerName={t('Type')}
|
||||||
|
@ -259,4 +259,13 @@ describe('Deposit form', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('shows "View asset details" button when an asset is selected', async () => {
|
||||||
|
render(<DepositForm {...props} selectedAsset={asset} />);
|
||||||
|
expect(await screen.getByTestId('view-asset-details')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not shows "View asset details" button when no asset is selected', async () => {
|
||||||
|
render(<DepositForm {...props} />);
|
||||||
|
expect(await screen.queryAllByTestId('view-asset-details')).toHaveLength(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -25,6 +25,7 @@ import type { ReactNode } from 'react';
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { Controller, useForm, useWatch } from 'react-hook-form';
|
import { Controller, useForm, useWatch } from 'react-hook-form';
|
||||||
import { DepositLimits } from './deposit-limits';
|
import { DepositLimits } from './deposit-limits';
|
||||||
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/market-list';
|
||||||
|
|
||||||
interface FormFields {
|
interface FormFields {
|
||||||
asset: string;
|
asset: string;
|
||||||
@ -64,6 +65,8 @@ export const DepositForm = ({
|
|||||||
allowance,
|
allowance,
|
||||||
isFaucetable,
|
isFaucetable,
|
||||||
}: DepositFormProps) => {
|
}: DepositFormProps) => {
|
||||||
|
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
|
||||||
|
useAssetDetailsDialogStore();
|
||||||
const { account } = useWeb3React();
|
const { account } = useWeb3React();
|
||||||
const { keypair } = useVegaWallet();
|
const { keypair } = useVegaWallet();
|
||||||
const {
|
const {
|
||||||
@ -180,6 +183,18 @@ export const DepositForm = ({
|
|||||||
{t(`Get ${selectedAsset.symbol}`)}
|
{t(`Get ${selectedAsset.symbol}`)}
|
||||||
</UseButton>
|
</UseButton>
|
||||||
)}
|
)}
|
||||||
|
{!errors.asset?.message && selectedAsset && (
|
||||||
|
<button
|
||||||
|
data-testid="view-asset-details"
|
||||||
|
className="text-ui underline"
|
||||||
|
onClick={() => {
|
||||||
|
setAssetDetailsDialogOpen(true);
|
||||||
|
setAssetDetailsDialogSymbol(selectedAsset);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('View asset details')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup label={t('To (Vega key)')} labelFor="to" className="relative">
|
<FormGroup label={t('To (Vega key)')} labelFor="to" className="relative">
|
||||||
<Input
|
<Input
|
||||||
|
84
libs/market-list/src/lib/components/asset-details-dialog/__generated__/AssetsConnection.ts
generated
Normal file
84
libs/market-list/src/lib/components/asset-details-dialog/__generated__/AssetsConnection.ts
generated
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL query operation: AssetsConnection
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface AssetsConnection_assetsConnection_edges_node_source_BuiltinAsset {
|
||||||
|
__typename: "BuiltinAsset";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssetsConnection_assetsConnection_edges_node_source_ERC20 {
|
||||||
|
__typename: "ERC20";
|
||||||
|
/**
|
||||||
|
* The address of the erc20 contract
|
||||||
|
*/
|
||||||
|
contractAddress: string;
|
||||||
|
/**
|
||||||
|
* The lifetime limits deposit per address
|
||||||
|
* Note: this is a temporary measure for restricted mainnet
|
||||||
|
*/
|
||||||
|
lifetimeLimit: string;
|
||||||
|
/**
|
||||||
|
* The maximum allowed per withdraw
|
||||||
|
* Note: this is a temporary measure for restricted mainnet
|
||||||
|
*/
|
||||||
|
withdrawThreshold: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AssetsConnection_assetsConnection_edges_node_source = AssetsConnection_assetsConnection_edges_node_source_BuiltinAsset | AssetsConnection_assetsConnection_edges_node_source_ERC20;
|
||||||
|
|
||||||
|
export interface AssetsConnection_assetsConnection_edges_node {
|
||||||
|
__typename: "Asset";
|
||||||
|
/**
|
||||||
|
* The id of the asset
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* The full name of the asset (e.g: Great British Pound)
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* The symbol of the asset (e.g: GBP)
|
||||||
|
*/
|
||||||
|
symbol: string;
|
||||||
|
/**
|
||||||
|
* The total supply of the market
|
||||||
|
*/
|
||||||
|
totalSupply: string;
|
||||||
|
/**
|
||||||
|
* The precision of the asset
|
||||||
|
*/
|
||||||
|
decimals: number;
|
||||||
|
/**
|
||||||
|
* The minimum economically meaningful amount in the asset
|
||||||
|
*/
|
||||||
|
quantum: string;
|
||||||
|
/**
|
||||||
|
* The origin source of the asset (e.g: an erc20 asset)
|
||||||
|
*/
|
||||||
|
source: AssetsConnection_assetsConnection_edges_node_source;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssetsConnection_assetsConnection_edges {
|
||||||
|
__typename: "AssetEdge";
|
||||||
|
node: AssetsConnection_assetsConnection_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssetsConnection_assetsConnection {
|
||||||
|
__typename: "AssetsConnection";
|
||||||
|
/**
|
||||||
|
* The assets
|
||||||
|
*/
|
||||||
|
edges: (AssetsConnection_assetsConnection_edges | null)[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssetsConnection {
|
||||||
|
/**
|
||||||
|
* The list of all assets in use in the vega network or the specified asset if id is provided
|
||||||
|
*/
|
||||||
|
assetsConnection: AssetsConnection_assetsConnection;
|
||||||
|
}
|
@ -0,0 +1,341 @@
|
|||||||
|
import { MockedProvider } from '@apollo/react-testing';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import {
|
||||||
|
AssetDetailsDialog,
|
||||||
|
ASSETS_CONNECTION_QUERY,
|
||||||
|
} from './asset-details-dialog';
|
||||||
|
|
||||||
|
const mockedData = {
|
||||||
|
data: {
|
||||||
|
assetsConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'XYZalpha',
|
||||||
|
name: 'XYZ (α alpha)',
|
||||||
|
symbol: 'XYZalpha',
|
||||||
|
totalSupply: '10000000000000000000000000000',
|
||||||
|
decimals: 5,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
__typename: 'BuiltinAsset',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'XYZbeta',
|
||||||
|
name: 'XYZ (β beta)',
|
||||||
|
symbol: 'XYZbeta',
|
||||||
|
totalSupply: '1000000000',
|
||||||
|
decimals: 5,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
__typename: 'BuiltinAsset',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'XYZdelta',
|
||||||
|
name: 'XYZ (δ delta)',
|
||||||
|
symbol: 'XYZdelta',
|
||||||
|
totalSupply: '1000000000',
|
||||||
|
decimals: 5,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
__typename: 'BuiltinAsset',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'XYZepsilon',
|
||||||
|
name: 'XYZ (ε epsilon)',
|
||||||
|
symbol: 'XYZepsilon',
|
||||||
|
totalSupply: '1000000000',
|
||||||
|
decimals: 5,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
__typename: 'BuiltinAsset',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'XYZgamma',
|
||||||
|
name: 'XYZ (γ gamma)',
|
||||||
|
symbol: 'XYZgamma',
|
||||||
|
totalSupply: '1000000000',
|
||||||
|
decimals: 5,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
__typename: 'BuiltinAsset',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '2282ffc06a557173d297739305cc69f6444cdbbb1089df7d9aef32bbfd735ba1',
|
||||||
|
name: 'Tim Token (Vega)',
|
||||||
|
symbol: 'TIM',
|
||||||
|
totalSupply: '1000000000000000000000000000',
|
||||||
|
decimals: 18,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0x920B2375BCAC8cCDfDEFD74426c55C48e0304e4F',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '449dbfb66e7a444c485b4fdc77ddc6bbf81abbf7c8e247ac299c25e9557b99cf',
|
||||||
|
name: 'Taker Reward Token (Vega)',
|
||||||
|
symbol: 'TAK',
|
||||||
|
totalSupply: '1000000000000000000000000000',
|
||||||
|
decimals: 18,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0xf700Ce952B6EA11c01b43e5579C6D63286ff8CF0',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||||
|
name: 'tBTC TEST',
|
||||||
|
symbol: 'tBTC',
|
||||||
|
totalSupply: '21000000',
|
||||||
|
decimals: 5,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0xC912F059b4eCCEF6C969B2E0e2544A1A2581C094',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||||
|
name: 'tDAI TEST',
|
||||||
|
symbol: 'tDAI',
|
||||||
|
totalSupply: '21000000',
|
||||||
|
decimals: 5,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0xF4A2bcC43D24D14C4189Ef45fCf681E870675333',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
|
||||||
|
name: 'tEURO TEST',
|
||||||
|
symbol: 'tEURO',
|
||||||
|
totalSupply: '21000000',
|
||||||
|
decimals: 5,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0xD52b6C949E35A6E4C64b987B1B192A8608931a7b',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '98032ba34576f8012de9b822e1da3ed4b6223a4f4e05f573002d441ffb4bf314',
|
||||||
|
name: 'Liquidity Reward Token (Vega)',
|
||||||
|
symbol: 'LIQ',
|
||||||
|
totalSupply: '1000000200000000000000000000',
|
||||||
|
decimals: 18,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0xD2f21E37e78dD91b60FE3dD74A112e1a53b33057',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '993ed98f4f770d91a796faab1738551193ba45c62341d20597df70fea6704ede',
|
||||||
|
name: 'tUSDC TEST',
|
||||||
|
symbol: 'tUSDC',
|
||||||
|
totalSupply: '21000000',
|
||||||
|
decimals: 5,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0x3773A5c7aFF77e014cBF067dd31801b4C6dc4136',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'ba98cdeeec849a053e60cc03808e91e90d9d2e62425c76a590617b95ad41a066',
|
||||||
|
name: 'Steve Token (Vega)',
|
||||||
|
symbol: 'STE',
|
||||||
|
totalSupply: '1000000000000000000000000000',
|
||||||
|
decimals: 18,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0x5a16941cca2Db4AcdFC28Ac77a3e9652Fdf102e1',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'ce3fb1ab0717f0adbce019d7aef53aacdbadefe2d30ad1647b55f134d4072c90',
|
||||||
|
name: 'Woz Token (Vega)',
|
||||||
|
symbol: 'WOZ',
|
||||||
|
totalSupply: '1000000000000000000000000000',
|
||||||
|
decimals: 18,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0x5E4b9aDA947130Fc320a144cd22bC1641e5c9d81',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d',
|
||||||
|
name: 'Maker Reward Token (Vega)',
|
||||||
|
symbol: 'MAK',
|
||||||
|
totalSupply: '1000000000000000000000000000',
|
||||||
|
decimals: 18,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0x8ec701DA58394F5d2c8C2873D31039454D5845C1',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55',
|
||||||
|
name: 'Vega (testnet)',
|
||||||
|
symbol: 'VEGA',
|
||||||
|
totalSupply: '64999723000000000000000000',
|
||||||
|
decimals: 18,
|
||||||
|
quantum: '1',
|
||||||
|
source: {
|
||||||
|
contractAddress: '0xDc335304979D378255015c33AbFf09B60c31EBAb',
|
||||||
|
lifetimeLimit: '0',
|
||||||
|
withdrawThreshold: '0',
|
||||||
|
__typename: 'ERC20',
|
||||||
|
},
|
||||||
|
__typename: 'Asset',
|
||||||
|
},
|
||||||
|
__typename: 'AssetEdge',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
__typename: 'AssetsConnection',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mocks = [
|
||||||
|
{
|
||||||
|
request: {
|
||||||
|
query: ASSETS_CONNECTION_QUERY,
|
||||||
|
variables: {},
|
||||||
|
},
|
||||||
|
result: mockedData,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const WrappedAssetDetailsDialog = ({
|
||||||
|
assetSymbol,
|
||||||
|
}: {
|
||||||
|
assetSymbol: string;
|
||||||
|
}) => (
|
||||||
|
<MockedProvider mocks={mocks}>
|
||||||
|
<AssetDetailsDialog
|
||||||
|
assetSymbol={assetSymbol}
|
||||||
|
open={true}
|
||||||
|
onChange={() => false}
|
||||||
|
></AssetDetailsDialog>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('AssetDetailsDialog', () => {
|
||||||
|
it('should show no data message given unknown asset symbol', () => {
|
||||||
|
render(<WrappedAssetDetailsDialog assetSymbol={'UNKNOWN_FOR_SURE'} />);
|
||||||
|
expect(screen.getByText('No data')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const cases = [
|
||||||
|
['tDAI', 'tDAI', 'tDAI TEST', '21,000,000'],
|
||||||
|
['VEGA', 'VEGA', 'Vega (testnet)', '64,999,723,000,000,000,000,000,000'],
|
||||||
|
['tUSDC', 'tUSDC', 'tUSDC TEST', '21,000,000'],
|
||||||
|
];
|
||||||
|
it.each(cases)(
|
||||||
|
'should show correct data given %p symbol',
|
||||||
|
async (requestedSymbol, symbol, name, totalSupply) => {
|
||||||
|
render(<WrappedAssetDetailsDialog assetSymbol={requestedSymbol} />);
|
||||||
|
expect((await screen.findByTestId('symbol_value')).textContent).toContain(
|
||||||
|
symbol
|
||||||
|
);
|
||||||
|
expect((await screen.findByTestId('name_value')).textContent).toContain(
|
||||||
|
name
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
(await screen.findByTestId('totalsupply_value')).textContent
|
||||||
|
).toContain(totalSupply);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,205 @@
|
|||||||
|
import { gql, useQuery } from '@apollo/client';
|
||||||
|
import { formatNumber, t, toBigNum } from '@vegaprotocol/react-helpers';
|
||||||
|
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
Icon,
|
||||||
|
Intent,
|
||||||
|
Splash,
|
||||||
|
Tooltip,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type {
|
||||||
|
AssetsConnection,
|
||||||
|
AssetsConnection_assetsConnection_edges_node_source_ERC20,
|
||||||
|
} from './__generated__/AssetsConnection';
|
||||||
|
import create from 'zustand';
|
||||||
|
|
||||||
|
export type AssetDetailsDialogStore = {
|
||||||
|
isAssetDetailsDialogOpen: boolean;
|
||||||
|
assetDetailsDialogSymbol: string | Asset;
|
||||||
|
setAssetDetailsDialogOpen: (isOpen: boolean) => void;
|
||||||
|
setAssetDetailsDialogSymbol: (symbol: string | Asset) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAssetDetailsDialogStore = create<AssetDetailsDialogStore>(
|
||||||
|
(set) => ({
|
||||||
|
isAssetDetailsDialogOpen: false,
|
||||||
|
assetDetailsDialogSymbol: '',
|
||||||
|
setAssetDetailsDialogOpen: (isOpen: boolean) => {
|
||||||
|
set({ isAssetDetailsDialogOpen: isOpen });
|
||||||
|
},
|
||||||
|
setAssetDetailsDialogSymbol: (symbol: string | Asset) => {
|
||||||
|
set({ assetDetailsDialogSymbol: symbol });
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
type AssetDetails = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
tooltip: string;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
export const ASSETS_CONNECTION_QUERY = gql`
|
||||||
|
query AssetsConnection {
|
||||||
|
assetsConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
symbol
|
||||||
|
totalSupply
|
||||||
|
decimals
|
||||||
|
quantum
|
||||||
|
source {
|
||||||
|
... on ERC20 {
|
||||||
|
contractAddress
|
||||||
|
lifetimeLimit
|
||||||
|
withdrawThreshold
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export interface AssetDetailsDialogProps {
|
||||||
|
assetSymbol: string | Asset;
|
||||||
|
open: boolean;
|
||||||
|
onChange: (open: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AssetDetailsDialog = ({
|
||||||
|
assetSymbol,
|
||||||
|
open,
|
||||||
|
onChange,
|
||||||
|
}: AssetDetailsDialogProps) => {
|
||||||
|
const { data } = useQuery<AssetsConnection>(ASSETS_CONNECTION_QUERY);
|
||||||
|
const symbol =
|
||||||
|
typeof assetSymbol === 'string' ? assetSymbol : assetSymbol.symbol;
|
||||||
|
const asset = data?.assetsConnection.edges?.find(
|
||||||
|
(e) => e?.node.symbol === symbol
|
||||||
|
);
|
||||||
|
|
||||||
|
let details: AssetDetails = [];
|
||||||
|
if (asset != null) {
|
||||||
|
details = [
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
label: t('Name'),
|
||||||
|
value: asset.node.name,
|
||||||
|
tooltip: '', // t('Name of the asset (e.g: Great British Pound)')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'symbol',
|
||||||
|
label: t('Symbol'),
|
||||||
|
value: asset.node.symbol,
|
||||||
|
tooltip: '', // t('Symbol of the asset (e.g: GBP)')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'decimals',
|
||||||
|
label: t('Decimals'),
|
||||||
|
value: asset.node.decimals.toString(),
|
||||||
|
tooltip: t('Number of decimal / precision handled by this asset'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'quantum',
|
||||||
|
label: t('Quantum'),
|
||||||
|
value: asset.node.quantum,
|
||||||
|
tooltip: t('The minimum economically meaningful amount in the asset'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'totalsupply',
|
||||||
|
label: t('Total supply'),
|
||||||
|
value: formatNumber(toBigNum(asset.node.totalSupply, 0)),
|
||||||
|
tooltip: t('Total circulating supply for the asset'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'contractaddress',
|
||||||
|
label: t('Contract address'),
|
||||||
|
value: (
|
||||||
|
asset.node
|
||||||
|
.source as AssetsConnection_assetsConnection_edges_node_source_ERC20
|
||||||
|
).contractAddress,
|
||||||
|
tooltip: t(
|
||||||
|
'The address of the contract for the token, on the ethereum network'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'withdrawalthreshold',
|
||||||
|
label: t('Withdrawal threshold'),
|
||||||
|
value: (
|
||||||
|
asset.node
|
||||||
|
.source as AssetsConnection_assetsConnection_edges_node_source_ERC20
|
||||||
|
).withdrawThreshold,
|
||||||
|
tooltip: t(
|
||||||
|
'The maximum allowed per withdraw note: this is a temporary measure for restricted mainnet'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'lifetimelimit',
|
||||||
|
label: t('Lifetime limit'),
|
||||||
|
value: (
|
||||||
|
asset.node
|
||||||
|
.source as AssetsConnection_assetsConnection_edges_node_source_ERC20
|
||||||
|
).lifetimeLimit,
|
||||||
|
tooltip: t(
|
||||||
|
'The lifetime limits deposit per address note: this is a temporary measure for restricted mainnet'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = asset ? (
|
||||||
|
<div className="pt-8 pb-20 table w-full">
|
||||||
|
{details
|
||||||
|
.filter(({ value }) => value && value.length > 0)
|
||||||
|
.map(({ key, label, value, tooltip }) => (
|
||||||
|
<div key={key} className="flex flex-col md:table-row">
|
||||||
|
<div
|
||||||
|
data-testid={`${key}_label`}
|
||||||
|
className="table-cell w-1/3 py-2 first-letter:uppercase"
|
||||||
|
>
|
||||||
|
{tooltip.length > 0 ? (
|
||||||
|
<Tooltip description={tooltip}>
|
||||||
|
<span className="underline underline-offset-2 decoration-dotted cursor-help">
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
<span>{label}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
data-testid={`${key}_value`}
|
||||||
|
className="table-cell pb-5 md:pb-0"
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="py-40">
|
||||||
|
<Splash>{t('No data')}</Splash>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
title={t(`Asset details - ${symbol}`)}
|
||||||
|
intent={Intent.Primary}
|
||||||
|
icon={<Icon name="info-sign"></Icon>}
|
||||||
|
open={open}
|
||||||
|
onChange={(isOpen) => onChange(isOpen)}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
<Button className="w-1/4" onClick={() => onChange(false)}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './asset-details-dialog';
|
@ -1,4 +1,5 @@
|
|||||||
export * from './markets-container';
|
export * from './markets-container';
|
||||||
|
export * from './asset-details-dialog';
|
||||||
export * from './select-market-columns';
|
export * from './select-market-columns';
|
||||||
export * from './select-market-table';
|
export * from './select-market-table';
|
||||||
export * from './select-market';
|
export * from './select-market';
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
import type { ValueFormatterParams } from 'ag-grid-community';
|
import type {
|
||||||
|
GroupCellRendererParams,
|
||||||
|
ValueFormatterParams,
|
||||||
|
} from 'ag-grid-community';
|
||||||
import {
|
import {
|
||||||
PriceFlashCell,
|
PriceFlashCell,
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
@ -18,6 +21,7 @@ import type {
|
|||||||
MarketList_markets,
|
MarketList_markets,
|
||||||
MarketList_markets_data,
|
MarketList_markets_data,
|
||||||
} from '../../__generated__';
|
} from '../../__generated__';
|
||||||
|
import { useAssetDetailsDialogStore } from '../asset-details-dialog';
|
||||||
|
|
||||||
type Props = AgGridReactProps | AgReactUiProps;
|
type Props = AgGridReactProps | AgReactUiProps;
|
||||||
|
|
||||||
@ -29,6 +33,8 @@ type MarketListTableValueFormatterParams = Omit<
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const MarketListTable = forwardRef<AgGridReact, Props>((props, ref) => {
|
export const MarketListTable = forwardRef<AgGridReact, Props>((props, ref) => {
|
||||||
|
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
|
||||||
|
useAssetDetailsDialogStore();
|
||||||
return (
|
return (
|
||||||
<AgGrid
|
<AgGrid
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{ width: '100%', height: '100%' }}
|
||||||
@ -50,6 +56,21 @@ export const MarketListTable = forwardRef<AgGridReact, Props>((props, ref) => {
|
|||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Settlement asset')}
|
headerName={t('Settlement asset')}
|
||||||
field="tradableInstrument.instrument.product.settlementAsset.symbol"
|
field="tradableInstrument.instrument.product.settlementAsset.symbol"
|
||||||
|
cellRenderer={({ value }: GroupCellRendererParams) =>
|
||||||
|
value && value.length > 0 ? (
|
||||||
|
<button
|
||||||
|
className="hover:underline"
|
||||||
|
onClick={() => {
|
||||||
|
setAssetDetailsDialogOpen(true);
|
||||||
|
setAssetDetailsDialogSymbol(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Trading mode')}
|
headerName={t('Trading mode')}
|
||||||
|
@ -4,7 +4,7 @@ import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
|||||||
import { MarketListTable } from './market-list-table';
|
import { MarketListTable } from './market-list-table';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import type { IGetRowsParams } from 'ag-grid-community';
|
import type { IGetRowsParams, RowClickedEvent } from 'ag-grid-community';
|
||||||
import type {
|
import type {
|
||||||
MarketList_markets,
|
MarketList_markets,
|
||||||
MarketList_markets_data,
|
MarketList_markets_data,
|
||||||
@ -56,9 +56,13 @@ export const MarketsContainer = () => {
|
|||||||
rowModelType="infinite"
|
rowModelType="infinite"
|
||||||
datasource={{ getRows }}
|
datasource={{ getRows }}
|
||||||
ref={gridRef}
|
ref={gridRef}
|
||||||
onRowClicked={({ data }: { data: MarketList_markets }) =>
|
onRowClicked={(rowEvent: RowClickedEvent) => {
|
||||||
push(`/markets/${data.id}`)
|
const { data, event } = rowEvent;
|
||||||
}
|
// filters out clicks on the symbol column because it should display asset details
|
||||||
|
if ((event?.target as HTMLElement).tagName.toUpperCase() === 'BUTTON')
|
||||||
|
return;
|
||||||
|
push(`/markets/${(data as MarketList_markets).id}`);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</AsyncRenderer>
|
</AsyncRenderer>
|
||||||
);
|
);
|
||||||
|
@ -15,9 +15,10 @@ import {
|
|||||||
} from '../../utils/class-names';
|
} from '../../utils/class-names';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
type Variant = 'primary' | 'secondary' | 'trade' | 'accent' | 'inline-link';
|
||||||
interface CommonProps {
|
interface CommonProps {
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
variant?: 'primary' | 'secondary' | 'trade' | 'accent' | 'inline-link';
|
variant?: Variant;
|
||||||
className?: string;
|
className?: string;
|
||||||
prependIconName?: IconName;
|
prependIconName?: IconName;
|
||||||
appendIconName?: IconName;
|
appendIconName?: IconName;
|
||||||
@ -33,7 +34,7 @@ export interface AnchorButtonProps
|
|||||||
|
|
||||||
export const getButtonClasses = (
|
export const getButtonClasses = (
|
||||||
className?: string,
|
className?: string,
|
||||||
variant?: 'primary' | 'secondary' | 'trade' | 'accent' | 'inline-link',
|
variant?: Variant,
|
||||||
boxShadow?: boolean
|
boxShadow?: boolean
|
||||||
) => {
|
) => {
|
||||||
const paddingLeftProvided = includesLeftPadding(className);
|
const paddingLeftProvided = includesLeftPadding(className);
|
||||||
|
Loading…
Reference in New Issue
Block a user