feat(governance): improve asset proposal details view (#4216)
This commit is contained in:
parent
5e93e98f07
commit
a31008ea26
@ -836,5 +836,6 @@
|
||||
"AllProposals": "All proposals",
|
||||
"RejectedProposals": "Rejected proposals",
|
||||
"networkGovernance": "Network governance",
|
||||
"networkUpgrades": "Network upgrades"
|
||||
"networkUpgrades": "Network upgrades",
|
||||
"assetSpecification": "Asset specification"
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
export * from './proposal-asset-details';
|
@ -0,0 +1,48 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
import { AssetDetail, AssetDetailsTable } from '@vegaprotocol/assets';
|
||||
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||
|
||||
export const ProposalAssetDetails = ({
|
||||
asset,
|
||||
}: {
|
||||
asset: AssetFieldsFragment;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [showAssetDetails, setShowAssetDetails] = useState(false);
|
||||
|
||||
return (
|
||||
<section data-testid="proposal-asset-details">
|
||||
<CollapsibleToggle
|
||||
toggleState={showAssetDetails}
|
||||
setToggleState={setShowAssetDetails}
|
||||
dataTestId={'proposal-asset-details-toggle'}
|
||||
>
|
||||
<SubHeading title={t('assetSpecification')} />
|
||||
</CollapsibleToggle>
|
||||
|
||||
{showAssetDetails && (
|
||||
<div className="mb-10 pb-4">
|
||||
<AssetDetailsTable
|
||||
asset={asset}
|
||||
omitRows={[
|
||||
AssetDetail.STATUS,
|
||||
AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
|
||||
AssetDetail.GLOBAL_REWARD_POOL_ACCOUNT_BALANCE,
|
||||
AssetDetail.MAKER_PAID_FEES_ACCOUNT_BALANCE,
|
||||
AssetDetail.MAKER_RECEIVED_FEES_ACCOUNT_BALANCE,
|
||||
AssetDetail.LP_FEE_REWARD_ACCOUNT_BALANCE,
|
||||
AssetDetail.MARKET_PROPOSER_REWARD_ACCOUNT_BALANCE,
|
||||
]}
|
||||
inline={true}
|
||||
noBorder={true}
|
||||
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
|
||||
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
@ -10,6 +10,7 @@ import { ProposalDescription } from '../proposal-description';
|
||||
import { ProposalChangeTable } from '../proposal-change-table';
|
||||
import { ProposalJson } from '../proposal-json';
|
||||
import { ProposalVotesTable } from '../proposal-votes-table';
|
||||
import { ProposalAssetDetails } from '../proposal-asset-details';
|
||||
import { VoteDetails } from '../vote-details';
|
||||
import { ListAsset } from '../list-asset';
|
||||
import Routes from '../../../routes';
|
||||
@ -17,6 +18,8 @@ import { ProposalMarketData } from '../proposal-market-data';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||
import type { AssetQuery } from '@vegaprotocol/assets';
|
||||
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
|
||||
export enum ProposalType {
|
||||
@ -30,6 +33,7 @@ export enum ProposalType {
|
||||
export interface ProposalProps {
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
newMarketData?: MarketInfoWithData | null;
|
||||
assetData?: AssetQuery | null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
restData: any;
|
||||
}
|
||||
@ -38,6 +42,7 @@ export const Proposal = ({
|
||||
proposal,
|
||||
restData,
|
||||
newMarketData,
|
||||
assetData,
|
||||
}: ProposalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { params, loading, error } = useNetworkParams([
|
||||
@ -54,6 +59,23 @@ export const Proposal = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
let asset = assetData
|
||||
? removePaginationWrapper(assetData.assetsConnection?.edges)[0]
|
||||
: undefined;
|
||||
|
||||
if (proposal.terms.change.__typename === 'UpdateAsset' && asset) {
|
||||
asset = {
|
||||
...asset,
|
||||
quantum: proposal.terms.change.quantum,
|
||||
};
|
||||
|
||||
if (asset.source.__typename === 'ERC20') {
|
||||
asset.source.lifetimeLimit = proposal.terms.change.source.lifetimeLimit;
|
||||
asset.source.withdrawThreshold =
|
||||
proposal.terms.change.source.withdrawThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
let minVoterBalance = null;
|
||||
let proposalType = null;
|
||||
|
||||
@ -138,6 +160,14 @@ export const Proposal = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(proposal.terms.change.__typename === 'NewAsset' ||
|
||||
proposal.terms.change.__typename === 'UpdateAsset') &&
|
||||
asset && (
|
||||
<div className="mb-4">
|
||||
<ProposalAssetDetails asset={asset} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-6">
|
||||
<ProposalJson proposal={restData?.data?.proposal} />
|
||||
</div>
|
||||
|
@ -191,12 +191,13 @@ export const ProposalsList = ({
|
||||
{sortedProposals.open.length > 0 ||
|
||||
sortedProtocolUpgradeProposals.open.length > 0 ? (
|
||||
<ul data-testid="open-proposals">
|
||||
{sortedProtocolUpgradeProposals.open.map((proposal) => (
|
||||
<ProtocolUpgradeProposalsListItem
|
||||
key={proposal.upgradeBlockHeight}
|
||||
proposal={proposal}
|
||||
/>
|
||||
))}
|
||||
{filterString.length < 1 &&
|
||||
sortedProtocolUpgradeProposals.open.map((proposal) => (
|
||||
<ProtocolUpgradeProposalsListItem
|
||||
key={proposal.upgradeBlockHeight}
|
||||
proposal={proposal}
|
||||
/>
|
||||
))}
|
||||
|
||||
{sortedProposals.open.filter(filterPredicate).map((proposal) => (
|
||||
<ProposalsListItem key={proposal?.id} proposal={proposal} />
|
||||
|
@ -9,6 +9,7 @@ import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { ENV } from '../../../config';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { marketInfoWithDataProvider } from '@vegaprotocol/markets';
|
||||
import { useAssetQuery } from '@vegaprotocol/assets';
|
||||
|
||||
export const ProposalContainer = () => {
|
||||
const params = useParams<{ proposalId: string }>();
|
||||
@ -35,6 +36,25 @@ export const ProposalContainer = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
data: assetData,
|
||||
loading: assetLoading,
|
||||
error: assetError,
|
||||
} = useAssetQuery({
|
||||
fetchPolicy: 'network-only',
|
||||
variables: {
|
||||
assetId:
|
||||
(data?.proposal?.terms.change.__typename === 'NewAsset' &&
|
||||
data?.proposal?.id) ||
|
||||
(data?.proposal?.terms.change.__typename === 'UpdateAsset' &&
|
||||
data.proposal.terms.change.assetId) ||
|
||||
'',
|
||||
},
|
||||
skip: !['NewAsset', 'UpdateAsset'].includes(
|
||||
data?.proposal?.terms?.change?.__typename || ''
|
||||
),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(refetch, 2000);
|
||||
return () => clearInterval(interval);
|
||||
@ -42,15 +62,20 @@ export const ProposalContainer = () => {
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
loading={loading || newMarketLoading}
|
||||
error={error || newMarketError}
|
||||
data={newMarketData ? { newMarketData, data } : data}
|
||||
loading={loading || newMarketLoading || assetLoading}
|
||||
error={error || newMarketError || assetError}
|
||||
data={{
|
||||
...data,
|
||||
...(newMarketData ? { newMarketData } : {}),
|
||||
...(assetData ? { assetData } : {}),
|
||||
}}
|
||||
>
|
||||
{data?.proposal ? (
|
||||
<Proposal
|
||||
proposal={data.proposal}
|
||||
restData={restData}
|
||||
newMarketData={newMarketData}
|
||||
assetData={assetData}
|
||||
/>
|
||||
) : (
|
||||
<ProposalNotFound />
|
||||
|
@ -80,4 +80,14 @@ describe('AssetDetailsTable', () => {
|
||||
}
|
||||
}
|
||||
);
|
||||
it('omits specified rows when omitRows prop is provided', async () => {
|
||||
const asset = generateERC20Asset(1, Schema.AssetStatus.STATUS_ENABLED);
|
||||
const omittedKeys = [AssetDetail.TYPE, AssetDetail.DECIMALS];
|
||||
render(<AssetDetailsTable asset={asset} omitRows={omittedKeys} />);
|
||||
|
||||
for (const key of omittedKeys) {
|
||||
expect(screen.queryByTestId(testId(key, 'label'))).toBeNull();
|
||||
expect(screen.queryByTestId(testId(key, 'value'))).toBeNull();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -224,9 +224,11 @@ export const testId = (detail: AssetDetail, field: 'label' | 'value') =>
|
||||
|
||||
export type AssetDetailsTableProps = {
|
||||
asset: Asset;
|
||||
omitRows?: AssetDetail[];
|
||||
} & Omit<KeyValueTableRowProps, 'children'>;
|
||||
export const AssetDetailsTable = ({
|
||||
asset,
|
||||
omitRows = [],
|
||||
...props
|
||||
}: AssetDetailsTableProps) => {
|
||||
const longStringModifiers = (key: AssetDetail, value: string) =>
|
||||
@ -243,7 +245,7 @@ export const AssetDetailsTable = ({
|
||||
return (
|
||||
<KeyValueTable>
|
||||
{details
|
||||
.filter(({ value }) => Boolean(value))
|
||||
.filter(({ key, value }) => Boolean(value) && !omitRows.includes(key))
|
||||
.map(({ key, label, value, tooltip, valueTooltip }) => (
|
||||
<KeyValueTableRow key={key} {...props}>
|
||||
<div
|
||||
|
Loading…
Reference in New Issue
Block a user