diff --git a/src/components/DeviceHeader/index.js b/src/components/DeviceHeader/index.js
index c47e3d3b..8315b326 100644
--- a/src/components/DeviceHeader/index.js
+++ b/src/components/DeviceHeader/index.js
@@ -1,12 +1,9 @@
-import React, { Component } from 'react';
+import React from 'react';
import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';
-import Icon from 'components/Icon';
-import icons from 'config/icons';
import {
getStatusColor,
getStatusName,
- isDisabled,
getStatus,
getVersion,
} from 'utils/device';
@@ -19,15 +16,17 @@ const Wrapper = styled.div`
width: 320px;
display: flex;
align-items: center;
- background: ${colors.WHITE};
- border-radius: 4px 0 0 0;
- box-shadow: 0 3px 8px rgba(0, 0, 0, 0.04);
+ background: ${props => (props.disabled ? colors.GRAY_LIGHT : 'transparent')};
+ background: ${props => (props.isSelected ? colors.WHITE : 'transparent')};
- ${props => props.isOpen && css`
+ border-radius: 4px 0 0 0;
+ box-shadow: ${props => (props.disabled ? 'none' : '0 3px 8px rgba(0, 0, 0, 0.04)')};
+
+ ${props => (props.isOpen || !props.isSelected) && css`
box-shadow: none;
`}
- ${props => props.isHoverable && css`
+ ${props => props.isHoverable && !props.disabled && css`
&:hover {
background: ${colors.GRAY_LIGHT};
}
@@ -43,7 +42,7 @@ const ClickWrapper = styled.div`
cursor: pointer;
${props => props.disabled && css`
- cursor: initial;
+ cursor: default;
`}
`;
@@ -71,18 +70,6 @@ const Status = styled.div`
color: ${colors.TEXT_SECONDARY};
`;
-const Counter = styled.div`
- border: 1px solid ${colors.DIVIDER};
- border-radius: 50%;
- color: ${colors.TEXT_SECONDARY};
- width: 24px;
- height: 24px;
- line-height: 22px;
- text-align: center;
- font-size: 11px;
- margin-right: 8px;
-`;
-
const IconWrapper = styled.div`
padding-right: 25px;
display: flex;
@@ -104,72 +91,53 @@ const Dot = styled.div`
height: 10px;
`;
-class DeviceHeader extends Component {
- constructor(props) {
- super(props);
- this.state = {
- clicked: false,
- };
- }
- isDisabled(device, devices, transport) {
- return isDisabled(device, devices, transport);
- }
-
- handleClickWrapper() {
- this.setState({ clicked: true });
- if (!this.props.disabled) {
- this.props.onClickWrapper();
- }
- }
-
- render() {
- const {
- isOpen, icon, device, devices, transport, isHoverable,
- } = this.props;
- const status = getStatus(device);
- const disabled = isDisabled(device, devices, transport);
- const deviceCount = devices.length;
-
- return (
-
- this.handleClickWrapper()}>
-
-
-
-
-
- {device.instanceLabel}
- {getStatusName(status)}
-
-
- {icon && icon}
- {!icon && deviceCount > 1 && {deviceCount}}
- {!icon && !disabled && (
-
- )
- }
-
-
-
- );
- }
-}
+const DeviceHeader = ({
+ isOpen,
+ icon,
+ device,
+ isHoverable = true,
+ onClickWrapper,
+ isBootloader = false,
+ disabled = false,
+ isSelected = false,
+}) => {
+ const status = getStatus(device);
+ return (
+
+
+
+
+
+
+
+ {device.instanceLabel}
+ {getStatusName(status)}
+
+
+ {icon && !disabled && !isBootloader && icon}
+
+
+
+ );
+};
DeviceHeader.propTypes = {
+ isBootloader: PropTypes.bool,
device: PropTypes.object,
- devices: PropTypes.array,
- transport: PropTypes.object,
icon: PropTypes.element,
isHoverable: PropTypes.bool,
disabled: PropTypes.bool,
isOpen: PropTypes.bool,
+ isSelected: PropTypes.bool,
onClickWrapper: PropTypes.func.isRequired,
};
diff --git a/src/utils/device.js b/src/utils/device.js
index de04d66f..a8b03564 100644
--- a/src/utils/device.js
+++ b/src/utils/device.js
@@ -2,7 +2,9 @@ import colors from 'config/colors';
const getStatus = (device) => {
let status = 'connected';
- if (!device.connected) {
+ if (device.features && device.features.bootloader_mode) {
+ status = 'connected-bootloader';
+ } else if (!device.connected) {
status = 'disconnected';
} else if (!device.available) {
status = 'unavailable';
@@ -26,6 +28,9 @@ const getStatusName = (deviceStatus) => {
case 'connected':
statusName = 'Connected';
break;
+ case 'connected-bootloader':
+ statusName = 'Connected (bootloader mode)';
+ break;
case 'disconnected':
statusName = 'Disconnected';
break;
@@ -43,7 +48,15 @@ const getStatusName = (deviceStatus) => {
const isWebUSB = transport => !!((transport && transport.version.indexOf('webusb') >= 0));
-const isDisabled = (selectedDevice, devices, transport) => (devices.length < 1 && !isWebUSB(transport)) || (devices.length === 1 && !selectedDevice.features && !isWebUSB(transport));
+const isDisabled = (selectedDevice, devices, transport) => {
+ if (isWebUSB(transport)) return false; // always enabled if webusb
+ if (devices.length < 1) return true; // no devices
+ if (devices.length === 1) {
+ if (!selectedDevice.features) return true; // unacquired, unreadable
+ if (selectedDevice.features.bootloader_mode || !selectedDevice.features.initialized) return true; // bootlader, not initialized
+ }
+ return false; // default
+};
const getVersion = (device) => {
let version;
@@ -64,6 +77,9 @@ const getStatusColor = (deviceStatus) => {
case 'connected':
color = colors.GREEN_PRIMARY;
break;
+ case 'connected-bootloader':
+ color = colors.WARNING_PRIMARY;
+ break;
case 'unacquired':
color = colors.WARNING_PRIMARY;
break;
diff --git a/src/views/Wallet/components/LeftNavigation/Container.js b/src/views/Wallet/components/LeftNavigation/Container.js
index e297c59c..f5dd762f 100644
--- a/src/views/Wallet/components/LeftNavigation/Container.js
+++ b/src/views/Wallet/components/LeftNavigation/Container.js
@@ -21,7 +21,6 @@ const mapStateToProps: MapStateToProps = (state: St
connect: state.connect,
accounts: state.accounts,
router: state.router,
- deviceDropdownOpened: state.wallet.dropdownOpened,
fiat: state.fiat,
localStorage: state.localStorage,
discovery: state.discovery,
diff --git a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/DeviceList/index.js b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/DeviceList/index.js
index faca2a75..d4b86412 100644
--- a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/DeviceList/index.js
+++ b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/DeviceList/index.js
@@ -4,6 +4,7 @@ import Icon from 'components/Icon';
import DeviceHeader from 'components/DeviceHeader';
import icons from 'config/icons';
import colors from 'config/colors';
+import { withRouter } from 'react-router-dom';
const Wrapper = styled.div``;
const IconClick = styled.div``;
@@ -14,8 +15,14 @@ class DeviceList extends Component {
return a.instance > b.instance ? 1 : -1;
}
+ redirectToBootloader(selectedDevice) {
+ this.props.history.push(`/device/${selectedDevice.features.device_id}/bootloader`);
+ }
+
render() {
- const { devices, selectedDevice, onSelectDevice } = this.props;
+ const {
+ devices, selectedDevice, onSelectDevice, forgetDevice,
+ } = this.props;
return (
{devices
@@ -23,22 +30,32 @@ class DeviceList extends Component {
.map(device => (
device !== selectedDevice && (
onSelectDevice(device)}
- onClickIcon={() => this.onDeviceMenuClick({ type: 'forget', label: '' }, device)}
+ key={device.state || device.path}
+ isBootloader={device.features.bootloader_mode}
+ onClickWrapper={() => {
+ if (device.features) {
+ if (device.features.bootloader_mode) {
+ this.redirectToBootloader(selectedDevice);
+ }
+ onSelectDevice(device);
+ }
+ }}
+ onClickIcon={() => forgetDevice(device)}
icon={(
- {
- event.stopPropagation();
- event.preventDefault();
- this.onDeviceMenuClick({ type: 'forget', label: '' }, device);
- }}
- >
-
-
+
+ {
+ event.stopPropagation();
+ event.preventDefault();
+ forgetDevice(device);
+ }}
+ >
+
+
+
)}
device={device}
devices={devices}
@@ -52,4 +69,4 @@ class DeviceList extends Component {
}
}
-export default DeviceList;
\ No newline at end of file
+export default withRouter(DeviceList);
\ No newline at end of file
diff --git a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js
index 5c0b9d15..7ca2c305 100644
--- a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js
+++ b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/components/MenuItems/index.js
@@ -41,6 +41,11 @@ class MenuItems extends Component {
}
}
+ showDeviceMenu() {
+ const device = this.props.device;
+ return device && device.features && !device.features.bootloader_mode && device.features.initialized;
+ }
+
showClone() {
return this.props.device && this.props.device.features.passphrase_protection && this.props.device.connected && this.props.device.available;
}
@@ -50,6 +55,7 @@ class MenuItems extends Component {
}
render() {
+ if (!this.showDeviceMenu()) return null;
return (
- this.onDeviceMenuClick('settings', this.props.device)}>
diff --git a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js
index 4d50fba5..dc34884e 100644
--- a/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js
+++ b/src/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js
@@ -98,7 +98,7 @@ class DeviceMenu extends Component {
}
render() {
- const { devices, onSelectDevice } = this.props;
+ const { devices, onSelectDevice, forgetDevice } = this.props;
const { transport } = this.props.connect;
const { selectedDevice } = this.props.wallet;
@@ -110,6 +110,7 @@ class DeviceMenu extends Component {
devices={devices}
selectedDevice={selectedDevice}
onSelectDevice={onSelectDevice}
+ forgetDevice={forgetDevice}
/>
{isWebUSB(transport) && (
diff --git a/src/views/Wallet/components/LeftNavigation/components/common.js b/src/views/Wallet/components/LeftNavigation/components/common.js
index ee7f1d37..0e3a66c4 100644
--- a/src/views/Wallet/components/LeftNavigation/components/common.js
+++ b/src/views/Wallet/components/LeftNavigation/components/common.js
@@ -8,7 +8,6 @@ export type StateProps = {
connect: $ElementType,
accounts: $ElementType,
router: $ElementType,
- deviceDropdownOpened: boolean,
fiat: $ElementType,
localStorage: $ElementType,
discovery: $ElementType,
diff --git a/src/views/Wallet/components/LeftNavigation/index.js b/src/views/Wallet/components/LeftNavigation/index.js
index 6f3bf158..e399e10d 100644
--- a/src/views/Wallet/components/LeftNavigation/index.js
+++ b/src/views/Wallet/components/LeftNavigation/index.js
@@ -1,5 +1,3 @@
-/* @flow */
-
import * as React from 'react';
import PropTypes from 'prop-types';
import colors from 'config/colors';
@@ -16,6 +14,18 @@ import type { Props } from './components/common';
const Header = styled(DeviceHeader)``;
+const Counter = styled.div`
+ border: 1px solid ${colors.DIVIDER};
+ border-radius: 50%;
+ color: ${colors.TEXT_SECONDARY};
+ width: 24px;
+ height: 24px;
+ line-height: 22px;
+ text-align: center;
+ font-size: 11px;
+ margin-right: 8px;
+`;
+
const TransitionGroupWrapper = styled(TransitionGroup)`
width: 640px;
`;
@@ -103,26 +113,26 @@ class LeftNavigation extends React.PureComponent {
this.state = {
animationType: hasNetwork ? 'slide-left' : null,
shouldRenderDeviceSelection: false,
+ clicked: false,
};
}
- componentWillReceiveProps(nextProps: Props) {
- const { deviceDropdownOpened } = nextProps;
- const { selectedDevice } = nextProps.wallet;
- const hasNetwork = nextProps.router.location.state && nextProps.router.location.state.network;
- const deviceReady = selectedDevice && selectedDevice.features && !selectedDevice.features.bootloader_mode && selectedDevice.features.initialized;
-
- if (deviceDropdownOpened) {
+ componentWillReceiveProps(nextProps) {
+ const { dropdownOpened, selectedDevice } = nextProps.wallet;
+ const hasNetwork = nextProps.location.state && nextProps.location.state.network;
+ const hasFeatures = selectedDevice && selectedDevice.features;
+ const deviceReady = hasFeatures && !selectedDevice.features.bootloader_mode && selectedDevice.features.initialized;
+ if (dropdownOpened) {
this.setState({ shouldRenderDeviceSelection: true });
} else if (hasNetwork) {
this.setState({
shouldRenderDeviceSelection: false,
animationType: 'slide-left',
});
- } else if (deviceReady) {
+ } else {
this.setState({
shouldRenderDeviceSelection: false,
- animationType: 'slide-right',
+ animationType: deviceReady ? 'slide-right' : null,
});
}
}
@@ -139,7 +149,8 @@ class LeftNavigation extends React.PureComponent {
}
handleOpen() {
- this.props.toggleDeviceDropdown(!this.props.deviceDropdownOpened);
+ this.setState({ clicked: true });
+ this.props.toggleDeviceDropdown(!this.props.wallet.dropdownOpened);
}
shouldRenderCoins() {
@@ -163,22 +174,42 @@ class LeftNavigation extends React.PureComponent {
);
}
+ const isDeviceInBootloader = this.props.wallet.selectedDevice.features && this.props.wallet.selectedDevice.features.bootloader_mode;
return (
this.handleOpen()}
+ isSelected
+ isHoverable={false}
+ onClickWrapper={() => {
+ if (!isDeviceInBootloader || this.props.devices.length > 1) {
+ this.handleOpen();
+ }
+ }}
device={this.props.wallet.selectedDevice}
- transport={this.props.connect.transport}
- devices={this.props.devices}
- isOpen={this.props.deviceDropdownOpened}
+ disabled={isDeviceInBootloader && this.props.devices.length === 1}
+ isOpen={this.props.wallet.dropdownOpened}
+ icon={(
+
+ {this.props.devices.length > 1 && (
+ {this.props.devices.length}
+ )}
+
+
+ )}
{...this.props}
/>
{this.state.shouldRenderDeviceSelection && }
- {menu}
+ {!isDeviceInBootloader && menu}