1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-22 19:26:13 +02:00

Fix v10.11: Unable to find value of key "eth_accounts" for locale "en" in Permissions Modal (#13833)

* ConnectedAccountsPermissions: convert to FC

* permissions: add usePermissionsDescriptions
- fix ConnectedAccountsPermissions eth_accounts i18n

* ConnectedAccountsPermissions: rm .component
from path

* ConnectedAccountsPermissions: fix toggleExpanded

ensure we change previous state value

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

Co-authored-by: Mark Stacey <markjstacey@gmail.com>
This commit is contained in:
Ariella Vu 2022-03-04 13:56:31 -03:00 committed by Dan Miller
parent 98b3da31c7
commit 34bf555e50
5 changed files with 188 additions and 193 deletions

View File

@ -1,86 +0,0 @@
import classnames from 'classnames';
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import CheckBox from '../../ui/check-box';
export default class ConnectedAccountsPermissions extends PureComponent {
static contextTypes = {
t: PropTypes.func.isRequired,
};
static defaultProps = {
permissions: [],
};
static propTypes = {
permissions: PropTypes.arrayOf(
PropTypes.shape({
key: PropTypes.string.isRequired,
}),
),
};
state = {
expanded: false,
};
toggleExpanded = () => {
this.setState((prevState) => ({
expanded: !prevState.expanded,
}));
};
render() {
const { permissions } = this.props;
const { t } = this.context;
const { expanded } = this.state;
if (permissions.length === 0) {
return null;
}
return (
<div className="connected-accounts-permissions">
<p
className="connected-accounts-permissions__header"
onClick={this.toggleExpanded}
>
<strong>{t('permissions')}</strong>
<button
className={classnames('fas', {
'fa-angle-down': !expanded,
'fa-angle-up': expanded,
})}
title={t('showPermissions')}
/>
</p>
<div
className={classnames(
'connected-accounts-permissions__list-container',
{
'connected-accounts-permissions__list-container--expanded': expanded,
},
)}
>
<p>{t('authorizedPermissions')}:</p>
<ul className="connected-accounts-permissions__list">
{permissions.map(({ key: permissionName }) => (
<li
key={permissionName}
className="connected-accounts-permissions__list-item"
>
<CheckBox
checked
disabled
id={permissionName}
className="connected-accounts-permissions__checkbox"
/>
<label htmlFor={permissionName}>{t(permissionName)}</label>
</li>
))}
</ul>
</div>
</div>
);
}
}

View File

@ -0,0 +1,83 @@
import classnames from 'classnames';
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import CheckBox from '../../ui/check-box';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { usePermissionDescriptions } from '../../../hooks/usePermissionDescriptions';
const ConnectedAccountsPermissions = ({ permissions }) => {
const t = useI18nContext();
const [expanded, setExpanded] = useState(false);
const getPermissionDescription = usePermissionDescriptions();
const toggleExpanded = () => {
setExpanded((_expanded) => !_expanded);
};
if (!permissions.length) {
return null;
}
return (
<div className="connected-accounts-permissions">
<p
className="connected-accounts-permissions__header"
onClick={toggleExpanded}
>
<strong>{t('permissions')}</strong>
<button
className={classnames('fas', {
'fa-angle-down': !expanded,
'fa-angle-up': expanded,
})}
title={t('showPermissions')}
/>
</p>
<div
className={classnames(
'connected-accounts-permissions__list-container',
{
'connected-accounts-permissions__list-container--expanded': expanded,
},
)}
>
<p>{t('authorizedPermissions')}:</p>
<ul className="connected-accounts-permissions__list">
{permissions.map(({ key: permissionName }) => (
<li
key={permissionName}
className="connected-accounts-permissions__list-item"
>
<CheckBox
checked
disabled
id={permissionName}
className="connected-accounts-permissions__checkbox"
/>
<label htmlFor={permissionName}>
{getPermissionDescription(permissionName).label}
</label>
</li>
))}
</ul>
</div>
</div>
);
};
ConnectedAccountsPermissions.propTypes = {
permissions: PropTypes.arrayOf(
PropTypes.shape({
key: PropTypes.string.isRequired,
}),
),
};
ConnectedAccountsPermissions.defaultProps = {
permissions: [],
};
ConnectedAccountsPermissions.displayName = 'ConnectedAccountsPermissions';
export default React.memo(ConnectedAccountsPermissions);

View File

@ -1 +1 @@
export { default } from './connected-accounts-permissions.component';
export { default } from './connected-accounts-permissions';

View File

@ -1,116 +1,16 @@
import React, { useMemo } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {
RestrictedMethods,
///: BEGIN:ONLY_INCLUDE_IN(flask)
EndowmentPermissions,
PermissionNamespaces,
///: END:ONLY_INCLUDE_IN
} from '../../../../shared/constants/permissions';
import { useI18nContext } from '../../../hooks/useI18nContext';
///: BEGIN:ONLY_INCLUDE_IN(flask)
import { coinTypeToProtocolName } from '../../../helpers/utils/util';
///: END:ONLY_INCLUDE_IN
const UNKNOWN_PERMISSION = Symbol('unknown');
/**
* @typedef {Object} PermissionLabelObject
* @property {string} label - The text label.
* @property {string} leftIcon - The left icon.
* @property {string} rightIcon - The right icon.
*/
/**
* Gets the permission list label dictionary key for the specified permission
* name.
*
* @param {string} permissionName - The name of the permission whose key to
* retrieve.
* @param {Record<string, PermissionLabelObject>} permissionDictionary - The
* dictionary object mapping permission keys to label objects.
*/
function getPermissionKey(permissionName, permissionDictionary) {
if (Object.hasOwnProperty.call(permissionDictionary, permissionName)) {
return permissionName;
}
///: BEGIN:ONLY_INCLUDE_IN(flask)
for (const namespace of Object.keys(PermissionNamespaces)) {
if (permissionName.startsWith(namespace)) {
return PermissionNamespaces[namespace];
}
}
///: END:ONLY_INCLUDE_IN
return UNKNOWN_PERMISSION;
}
import { usePermissionDescriptions } from '../../../hooks/usePermissionDescriptions';
export default function PermissionsConnectPermissionList({ permissions }) {
const t = useI18nContext();
const PERMISSION_LIST_VALUES = useMemo(() => {
return {
[RestrictedMethods.eth_accounts]: {
leftIcon: 'fas fa-eye',
label: t('permission_ethereumAccounts'),
rightIcon: null,
},
///: BEGIN:ONLY_INCLUDE_IN(flask)
[RestrictedMethods.snap_confirm]: {
leftIcon: 'fas fa-user-check',
label: t('permission_customConfirmation'),
rightIcon: null,
},
[RestrictedMethods['snap_getBip44Entropy_*']]: (permissionName) => {
const coinType = permissionName.split('_').slice(-1);
return {
leftIcon: 'fas fa-door-open',
label: t('permission_manageBip44Keys', [
coinTypeToProtocolName(coinType) ||
`${coinType} (Unrecognized protocol)`,
]),
rightIcon: null,
};
},
[RestrictedMethods.snap_manageState]: {
leftIcon: 'fas fa-download',
label: t('permission_manageState'),
rightIcon: null,
},
[RestrictedMethods['wallet_snap_*']]: (permissionName) => {
const snapId = permissionName.split('_').slice(-1);
return {
leftIcon: 'fas fa-bolt',
label: t('permission_accessSnap', [snapId]),
rightIcon: null,
};
},
[EndowmentPermissions['endowment:network-access']]: {
leftIcon: 'fas fa-wifi',
label: t('permission_accessNetwork'),
rightIcon: null,
},
///: END:ONLY_INCLUDE_IN
[UNKNOWN_PERMISSION]: (permissionName) => {
return {
leftIcon: 'fas fa-times-circle',
label: t('permission_unknown', [permissionName ?? 'undefined']),
rightIcon: null,
};
},
};
}, [t]);
const getPermissionDescription = usePermissionDescriptions();
return (
<div className="permissions-connect-permission-list">
{Object.keys(permissions).map((permission) => {
const listValue =
PERMISSION_LIST_VALUES[
getPermissionKey(permission, PERMISSION_LIST_VALUES)
];
const { label, leftIcon, rightIcon } =
typeof listValue === 'function' ? listValue(permission) : listValue;
const { label, leftIcon, rightIcon } = getPermissionDescription(
permission,
);
return (
<div className="permission" key={permission}>

View File

@ -0,0 +1,98 @@
import { useMemo } from 'react';
import {
RestrictedMethods,
///: BEGIN:ONLY_INCLUDE_IN(flask)
EndowmentPermissions,
PermissionNamespaces,
///: END:ONLY_INCLUDE_IN
} from '../../shared/constants/permissions';
///: BEGIN:ONLY_INCLUDE_IN(flask)
import { coinTypeToProtocolName } from '../helpers/utils/util';
///: END:ONLY_INCLUDE_IN
import { useI18nContext } from './useI18nContext';
const UNKNOWN_PERMISSION = Symbol('unknown');
/**
* @typedef {Object} PermissionLabelObject
* @property {string} label - The text label.
* @property {string} leftIcon - The left icon.
* @property {string} rightIcon - The right icon.
*/
/**
* @returns {(permissionName:string) => PermissionLabelObject}
*/
export const usePermissionDescriptions = () => {
const t = useI18nContext();
return useMemo(() => {
const permissionDescriptions = {
[RestrictedMethods.eth_accounts]: {
leftIcon: 'fas fa-eye',
label: t('permission_ethereumAccounts'),
rightIcon: null,
},
///: BEGIN:ONLY_INCLUDE_IN(flask)
[RestrictedMethods.snap_confirm]: {
leftIcon: 'fas fa-user-check',
label: t('permission_customConfirmation'),
rightIcon: null,
},
[RestrictedMethods['snap_getBip44Entropy_*']]: (permissionName) => {
const coinType = permissionName.split('_').slice(-1);
return {
leftIcon: 'fas fa-door-open',
label: t('permission_manageBip44Keys', [
coinTypeToProtocolName(coinType) ||
`${coinType} (Unrecognized protocol)`,
]),
rightIcon: null,
};
},
[RestrictedMethods.snap_manageState]: {
leftIcon: 'fas fa-download',
label: t('permission_manageState'),
rightIcon: null,
},
[RestrictedMethods['wallet_snap_*']]: (permissionName) => {
const snapId = permissionName.split('_').slice(-1);
return {
leftIcon: 'fas fa-bolt',
label: t('permission_accessSnap', [snapId]),
rightIcon: null,
};
},
[EndowmentPermissions['endowment:network-access']]: {
leftIcon: 'fas fa-wifi',
label: t('permission_accessNetwork'),
rightIcon: null,
},
///: END:ONLY_INCLUDE_IN
[UNKNOWN_PERMISSION]: (permissionName) => {
return {
leftIcon: 'fas fa-times-circle',
label: t('permission_unknown', [permissionName ?? 'undefined']),
rightIcon: null,
};
},
};
return (permissionName) => {
let value = permissionDescriptions[UNKNOWN_PERMISSION];
if (Object.hasOwnProperty.call(permissionDescriptions, permissionName)) {
value = permissionDescriptions[permissionName];
}
///: BEGIN:ONLY_INCLUDE_IN(flask)
for (const namespace of Object.keys(PermissionNamespaces)) {
if (permissionName.startsWith(namespace)) {
value = permissionDescriptions[PermissionNamespaces[namespace]];
}
}
///: END:ONLY_INCLUDE_IN
return typeof value === 'function' ? value(permissionName) : value;
};
}, [t]);
};