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

View File

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

View File

@ -3,7 +3,7 @@ import React from 'react';
import { RouteTitle } from '../../components/route-title'; import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading'; import { SubHeading } from '../../components/sub-heading';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit'; import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { useExplorerProposalsQuery } from './__generated__/proposals'; import { useExplorerProposalsQuery } from './__generated__/Proposals';
import { useDocumentTitle } from '../../hooks/use-document-title'; import { useDocumentTitle } from '../../hooks/use-document-title';
const Governance = () => { 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!) { query ExplorerPartyAssets($partyId: ID!) {
partiesConnection(id: $partyId) { partiesConnection(id: $partyId) {
edges { edges {
@ -21,28 +46,7 @@ query ExplorerPartyAssets($partyId: ID!) {
accountsConnection { accountsConnection {
edges { edges {
node { node {
asset { ...ExplorerPartyAssetsAccounts
name
id
decimals
symbol
source {
__typename
... on ERC20 {
contractAddress
}
}
}
type
balance
market {
id
tradableInstrument {
instrument {
name
}
}
}
} }
} }
} }

View File

@ -3,6 +3,8 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; 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<{ export type ExplorerPartyAssetsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID']; 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 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` export const ExplorerPartyAssetsDocument = gql`
query ExplorerPartyAssets($partyId: ID!) { query ExplorerPartyAssets($partyId: ID!) {
partiesConnection(id: $partyId) { partiesConnection(id: $partyId) {
@ -35,28 +62,7 @@ export const ExplorerPartyAssetsDocument = gql`
accountsConnection { accountsConnection {
edges { edges {
node { node {
asset { ...ExplorerPartyAssetsAccounts
name
id
decimals
symbol
source {
__typename
... on ERC20 {
contractAddress
}
}
}
type
balance
market {
id
tradableInstrument {
instrument {
name
}
}
}
} }
} }
} }
@ -64,7 +70,7 @@ export const ExplorerPartyAssetsDocument = gql`
} }
} }
} }
`; ${ExplorerPartyAssetsAccountsFragmentDoc}`;
/** /**
* __useExplorerPartyAssetsQuery__ * __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 { import { getNodes, t, useScreenDimensions } from '@vegaprotocol/react-helpers';
t,
addDecimalsFormatNumber,
useScreenDimensions,
} from '@vegaprotocol/react-helpers';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { SubHeading } from '../../../components/sub-heading'; import { SubHeading } from '../../../components/sub-heading';
import { Panel } from '../../../components/panel'; import { Panel } from '../../../components/panel';
import { InfoPanel } from '../../../components/info-panel';
import { toNonHex } from '../../../components/search/detect-search'; import { toNonHex } from '../../../components/search/detect-search';
import { useTxsData } from '../../../hooks/use-txs-data'; import { useTxsData } from '../../../hooks/use-txs-data';
import { TxsInfiniteList } from '../../../components/txs'; import { TxsInfiniteList } from '../../../components/txs';
import { PageHeader } from '../../../components/page-header'; import { PageHeader } from '../../../components/page-header';
import { useExplorerPartyAssetsQuery } from './__generated__/party-assets'; import { useExplorerPartyAssetsQuery } from './__generated__/Party-assets';
import type * as Schema from '@vegaprotocol/types'; import type { ExplorerPartyAssetsAccountsFragment } from './__generated__/Party-assets';
import get from 'lodash/get';
import { useDocumentTitle } from '../../../hooks/use-document-title'; import { useDocumentTitle } from '../../../hooks/use-document-title';
import GovernanceAssetBalance from '../../../components/asset-balance/governance-asset-balance';
const accountTypeString: Record<Schema.AccountType, string> = { import { PartyAccounts } from './components/party-accounts';
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'),
};
const Party = () => { const Party = () => {
const { party } = useParams<{ party: string }>(); const { party } = useParams<{ party: string }>();
@ -71,63 +48,23 @@ const Party = () => {
</Panel> </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 = ( const staking = (
<section> <section>
{p?.stakingSummary?.currentStakeAvailable ? ( {p?.stakingSummary?.currentStakeAvailable ? (
<InfoPanel <p className="mt-4 leading-3">
title={t('Current Stake Available')} <strong className="font-semibold">{t('Staking Balance: ')}</strong>
id={p?.stakingSummary?.currentStakeAvailable} <GovernanceAssetBalance
copy={false} price={p.stakingSummary.currentStakeAvailable}
/> />
) : ( </p>
<Panel> ) : null}
<p>Nothing staked for {party}</p>
</Panel>
)}
</section> </section>
); );
const accounts = getNodes<ExplorerPartyAssetsAccountsFragment>(
p?.accountsConnection
);
return ( return (
<section> <section>
<h1 <h1
@ -140,8 +77,7 @@ const Party = () => {
<> <>
{header} {header}
<SubHeading>{t('Asset data')}</SubHeading> <SubHeading>{t('Asset data')}</SubHeading>
{accounts} {accounts ? <PartyAccounts accounts={accounts} /> : null}
<SubHeading>{t('Staking')}</SubHeading>
{staking} {staking}
<SubHeading>{t('Transactions')}</SubHeading> <SubHeading>{t('Transactions')}</SubHeading>

View File

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