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

[MMI] Added code fencing in app menu bar (#18069)

* Added code fencing in app me nu bar

* Fixed lint issues

* Fixed yarn.lock

* Fixed issue

* Fixed tests

* Fixed yarn.lock

* Fixing policies

* Fixing lavamoat

* fixed yarn.lock

* Fixed storybook

* clean up and adds test

* lint

* typo

* adds test

---------

Co-authored-by: Antonio Regadas <antonio.regadas@consensys.net>
This commit is contained in:
Albert Olivé 2023-05-23 14:51:39 +02:00 committed by GitHub
parent 290dbd77ce
commit dfb2c0e0e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 273 additions and 1 deletions

View File

@ -5,6 +5,9 @@ import { useDispatch, useSelector } from 'react-redux';
import { getAccountLink } from '@metamask/etherscan-link';
import { showModal } from '../../../store/actions';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
import { mmiActionsFactory } from '../../../store/institutional/institution-background';
///: END:ONLY_INCLUDE_IN
import {
CONNECTED_ROUTE,
NETWORKS_ROUTE,
@ -17,10 +20,16 @@ import {
getCurrentKeyring,
getRpcPrefsForCurrentProvider,
getSelectedIdentity,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
getMetaMaskAccountsOrdered,
///: END:ONLY_INCLUDE_IN
} from '../../../selectors';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../shared/constants/app';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils';
///: END:ONLY_INCLUDE_IN
import { KeyringType } from '../../../../shared/constants/keyring';
import {
MetaMetricsEventCategory,
@ -46,6 +55,12 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
const trackEvent = useContext(MetaMetricsContext);
const blockExplorerLinkText = useSelector(getBlockExplorerLinkText);
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const accounts = useSelector(getMetaMaskAccountsOrdered);
const isCustodial = /Custody/u.test(keyring.type);
const mmiActions = mmiActionsFactory();
///: END:ONLY_INCLUDE_IN
const isRemovable = keyring.type !== KeyringType.hdKeyTree;
const routeToAddBlockExplorerUrl = () => {
@ -165,6 +180,37 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
{t('removeAccount')}
</MenuItem>
) : null}
{
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
isCustodial ? (
<MenuItem
data-testid="account-options-menu__remove-jwt"
onClick={async () => {
const token = await dispatch(mmiActions.getCustodianToken());
const custodyAccountDetails = await dispatch(
mmiActions.getAllCustodianAccountsWithToken(
keyring.type.split(' - ')[1],
token,
),
);
dispatch(
showModal({
name: 'CONFIRM_REMOVE_JWT',
token,
custodyAccountDetails,
accounts,
selectedAddress: toChecksumHexAddress(address),
}),
);
onClose();
}}
iconClassName="fas fa-trash-alt"
>
{t('removeJWT')}
</MenuItem>
) : null
///: END:ONLY_INCLUDE_IN
}
</Menu>
);
}

View File

@ -0,0 +1,104 @@
import React from 'react';
import configureStore from 'redux-mock-store';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import mockState from '../../../../test/data/mock-state.json';
import AccountOptionsMenu from './account-options-menu';
const initState = {
...mockState,
metamask: {
...mockState.metamask,
providerConfig: {
type: 'test',
chainId: '1',
},
identities: {
'0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': {
name: 'Custody Account A',
address: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275',
},
},
selectedAddress: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275',
keyrings: [
{
type: 'Custody',
accounts: ['0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275'],
},
],
custodyStatusMaps: '123',
custodyAccountDetails: {
'0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': {
custodianName: 'saturn',
},
},
custodianSupportedChains: {
'0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': {
supportedChains: ['1', '2'],
custodianName: 'saturn',
},
},
mmiConfiguration: {
portfolio: {
enabled: true,
url: 'https://dashboard.metamask-institutional.io',
},
custodians: [
{
type: 'saturn',
name: 'saturn',
apiUrl: 'https://saturn-custody.dev.metamask-institutional.io',
iconUrl: 'images/saturn.svg',
displayName: 'Saturn Custody',
production: true,
refreshTokenUrl: null,
isNoteToTraderSupported: false,
version: 1,
},
],
},
},
};
const mockStore = configureStore();
const props = {
onClose: jest.fn(),
anchorElement: document.body,
};
const mockedGetCustodianToken = jest.fn().mockReturnValue({ type: 'TYPE' });
const mockedGetAllCustodianAccountsWithToken = jest
.fn()
.mockReturnValue({ type: 'TYPE' });
jest.mock('../../../store/institutional/institution-background', () => ({
mmiActionsFactory: () => ({
getCustodianToken: mockedGetCustodianToken,
getAllCustodianAccountsWithToken: mockedGetAllCustodianAccountsWithToken,
}),
}));
describe('AccountOptionsMenu', () => {
it('shows the remove account and remove jwt menu options', async () => {
const store = mockStore(initState);
renderWithProvider(<AccountOptionsMenu {...props} />, store);
await waitFor(() => {
expect(
screen.queryByTestId('account-options-menu__connected-sites'),
).toBeInTheDocument();
const removeAccount = screen.queryByTestId(
'account-options-menu__remove-account',
);
fireEvent.click(removeAccount);
expect(props.onClose).toHaveBeenCalled();
const removeJwt = screen.queryByTestId(
'account-options-menu__remove-jwt',
);
fireEvent.click(removeJwt);
expect(mockedGetCustodianToken).toHaveBeenCalled();
});
});
});

View File

@ -14,6 +14,19 @@
color: var(--color-text-default);
}
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
&__custody-logo {
@media screen and (max-width: $break-small) {
display: none;
}
&--icon {
height: 35px;
margin-left: 10px;
}
}
///: END:ONLY_INCLUDE_IN
.selected-account {
grid-column: 2 / span 1;
place-self: center stretch;

View File

@ -2,6 +2,11 @@ import React, { useState, useContext, useRef } from 'react';
import browser from 'webextension-polyfill';
import { useHistory } from 'react-router-dom';
import { useSelector } from 'react-redux';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
import { getCustodianIconForAddress } from '../../../selectors/institutional/selectors';
import Box from '../../ui/box';
import { DISPLAY, AlignItems } from '../../../helpers/constants/design-system';
///: END:ONLY_INCLUDE_IN
import SelectedAccount from '../selected-account';
import ConnectedStatusIndicator from '../connected-status-indicator';
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
@ -12,7 +17,12 @@ import {
} from '../../../../shared/constants/metametrics';
import { CONNECTED_ACCOUNTS_ROUTE } from '../../../helpers/constants/routes';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { getOriginOfCurrentTab } from '../../../selectors';
import {
getOriginOfCurrentTab,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
getSelectedAddress,
///: END:ONLY_INCLUDE_IN
} from '../../../selectors';
import { MetaMetricsContext } from '../../../contexts/metametrics';
import { ButtonIcon, IconName } from '../../component-library';
import AccountOptionsMenu from './account-options-menu';
@ -23,6 +33,12 @@ export default function MenuBar() {
const history = useHistory();
const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false);
const origin = useSelector(getOriginOfCurrentTab);
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const selectedAddress = useSelector(getSelectedAddress);
const custodianIcon = useSelector((state) =>
getCustodianIconForAddress(state, selectedAddress),
);
///: END:ONLY_INCLUDE_IN
const ref = useRef(false);
const showStatus =
@ -37,6 +53,24 @@ export default function MenuBar() {
onClick={() => history.push(CONNECTED_ACCOUNTS_ROUTE)}
/>
) : null}
{
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
custodianIcon && (
<Box
display={DISPLAY.FLEX}
alignItems={AlignItems.center}
className="menu-bar__custody-logo"
data-testid="custody-logo"
>
<img
src={custodianIcon}
className="menu-bar__custody-logo--icon"
alt=""
/>
</Box>
)
///: END:ONLY_INCLUDE_IN
}
<SelectedAccount />
<span style={{ display: 'inherit' }} ref={ref}>
<ButtonIcon

View File

@ -4,11 +4,14 @@ import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import { CHAIN_IDS } from '../../../../shared/constants/network';
import { KeyringType } from '../../../../shared/constants/keyring';
import mockState from '../../../../test/data/mock-state.json';
import MenuBar from './menu-bar';
const initState = {
...mockState,
activeTab: {},
metamask: {
...mockState.metamask,
providerConfig: {
chainId: CHAIN_IDS.GOERLI,
},
@ -64,4 +67,76 @@ describe('MenuBar', () => {
expect(accountOptionsMenu).not.toBeInTheDocument();
});
it('shows a custodial account detail', async () => {
const customState = {
...mockState,
activeTab: {},
metamask: {
...mockState.metamask,
networkConfigurations: {},
providerConfig: {
type: 'test',
chainId: '1',
},
identities: {
'0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': {
name: 'Custody Account A',
address: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275',
},
},
selectedAddress: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275',
waitForConfirmDeepLinkDialog: '123',
keyrings: [
{
type: 'Custody',
accounts: ['0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275'],
},
],
custodyStatusMaps: '123',
custodyAccountDetails: {
'0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': {
custodianName: 'saturn',
},
},
custodianSupportedChains: {
'0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': {
supportedChains: ['1', '2'],
custodianName: 'saturn',
},
},
mmiConfiguration: {
portfolio: {
enabled: true,
url: 'https://dashboard.metamask-institutional.io',
},
custodians: [
{
type: 'saturn',
name: 'saturn',
apiUrl: 'https://saturn-custody.dev.metamask-institutional.io',
iconUrl: 'images/saturn.svg',
displayName: 'Saturn Custody',
production: true,
refreshTokenUrl: null,
isNoteToTraderSupported: false,
version: 1,
},
],
},
},
};
const store = mockStore(customState);
renderWithProvider(<MenuBar />, store);
const accountOptions = screen.queryByTestId('account-options-menu-button');
fireEvent.click(accountOptions);
await waitFor(() => {
const custodyLogo = screen.queryByTestId('custody-logo');
expect(custodyLogo).toBeInTheDocument();
});
});
});