feat(explorer): improve party account list display (#2391)

* feat(explorer): party account list as table
This commit is contained in:
Edd 2022-12-14 16:36:47 +00:00 committed by GitHub
parent 071a9ab34b
commit b47caa7667
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 167 additions and 133 deletions

View File

@ -5,13 +5,18 @@ import { useExplorerAssetQuery } from '../links/asset-link/__generated__/Asset';
export type AssetBalanceProps = {
assetId: string;
price: string;
showAssetLink?: boolean;
};
/**
* Given a market ID and a price it will fetch the market
* and format the price in that market's decimal places.
*/
const AssetBalance = ({ assetId, price }: AssetBalanceProps) => {
const AssetBalance = ({
assetId,
price,
showAssetLink = true,
}: AssetBalanceProps) => {
const { data } = useExplorerAssetQuery({
fetchPolicy: 'cache-first',
variables: { id: assetId },
@ -25,7 +30,9 @@ const AssetBalance = ({ assetId, price }: AssetBalanceProps) => {
return (
<div className="inline-block">
<span>{label}</span>{' '}
{data?.asset?.id ? <AssetLink id={data.asset.id} /> : null}
{showAssetLink && data?.asset?.id ? (
<AssetLink id={data.asset.id} />
) : null}
</div>
);
};

View File

@ -2,8 +2,8 @@ import { t } from '@vegaprotocol/react-helpers';
import { useEffect } from 'react';
import { InfoBlock } from '../../components/info-block';
import { Panel } from '../../components/panel';
import { useExplorerStatsQuery } from './__generated__/explorer-stats';
import type { ExplorerStatsFieldsFragment } from './__generated__/explorer-stats';
import { useExplorerStatsQuery } from './__generated__/Explorer-stats';
import type { ExplorerStatsFieldsFragment } from './__generated__/Explorer-stats';
interface StatsMap {
field: keyof ExplorerStatsFieldsFragment;

View File

@ -3,7 +3,7 @@ import React from 'react';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { useExplorerProposalsQuery } from './__generated__/proposals';
import { useExplorerProposalsQuery } from './__generated__/Proposals';
import { useDocumentTitle } from '../../hooks/use-document-title';
const Governance = () => {

View File

@ -1,3 +1,28 @@
fragment ExplorerPartyAssetsAccounts on AccountBalance {
asset {
name
id
decimals
symbol
source {
__typename
... on ERC20 {
contractAddress
}
}
}
type
balance
market {
id
tradableInstrument {
instrument {
name
}
}
}
}
query ExplorerPartyAssets($partyId: ID!) {
partiesConnection(id: $partyId) {
edges {
@ -21,28 +46,7 @@ query ExplorerPartyAssets($partyId: ID!) {
accountsConnection {
edges {
node {
asset {
name
id
decimals
symbol
source {
__typename
... on ERC20 {
contractAddress
}
}
}
type
balance
market {
id
tradableInstrument {
instrument {
name
}
}
}
...ExplorerPartyAssetsAccounts
}
}
}

View File

@ -3,6 +3,8 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type ExplorerPartyAssetsAccountsFragment = { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } | null };
export type ExplorerPartyAssetsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
}>;
@ -10,7 +12,32 @@ export type ExplorerPartyAssetsQueryVariables = Types.Exact<{
export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } | null } } | null> | null } | null } }> } | null };
export const ExplorerPartyAssetsAccountsFragmentDoc = gql`
fragment ExplorerPartyAssetsAccounts on AccountBalance {
asset {
name
id
decimals
symbol
source {
__typename
... on ERC20 {
contractAddress
}
}
}
type
balance
market {
id
tradableInstrument {
instrument {
name
}
}
}
}
`;
export const ExplorerPartyAssetsDocument = gql`
query ExplorerPartyAssets($partyId: ID!) {
partiesConnection(id: $partyId) {
@ -35,28 +62,7 @@ export const ExplorerPartyAssetsDocument = gql`
accountsConnection {
edges {
node {
asset {
name
id
decimals
symbol
source {
__typename
... on ERC20 {
contractAddress
}
}
}
type
balance
market {
id
tradableInstrument {
instrument {
name
}
}
}
...ExplorerPartyAssetsAccounts
}
}
}
@ -64,7 +70,7 @@ export const ExplorerPartyAssetsDocument = gql`
}
}
}
`;
${ExplorerPartyAssetsAccountsFragmentDoc}`;
/**
* __useExplorerPartyAssetsQuery__

View File

@ -0,0 +1,81 @@
import { t } from '@vegaprotocol/react-helpers';
import get from 'lodash/get';
import AssetBalance from '../../../../components/asset-balance/asset-balance';
import { AssetLink, MarketLink } from '../../../../components/links';
import { Table, TableRow } from '../../../../components/table';
import type * as Schema from '@vegaprotocol/types';
import type { ExplorerPartyAssetsAccountsFragment } from '../__generated__/Party-assets';
const accountTypeString: Record<Schema.AccountType, string> = {
ACCOUNT_TYPE_BOND: t('Bond'),
ACCOUNT_TYPE_EXTERNAL: t('External'),
ACCOUNT_TYPE_FEES_INFRASTRUCTURE: t('Fees (Infrastructure)'),
ACCOUNT_TYPE_FEES_LIQUIDITY: t('Fees (Liquidity)'),
ACCOUNT_TYPE_FEES_MAKER: t('Fees (Maker)'),
ACCOUNT_TYPE_GENERAL: t('General'),
ACCOUNT_TYPE_GLOBAL_INSURANCE: t('Global Insurance Pool'),
ACCOUNT_TYPE_GLOBAL_REWARD: t('Global Reward Pool'),
ACCOUNT_TYPE_INSURANCE: t('Insurance'),
ACCOUNT_TYPE_MARGIN: t('Margin'),
ACCOUNT_TYPE_PENDING_TRANSFERS: t('Pending Transfers'),
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: t('Reward - LP Fees received'),
ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: t('Reward - Maker fees paid'),
ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: t('Reward - Maker fees received'),
ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: t('Reward - Market proposers'),
ACCOUNT_TYPE_SETTLEMENT: t('Settlement'),
};
interface PartyAccountsProps {
accounts: ExplorerPartyAssetsAccountsFragment[];
}
/**
* Renders a list of a party's accounts as a table. Currently unsorted, but could
* probably do with sorting by asset, and then within asset, by type with general
* appearing first and... tbd
*/
export const PartyAccounts = ({ accounts }: PartyAccountsProps) => {
return (
<Table className="max-w-5xl min-w-fit">
<thead>
<TableRow modifier="bordered" className="font-mono">
<td>{t('Type')}</td>
<td>{t('Market')}</td>
<td className="text-right pr-2">{t('Balance')}</td>
<td>{t('Asset')}</td>
</TableRow>
</thead>
<tbody>
{accounts.map((account) => {
const m = get(account, 'market.tradableInstrument.instrument.name');
return (
<TableRow
title={account.asset.name}
id={`${accountTypeString[account.type]} ${m ? ` - ${m}` : ''}`}
>
<td className="text-md">{accountTypeString[account.type]}</td>
<td className="text-md">
{account.market?.id ? (
<MarketLink id={account.market?.id} />
) : (
<p>-</p>
)}
</td>
<td className="text-md text-right pr-2">
<AssetBalance
assetId={account.asset.id}
price={account.balance}
showAssetLink={false}
/>
</td>
<td className="text-md">
<AssetLink id={account.asset.id} />
</td>
</TableRow>
);
})}
</tbody>
</Table>
);
};

View File

@ -1,40 +1,17 @@
import {
t,
addDecimalsFormatNumber,
useScreenDimensions,
} from '@vegaprotocol/react-helpers';
import { getNodes, t, useScreenDimensions } from '@vegaprotocol/react-helpers';
import { useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { SubHeading } from '../../../components/sub-heading';
import { Panel } from '../../../components/panel';
import { InfoPanel } from '../../../components/info-panel';
import { toNonHex } from '../../../components/search/detect-search';
import { useTxsData } from '../../../hooks/use-txs-data';
import { TxsInfiniteList } from '../../../components/txs';
import { PageHeader } from '../../../components/page-header';
import { useExplorerPartyAssetsQuery } from './__generated__/party-assets';
import type * as Schema from '@vegaprotocol/types';
import get from 'lodash/get';
import { useExplorerPartyAssetsQuery } from './__generated__/Party-assets';
import type { ExplorerPartyAssetsAccountsFragment } from './__generated__/Party-assets';
import { useDocumentTitle } from '../../../hooks/use-document-title';
const accountTypeString: Record<Schema.AccountType, string> = {
ACCOUNT_TYPE_BOND: t('Bond'),
ACCOUNT_TYPE_EXTERNAL: t('External'),
ACCOUNT_TYPE_FEES_INFRASTRUCTURE: t('Fees (Infrastructure)'),
ACCOUNT_TYPE_FEES_LIQUIDITY: t('Fees (Liquidity)'),
ACCOUNT_TYPE_FEES_MAKER: t('Fees (Maker)'),
ACCOUNT_TYPE_GENERAL: t('General'),
ACCOUNT_TYPE_GLOBAL_INSURANCE: t('Global Insurance Pool'),
ACCOUNT_TYPE_GLOBAL_REWARD: t('Global Reward Pool'),
ACCOUNT_TYPE_INSURANCE: t('Insurance'),
ACCOUNT_TYPE_MARGIN: t('Margin'),
ACCOUNT_TYPE_PENDING_TRANSFERS: t('Pending Transfers'),
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: t('Reward - LP Fees received'),
ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: t('Reward - Maker fees paid'),
ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: t('Reward - Maker fees received'),
ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: t('Reward - Market proposers'),
ACCOUNT_TYPE_SETTLEMENT: t('Settlement'),
};
import GovernanceAssetBalance from '../../../components/asset-balance/governance-asset-balance';
import { PartyAccounts } from './components/party-accounts';
const Party = () => {
const { party } = useParams<{ party: string }>();
@ -71,63 +48,23 @@ const Party = () => {
</Panel>
);
const accounts = (
<section>
{p?.accountsConnection?.edges?.length ? (
p.accountsConnection?.edges?.map((a) => {
const account = a?.node;
if (!account || !account.asset) {
return '';
}
const m = get(account, 'market.tradableInstrument.instrument.name');
return (
<InfoPanel
title={account.asset.name}
id={`${accountTypeString[account.type]} ${m ? ` - ${m}` : ''}`}
>
<section>
<dl className="flex gap-2 flex-wrap">
<dt className="text-zinc-500 dark:text-zinc-400 text-md">
<p>
{t('Balance')} ({account.asset.symbol})
</p>
</dt>
<dd className="text-md">
{addDecimalsFormatNumber(
account.balance,
account.asset.decimals
)}
</dd>
</dl>
</section>
</InfoPanel>
);
})
) : (
<Panel>
<p>No Data</p>
</Panel>
)}
</section>
);
const staking = (
<section>
{p?.stakingSummary?.currentStakeAvailable ? (
<InfoPanel
title={t('Current Stake Available')}
id={p?.stakingSummary?.currentStakeAvailable}
copy={false}
/>
) : (
<Panel>
<p>Nothing staked for {party}</p>
</Panel>
)}
<p className="mt-4 leading-3">
<strong className="font-semibold">{t('Staking Balance: ')}</strong>
<GovernanceAssetBalance
price={p.stakingSummary.currentStakeAvailable}
/>
</p>
) : null}
</section>
);
const accounts = getNodes<ExplorerPartyAssetsAccountsFragment>(
p?.accountsConnection
);
return (
<section>
<h1
@ -140,8 +77,7 @@ const Party = () => {
<>
{header}
<SubHeading>{t('Asset data')}</SubHeading>
{accounts}
<SubHeading>{t('Staking')}</SubHeading>
{accounts ? <PartyAccounts accounts={accounts} /> : null}
{staking}
<SubHeading>{t('Transactions')}</SubHeading>

View File

@ -6,7 +6,7 @@ import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { DATA_SOURCES } from '../../config';
import { useFetch } from '@vegaprotocol/react-helpers';
import type { TendermintValidatorsResponse } from './tendermint-validator-response';
import { useExplorerNodesQuery } from './__generated__/nodes';
import { useExplorerNodesQuery } from './__generated__/Nodes';
import { useDocumentTitle } from '../../hooks/use-document-title';
const Validators = () => {