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

Refactor NetworkDisplay, ConnectedStatusIndicator, etc to use ColorIndicator (#10214)

This commit is contained in:
Brad Decker 2021-01-27 10:51:59 -06:00 committed by GitHub
parent 569672027c
commit 3806e0a2a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 396 additions and 776 deletions

View File

@ -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')]`))

View File

@ -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(

View File

@ -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)
})

View File

@ -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)

View File

@ -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 {
<div className="app-header__account-menu-container">
{!hideNetworkIndicator && (
<div className="app-header__network-component-wrapper">
<NetworkIndicator
network={network}
provider={provider}
<NetworkDisplay
colored={false}
outline
iconClassName="app-header__network-down-arrow"
onClick={(event) => this.handleNetworkIndicatorClick(event)}
disabled={disabled || disableNetworkIndicator}
/>

View File

@ -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;
}
}

View File

@ -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,

View File

@ -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 {

View File

@ -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 (
<div
className={classnames({
'connected-status-indicator__green-circle':
status === STATUS_CONNECTED,
'connected-status-indicator__yellow-circle':
status === STATUS_CONNECTED_TO_ANOTHER_ACCOUNT,
'connected-status-indicator__grey-circle':
status === STATUS_NOT_CONNECTED,
})}
>
<span className="connected-status-indicator__inner-circle" />
</div>
)
}
renderStatusText = () => {
const { t } = this.context
const { status } = this.props
const text =
status === STATUS_CONNECTED
? t('statusConnected')
: t('statusNotConnected')
return <div className="connected-status-indicator__text">{text}</div>
}
render() {
return (
<button
className="connected-status-indicator"
onClick={this.props.onClick}
>
{this.renderStatusCircle()}
{this.renderStatusText()}
</button>
)
}
}

View File

@ -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)

View File

@ -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 (
<button className="connected-status-indicator" onClick={onClick}>
<ColorIndicator color={indicatorColor} type={indicatorType} />
<div className="connected-status-indicator__text">{text}</div>
</button>
)
}
ConnectedStatusIndicator.defaultProps = {
onClick: undefined,
}
ConnectedStatusIndicator.propTypes = {
onClick: PropTypes.func,
}

View File

@ -1 +1 @@
export { default } from './connected-status-indicator.container'
export { default } from './connected-status-indicator'

View File

@ -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}
</li>

View File

@ -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 ? (
<span
className="pointer network-indicator"
style={{
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
}}
>
<img alt="" style={{ width: '27px' }} src="images/loading.svg" />
</span>
) : (
<div className={`menu-icon-circle${isSelected ? '--active' : ''}`}>
<div
style={{
background: backgroundColor,
border: innerBorder,
height: `${diameter}px`,
width: `${diameter}px`,
}}
/>
</div>
)
}
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

View File

@ -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 {
) : (
<div className="network-check__transparent"></div>
)}
<NetworkDropdownIcon
backgroundColor="#d6d9dc"
isSelected={isCurrentRpcTarget}
<ColorIndicator
color={COLORS.UI2}
size={ColorIndicator.SIZES.LARGE}
type={ColorIndicator.TYPES.FILLED}
borderColor={isCurrentRpcTarget ? COLORS.WHITE : COLORS.UI2}
/>
<span
className="network-name-item"
@ -192,19 +201,48 @@ class NetworkDropdown extends Component {
return name
}
renderNetworkEntry(network) {
const {
provider: { type: providerType },
} = this.props
return (
<DropdownMenuItem
key={network}
closeMenu={this.props.hideNetworkDropdown}
onClick={() => this.handleClick(network)}
style={DROP_DOWN_MENU_ITEM_STYLE}
>
{providerType === network ? (
<i className="fa fa-check" />
) : (
<div className="network-check__transparent"></div>
)}
<ColorIndicator
color={network}
size={ColorIndicator.SIZES.LARGE}
type={ColorIndicator.TYPES.FILLED}
borderColor={providerType === network ? COLORS.WHITE : network}
/>
<span
className="network-name-item"
style={{
color: providerType === network ? '#ffffff' : '#9b9b9b',
}}
>
{this.context.t(network)}
</span>
</DropdownMenuItem>
)
}
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 (
<Dropdown
@ -241,126 +279,12 @@ class NetworkDropdown extends Component {
{this.context.t('defaultNetwork')}
</div>
</div>
<DropdownMenuItem
key="main"
closeMenu={() => this.props.hideNetworkDropdown()}
onClick={() => this.handleClick('mainnet')}
style={{ ...dropdownMenuItemStyle, borderColor: '#038789' }}
>
{providerType === 'mainnet' ? (
<i className="fa fa-check" />
) : (
<div className="network-check__transparent"></div>
)}
<NetworkDropdownIcon
backgroundColor="#29B6AF"
isSelected={providerType === 'mainnet'}
/>
<span
className="network-name-item"
style={{
color: providerType === 'mainnet' ? '#ffffff' : '#9b9b9b',
}}
>
{this.context.t('mainnet')}
</span>
</DropdownMenuItem>
<DropdownMenuItem
key="ropsten"
closeMenu={() => this.props.hideNetworkDropdown()}
onClick={() => this.handleClick('ropsten')}
style={dropdownMenuItemStyle}
>
{providerType === 'ropsten' ? (
<i className="fa fa-check" />
) : (
<div className="network-check__transparent"></div>
)}
<NetworkDropdownIcon
backgroundColor="#ff4a8d"
isSelected={providerType === 'ropsten'}
/>
<span
className="network-name-item"
style={{
color: providerType === 'ropsten' ? '#ffffff' : '#9b9b9b',
}}
>
{this.context.t('ropsten')}
</span>
</DropdownMenuItem>
<DropdownMenuItem
key="kovan"
closeMenu={() => this.props.hideNetworkDropdown()}
onClick={() => this.handleClick('kovan')}
style={dropdownMenuItemStyle}
>
{providerType === 'kovan' ? (
<i className="fa fa-check" />
) : (
<div className="network-check__transparent"></div>
)}
<NetworkDropdownIcon
backgroundColor="#7057ff"
isSelected={providerType === 'kovan'}
/>
<span
className="network-name-item"
style={{
color: providerType === 'kovan' ? '#ffffff' : '#9b9b9b',
}}
>
{this.context.t('kovan')}
</span>
</DropdownMenuItem>
<DropdownMenuItem
key="rinkeby"
closeMenu={() => this.props.hideNetworkDropdown()}
onClick={() => this.handleClick('rinkeby')}
style={dropdownMenuItemStyle}
>
{providerType === 'rinkeby' ? (
<i className="fa fa-check" />
) : (
<div className="network-check__transparent"></div>
)}
<NetworkDropdownIcon
backgroundColor="#f6c343"
isSelected={providerType === 'rinkeby'}
/>
<span
className="network-name-item"
style={{
color: providerType === 'rinkeby' ? '#ffffff' : '#9b9b9b',
}}
>
{this.context.t('rinkeby')}
</span>
</DropdownMenuItem>
<DropdownMenuItem
key="goerli"
closeMenu={() => this.props.hideNetworkDropdown()}
onClick={() => this.handleClick('goerli')}
style={dropdownMenuItemStyle}
>
{providerType === 'goerli' ? (
<i className="fa fa-check" />
) : (
<div className="network-check__transparent"></div>
)}
<NetworkDropdownIcon
backgroundColor="#3099f2"
isSelected={providerType === 'goerli'}
/>
<span
className="network-name-item"
style={{
color: providerType === 'goerli' ? '#ffffff' : '#9b9b9b',
}}
>
{this.context.t('goerli')}
</span>
</DropdownMenuItem>
{this.renderNetworkEntry('mainnet')}
{this.renderNetworkEntry('ropsten')}
{this.renderNetworkEntry('kovan')}
{this.renderNetworkEntry('rinkeby')}
{this.renderNetworkEntry('goerli')}
{this.renderCustomRpcList(rpcListDetail, this.props.provider)}
<DropdownMenuItem
closeMenu={() => this.props.hideNetworkDropdown()}
@ -373,16 +297,18 @@ class NetworkDropdown extends Component {
setSelectedSettingsRpcUrl('')
setNetworksTabAddMode(true)
}}
style={dropdownMenuItemStyle}
style={DROP_DOWN_MENU_ITEM_STYLE}
>
{activeNetwork === 'custom' ? (
<i className="fa fa-check" />
) : (
<div className="network-check__transparent"></div>
)}
<NetworkDropdownIcon
isSelected={activeNetwork === 'custom'}
innerBorder="1px solid #9b9b9b"
<ColorIndicator
type={ColorIndicator.TYPES.FILLED}
color={COLORS.TRANSPARENT}
borderColor={COLORS.UI2}
size={ColorIndicator.SIZES.LARGE}
/>
<span
className="network-name-item"

View File

@ -1,22 +0,0 @@
import assert from 'assert'
import React from 'react'
import { shallow } from 'enzyme'
import NetworkDropdownIcon from '../components/network-dropdown-icon'
describe('Network Dropdown Icon', function () {
it('adds style props based on props', function () {
const wrapper = shallow(
<NetworkDropdownIcon
backgroundColor="red"
isSelected={false}
innerBorder="none"
diameter="12"
/>,
)
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')
})
})

View File

@ -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 () {

View File

@ -1,3 +1 @@
import NetworkDisplay from './network-display.container'
export default NetworkDisplay
export { default } from './network-display'

View File

@ -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;
}
}

View File

@ -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 ? (
<div
className={`network-display__icon network-display__icon--${networkType}`}
/>
) : (
<div
className="i fa fa-question-circle fa-med"
style={{
margin: '0 4px',
color: 'rgb(125, 128, 130)',
}}
/>
)
}
render() {
const { colored, networkNickname, networkType } = this.props
return (
<div
className={classnames('network-display__container', {
'network-display__container--colored': colored,
[`network-display__container--${networkType}`]:
colored && networkType,
})}
>
{networkType ? (
<div
className={`network-display__icon network-display__icon--${networkType}`}
/>
) : (
<div
className="i fa fa-question-circle fa-med"
style={{
margin: '0 4px',
color: 'rgb(125, 128, 130)',
}}
/>
)}
<div className="network-display__name">
{networkType === NETWORK_TYPE_RPC && networkNickname
? networkNickname
: this.context.t(networkType)}
</div>
</div>
)
}
}

View File

@ -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)

View File

@ -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 (
<Chip
borderColor={outline ? COLORS.UI3 : COLORS.TRANSPARENT}
onClick={onClick}
leftIcon={
<LoadingIndicator
alt={t('attemptingConnect')}
title={t('attemptingConnect')}
isLoading={network === 'loading'}
>
<ColorIndicator
color={networkType === NETWORK_TYPE_RPC ? COLORS.UI4 : networkType}
size={ColorIndicator.SIZES.LARGE}
type={ColorIndicator.TYPES.FILLED}
iconClassName={
networkType === NETWORK_TYPE_RPC ? 'fa fa-question' : undefined
}
/>
</LoadingIndicator>
}
rightIcon={
iconClassName && (
<i className={classnames('network-display__icon', 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,
}

View File

@ -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 (
<div
className={classnames('network-component pointer', {
'network-component--disabled': disabled,
'ethereum-network': providerName === 'mainnet',
'ropsten-test-network': providerName === 'ropsten',
'kovan-test-network': providerName === 'kovan',
'rinkeby-test-network': providerName === 'rinkeby',
'goerli-test-network': providerName === 'goerli',
})}
title={hoverText}
onClick={(event) => {
if (!disabled) {
onClick(event)
}
}}
>
<div className="network-indicator">
{children}
<div className="network-indicator__down-arrow" />
</div>
</div>
)
}
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 (
<NetworkIndicator
disabled={disabled}
hoverText={t('mainnet')}
onClick={onClick}
providerName={providerName}
>
<NetworkDropdownIcon
backgroundColor="#038789"
nonSelectBackgroundColor="#15afb2"
loading={networkNumber === 'loading'}
/>
<div className="network-name">{t('mainnet')}</div>
</NetworkIndicator>
)
case 'ropsten':
return (
<NetworkIndicator
disabled={disabled}
hoverText={t('ropsten')}
onClick={onClick}
providerName={providerName}
>
<NetworkDropdownIcon
backgroundColor="#e91550"
nonSelectBackgroundColor="#ec2c50"
loading={networkNumber === 'loading'}
/>
<div className="network-name">{t('ropsten')}</div>
</NetworkIndicator>
)
case 'kovan':
return (
<NetworkIndicator
disabled={disabled}
hoverText={t('kovan')}
onClick={onClick}
providerName={providerName}
>
<NetworkDropdownIcon
backgroundColor="#690496"
nonSelectBackgroundColor="#b039f3"
loading={networkNumber === 'loading'}
/>
<div className="network-name">{t('kovan')}</div>
</NetworkIndicator>
)
case 'rinkeby':
return (
<NetworkIndicator
disabled={disabled}
hoverText={t('rinkeby')}
onClick={onClick}
providerName={providerName}
>
<NetworkDropdownIcon
backgroundColor="#ebb33f"
nonSelectBackgroundColor="#ecb23e"
loading={networkNumber === 'loading'}
/>
<div className="network-name">{t('rinkeby')}</div>
</NetworkIndicator>
)
case 'goerli':
return (
<NetworkIndicator
disabled={disabled}
hoverText={t('goerli')}
onClick={onClick}
providerName={providerName}
>
<NetworkDropdownIcon
backgroundColor="#3099f2"
nonSelectBackgroundColor="#ecb23e"
loading={networkNumber === 'loading'}
/>
<div className="network-name">{t('goerli')}</div>
</NetworkIndicator>
)
default:
return (
<NetworkIndicator
disabled={disabled}
hoverText={providerNick || providerName || providerUrl || null}
onClick={onClick}
providerName={providerName}
>
{networkNumber === 'loading' ? (
<span
className="pointer network-loading-spinner"
onClick={(event) => onClick(event)}
>
<img
title={t('attemptingConnect')}
src="images/loading.svg"
alt={t('attemptingConnect')}
/>
</span>
) : (
<i
className="fa fa-question-circle fa-lg"
style={{ color: 'rgb(125, 128, 130)' }}
/>
)}
<div className="network-name">
{providerNick || t('privateNetwork')}
</div>
</NetworkIndicator>
)
}
}
}

View File

@ -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'

View File

@ -1 +0,0 @@
export { default } from './permission-page-container-header.component'

View File

@ -1,12 +0,0 @@
import React from 'react'
import NetworkDisplay from '../../network-display'
const ProviderPageContainerHeader = () => {
return (
<div className="provider-approval-container__header">
<NetworkDisplay colored={false} />
</div>
)
}
export default ProviderPageContainerHeader

View File

@ -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;
}
}

View File

@ -15,9 +15,16 @@ export default function Chip({
rightIcon,
onClick,
}) {
const onKeyPress = (event) => {
if (event.key === 'Enter' && onClick) {
onClick(event)
}
}
return (
<div
onClick={onClick}
onKeyPress={onKeyPress}
className={classnames(className, 'chip', {
'chip--with-left-icon': Boolean(leftIcon),
'chip--with-right-icon': Boolean(rightIcon),

View File

@ -0,0 +1 @@
export { default } from './loading-indicator'

View File

@ -0,0 +1,29 @@
import React from 'react'
import PropTypes from 'prop-types'
export default function LoadingIndicator({
alt,
title,
isLoading,
children = null,
}) {
return isLoading ? (
<span className="loading-indicator">
<img
className="loading-indicator__spinner"
alt={alt}
title={title}
src="images/loading.svg"
/>
</span>
) : (
children
)
}
LoadingIndicator.propTypes = {
isLoading: PropTypes.bool.isRequired,
alt: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
children: PropTypes.node,
}

View File

@ -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;
}
}

View File

@ -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';

View File

@ -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);
}

View File

@ -142,8 +142,9 @@
display: flex;
padding: 13px 0 13px 17px;
position: relative;
align-items: center;
.menu-icon-circle {
.color-indicator {
&:hover {
cursor: pointer;
}

View File

@ -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 {
}
}}
>
<NetworkDropdownIcon
backgroundColor={iconColor || 'white'}
innerBorder={border}
<ColorIndicator
color={labelKey}
type={ColorIndicator.TYPES.FILLED}
size={ColorIndicator.SIZES.LARGE}
/>
<div
className={classnames('networks-tab__networks-list-name', {
@ -155,9 +155,11 @@ export default class NetworksTab extends PureComponent {
)}
{networksTabIsInAddMode && (
<div className="networks-tab__networks-list-item">
<NetworkDropdownIcon
backgroundColor="white"
innerBorder="1px solid rgb(106, 115, 125)"
<ColorIndicator
type={ColorIndicator.TYPES.FILLED}
color={COLORS.WHITE}
borderColor={COLORS.UI4}
size={ColorIndicator.SIZES.LARGE}
/>
<div className="networks-tab__networks-list-name networks-tab__networks-list-name--selected">
{this.context.t('newNetwork')}