From 3806e0a2a665522bf08bd09010add8a8fcce6ff4 Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Wed, 27 Jan 2021 10:51:59 -0600 Subject: [PATCH] Refactor NetworkDisplay, ConnectedStatusIndicator, etc to use ColorIndicator (#10214) --- test/e2e/ethereum-on.spec.js | 2 +- test/e2e/from-import-ui.spec.js | 2 +- test/e2e/metamask-responsive-ui.spec.js | 6 +- test/e2e/metamask-ui.spec.js | 8 +- .../app/app-header/app-header.component.js | 19 +- ui/app/components/app/app-header/index.scss | 13 +- .../app/app-header/tests/app-header.test.js | 5 +- .../confirm-page-container-header/index.scss | 5 + .../connected-status-indicator.component.js | 71 ------- .../connected-status-indicator.container.js | 39 ---- .../connected-status-indicator.js | 66 ++++++ .../app/connected-status-indicator/index.js | 2 +- .../app/dropdowns/components/dropdown.js | 7 + .../components/network-dropdown-icon.js | 48 ----- .../app/dropdowns/network-dropdown.js | 194 ++++++------------ .../tests/network-dropdown-icon.test.js | 22 -- .../dropdowns/tests/network-dropdown.test.js | 57 +++-- .../components/app/network-display/index.js | 4 +- .../components/app/network-display/index.scss | 104 +++++----- .../network-display.component.js | 71 ------- .../network-display.container.js | 15 -- .../app/network-display/network-display.js | 78 +++++++ ui/app/components/app/network.js | 192 ----------------- .../app/permission-page-container/index.js | 1 - .../permission-page-container-header/index.js | 1 - ...mission-page-container-header.component.js | 12 -- .../app/signature-request/index.scss | 10 +- ui/app/components/ui/chip/chip.js | 7 + .../components/ui/loading-indicator/index.js | 1 + .../ui/loading-indicator/loading-indicator.js | 29 +++ .../loading-indicator/loading-indicator.scss | 17 ++ ui/app/components/ui/ui-components.scss | 1 + ui/app/css/itcss/components/network.scss | 40 +--- ui/app/pages/settings/networks-tab/index.scss | 3 +- .../networks-tab/networks-tab.component.js | 20 +- 35 files changed, 396 insertions(+), 776 deletions(-) delete mode 100644 ui/app/components/app/connected-status-indicator/connected-status-indicator.component.js delete mode 100644 ui/app/components/app/connected-status-indicator/connected-status-indicator.container.js create mode 100644 ui/app/components/app/connected-status-indicator/connected-status-indicator.js delete mode 100644 ui/app/components/app/dropdowns/components/network-dropdown-icon.js delete mode 100644 ui/app/components/app/dropdowns/tests/network-dropdown-icon.test.js delete mode 100644 ui/app/components/app/network-display/network-display.component.js delete mode 100644 ui/app/components/app/network-display/network-display.container.js create mode 100644 ui/app/components/app/network-display/network-display.js delete mode 100644 ui/app/components/app/network.js delete mode 100644 ui/app/components/app/permission-page-container/permission-page-container-header/index.js delete mode 100644 ui/app/components/app/permission-page-container/permission-page-container-header/permission-page-container-header.component.js create mode 100644 ui/app/components/ui/loading-indicator/index.js create mode 100644 ui/app/components/ui/loading-indicator/loading-indicator.js create mode 100644 ui/app/components/ui/loading-indicator/loading-indicator.scss diff --git a/test/e2e/ethereum-on.spec.js b/test/e2e/ethereum-on.spec.js index 81f178c9d..52485d76a 100644 --- a/test/e2e/ethereum-on.spec.js +++ b/test/e2e/ethereum-on.spec.js @@ -171,7 +171,7 @@ describe('MetaMask', function () { it('changes the network', async function () { await driver.switchToWindow(extension) - await driver.clickElement(By.css('.network-name')) + await driver.clickElement(By.css('.network-display')) await driver.delay(regularDelayMs) await driver.clickElement(By.xpath(`//span[contains(text(), 'Ropsten')]`)) diff --git a/test/e2e/from-import-ui.spec.js b/test/e2e/from-import-ui.spec.js index dc5457f7d..8dbabbcac 100644 --- a/test/e2e/from-import-ui.spec.js +++ b/test/e2e/from-import-ui.spec.js @@ -177,7 +177,7 @@ describe('Using MetaMask with an existing account', function () { describe('Add an account', function () { it('switches to localhost', async function () { - await driver.clickElement(By.css('.network-name')) + await driver.clickElement(By.css('.network-display')) await driver.delay(regularDelayMs) await driver.clickElement( diff --git a/test/e2e/metamask-responsive-ui.spec.js b/test/e2e/metamask-responsive-ui.spec.js index 1474960ef..60fe1c901 100644 --- a/test/e2e/metamask-responsive-ui.spec.js +++ b/test/e2e/metamask-responsive-ui.spec.js @@ -205,11 +205,13 @@ describe('MetaMask', function () { }) it('switches to localhost', async function () { - await driver.clickElement(By.css('.network-name')) + await driver.clickElement(By.css('.network-display')) await driver.delay(regularDelayMs) await driver.clickElement( - By.xpath(`//span[contains(text(), 'Localhost')]`), + By.xpath( + `//span[contains(@class, 'network-name-item') and contains(text(), 'Localhost 8545')]`, + ), ) await driver.delay(largeDelayMs * 2) }) diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js index 561ad737a..52819a7ac 100644 --- a/test/e2e/metamask-ui.spec.js +++ b/test/e2e/metamask-ui.spec.js @@ -1723,7 +1723,7 @@ describe('MetaMask', function () { const rpcUrl = 'http://127.0.0.1:8545/1' const chainId = '0x539' // Ganache default, decimal 1337 - await driver.clickElement(By.css('.network-name')) + await driver.clickElement(By.css('.network-display')) await driver.delay(regularDelayMs) await driver.clickElement( @@ -1753,7 +1753,7 @@ describe('MetaMask', function () { const rpcUrl = 'http://127.0.0.1:8545/2' const chainId = '0x539' // Ganache default, decimal 1337 - await driver.clickElement(By.css('.network-name')) + await driver.clickElement(By.css('.network-display')) await driver.delay(regularDelayMs) await driver.clickElement( @@ -1780,7 +1780,7 @@ describe('MetaMask', function () { }) it('selects another provider', async function () { - await driver.clickElement(By.css('.network-name')) + await driver.clickElement(By.css('.network-display')) await driver.delay(regularDelayMs) await driver.clickElement( @@ -1790,7 +1790,7 @@ describe('MetaMask', function () { }) it('finds all recent RPCs in history', async function () { - await driver.clickElement(By.css('.network-name')) + await driver.clickElement(By.css('.network-display')) await driver.delay(regularDelayMs) // only recent 3 are found and in correct order (most recent at the top) diff --git a/ui/app/components/app/app-header/app-header.component.js b/ui/app/components/app/app-header/app-header.component.js index 7ad30d3d3..c8e388880 100644 --- a/ui/app/components/app/app-header/app-header.component.js +++ b/ui/app/components/app/app-header/app-header.component.js @@ -4,13 +4,11 @@ import classnames from 'classnames' import Identicon from '../../ui/identicon' import MetaFoxLogo from '../../ui/metafox-logo' import { DEFAULT_ROUTE } from '../../../helpers/constants/routes' -import NetworkIndicator from '../network' +import NetworkDisplay from '../network-display' export default class AppHeader extends PureComponent { static propTypes = { history: PropTypes.object, - network: PropTypes.string, - provider: PropTypes.object, networkDropdownOpen: PropTypes.bool, showNetworkDropdown: PropTypes.func, hideNetworkDropdown: PropTypes.func, @@ -37,8 +35,14 @@ export default class AppHeader extends PureComponent { networkDropdownOpen, showNetworkDropdown, hideNetworkDropdown, + disabled, + disableNetworkIndicator, } = this.props + if (disabled || disableNetworkIndicator) { + return + } + if (networkDropdownOpen === false) { this.context.metricsEvent({ eventOpts: { @@ -91,8 +95,6 @@ export default class AppHeader extends PureComponent { render() { const { history, - network, - provider, isUnlocked, hideNetworkIndicator, disableNetworkIndicator, @@ -119,9 +121,10 @@ export default class AppHeader extends PureComponent {
{!hideNetworkIndicator && (
- this.handleNetworkIndicatorClick(event)} disabled={disabled || disableNetworkIndicator} /> diff --git a/ui/app/components/app/app-header/index.scss b/ui/app/components/app/app-header/index.scss index aacbbf9be..0a3b09635 100644 --- a/ui/app/components/app/app-header/index.scss +++ b/ui/app/components/app/app-header/index.scss @@ -95,13 +95,12 @@ flex: 1 0 auto; width: 0; justify-content: flex-end; + } - .network-component.pointer { - max-width: 200px; - } - - .network-indicator { - width: 100%; - } + &__network-down-arrow { + background-image: url(/images/icons/caret-down.svg); + background-repeat: no-repeat; + background-size: contain; + background-position: center; } } diff --git a/ui/app/components/app/app-header/tests/app-header.test.js b/ui/app/components/app/app-header/tests/app-header.test.js index 7a1b43ee7..c736d6549 100644 --- a/ui/app/components/app/app-header/tests/app-header.test.js +++ b/ui/app/components/app/app-header/tests/app-header.test.js @@ -4,6 +4,7 @@ import sinon from 'sinon' import { shallow } from 'enzyme' import MetaFoxLogo from '../../../ui/metafox-logo' import AppHeader from '..' +import NetworkDisplay from '../../network-display' describe('App Header', function () { let wrapper @@ -49,7 +50,7 @@ describe('App Header', function () { describe('Network', function () { it('shows network dropdown when networkDropdownOpen is false', function () { - const network = wrapper.find({ network: 'test' }) + const network = wrapper.find(NetworkDisplay) network.simulate('click', { preventDefault: () => undefined, @@ -61,7 +62,7 @@ describe('App Header', function () { it('hides network dropdown when networkDropdownOpen is true', function () { wrapper.setProps({ networkDropdownOpen: true }) - const network = wrapper.find({ network: 'test' }) + const network = wrapper.find(NetworkDisplay) network.simulate('click', { preventDefault: () => undefined, diff --git a/ui/app/components/app/confirm-page-container/confirm-page-container-header/index.scss b/ui/app/components/app/confirm-page-container/confirm-page-container-header/index.scss index 79d79e55b..9268e12a0 100644 --- a/ui/app/components/app/confirm-page-container/confirm-page-container-header/index.scss +++ b/ui/app/components/app/confirm-page-container/confirm-page-container-header/index.scss @@ -10,6 +10,11 @@ padding: 4px 13px 4px 13px; flex: 0 0 auto; align-items: center; + + & .network-display { + margin-right: 0; + height: 25px; + } } &__back-button-container { diff --git a/ui/app/components/app/connected-status-indicator/connected-status-indicator.component.js b/ui/app/components/app/connected-status-indicator/connected-status-indicator.component.js deleted file mode 100644 index 7734dc9cc..000000000 --- a/ui/app/components/app/connected-status-indicator/connected-status-indicator.component.js +++ /dev/null @@ -1,71 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' -import { - STATUS_CONNECTED, - STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, - STATUS_NOT_CONNECTED, -} from '../../../helpers/constants/connected-sites' - -export default class ConnectedStatusIndicator extends Component { - static contextTypes = { - t: PropTypes.func, - } - - static propTypes = { - status: PropTypes.oneOf([ - STATUS_CONNECTED, - STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, - STATUS_NOT_CONNECTED, - ]), - onClick: PropTypes.func, - } - - static defaultProps = { - status: STATUS_NOT_CONNECTED, - onClick: undefined, - } - - renderStatusCircle = () => { - const { status } = this.props - - return ( -
- -
- ) - } - - renderStatusText = () => { - const { t } = this.context - const { status } = this.props - - const text = - status === STATUS_CONNECTED - ? t('statusConnected') - : t('statusNotConnected') - - return
{text}
- } - - render() { - return ( - - ) - } -} diff --git a/ui/app/components/app/connected-status-indicator/connected-status-indicator.container.js b/ui/app/components/app/connected-status-indicator/connected-status-indicator.container.js deleted file mode 100644 index 253027959..000000000 --- a/ui/app/components/app/connected-status-indicator/connected-status-indicator.container.js +++ /dev/null @@ -1,39 +0,0 @@ -import { findKey } from 'lodash' -import { connect } from 'react-redux' -import { - STATUS_CONNECTED, - STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, - STATUS_NOT_CONNECTED, -} from '../../../helpers/constants/connected-sites' -import { - getAddressConnectedDomainMap, - getOriginOfCurrentTab, - getSelectedAddress, -} from '../../../selectors' -import ConnectedStatusIndicator from './connected-status-indicator.component' - -const mapStateToProps = (state) => { - const selectedAddress = getSelectedAddress(state) - const addressConnectedDomainMap = getAddressConnectedDomainMap(state) - const originOfCurrentTab = getOriginOfCurrentTab(state) - - const selectedAddressDomainMap = addressConnectedDomainMap[selectedAddress] - const currentTabIsConnectedToSelectedAddress = Boolean( - selectedAddressDomainMap && selectedAddressDomainMap[originOfCurrentTab], - ) - - let status - if (currentTabIsConnectedToSelectedAddress) { - status = STATUS_CONNECTED - } else if (findKey(addressConnectedDomainMap, originOfCurrentTab)) { - status = STATUS_CONNECTED_TO_ANOTHER_ACCOUNT - } else { - status = STATUS_NOT_CONNECTED - } - - return { - status, - } -} - -export default connect(mapStateToProps)(ConnectedStatusIndicator) diff --git a/ui/app/components/app/connected-status-indicator/connected-status-indicator.js b/ui/app/components/app/connected-status-indicator/connected-status-indicator.js new file mode 100644 index 000000000..31cb2b137 --- /dev/null +++ b/ui/app/components/app/connected-status-indicator/connected-status-indicator.js @@ -0,0 +1,66 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { useSelector } from 'react-redux' +import { findKey } from 'lodash' +import { + STATUS_CONNECTED, + STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, + STATUS_NOT_CONNECTED, +} from '../../../helpers/constants/connected-sites' +import ColorIndicator from '../../ui/color-indicator' +import { COLORS } from '../../../helpers/constants/design-system' +import { useI18nContext } from '../../../hooks/useI18nContext' +import { + getAddressConnectedDomainMap, + getOriginOfCurrentTab, + getSelectedAddress, +} from '../../../selectors' + +export default function ConnectedStatusIndicator({ onClick }) { + const t = useI18nContext() + + const selectedAddress = useSelector(getSelectedAddress) + const addressConnectedDomainMap = useSelector(getAddressConnectedDomainMap) + const originOfCurrentTab = useSelector(getOriginOfCurrentTab) + + const selectedAddressDomainMap = addressConnectedDomainMap[selectedAddress] + const currentTabIsConnectedToSelectedAddress = Boolean( + selectedAddressDomainMap && selectedAddressDomainMap[originOfCurrentTab], + ) + let status + if (currentTabIsConnectedToSelectedAddress) { + status = STATUS_CONNECTED + } else if (findKey(addressConnectedDomainMap, originOfCurrentTab)) { + status = STATUS_CONNECTED_TO_ANOTHER_ACCOUNT + } else { + status = STATUS_NOT_CONNECTED + } + + let indicatorType = ColorIndicator.TYPES.OUTLINE + let indicatorColor = COLORS.UI4 + + if (status === STATUS_CONNECTED) { + indicatorColor = COLORS.SUCCESS1 + indicatorType = ColorIndicator.TYPES.PARTIAL + } else if (status === STATUS_CONNECTED_TO_ANOTHER_ACCOUNT) { + indicatorColor = COLORS.ALERT1 + } + + const text = + status === STATUS_CONNECTED ? t('statusConnected') : t('statusNotConnected') + + return ( + + ) +} + +ConnectedStatusIndicator.defaultProps = { + onClick: undefined, +} + +ConnectedStatusIndicator.propTypes = { + onClick: PropTypes.func, +} diff --git a/ui/app/components/app/connected-status-indicator/index.js b/ui/app/components/app/connected-status-indicator/index.js index 37679809b..4f654fae4 100644 --- a/ui/app/components/app/connected-status-indicator/index.js +++ b/ui/app/components/app/connected-status-indicator/index.js @@ -1 +1 @@ -export { default } from './connected-status-indicator.container' +export { default } from './connected-status-indicator' diff --git a/ui/app/components/app/dropdowns/components/dropdown.js b/ui/app/components/app/dropdowns/components/dropdown.js index 52a4af4ef..da67c700f 100644 --- a/ui/app/components/app/dropdowns/components/dropdown.js +++ b/ui/app/components/app/dropdowns/components/dropdown.js @@ -73,6 +73,12 @@ export class DropdownMenuItem extends Component { onClick() closeMenu() }} + onKeyPress={(event) => { + if (event.key === 'Enter') { + onClick() + closeMenu() + } + }} style={{ listStyle: 'none', padding: '8px 0px', @@ -85,6 +91,7 @@ export class DropdownMenuItem extends Component { color: 'white', ...style, }} + tabIndex="0" > {children} diff --git a/ui/app/components/app/dropdowns/components/network-dropdown-icon.js b/ui/app/components/app/dropdowns/components/network-dropdown-icon.js deleted file mode 100644 index 2201651b8..000000000 --- a/ui/app/components/app/dropdowns/components/network-dropdown-icon.js +++ /dev/null @@ -1,48 +0,0 @@ -import PropTypes from 'prop-types' -import React from 'react' - -function NetworkDropdownIcon(props) { - const { backgroundColor, isSelected, innerBorder, diameter, loading } = props - - return loading ? ( - - - - ) : ( -
-
-
- ) -} - -NetworkDropdownIcon.defaultProps = { - backgroundColor: undefined, - loading: false, - innerBorder: 'none', - diameter: '12', - isSelected: false, -} - -NetworkDropdownIcon.propTypes = { - backgroundColor: PropTypes.string, - loading: PropTypes.bool, - innerBorder: PropTypes.string, - diameter: PropTypes.string, - isSelected: PropTypes.bool, -} - -export default NetworkDropdownIcon diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js index c9e9464dc..613de6b28 100644 --- a/ui/app/components/app/dropdowns/network-dropdown.js +++ b/ui/app/components/app/dropdowns/network-dropdown.js @@ -14,8 +14,9 @@ import { NETWORK_TYPE_RPC } from '../../../../../shared/constants/network' import { isPrefixedFormattedHexString } from '../../../../../shared/modules/utils' import { getEnvironmentType } from '../../../../../app/scripts/lib/util' +import ColorIndicator from '../../ui/color-indicator' +import { COLORS } from '../../../helpers/constants/design-system' import { Dropdown, DropdownMenuItem } from './components/dropdown' -import NetworkDropdownIcon from './components/network-dropdown-icon' // classes from nodes of the toggle element. const notToggleElementClassnames = [ @@ -26,6 +27,12 @@ const notToggleElementClassnames = [ 'network-component', ] +const DROP_DOWN_MENU_ITEM_STYLE = { + fontSize: '16px', + lineHeight: '20px', + padding: '12px 0', +} + function mapStateToProps(state) { return { provider: state.metamask.provider, @@ -140,9 +147,11 @@ class NetworkDropdown extends Component { ) : (
)} - this.handleClick(network)} + style={DROP_DOWN_MENU_ITEM_STYLE} + > + {providerType === network ? ( + + ) : ( +
+ )} + + + {this.context.t(network)} + + + ) + } + render() { const { - provider: { type: providerType, rpcUrl: activeNetwork }, + provider: { rpcUrl: activeNetwork }, setNetworksTabAddMode, setSelectedSettingsRpcUrl, } = this.props const rpcListDetail = this.props.frequentRpcListDetail const isOpen = this.props.networkDropdownOpen - const dropdownMenuItemStyle = { - fontSize: '16px', - lineHeight: '20px', - padding: '12px 0', - } return (
- this.props.hideNetworkDropdown()} - onClick={() => this.handleClick('mainnet')} - style={{ ...dropdownMenuItemStyle, borderColor: '#038789' }} - > - {providerType === 'mainnet' ? ( - - ) : ( -
- )} - - - {this.context.t('mainnet')} - -
- this.props.hideNetworkDropdown()} - onClick={() => this.handleClick('ropsten')} - style={dropdownMenuItemStyle} - > - {providerType === 'ropsten' ? ( - - ) : ( -
- )} - - - {this.context.t('ropsten')} - -
- this.props.hideNetworkDropdown()} - onClick={() => this.handleClick('kovan')} - style={dropdownMenuItemStyle} - > - {providerType === 'kovan' ? ( - - ) : ( -
- )} - - - {this.context.t('kovan')} - -
- this.props.hideNetworkDropdown()} - onClick={() => this.handleClick('rinkeby')} - style={dropdownMenuItemStyle} - > - {providerType === 'rinkeby' ? ( - - ) : ( -
- )} - - - {this.context.t('rinkeby')} - -
- this.props.hideNetworkDropdown()} - onClick={() => this.handleClick('goerli')} - style={dropdownMenuItemStyle} - > - {providerType === 'goerli' ? ( - - ) : ( -
- )} - - - {this.context.t('goerli')} - -
+ {this.renderNetworkEntry('mainnet')} + {this.renderNetworkEntry('ropsten')} + {this.renderNetworkEntry('kovan')} + {this.renderNetworkEntry('rinkeby')} + {this.renderNetworkEntry('goerli')} + {this.renderCustomRpcList(rpcListDetail, this.props.provider)} this.props.hideNetworkDropdown()} @@ -373,16 +297,18 @@ class NetworkDropdown extends Component { setSelectedSettingsRpcUrl('') setNetworksTabAddMode(true) }} - style={dropdownMenuItemStyle} + style={DROP_DOWN_MENU_ITEM_STYLE} > {activeNetwork === 'custom' ? ( ) : (
)} - , - ) - const styleProp = wrapper.find('.menu-icon-circle').children().prop('style') - assert.strictEqual(styleProp.background, 'red') - assert.strictEqual(styleProp.border, 'none') - assert.strictEqual(styleProp.height, '12px') - assert.strictEqual(styleProp.width, '12px') - }) -}) diff --git a/ui/app/components/app/dropdowns/tests/network-dropdown.test.js b/ui/app/components/app/dropdowns/tests/network-dropdown.test.js index 2df87f956..50e607ac9 100644 --- a/ui/app/components/app/dropdowns/tests/network-dropdown.test.js +++ b/ui/app/components/app/dropdowns/tests/network-dropdown.test.js @@ -5,7 +5,7 @@ import thunk from 'redux-thunk' import { mountWithRouter } from '../../../../../../test/lib/render-helpers' import NetworkDropdown from '../network-dropdown' import { DropdownMenuItem } from '../components/dropdown' -import NetworkDropdownIcon from '../components/network-dropdown-icon' +import ColorIndicator from '../../../ui/color-indicator' describe('Network Dropdown', function () { let wrapper @@ -65,46 +65,41 @@ describe('Network Dropdown', function () { assert.strictEqual(wrapper.find(DropdownMenuItem).length, 8) }) - it('checks background color for first NetworkDropdownIcon', function () { - assert.strictEqual( - wrapper.find(NetworkDropdownIcon).at(0).prop('backgroundColor'), - '#29B6AF', - ) // Ethereum Mainnet Teal + it('checks background color for first ColorIndicator', function () { + const colorIndicator = wrapper.find(ColorIndicator).at(0) + assert.strictEqual(colorIndicator.prop('color'), 'mainnet') + assert.strictEqual(colorIndicator.prop('borderColor'), 'mainnet') }) - it('checks background color for second NetworkDropdownIcon', function () { - assert.strictEqual( - wrapper.find(NetworkDropdownIcon).at(1).prop('backgroundColor'), - '#ff4a8d', - ) // Ropsten Red + it('checks background color for second ColorIndicator', function () { + const colorIndicator = wrapper.find(ColorIndicator).at(1) + assert.strictEqual(colorIndicator.prop('color'), 'ropsten') + assert.strictEqual(colorIndicator.prop('borderColor'), 'ropsten') }) - it('checks background color for third NetworkDropdownIcon', function () { - assert.strictEqual( - wrapper.find(NetworkDropdownIcon).at(2).prop('backgroundColor'), - '#7057ff', - ) // Kovan Purple + it('checks background color for third ColorIndicator', function () { + const colorIndicator = wrapper.find(ColorIndicator).at(2) + assert.strictEqual(colorIndicator.prop('color'), 'kovan') + assert.strictEqual(colorIndicator.prop('borderColor'), 'kovan') }) - it('checks background color for fourth NetworkDropdownIcon', function () { - assert.strictEqual( - wrapper.find(NetworkDropdownIcon).at(3).prop('backgroundColor'), - '#f6c343', - ) // Rinkeby Yellow + it('checks background color for fourth ColorIndicator', function () { + const colorIndicator = wrapper.find(ColorIndicator).at(3) + assert.strictEqual(colorIndicator.prop('color'), 'rinkeby') + assert.strictEqual(colorIndicator.prop('borderColor'), 'rinkeby') }) - it('checks background color for fifth NetworkDropdownIcon', function () { - assert.strictEqual( - wrapper.find(NetworkDropdownIcon).at(4).prop('backgroundColor'), - '#3099f2', - ) // Goerli Blue + it('checks background color for fifth ColorIndicator', function () { + const colorIndicator = wrapper.find(ColorIndicator).at(4) + assert.strictEqual(colorIndicator.prop('color'), 'goerli') + assert.strictEqual(colorIndicator.prop('borderColor'), 'goerli') }) - it('checks background color for sixth NetworkDropdownIcon', function () { - assert.strictEqual( - wrapper.find(NetworkDropdownIcon).at(5).prop('backgroundColor'), - '#d6d9dc', - ) // "Custom network grey" + it('checks background color for sixth ColorIndicator', function () { + const colorIndicator = wrapper.find(ColorIndicator).at(5) + const customNetworkGray = 'ui-2' + assert.strictEqual(colorIndicator.prop('color'), customNetworkGray) + assert.strictEqual(colorIndicator.prop('borderColor'), customNetworkGray) }) it('checks dropdown for frequestRPCList from state', function () { diff --git a/ui/app/components/app/network-display/index.js b/ui/app/components/app/network-display/index.js index 9fbb16700..6e361e905 100644 --- a/ui/app/components/app/network-display/index.js +++ b/ui/app/components/app/network-display/index.js @@ -1,3 +1 @@ -import NetworkDisplay from './network-display.container' - -export default NetworkDisplay +export { default } from './network-display' diff --git a/ui/app/components/app/network-display/index.scss b/ui/app/components/app/network-display/index.scss index 4ded13d54..c07126b6f 100644 --- a/ui/app/components/app/network-display/index.scss +++ b/ui/app/components/app/network-display/index.scss @@ -1,66 +1,58 @@ .network-display { - &__container { - display: flex; - align-items: center; - justify-content: flex-start; - padding: 0 10px; - border-radius: 4px; - height: 25px; + display: flex; + align-items: center; + justify-content: flex-start; + padding: 0 10px; + border-radius: 4px; + min-height: 25px; + cursor: pointer; - &--colored { - background-color: lighten(rgb(125, 128, 130), 45%); - } - - &--mainnet { - background-color: lighten($blue-lagoon, 68%); - } - - &--ropsten { - background-color: lighten($crimson, 45%); - } - - &--kovan { - background-color: lighten($purple, 65%); - } - - &--rinkeby { - background-color: lighten($tulip-tree, 35%); - } - - &--goerli { - background-color: lighten($dodger-blue, 35%); - } + &--disabled { + cursor: not-allowed; } - &__name { - @include H7; + &--colored { + background-color: lighten(rgb(125, 128, 130), 45%); + } - padding-left: 5px; + &--mainnet { + background-color: lighten($blue-lagoon, 68%); + } + + &--ropsten { + background-color: lighten($crimson, 45%); + } + + &--kovan { + background-color: lighten($purple, 65%); + } + + &--rinkeby { + background-color: lighten($tulip-tree, 35%); + } + + &--goerli { + background-color: lighten($dodger-blue, 35%); + } + + + & .chip__label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + & .chip__left-icon { + margin-left: 4px; + } + + & .chip__right-icon { + margin-right: 4px; } &__icon { - height: 10px; - width: 10px; - border-radius: 10px; - - &--mainnet { - background-color: $blue-lagoon; - } - - &--ropsten { - background-color: $crimson; - } - - &--kovan { - background-color: $purple; - } - - &--rinkeby { - background-color: $tulip-tree; - } - - &--goerli { - background-color: $dodger-blue; - } + height: 8px; + width: 12px; + display: block; } } diff --git a/ui/app/components/app/network-display/network-display.component.js b/ui/app/components/app/network-display/network-display.component.js deleted file mode 100644 index c045c1527..000000000 --- a/ui/app/components/app/network-display/network-display.component.js +++ /dev/null @@ -1,71 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' -import { NETWORK_TYPE_RPC } from '../../../../../shared/constants/network' - -export default class NetworkDisplay extends Component { - static defaultProps = { - colored: true, - } - - static propTypes = { - networkNickname: PropTypes.string.isRequired, - networkType: PropTypes.string.isRequired, - colored: PropTypes.bool, - } - - static contextTypes = { - t: PropTypes.func, - } - - renderNetworkIcon() { - const { networkType } = this.props - - return networkType ? ( -
- ) : ( -
- ) - } - - render() { - const { colored, networkNickname, networkType } = this.props - - return ( -
- {networkType ? ( -
- ) : ( -
- )} -
- {networkType === NETWORK_TYPE_RPC && networkNickname - ? networkNickname - : this.context.t(networkType)} -
-
- ) - } -} diff --git a/ui/app/components/app/network-display/network-display.container.js b/ui/app/components/app/network-display/network-display.container.js deleted file mode 100644 index 136336448..000000000 --- a/ui/app/components/app/network-display/network-display.container.js +++ /dev/null @@ -1,15 +0,0 @@ -import { connect } from 'react-redux' -import NetworkDisplay from './network-display.component' - -const mapStateToProps = ({ - metamask: { - provider: { nickname, type }, - }, -}) => { - return { - networkNickname: nickname, - networkType: type, - } -} - -export default connect(mapStateToProps)(NetworkDisplay) diff --git a/ui/app/components/app/network-display/network-display.js b/ui/app/components/app/network-display/network-display.js new file mode 100644 index 000000000..59e898c88 --- /dev/null +++ b/ui/app/components/app/network-display/network-display.js @@ -0,0 +1,78 @@ +import React from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import { useSelector } from 'react-redux' +import { NETWORK_TYPE_RPC } from '../../../../../shared/constants/network' + +import LoadingIndicator from '../../ui/loading-indicator' +import ColorIndicator from '../../ui/color-indicator' +import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system' +import Chip from '../../ui/chip/chip' +import { useI18nContext } from '../../../hooks/useI18nContext' + +export default function NetworkDisplay({ + colored, + outline, + iconClassName, + disabled, + onClick, +}) { + const { network, networkNickname, networkType } = useSelector((state) => ({ + network: state.metamask.network, + networkNickname: state.metamask.provider.nickname, + networkType: state.metamask.provider.type, + })) + const t = useI18nContext() + + return ( + + + + } + rightIcon={ + iconClassName && ( + + ) + } + label={ + networkType === NETWORK_TYPE_RPC + ? networkNickname ?? t('privateNetwork') + : t(networkType) + } + className={classnames('network-display', { + 'network-display--colored': colored, + 'network-display--disabled': disabled, + [`network-display--${networkType}`]: colored && networkType, + })} + labelProps={{ + variant: TYPOGRAPHY.H7, + }} + /> + ) +} +NetworkDisplay.propTypes = { + colored: PropTypes.bool, + outline: PropTypes.bool, + disabled: PropTypes.bool, + iconClassName: PropTypes.string, + onClick: PropTypes.func, +} + +NetworkDisplay.defaultProps = { + colored: true, +} diff --git a/ui/app/components/app/network.js b/ui/app/components/app/network.js deleted file mode 100644 index 194e65c65..000000000 --- a/ui/app/components/app/network.js +++ /dev/null @@ -1,192 +0,0 @@ -import PropTypes from 'prop-types' -import React, { Component } from 'react' -import classnames from 'classnames' -import NetworkDropdownIcon from './dropdowns/components/network-dropdown-icon' - -function NetworkIndicator({ - disabled, - children, - hoverText, - onClick, - providerName, -}) { - return ( -
{ - if (!disabled) { - onClick(event) - } - }} - > -
- {children} -
-
-
- ) -} - -NetworkIndicator.propTypes = { - children: PropTypes.node.isRequired, - disabled: PropTypes.bool, - hoverText: PropTypes.string, - onClick: PropTypes.func, - providerName: PropTypes.string, -} - -export default class Network extends Component { - static contextTypes = { - t: PropTypes.func, - } - - static propTypes = { - network: PropTypes.string.isRequired, - provider: PropTypes.shape({ - type: PropTypes.string, - nickname: PropTypes.string, - rpcUrl: PropTypes.string, - }).isRequired, - disabled: PropTypes.bool, - onClick: PropTypes.func.isRequired, - } - - render() { - const { t } = this.context - - const { disabled, network: networkNumber, onClick, provider } = this.props - - let providerName, providerNick, providerUrl - if (provider) { - providerName = provider.type - providerNick = provider.nickname || '' - providerUrl = provider.rpcUrl - } - - switch (providerName) { - case 'mainnet': - return ( - - -
{t('mainnet')}
-
- ) - - case 'ropsten': - return ( - - -
{t('ropsten')}
-
- ) - - case 'kovan': - return ( - - -
{t('kovan')}
-
- ) - - case 'rinkeby': - return ( - - -
{t('rinkeby')}
-
- ) - - case 'goerli': - return ( - - -
{t('goerli')}
-
- ) - - default: - return ( - - {networkNumber === 'loading' ? ( - onClick(event)} - > - {t('attemptingConnect')} - - ) : ( - - )} -
- {providerNick || t('privateNetwork')} -
-
- ) - } - } -} diff --git a/ui/app/components/app/permission-page-container/index.js b/ui/app/components/app/permission-page-container/index.js index 63e8265c2..8fe6b44b9 100644 --- a/ui/app/components/app/permission-page-container/index.js +++ b/ui/app/components/app/permission-page-container/index.js @@ -1,3 +1,2 @@ export { default } from './permission-page-container.container' export { default as PermissionPageContainerContent } from './permission-page-container-content' -export { default as PermissionPageContainerHeader } from './permission-page-container-header' diff --git a/ui/app/components/app/permission-page-container/permission-page-container-header/index.js b/ui/app/components/app/permission-page-container/permission-page-container-header/index.js deleted file mode 100644 index d57a5370b..000000000 --- a/ui/app/components/app/permission-page-container/permission-page-container-header/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './permission-page-container-header.component' diff --git a/ui/app/components/app/permission-page-container/permission-page-container-header/permission-page-container-header.component.js b/ui/app/components/app/permission-page-container/permission-page-container-header/permission-page-container-header.component.js deleted file mode 100644 index 72bd17f82..000000000 --- a/ui/app/components/app/permission-page-container/permission-page-container-header/permission-page-container-header.component.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react' -import NetworkDisplay from '../../network-display' - -const ProviderPageContainerHeader = () => { - return ( -
- -
- ) -} - -export default ProviderPageContainerHeader diff --git a/ui/app/components/app/signature-request/index.scss b/ui/app/components/app/signature-request/index.scss index 16008cbc2..f4df222a1 100644 --- a/ui/app/components/app/signature-request/index.scss +++ b/ui/app/components/app/signature-request/index.scss @@ -16,16 +16,10 @@ .signature-request-header { flex: 1; - .network-display__container { + .network-display { padding: 0; justify-content: flex-end; - } - - .network-display__name { - @include H7; - - white-space: nowrap; - font-weight: 500; + margin-left: auto; } } diff --git a/ui/app/components/ui/chip/chip.js b/ui/app/components/ui/chip/chip.js index c2281f7d4..78dc8173d 100644 --- a/ui/app/components/ui/chip/chip.js +++ b/ui/app/components/ui/chip/chip.js @@ -15,9 +15,16 @@ export default function Chip({ rightIcon, onClick, }) { + const onKeyPress = (event) => { + if (event.key === 'Enter' && onClick) { + onClick(event) + } + } + return (
+ {alt} + + ) : ( + children + ) +} + +LoadingIndicator.propTypes = { + isLoading: PropTypes.bool.isRequired, + alt: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + children: PropTypes.node, +} diff --git a/ui/app/components/ui/loading-indicator/loading-indicator.scss b/ui/app/components/ui/loading-indicator/loading-indicator.scss new file mode 100644 index 000000000..1942b8389 --- /dev/null +++ b/ui/app/components/ui/loading-indicator/loading-indicator.scss @@ -0,0 +1,17 @@ +.loading-indicator { + display: flex; + flex-flow: row nowrap; + align-items: center; + position: relative; + height: 16px; + width: 16px; + margin-left: 5px; + + &__spinner { + width: 27px; + height: 26px; + position: absolute; + top: -5px; + left: -6px; + } +} diff --git a/ui/app/components/ui/ui-components.scss b/ui/app/components/ui/ui-components.scss index 2317072e1..2b76068d2 100644 --- a/ui/app/components/ui/ui-components.scss +++ b/ui/app/components/ui/ui-components.scss @@ -26,6 +26,7 @@ @import 'identicon/index'; @import 'info-tooltip/index'; @import 'list-item/index'; +@import 'loading-indicator/loading-indicator'; @import 'loading-screen/index'; @import 'menu/menu'; @import 'page-container/index'; diff --git a/ui/app/css/itcss/components/network.scss b/ui/app/css/itcss/components/network.scss index 34f905587..043626ff8 100644 --- a/ui/app/css/itcss/components/network.scss +++ b/ui/app/css/itcss/components/network.scss @@ -41,42 +41,6 @@ } } -.network-indicator { - @include H8; - - display: flex; - align-items: center; - - &__down-arrow { - height: 8px; - width: 12px; - display: block; - background-image: url(/images/icons/caret-down.svg); - background-repeat: no-repeat; - background-size: contain; - background-position: center; - margin: 0 8px; - } - - .fa-question-circle { - font-size: $font-size-paragraph; - margin: 0 4px 0 6px; - flex: 0 0 auto; - } -} - -.network-name { - @include H7; - - padding: 0 4px; - flex: 1 1 auto; - color: $tundora; - font-weight: 500; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} - .dropdown-menu-item .fa.delete { margin-right: 10px; display: none; @@ -89,6 +53,10 @@ .network-droppo { right: 2px; + .color-indicator { + margin: 0 14px; + } + @media screen and (min-width: 576px) { right: calc(((100% - 85vw) / 2) + 2px); } diff --git a/ui/app/pages/settings/networks-tab/index.scss b/ui/app/pages/settings/networks-tab/index.scss index 3b82a69fd..113657e83 100644 --- a/ui/app/pages/settings/networks-tab/index.scss +++ b/ui/app/pages/settings/networks-tab/index.scss @@ -142,8 +142,9 @@ display: flex; padding: 13px 0 13px 17px; position: relative; + align-items: center; - .menu-icon-circle { + .color-indicator { &:hover { cursor: pointer; } diff --git a/ui/app/pages/settings/networks-tab/networks-tab.component.js b/ui/app/pages/settings/networks-tab/networks-tab.component.js index 00e66cca8..02d987efb 100644 --- a/ui/app/pages/settings/networks-tab/networks-tab.component.js +++ b/ui/app/pages/settings/networks-tab/networks-tab.component.js @@ -8,7 +8,8 @@ import { NETWORKS_ROUTE, NETWORKS_FORM_ROUTE, } from '../../../helpers/constants/routes' -import NetworkDropdownIcon from '../../../components/app/dropdowns/components/network-dropdown-icon' +import ColorIndicator from '../../../components/ui/color-indicator' +import { COLORS } from '../../../helpers/constants/design-system' import NetworkForm from './network-form' export default class NetworksTab extends PureComponent { @@ -80,8 +81,6 @@ export default class NetworksTab extends PureComponent { isFullScreen, } = this.props const { - border, - iconColor, label, labelKey, rpcUrl, @@ -111,9 +110,10 @@ export default class NetworksTab extends PureComponent { } }} > -
-
{this.context.t('newNetwork')}