mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Added SiteOrigin and PermissionList components (#12832)
* Changed back button to the one in design * PermissionConnect now uses Chip component * Added SiteOrigin widget * WIP * Added new permission list * Fix linting errors * Removed unused messages * Removed more unused messages * Make SiteOrigin bigger * Fix lint * Code Review fixes * Fix SiteOrigin overflowing * Add stories * Fix lint * Added useMemo to constant * Fix Chip's max-content overflowing SiteOrigin * Fix code review issues Co-authored-by: Olaf Tomalka <olaftomalka@Olafs-MacBook-Pro-2.local>
This commit is contained in:
parent
4cd957953d
commit
90b656bd66
@ -989,7 +989,7 @@
|
||||
"message": "Backup gas price is provided as the main gas estimation service is unavailable right now."
|
||||
},
|
||||
"eth_accounts": {
|
||||
"message": "View the addresses of your permitted accounts (required)",
|
||||
"message": "See address, account balance, activity and initiate transactions",
|
||||
"description": "The description for the `eth_accounts` permission"
|
||||
},
|
||||
"ethereumPublicAddress": {
|
||||
@ -2036,15 +2036,9 @@
|
||||
"message": "You have (1) pending transaction.",
|
||||
"description": "$1 is count of pending transactions"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "You have approved this permission"
|
||||
},
|
||||
"permissionRequest": {
|
||||
"message": "Permission request"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "You have not approved this permission"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Permissions"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "Pendiente"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "Aprobó este permiso"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "No aprobó este permiso"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Permisos"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "Pendiente"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "Aprobó este permiso"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "No aprobó este permiso"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Permisos"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "लंबित"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "आपने इस अनुमति को अनुमोदित कर दिया है"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "आपने इस अनुमति को अनुमोदित नहीं किया है"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "अनुमतियाँ"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "Tunda"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "Anda telah menyetujui izin ini"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "Anda belum menyetujui izin ini"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Izin"
|
||||
},
|
||||
|
@ -1102,12 +1102,6 @@
|
||||
"pending": {
|
||||
"message": "in corso"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "Hai approvato questo permesso"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "Non hai approvato questo permesso"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Permessi"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "処理"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "この許可の承認が完了しました。"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "この許可の承認が完了していません。"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "許可"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "보류 중"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "이 권한을 승인했습니다."
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "이 권한을 승인하지 않았습니다."
|
||||
},
|
||||
"permissions": {
|
||||
"message": "권한"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "Nakabinbin"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "Inaprubahan mo ang pahintulot na ito"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "Hindi mo inaprubahan ang pahintulot na ito"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Mga Pahintulot"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "Pendente"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "Você aprovou esta permissão"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "Você não aprovou esta permissão"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Permissões"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "В ожидании"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "Вы одобрили это разрешение"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "Вы не одобрили это разрешение"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Разрешения"
|
||||
},
|
||||
|
@ -1093,12 +1093,6 @@
|
||||
"pending": {
|
||||
"message": "Nakabinbin"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "Inaprubahan mo ang pahintulot na ito"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "Hindi mo inaprubahan ang pahintulot na ito"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Mga Pahintulot"
|
||||
},
|
||||
|
@ -1343,12 +1343,6 @@
|
||||
"pending": {
|
||||
"message": "Đang chờ xử lý"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "Bạn đã phê duyệt quyền này"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "Bạn chưa phê duyệt quyền này"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "Quyền"
|
||||
},
|
||||
|
@ -1144,12 +1144,6 @@
|
||||
"pending": {
|
||||
"message": "待处理"
|
||||
},
|
||||
"permissionCheckedIconDescription": {
|
||||
"message": "您已同意该权限"
|
||||
},
|
||||
"permissionUncheckedIconDescription": {
|
||||
"message": "您还未同意该权限"
|
||||
},
|
||||
"permissions": {
|
||||
"message": "权限"
|
||||
},
|
||||
|
@ -32,6 +32,7 @@
|
||||
@import 'permission-page-container/index';
|
||||
@import 'permissions-connect-footer/index';
|
||||
@import 'permissions-connect-header/index';
|
||||
@import 'permissions-connect-permission-list/index';
|
||||
@import 'recovery-phrase-reminder/index';
|
||||
@import 'step-progress-bar/index.scss';
|
||||
@import 'selected-account/index';
|
||||
|
@ -23,7 +23,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import PermissionsConnectHeader from '../../permissions-connect-header';
|
||||
import Tooltip from '../../../ui/tooltip';
|
||||
import CheckBox from '../../../ui/check-box';
|
||||
import PermissionsConnectPermissionList from '../../permissions-connect-permission-list';
|
||||
|
||||
export default class PermissionPageContainerContent extends PureComponent {
|
||||
static propTypes = {
|
||||
@ -14,7 +14,6 @@ export default class PermissionPageContainerContent extends PureComponent {
|
||||
origin: PropTypes.string.isRequired,
|
||||
}),
|
||||
selectedPermissions: PropTypes.object.isRequired,
|
||||
onPermissionToggle: PropTypes.func.isRequired,
|
||||
selectedIdentities: PropTypes.array,
|
||||
allIdentitiesSelected: PropTypes.bool,
|
||||
};
|
||||
@ -29,43 +28,11 @@ export default class PermissionPageContainerContent extends PureComponent {
|
||||
};
|
||||
|
||||
renderRequestedPermissions() {
|
||||
const { selectedPermissions, onPermissionToggle } = this.props;
|
||||
const { t } = this.context;
|
||||
|
||||
const items = Object.keys(selectedPermissions).map((permissionName) => {
|
||||
const description = t(permissionName);
|
||||
// don't allow deselecting eth_accounts
|
||||
const isDisabled = permissionName === 'eth_accounts';
|
||||
const isChecked = Boolean(selectedPermissions[permissionName]);
|
||||
const title = isChecked
|
||||
? t('permissionCheckedIconDescription')
|
||||
: t('permissionUncheckedIconDescription');
|
||||
|
||||
return (
|
||||
<div
|
||||
className="permission-approval-container__content__permission"
|
||||
key={permissionName}
|
||||
onClick={() => {
|
||||
if (!isDisabled) {
|
||||
onPermissionToggle(permissionName);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CheckBox
|
||||
disabled={isDisabled}
|
||||
id={permissionName}
|
||||
className="permission-approval-container__checkbox"
|
||||
checked={isChecked}
|
||||
title={title}
|
||||
/>
|
||||
<label htmlFor={permissionName}>{description}</label>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
const { selectedPermissions } = this.props;
|
||||
|
||||
return (
|
||||
<div className="permission-approval-container__content__requested">
|
||||
{items}
|
||||
<PermissionsConnectPermissionList permissions={selectedPermissions} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -62,15 +62,6 @@ export default class PermissionPageContainer extends Component {
|
||||
return Object.keys(props.request.permissions || {});
|
||||
}
|
||||
|
||||
onPermissionToggle = (methodName) => {
|
||||
this.setState({
|
||||
selectedPermissions: {
|
||||
...this.state.selectedPermissions,
|
||||
[methodName]: !this.state.selectedPermissions[methodName],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.context.metricsEvent({
|
||||
eventOpts: {
|
||||
@ -129,7 +120,6 @@ export default class PermissionPageContainer extends Component {
|
||||
requestMetadata={requestMetadata}
|
||||
domainMetadata={targetDomainMetadata}
|
||||
selectedPermissions={this.state.selectedPermissions}
|
||||
onPermissionToggle={this.onPermissionToggle}
|
||||
selectedIdentities={selectedIdentities}
|
||||
allIdentitiesSelected={allIdentitiesSelected}
|
||||
/>
|
||||
|
@ -9,20 +9,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.icon-with-fallback__identicon-container,
|
||||
.icon-with-fallback__identicon-border {
|
||||
height: 64px;
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.icon-with-fallback__identicon-border {
|
||||
border: 1px solid $Grey-100;
|
||||
}
|
||||
|
||||
.icon-with-fallback__identicon-container {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
@ -33,7 +19,6 @@
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
&__text,
|
||||
&__subtitle {
|
||||
@include H6;
|
||||
|
||||
@ -41,16 +26,6 @@
|
||||
color: $Grey-500;
|
||||
}
|
||||
|
||||
&__text {
|
||||
width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
margin-top: 8px;
|
||||
|
||||
/*rtl:ignore*/
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import SiteIcon from '../../ui/site-icon';
|
||||
import SiteOrigin from '../../ui/site-origin/site-origin';
|
||||
|
||||
export default class PermissionsConnectHeader extends Component {
|
||||
static propTypes = {
|
||||
@ -22,8 +22,7 @@ export default class PermissionsConnectHeader extends Component {
|
||||
|
||||
return (
|
||||
<div className="permissions-connect-header__icon">
|
||||
<SiteIcon icon={icon} name={iconName} size={64} />
|
||||
<div className="permissions-connect-header__text">{siteOrigin}</div>
|
||||
<SiteOrigin siteOrigin={siteOrigin} iconSrc={icon} name={iconName} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
export { default } from './permissions-connect-permission-list';
|
@ -0,0 +1,22 @@
|
||||
.permissions-connect-permission-list {
|
||||
.permission {
|
||||
@include H6;
|
||||
|
||||
width: 100%;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid $Grey-100;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
color: $Black-100;
|
||||
|
||||
i {
|
||||
display: block;
|
||||
padding: 16px;
|
||||
min-width: 16px;
|
||||
min-height: 16px;
|
||||
color: $Grey-500;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
|
||||
export default function PermissionsConnectPermissionList({ permissions }) {
|
||||
const t = useI18nContext();
|
||||
|
||||
const PERMISSION_TYPES = useMemo(() => {
|
||||
return {
|
||||
eth_accounts: {
|
||||
leftIcon: 'fas fa-eye',
|
||||
label: t('eth_accounts'),
|
||||
rightIcon: null,
|
||||
},
|
||||
};
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<div className="permissions-connect-permission-list">
|
||||
{Object.keys(permissions).map((permission) => (
|
||||
<div className="permission" key={PERMISSION_TYPES[permission].label}>
|
||||
<i className={PERMISSION_TYPES[permission].leftIcon} />
|
||||
{PERMISSION_TYPES[permission].label}
|
||||
<i className={PERMISSION_TYPES[permission].rightIcon} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
PermissionsConnectPermissionList.propTypes = {
|
||||
permissions: PropTypes.objectOf(PropTypes.bool).isRequired,
|
||||
};
|
@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
|
||||
import PermissionsConnectList from '.';
|
||||
|
||||
export default {
|
||||
title: 'Components/App/PermissionsConnectList',
|
||||
id: __filename,
|
||||
component: PermissionsConnectList,
|
||||
argTypes: {
|
||||
permissions: {
|
||||
control: 'object',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const DefaultStory = (args) => <PermissionsConnectList {...args} />;
|
||||
|
||||
DefaultStory.storyName = 'Default';
|
||||
|
||||
DefaultStory.args = {
|
||||
permissions: {
|
||||
eth_accounts: true,
|
||||
},
|
||||
};
|
@ -16,6 +16,7 @@ export default function Chip({
|
||||
leftIcon,
|
||||
rightIcon,
|
||||
onClick,
|
||||
maxContent = true,
|
||||
}) {
|
||||
const onKeyPress = (event) => {
|
||||
if (event.key === 'Enter' && onClick) {
|
||||
@ -35,6 +36,7 @@ export default function Chip({
|
||||
'chip--with-right-icon': Boolean(rightIcon),
|
||||
[`chip--border-color-${borderColor}`]: true,
|
||||
[`chip--background-color-${backgroundColor}`]: true,
|
||||
'chip--max-content': maxContent,
|
||||
})}
|
||||
role={isInteractive ? 'button' : undefined}
|
||||
tabIndex={isInteractive ? 0 : undefined}
|
||||
@ -99,4 +101,9 @@ Chip.propTypes = {
|
||||
* The onClick handler to be passed to the Chip component
|
||||
*/
|
||||
onClick: PropTypes.func,
|
||||
/**
|
||||
* If the width: max-content; is used in css.
|
||||
* max-content can overflow the parent's width and break designs
|
||||
*/
|
||||
maxContent: PropTypes.bool,
|
||||
};
|
||||
|
@ -9,7 +9,6 @@
|
||||
margin: 0 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: max-content;
|
||||
|
||||
&__left-icon,
|
||||
&__right-icon {
|
||||
@ -63,4 +62,8 @@
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&--max-content {
|
||||
width: max-content;
|
||||
}
|
||||
}
|
||||
|
1
ui/components/ui/site-origin/index.js
Normal file
1
ui/components/ui/site-origin/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './site-origin';
|
15
ui/components/ui/site-origin/index.scss
Normal file
15
ui/components/ui/site-origin/index.scss
Normal file
@ -0,0 +1,15 @@
|
||||
.site-origin {
|
||||
.chip__left-icon {
|
||||
padding: 4px 0 4px 8px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
/*rtl:ignore*/
|
||||
direction: rtl;
|
||||
}
|
||||
}
|
22
ui/components/ui/site-origin/site-origin.js
Normal file
22
ui/components/ui/site-origin/site-origin.js
Normal file
@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Chip from '../chip';
|
||||
import IconWithFallback from '../icon-with-fallback';
|
||||
|
||||
export default function SiteOrigin({ siteOrigin, iconSrc, iconName }) {
|
||||
return (
|
||||
<div className="site-origin">
|
||||
<Chip
|
||||
label={siteOrigin}
|
||||
maxContent={false}
|
||||
leftIcon={<IconWithFallback icon={iconSrc} name={iconName} size={32} />}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
SiteOrigin.propTypes = {
|
||||
siteOrigin: PropTypes.string.isRequired,
|
||||
iconName: PropTypes.string,
|
||||
iconSrc: PropTypes.string,
|
||||
};
|
30
ui/components/ui/site-origin/site-origin.stories.js
Normal file
30
ui/components/ui/site-origin/site-origin.stories.js
Normal file
@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
|
||||
import SiteOrigin from '.';
|
||||
|
||||
export default {
|
||||
title: 'Components/UI/SiteOrigin',
|
||||
id: __filename,
|
||||
component: SiteOrigin,
|
||||
argTypes: {
|
||||
siteOrigin: {
|
||||
control: 'text',
|
||||
},
|
||||
iconSrc: {
|
||||
control: 'text',
|
||||
},
|
||||
iconName: {
|
||||
control: 'text',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const DefaultStory = (args) => <SiteOrigin {...args} />;
|
||||
|
||||
DefaultStory.storyName = 'Default';
|
||||
|
||||
DefaultStory.args = {
|
||||
siteOrigin: 'https://metamask.io',
|
||||
iconName: 'MetaMask',
|
||||
iconSrc: './metamark.svg',
|
||||
};
|
@ -45,6 +45,7 @@
|
||||
@import 'readonly-input/index';
|
||||
@import 'sender-to-recipient/index';
|
||||
@import 'snackbar/index';
|
||||
@import 'site-origin/index';
|
||||
@import 'slider/index';
|
||||
@import 'tabs/index';
|
||||
@import 'toggle-button/index';
|
||||
|
@ -24,9 +24,10 @@
|
||||
}
|
||||
|
||||
&__back {
|
||||
@include H6;
|
||||
@include H7;
|
||||
|
||||
color: $Grey-600;
|
||||
color: $Grey-500;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
@ -37,7 +38,7 @@
|
||||
&__page-count {
|
||||
@include H7;
|
||||
|
||||
color: #6a737d;
|
||||
color: $Grey-500;
|
||||
grid-column: 2;
|
||||
justify-self: end;
|
||||
font-weight: bold;
|
||||
|
@ -174,7 +174,7 @@ export default class PermissionConnect extends Component {
|
||||
className="permissions-connect__back"
|
||||
onClick={() => this.goBack()}
|
||||
>
|
||||
<i className="fas fa-chevron-left" />
|
||||
<i className="fas fa-chevron-left"></i>
|
||||
{t('back')}
|
||||
</div>
|
||||
) : null}
|
||||
|
Loading…
Reference in New Issue
Block a user