fix(explorer): fix bug where no votes displayed a yes icon (#3699)

This commit is contained in:
Edd 2023-05-11 15:55:00 +01:00 committed by GitHub
parent f121836b4e
commit 8a080d3279
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 113 additions and 16 deletions

View File

@ -1,3 +1,5 @@
import { Icon } from '@vegaprotocol/ui-toolkit';
// https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go
export const ErrorCodes = new Map([
[51, 'Transaction failed validation'],
@ -28,7 +30,11 @@ export const ChainResponseCode = ({
}: ChainResponseCodeProps) => {
const isSuccess = successCodes.has(code);
const icon = isSuccess ? '✅' : '❌';
const icon = isSuccess ? (
<Icon name="tick-circle" className="fill-vega-green-550" />
) : (
<Icon name="cross" className="fill-vega-pink-550" />
);
const label = ErrorCodes.get(code) || 'Unknown response code';
// Hack for batches with many errors - see https://github.com/vegaprotocol/vega/issues/7245
@ -36,7 +42,7 @@ export const ChainResponseCode = ({
error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error;
return (
<div title={`Response code: ${code} - ${label}`} className="inline-block">
<div title={`Response code: ${code} - ${label}`} className=" inline-block">
<span
className="mr-2"
aria-label={isSuccess ? 'Success' : 'Warning'}

View File

@ -4,6 +4,7 @@ import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint
import { TxDetailsShared } from './shared/tx-details-shared';
import { TableCell, TableRow, TableWithTbody } from '../../table';
import ProposalLink from '../../links/proposal-link/proposal-link';
import { VoteIcon } from '../../vote-icon/vote-icon';
interface TxProposalVoteProps {
txData: BlockExplorerTransactionResult | undefined;
@ -30,27 +31,22 @@ export const TxProposalVote = ({
return <>{t('Awaiting Block Explorer transaction details')}</>;
}
const vote = txData.command.voteSubmission.value ? '👍' : '👎';
const vote = txData.command.voteSubmission.value === 'VALUE_YES';
return (
<TableWithTbody className="mb-8" allowWrap={true}>
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
<TableRow modifier="bordered">
<TableCell>{t('Proposal ID')}</TableCell>
<TableCell>{txData.command.voteSubmission.proposalId}</TableCell>
</TableRow>
<TableRow modifier="bordered">
<TableCell>{t('Proposal details')}</TableCell>
<TableCell>
<ProposalLink id={txData.command.voteSubmission.proposalId} />
</TableCell>
</TableRow>
<TableRow modifier="bordered">
<TableCell>{t('Proposal')}</TableCell>
<TableCell>{txData.command.voteSubmission.proposalId}</TableCell>
</TableRow>
<TableRow modifier="bordered">
<TableCell>{t('Vote')}</TableCell>
<TableCell>{vote}</TableCell>
<TableCell>
<VoteIcon vote={vote} />
</TableCell>
</TableRow>
</TableWithTbody>
);

View File

@ -1,5 +1,6 @@
import { t } from '@vegaprotocol/i18n';
import type { components } from '../../../types/explorer';
import { VoteIcon } from '../vote-icon/vote-icon';
interface TxOrderTypeProps {
orderType: string;
@ -137,12 +138,15 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
let type = displayString[orderType] || orderType;
let colours =
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-150';
'text-white dark:text-white bg-vega-dark-150 dark:bg-vega-dark-250';
// This will get unwieldy and should probably produce a different colour of tag
if (type === 'Chain Event' && !!command?.chainEvent) {
type = getLabelForChainEvent(command.chainEvent);
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
} else if (type === 'Validator Heartbeat') {
colours =
'text-white dark-text-white bg-vega-light-200 dark:bg-vega-dark-100';
} else if (type === 'Proposal' || type === 'Governance Proposal') {
if (command && !!command.proposalSubmission) {
type = getLabelForProposal(command.proposalSubmission);
@ -150,6 +154,16 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
colours = 'text-black bg-vega-yellow';
}
if (type === 'Vote on Proposal') {
return (
<VoteIcon
vote={command?.voteSubmission?.value === 'VALUE_YES'}
yesText="Proposal vote"
noText="Proposal vote"
/>
);
}
if (type === 'Vote on Proposal' || type === 'Vote Submission') {
colours = 'text-black bg-vega-yellow';
}

View File

@ -98,6 +98,6 @@ describe('Txs infinite list item', () => {
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
expect(screen.getByTestId('tx-type')).toHaveTextContent('testType');
expect(screen.getByTestId('tx-block')).toHaveTextContent('1');
expect(screen.getByTestId('tx-success')).toHaveTextContent('Success: ✅');
expect(screen.getByTestId('tx-success')).toHaveTextContent('Success');
});
});

View File

@ -31,7 +31,7 @@ export const TxsInfiniteListItem = ({
return (
<div
data-testid="transaction-row"
className="flex items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item grid grid-cols-10 py-2"
className="flex items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item grid grid-cols-10"
>
<div
className="text-sm col-span-10 md:col-span-3 leading-none"
@ -83,7 +83,7 @@ export const TxsInfiniteListItem = ({
data-testid="tx-success"
>
<span className="md:hidden uppercase text-vega-dark-300">
Success:&nbsp;
Success&nbsp;
</span>
{isNumber(code) ? (
<ChainResponseCode code={code} hideLabel={true} />

View File

@ -0,0 +1,37 @@
import { render } from '@testing-library/react';
import { VoteIcon } from './vote-icon';
describe('Vote TX icon', () => {
it('should use the text For by default for yes votes', () => {
const yes = render(<VoteIcon vote={true} />);
expect(yes.getByTestId('label')).toHaveTextContent('For');
});
it('should use the yesText for yes votes if specified', () => {
const yes = render(<VoteIcon vote={true} yesText="Test" />);
expect(yes.getByTestId('label')).toHaveTextContent('Test');
});
it('should display the tick icon for yes votes', () => {
const no = render(<VoteIcon vote={true} />);
expect(no.getByRole('img')).toHaveAttribute(
'aria-label',
'tick-circle icon'
);
});
it('should use the text Against by default for no votes', () => {
const no = render(<VoteIcon vote={false} />);
expect(no.getByTestId('label')).toHaveTextContent('Against');
});
it('should use the noText for no votes if specified', () => {
const no = render(<VoteIcon vote={false} noText="Test" />);
expect(no.getByTestId('label')).toHaveTextContent('Test');
});
it('should display the delete icon for no votes', () => {
const no = render(<VoteIcon vote={false} />);
expect(no.getByRole('img')).toHaveAttribute('aria-label', 'delete icon');
});
});

View File

@ -0,0 +1,40 @@
import { Icon } from '@vegaprotocol/ui-toolkit';
import type { IconName } from '@vegaprotocol/ui-toolkit';
export interface VoteIconProps {
// True is a yes vote, false is undefined or no vorte
vote: boolean;
// Defaults to 'For', but can be any text
yesText?: string;
// Defaults to 'Against', but can be any text
noText?: string;
}
/**
* Displays a lozenge with an icon representing the way a user voted for a proposal.
* The yes and no text can be overridden
*
* @returns
*/
export function VoteIcon({
vote,
yesText = 'For',
noText = 'Against',
}: VoteIconProps) {
const label = vote ? yesText : noText;
const bg = vote ? 'bg-vega-green-550' : 'bg-vega-pink-550';
const icon: IconName = vote ? 'tick-circle' : 'delete';
const fill = vote ? 'vega-green-300' : 'vega-pink-300';
const text = vote ? 'vega-green-200' : 'vega-pink-200';
return (
<div
className={`voteicon inline-block my-1 py-1 px-2 py rounded-md text-white leading-one sm align-top ${bg}`}
>
<Icon name={icon} size={3} className={`mr-2 p-0 fill-${fill}`} />
<span className={`text-base text-${text}`} data-testid="label">
{label}
</span>
</div>
);
}

View File

@ -60,3 +60,7 @@
--ag-row-hover-color: theme(colors.neutral[800]);
--ag-font-size: 12px;
}
.voteicon svg {
vertical-align: baseline;
}