1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

17873 ledger instruction banner (#17937)

* switched to use banner alert and added story

* enabled dismiss functionality

* remove close button

* bump global branches coverage target

* replace Typography with Text and (link) Button with ButtonLink

* unit test for component rendering

* left-align button links to match text

* update copy to reflect figma mock ups

* update unit test snapshot

* bump coverage threshold

* update snapshot to reflect button component changes

* update snapshot to reflect box changes
This commit is contained in:
flexa-rob 2023-04-21 13:21:31 +10:00 committed by GitHub
parent a144b75fe8
commit 3c01011ffe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 31 deletions

View File

@ -1987,16 +1987,16 @@
"message": "Prior to clicking confirm:" "message": "Prior to clicking confirm:"
}, },
"ledgerConnectionInstructionStepFour": { "ledgerConnectionInstructionStepFour": {
"message": "Enable \"smart contract data\" or \"blind signing\" on your Ledger device" "message": "Enable \"smart contract data\" or \"blind signing\" on your Ledger device."
}, },
"ledgerConnectionInstructionStepOne": { "ledgerConnectionInstructionStepOne": {
"message": "Enable Use Ledger Live under Settings > Advanced" "message": "Enable Use Ledger Live under Settings > Advanced."
}, },
"ledgerConnectionInstructionStepThree": { "ledgerConnectionInstructionStepThree": {
"message": "Plug in your Ledger device and select the Ethereum app" "message": "Be sure your Ledger is plugged in and to select the Ethereum app."
}, },
"ledgerConnectionInstructionStepTwo": { "ledgerConnectionInstructionStepTwo": {
"message": "Open and unlock Ledger Live App" "message": "Open and unlock Ledger Live App."
}, },
"ledgerConnectionPreferenceDescription": { "ledgerConnectionPreferenceDescription": {
"message": "Customize how you connect your Ledger to MetaMask. $1 is recommended, but other options are available. Read more here: $2", "message": "Customize how you connect your Ledger to MetaMask. $1 is recommended, but other options are available. Read more here: $2",
@ -2795,7 +2795,7 @@
"message": "Open Codefi Compliance" "message": "Open Codefi Compliance"
}, },
"openFullScreenForLedgerWebHid": { "openFullScreenForLedgerWebHid": {
"message": "Open MetaMask in full screen to connect your ledger via WebHID.", "message": "Go to full screen to connect your Ledger.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid." "description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
}, },
"openInBlockExplorer": { "openInBlockExplorer": {

View File

@ -0,0 +1,52 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LedgerInstructionField Component rendering should render properly with data instruction 1`] = `
<div>
<div>
<div
class="confirm-detail-row"
>
<div
class="box mm-banner-base mm-banner-alert mm-banner-alert--severity-info box--padding-3 box--padding-left-2 box--display-flex box--gap-2 box--flex-direction-row box--background-color-primary-muted box--rounded-sm"
>
<span
class="box mm-icon mm-icon--size-lg box--display-inline-block box--flex-direction-row box--color-primary-default"
style="mask-image: url('./images/icons/info.svg');"
/>
<div>
<div
class="ledger-live-dialog"
>
<h6
class="box mm-text mm-text--body-md box--flex-direction-row box--color-text-default"
>
Prior to clicking confirm:
</h6>
<h6
class="box mm-text mm-text--body-md box--flex-direction-row box--color-text-default"
>
• Be sure your Ledger is plugged in and to select the Ethereum app.
</h6>
<h6
class="box mm-text mm-text--body-md box--flex-direction-row box--color-text-default"
>
• Enable "smart contract data" or "blind signing" on your Ledger device.
</h6>
<h6
class="box mm-text mm-text--body-md box--flex-direction-row box--color-text-default"
>
<span>
<button
class="box mm-text mm-button-base mm-button-link mm-button-link--size-auto mm-text--body-md mm-text--text-align-left box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-default box--background-color-transparent"
>
Go to full screen to connect your Ledger.
</button>
</span>
</h6>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -19,15 +19,13 @@ import {
getLedgerTransportStatus, getLedgerTransportStatus,
} from '../../../ducks/app/app'; } from '../../../ducks/app/app';
import Typography from '../../ui/typography/typography'; import { BannerAlert, ButtonLink, Text } from '../../component-library';
import Button from '../../ui/button';
import { useI18nContext } from '../../../hooks/useI18nContext'; import { useI18nContext } from '../../../hooks/useI18nContext';
import { import {
FONT_WEIGHT, SEVERITIES,
TEXT_ALIGN,
TextColor, TextColor,
TypographyVariant,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import Dialog from '../../ui/dialog';
import { import {
getPlatform, getPlatform,
getEnvironmentType, getEnvironmentType,
@ -42,14 +40,9 @@ const renderInstructionStep = (
) => { ) => {
return ( return (
show && ( show && (
<Typography <Text color={color} as="h6">
boxProps={{ margin: 0 }}
color={color}
fontWeight={FONT_WEIGHT.BOLD}
variant={TypographyVariant.H7}
>
{text} {text}
</Typography> </Text>
) )
); );
}; };
@ -71,8 +64,8 @@ export default function LedgerInstructionField({ showDataInstruction }) {
ledgerTransportType === LedgerTransportTypes.webhid && ledgerTransportType === LedgerTransportTypes.webhid &&
webHidConnectedStatus !== WebHIDConnectedStatuses.connected webHidConnectedStatus !== WebHIDConnectedStatuses.connected
) { ) {
const devices = await window.navigator.hid.getDevices(); const devices = await window.navigator?.hid?.getDevices();
const webHidIsConnected = devices.some( const webHidIsConnected = devices?.some(
(device) => device.vendorId === Number(LEDGER_USB_VENDOR_ID), (device) => device.vendorId === Number(LEDGER_USB_VENDOR_ID),
); );
dispatch( dispatch(
@ -136,28 +129,28 @@ export default function LedgerInstructionField({ showDataInstruction }) {
return ( return (
<div> <div>
<div className="confirm-detail-row"> <div className="confirm-detail-row">
<Dialog type="message"> <BannerAlert severity={SEVERITIES.INFO}>
<div className="ledger-live-dialog"> <div className="ledger-live-dialog">
{renderInstructionStep(t('ledgerConnectionInstructionHeader'))} {renderInstructionStep(t('ledgerConnectionInstructionHeader'))}
{renderInstructionStep( {renderInstructionStep(
`- ${t('ledgerConnectionInstructionStepOne')}`, ` ${t('ledgerConnectionInstructionStepOne')}`,
!isFirefox && usingLedgerLive, !isFirefox && usingLedgerLive,
)} )}
{renderInstructionStep( {renderInstructionStep(
`- ${t('ledgerConnectionInstructionStepTwo')}`, ` ${t('ledgerConnectionInstructionStepTwo')}`,
!isFirefox && usingLedgerLive, !isFirefox && usingLedgerLive,
)} )}
{renderInstructionStep( {renderInstructionStep(
`- ${t('ledgerConnectionInstructionStepThree')}`, ` ${t('ledgerConnectionInstructionStepThree')}`,
)} )}
{renderInstructionStep( {renderInstructionStep(
`- ${t('ledgerConnectionInstructionStepFour')}`, ` ${t('ledgerConnectionInstructionStepFour')}`,
showDataInstruction, showDataInstruction,
)} )}
{renderInstructionStep( {renderInstructionStep(
<span> <span>
<Button <ButtonLink
type="link" textAlign={TEXT_ALIGN.LEFT}
onClick={async () => { onClick={async () => {
if (environmentTypeIsFullScreen) { if (environmentTypeIsFullScreen) {
window.location.reload(); window.location.reload();
@ -167,14 +160,14 @@ export default function LedgerInstructionField({ showDataInstruction }) {
}} }}
> >
{t('ledgerConnectionInstructionCloseOtherApps')} {t('ledgerConnectionInstructionCloseOtherApps')}
</Button> </ButtonLink>
</span>, </span>,
transportStatus === HardwareTransportStates.deviceOpenFailure, transportStatus === HardwareTransportStates.deviceOpenFailure,
)} )}
{renderInstructionStep( {renderInstructionStep(
<span> <span>
<Button <ButtonLink
type="link" textAlign={TEXT_ALIGN.LEFT}
onClick={async () => { onClick={async () => {
if (environmentTypeIsFullScreen) { if (environmentTypeIsFullScreen) {
const connectedDevices = const connectedDevices =
@ -200,19 +193,20 @@ export default function LedgerInstructionField({ showDataInstruction }) {
{environmentTypeIsFullScreen {environmentTypeIsFullScreen
? t('clickToConnectLedgerViaWebHID') ? t('clickToConnectLedgerViaWebHID')
: t('openFullScreenForLedgerWebHid')} : t('openFullScreenForLedgerWebHid')}
</Button> </ButtonLink>
</span>, </span>,
usingWebHID && usingWebHID &&
webHidConnectedStatus === WebHIDConnectedStatuses.notConnected, webHidConnectedStatus === WebHIDConnectedStatuses.notConnected,
TextColor.WARNING_DEFAULT, TextColor.WARNING_DEFAULT,
)} )}
</div> </div>
</Dialog> </BannerAlert>
</div> </div>
</div> </div>
); );
} }
LedgerInstructionField.propTypes = { LedgerInstructionField.propTypes = {
// whether or not to show the data instruction
showDataInstruction: PropTypes.bool, showDataInstruction: PropTypes.bool,
}; };

View File

@ -0,0 +1,17 @@
import React from 'react';
import LedgerInstructionField from '.';
export default {
title: 'Components/App/LedgerInstructionField',
argTypes: {
showDataInstruction: {
control: {
type: 'boolean',
},
},
},
};
export const DefaultStory = (args) => <LedgerInstructionField {...args} />;
DefaultStory.storyName = 'Default';

View File

@ -0,0 +1,28 @@
import React from 'react';
import configureMockStore from 'redux-mock-store';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import LedgerInstructionField from '.';
describe('LedgerInstructionField Component', () => {
const mockStore = {
appState: {
ledgerWebHidConnectedStatus: 'notConnected',
},
metamask: {
ledgerTransportType: 'webhid',
},
};
describe('rendering', () => {
it('should render properly with data instruction', () => {
const store = configureMockStore()(mockStore);
const { container } = renderWithProvider(
<LedgerInstructionField showDataInstruction />,
store,
);
expect(container).toMatchSnapshot();
});
});
});