1
0
mirror of https://github.com/trezor/trezor-wallet synced 2024-11-24 09:18:09 +00:00
This commit is contained in:
Vladimir Volek 2018-10-09 13:58:59 +02:00
commit a0cfa4bf4a
18 changed files with 166 additions and 111 deletions

View File

@ -112,7 +112,7 @@ export const onDeviceConnect = (device: Device): ThunkAction => (dispatch: Dispa
} }
}; };
export const onWalletTypeRequest = (device: TrezorDevice, hidden: boolean): ThunkAction => (dispatch: Dispatch): void => { export const onWalletTypeRequest = (device: TrezorDevice, hidden: boolean, state: ?string): ThunkAction => (dispatch: Dispatch): void => {
dispatch({ dispatch({
type: MODAL.CLOSE, type: MODAL.CLOSE,
}); });
@ -120,6 +120,7 @@ export const onWalletTypeRequest = (device: TrezorDevice, hidden: boolean): Thun
type: CONNECT.RECEIVE_WALLET_TYPE, type: CONNECT.RECEIVE_WALLET_TYPE,
device, device,
hidden, hidden,
state,
}); });
}; };

View File

@ -11,6 +11,7 @@ import * as ValidationActions from 'actions/SendFormValidationActions';
import { initialState } from 'reducers/SendFormReducer'; import { initialState } from 'reducers/SendFormReducer';
import { findToken } from 'reducers/TokensReducer'; import { findToken } from 'reducers/TokensReducer';
import * as reducerUtils from 'reducers/utils'; import * as reducerUtils from 'reducers/utils';
import * as ethUtils from 'utils/ethUtils';
import type { import type {
Dispatch, Dispatch,
@ -397,8 +398,7 @@ const estimateGasPrice = (): AsyncAction => async (dispatch: Dispatch, getState:
} }
const requestedData = state.data; const requestedData = state.data;
const re = /^[0-9A-Fa-f]+$/g; // TODO: allow "0x" prefix if (!ethUtils.isHex(requestedData)) {
if (!re.test(requestedData)) {
// stop "calculatingGasLimit" process // stop "calculatingGasLimit" process
dispatch(onGasLimitChange(requestedData.length > 0 ? state.gasLimit : network.defaultGasLimit.toString())); dispatch(onGasLimitChange(requestedData.length > 0 ? state.gasLimit : network.defaultGasLimit.toString()));
return; return;

View File

@ -6,6 +6,7 @@ import EthereumjsUnits from 'ethereumjs-units';
import { findToken } from 'reducers/TokensReducer'; import { findToken } from 'reducers/TokensReducer';
import { findDevice, getPendingAmount } from 'reducers/utils'; import { findDevice, getPendingAmount } from 'reducers/utils';
import * as SEND from 'actions/constants/send'; import * as SEND from 'actions/constants/send';
import * as ethUtils from 'utils/ethUtils';
import type { import type {
Dispatch, Dispatch,
@ -19,7 +20,6 @@ const NUMBER_RE: RegExp = new RegExp('^(0|0\\.([0-9]+)?|[1-9][0-9]*\\.?([0-9]+)?
const UPPERCASE_RE = new RegExp('^(.*[A-Z].*)$'); const UPPERCASE_RE = new RegExp('^(.*[A-Z].*)$');
const ABS_RE = new RegExp('^[0-9]+$'); const ABS_RE = new RegExp('^[0-9]+$');
const ETH_18_RE = new RegExp('^(0|0\\.([0-9]{0,18})?|[1-9][0-9]*\\.?([0-9]{0,18})?|\\.[0-9]{0,18})$'); const ETH_18_RE = new RegExp('^(0|0\\.([0-9]{0,18})?|[1-9][0-9]*\\.?([0-9]{0,18})?|\\.[0-9]{0,18})$');
const HEX_RE = new RegExp('^[0-9A-Fa-f]+$');
const dynamicRegexp = (decimals: number): RegExp => { const dynamicRegexp = (decimals: number): RegExp => {
if (decimals > 0) { if (decimals > 0) {
return new RegExp(`^(0|0\\.([0-9]{0,${decimals}})?|[1-9][0-9]*\\.?([0-9]{0,${decimals}})?|\\.[0-9]{1,${decimals}})$`); return new RegExp(`^(0|0\\.([0-9]{0,${decimals}})?|[1-9][0-9]*\\.?([0-9]{0,${decimals}})?|\\.[0-9]{1,${decimals}})$`);
@ -326,7 +326,7 @@ export const nonceValidation = ($state: State): PayloadAction<State> => (dispatc
export const dataValidation = ($state: State): PayloadAction<State> => (): State => { export const dataValidation = ($state: State): PayloadAction<State> => (): State => {
const state = { ...$state }; const state = { ...$state };
if (!state.touched.data || state.data.length === 0) return state; if (!state.touched.data || state.data.length === 0) return state;
if (!HEX_RE.test(state.data)) { if (!ethUtils.isHex(state.data)) {
state.errors.data = 'Data is not valid hexadecimal'; state.errors.data = 'Data is not valid hexadecimal';
} }
return state; return state;

View File

@ -79,6 +79,7 @@ export type TrezorConnectAction = {
type: typeof CONNECT.RECEIVE_WALLET_TYPE, type: typeof CONNECT.RECEIVE_WALLET_TYPE,
device: TrezorDevice, device: TrezorDevice,
hidden: boolean, hidden: boolean,
state: ?string,
}; };
export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => { export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {

View File

@ -5,6 +5,7 @@ import EthereumjsUnits from 'ethereumjs-units';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { toHex } from 'web3-utils'; // eslint-disable-line import/no-extraneous-dependencies import { toHex } from 'web3-utils'; // eslint-disable-line import/no-extraneous-dependencies
import { initWeb3 } from 'actions/Web3Actions'; import { initWeb3 } from 'actions/Web3Actions';
import * as ethUtils from 'utils/ethUtils';
import type { import type {
Dispatch, Dispatch,
@ -29,10 +30,9 @@ type EthereumTxRequest = {
export const prepareEthereumTx = (tx: EthereumTxRequest): PromiseAction<EthereumTransaction> => async (dispatch: Dispatch): Promise<EthereumTransaction> => { export const prepareEthereumTx = (tx: EthereumTxRequest): PromiseAction<EthereumTransaction> => async (dispatch: Dispatch): Promise<EthereumTransaction> => {
const instance = await dispatch(initWeb3(tx.network)); const instance = await dispatch(initWeb3(tx.network));
const { token } = tx; const { token } = tx;
let data: string = `0x${tx.data}`; // TODO: check if already prefixed let data: string = ethUtils.sanitizeHex(tx.data);
let value: string = toHex(EthereumjsUnits.convert(tx.amount, 'ether', 'wei')); let value: string = toHex(EthereumjsUnits.convert(tx.amount, 'ether', 'wei'));
let to: string = tx.to; // eslint-disable-line prefer-destructuring let to: string = tx.to; // eslint-disable-line prefer-destructuring
if (token) { if (token) {
// smart contract transaction // smart contract transaction
const contract = instance.erc20.clone(); const contract = instance.erc20.clone();

View File

@ -7,6 +7,7 @@ import EthereumjsUnits from 'ethereumjs-units';
import type { EstimateGasOptions } from 'web3'; import type { EstimateGasOptions } from 'web3';
import * as WEB3 from 'actions/constants/web3'; import * as WEB3 from 'actions/constants/web3';
import * as PENDING from 'actions/constants/pendingTx'; import * as PENDING from 'actions/constants/pendingTx';
import * as ethUtils from 'utils/ethUtils';
import type { import type {
Dispatch, Dispatch,
@ -272,8 +273,7 @@ export const updateGasPrice = (network: string): PromiseAction<void> => async (d
export const estimateGasLimit = (network: string, $options: EstimateGasOptions): PromiseAction<string> => async (dispatch: Dispatch): Promise<string> => { export const estimateGasLimit = (network: string, $options: EstimateGasOptions): PromiseAction<string> => async (dispatch: Dispatch): Promise<string> => {
const instance = await dispatch(initWeb3(network)); const instance = await dispatch(initWeb3(network));
// TODO: allow data starting with 0x ... const data = ethUtils.sanitizeHex($options.data);
const data = `0x${$options.data.length % 2 === 0 ? $options.data : `0${$options.data}`}`;
const options = { const options = {
...$options, ...$options,
to: '0x0000000000000000000000000000000000000000', to: '0x0000000000000000000000000000000000000000',

View File

@ -6,13 +6,14 @@ const baseStyles = css`
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
color: ${colors.TEXT_PRIMARY}; color: ${colors.TEXT_PRIMARY};
font-weight: bold; font-weight: bold;
padding: 0;
margin: 0; margin: 0;
padding: 0;
`; `;
const H1 = styled.h1` const H1 = styled.h1`
${baseStyles}; ${baseStyles};
font-size: 18px; font-size: 18px;
padding-bottom: 10px;
`; `;
const H2 = styled.h2` const H2 = styled.h2`
@ -23,16 +24,19 @@ const H2 = styled.h2`
font-size: 36px; font-size: 36px;
padding-bottom: 24px padding-bottom: 24px
`} `}
padding-bottom: 10px;
`; `;
const H3 = styled.h3` const H3 = styled.h3`
${baseStyles}; ${baseStyles};
font-size: 14px; font-size: 14px;
margin-bottom: 10px;
`; `;
const H4 = styled.h4` const H4 = styled.h4`
${baseStyles}; ${baseStyles};
font-size: 12px; font-size: 12px;
padding-bottom: 10px;
`; `;
export { export {

View File

@ -9,6 +9,7 @@ const Wrapper = styled.p`
line-height: ${LINE_HEIGHT.BASE}; line-height: ${LINE_HEIGHT.BASE};
color: ${colors.TEXT_SECONDARY}; color: ${colors.TEXT_SECONDARY};
padding: 0; padding: 0;
margin: 0;
${props => props.isSmaller && css` ${props => props.isSmaller && css`
font-size: ${FONT_SIZE.SMALLER}; font-size: ${FONT_SIZE.SMALLER};

View File

@ -1,22 +1,31 @@
/* @flow */
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
type Props = {
model: string;
}
const Wrapper = styled.div``; const Wrapper = styled.div``;
const Img = styled.img` const Img = styled.img`
width: ${props => (props.model === 'T' ? '17px' : '13px')}; width: ${props => (props.model === 'T' ? '17px' : '13px')};
`; `;
const TrezorImage = ({ model }) => ( const TrezorImage = ({ model }: Props) => {
<Wrapper> // $FlowIssue
<Img model={model} src={model === 'T' ? './images/trezor-T.png' : './images/trezor-1.png'} /> const src = require(`./images/trezor-${model}.png`); // eslint-disable-line
</Wrapper> return (
); <Wrapper>
<Img model={model} src={src} />
</Wrapper>
);
};
TrezorImage.propTypes = { TrezorImage.propTypes = {
model: PropTypes.string, model: PropTypes.string,
status: PropTypes.string,
}; };
export default TrezorImage; export default TrezorImage;

View File

@ -86,10 +86,10 @@ class WalletType extends Component<Props> {
keyboardHandler: (event: KeyboardEvent) => void; keyboardHandler: (event: KeyboardEvent) => void;
changeType(hidden: boolean) { changeType(hidden: boolean, state: ?string) {
const { modal } = this.props; const { modal } = this.props;
if (!modal.opened) return; if (!modal.opened) return;
this.props.modalActions.onWalletTypeRequest(modal.device, hidden); this.props.modalActions.onWalletTypeRequest(modal.device, hidden, state);
} }
render() { render() {
@ -115,7 +115,7 @@ class WalletType extends Component<Props> {
Standard Wallet Standard Wallet
</Header> </Header>
<P isSmaller>Continue to access your standard wallet.</P> <P isSmaller>Continue to access your standard wallet.</P>
<StyledButton onClick={() => this.changeType(false)}>Go to your standard wallet</StyledButton> <StyledButton onClick={() => this.changeType(true)}>Go to your standard wallet</StyledButton>
</Content> </Content>
<Content> <Content>
<Tooltip <Tooltip
@ -139,7 +139,7 @@ class WalletType extends Component<Props> {
Hidden Wallet Hidden Wallet
</Header> </Header>
<P isSmaller>You will be asked to enter your passphrase to unlock your hidden wallet.</P> <P isSmaller>You will be asked to enter your passphrase to unlock your hidden wallet.</P>
<StyledButton isWhite onClick={() => this.changeType(true)}>Go to your hidden wallet</StyledButton> <StyledButton isWhite onClick={() => this.changeType(true, device.state)}>Go to your hidden wallet</StyledButton>
</Content> </Content>
</Wrapper> </Wrapper>
); );

View File

@ -18,6 +18,7 @@ const StyledInput = styled.input`
padding: 5px 31px 10px 20px; padding: 5px 31px 10px 20px;
color: ${colors.TEXT_PRIMARY}; color: ${colors.TEXT_PRIMARY};
background: transparent; background: transparent;
border: 1px solid ${colors.DIVIDER};
`; `;
const StyledIcon = styled(Icon)` const StyledIcon = styled(Icon)`

View File

@ -40,10 +40,6 @@ const Footer = styled.div`
`; `;
class Pin extends Component<Props, State> { class Pin extends Component<Props, State> {
keyboardHandler: (event: KeyboardEvent) => void;
state: State;
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
@ -52,6 +48,15 @@ class Pin extends Component<Props, State> {
}; };
} }
componentWillMount(): void {
this.keyboardHandler = this.keyboardHandler.bind(this);
window.addEventListener('keydown', this.keyboardHandler, false);
}
componentWillUnmount(): void {
window.removeEventListener('keydown', this.keyboardHandler, false);
}
onPinAdd = (input: number): void => { onPinAdd = (input: number): void => {
let { pin } = this.state; let { pin } = this.state;
if (pin.length < 9) { if (pin.length < 9) {
@ -120,18 +125,11 @@ class Pin extends Component<Props, State> {
case 105: case 105:
this.onPinAdd(9); this.onPinAdd(9);
break; break;
default: break;
} }
} }
keyboardHandler: (event: KeyboardEvent) => void;
componentWillMount(): void {
this.keyboardHandler = this.keyboardHandler.bind(this);
window.addEventListener('keydown', this.keyboardHandler, false);
}
componentWillUnmount(): void {
window.removeEventListener('keydown', this.keyboardHandler, false);
}
render() { render() {
if (!this.props.modal.opened) return null; if (!this.props.modal.opened) return null;
@ -165,7 +163,7 @@ class Pin extends Component<Props, State> {
<StyledP isSmaller>Not sure how PIN works? <StyledP isSmaller>Not sure how PIN works?
<StyledLink <StyledLink
isGreen isGreen
href="http://doc.satoshilabs.com/trezor-user/enteringyourpin.html" href="https://wiki.trezor.io/User_manual:Entering_PIN"
target="_blank" target="_blank"
rel="noreferrer noopener" rel="noreferrer noopener"
>Learn more >Learn more

View File

@ -6,12 +6,11 @@ import type { Props } from '../../index';
// There could be only one account notification // There could be only one account notification
export default (props: Props) => { export default (props: Props) => {
const { notification } = props.selectedAccount; const { network, notification } = props.selectedAccount;
if (notification) { if (network && notification) {
if (notification.type === 'backend') { if (notification.type === 'backend') {
// special case: backend is down // special case: backend is down
// TODO: this is a different component with "auto resolve" button // TODO: this is a different component with "auto resolve" button
return ( return (
<Notification <Notification
type="error" type="error"
@ -21,14 +20,12 @@ export default (props: Props) => {
[{ [{
label: 'Connect', label: 'Connect',
callback: async () => { callback: async () => {
await props.blockchainReconnect('trop'); await props.blockchainReconnect(network.network);
}, },
}] }]
} }
/> />
); );
// return (<Notification type="error" title={notification.title} message={notification.message} />);
} }
return (<Notification type={notification.type} title={notification.title} message={notification.message} />); return (<Notification type={notification.type} title={notification.title} message={notification.message} />);
} }

View File

@ -2,9 +2,7 @@
import React from 'react'; import React from 'react';
import { render } from 'react-dom'; import { render } from 'react-dom';
import baseStyles from 'support/styles'; import baseStyles from 'support/styles';
import { onBeforeUnload } from 'actions/WalletActions';
import App from 'views/index'; import App from 'views/index';
import store from './store';
const root: ?HTMLElement = document.getElementById('root'); const root: ?HTMLElement = document.getElementById('root');
if (root) { if (root) {
@ -13,7 +11,8 @@ if (root) {
} }
window.onbeforeunload = () => { window.onbeforeunload = () => {
store.dispatch(onBeforeUnload()); // $FlowIssue: render empty component
render(null, root);
}; };
// Application life cycle starts in services/WalletService.js // Application life cycle starts in services/WalletService.js

View File

@ -110,7 +110,9 @@ const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa
api.dispatch(DiscoveryActions.restore()); api.dispatch(DiscoveryActions.restore());
break; break;
case CONNECT.RECEIVE_WALLET_TYPE: case CONNECT.RECEIVE_WALLET_TYPE:
api.dispatch(RouterActions.selectFirstAvailableDevice(true)); if (action.state) {
api.dispatch(RouterActions.selectFirstAvailableDevice(true));
}
api.dispatch(TrezorConnectActions.authorizeDevice()); api.dispatch(TrezorConnectActions.authorizeDevice());
break; break;
default: break; default: break;

View File

@ -7,15 +7,14 @@ export const decimalToHex = (dec: number): string => new BigNumber(dec).toString
export const padLeftEven = (hex: string): string => (hex.length % 2 !== 0 ? `0${hex}` : hex); export const padLeftEven = (hex: string): string => (hex.length % 2 !== 0 ? `0${hex}` : hex);
export const sanitizeHex = ($hex: number | string): ?string => { export const sanitizeHex = ($hex: string): string => {
if (typeof $hex !== 'string') return null; const hex = $hex.toLowerCase().substring(0, 2) === '0x' ? $hex.substring(2) : $hex;
const hex = $hex.substring(0, 2) === '0x' ? $hex.substring(2) : $hex;
if (hex === '') return ''; if (hex === '') return '';
return `0x${padLeftEven(hex)}`; return `0x${padLeftEven(hex)}`;
}; };
export const hexToDecimal = (hex: number): string => { export const hexToDecimal = (hex: number): string => {
const sanitized: ?string = sanitizeHex(hex); const sanitized: ?string = sanitizeHex(hex.toString());
return !sanitized ? 'null' : new BigNumber(sanitized).toString(); return !sanitized ? 'null' : new BigNumber(sanitized).toString();
}; };
@ -40,4 +39,9 @@ export const validateAddress = (address: string): ?string => {
return 'Address is not a valid checksum'; return 'Address is not a valid checksum';
} }
return null; return null;
};
export const isHex = (str: string): boolean => {
const regExp = /^(0x|0X)?[0-9A-Fa-f]+$/g;
return regExp.test(str);
}; };

View File

@ -3,9 +3,11 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import colors from 'config/colors'; import colors from 'config/colors';
import PropTypes from 'prop-types';
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables'; import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
import { Select } from 'components/Select'; import { Select } from 'components/Select';
import Link from 'components/Link'; import Link from 'components/Link';
import { H1 } from 'components/Heading';
import Button from 'components/Button'; import Button from 'components/Button';
import Loader from 'components/Loader'; import Loader from 'components/Loader';
import P from 'components/Paragraph'; import P from 'components/Paragraph';
@ -30,26 +32,39 @@ type State = {
} }
type Props = { type Props = {
selectFirstAvailableDevice: typeof RouterActions.selectFirstAvailableDevice,
transport: $ElementType<TrezorConnectState, 'transport'>; transport: $ElementType<TrezorConnectState, 'transport'>;
} }
const InstallBridgeWrapper = styled.div` const Wrapper = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
padding-top: 0px; align-items: center;
max-width: 500px; max-width: 500px;
`; `;
const TitleHeader = styled.h3` const Top = styled.div`
font-size: ${FONT_SIZE.BIGGEST};
display: flex; display: flex;
flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; max-width: 500px;
margin-bottom: 24px; flex: 1;
padding-top: 30px;
`; `;
const BridgeVersion = styled.span` const Bottom = styled.div`
padding-bottom: 20px;
`;
const TitleHeader = styled(H1)`
display: flex;
font-size: ${FONT_SIZE.BIGGEST};
justify-content: center;
align-items: center;
`;
const Version = styled.span`
color: ${colors.GREEN_PRIMARY}; color: ${colors.GREEN_PRIMARY};
padding: 6px 10px; padding: 6px 10px;
border: 1px solid ${colors.GREEN_PRIMARY}; border: 1px solid ${colors.GREEN_PRIMARY};
@ -68,7 +83,7 @@ const SelectWrapper = styled(Select)`
width: 180px; width: 180px;
`; `;
const DownloadBridgeWrapper = styled.div` const Download = styled.div`
margin: 24px auto; margin: 24px auto;
display: flex; display: flex;
align-items: center; align-items: center;
@ -81,7 +96,29 @@ const DownloadBridgeButton = styled(Button)`
align-items: center; align-items: center;
`; `;
export default class InstallBridge extends Component<Props, State> { const GoBack = styled.span`
color: ${colors.GREEN_PRIMARY};
text-decoration: underline;
&:hover {
cursor: pointer;
text-decoration: none;
}
`;
const Ol = styled.ul`
margin: 0 auto;
color: ${colors.TEXT_SECONDARY};
font-size: ${FONT_SIZE.BASE};
padding: 10px 0 15px 25px;
text-align: left;
`;
const Li = styled.li`
text-align: justify;
`;
class InstallBridge extends Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
@ -113,67 +150,68 @@ export default class InstallBridge extends Component<Props, State> {
if (!target) { if (!target) {
return <Loader text="Loading" size={100} />; return <Loader text="Loading" size={100} />;
} }
const changelog = this.props.transport.bridge.changelog.map(entry => (
<li key={entry}>{entry}</li>
));
const url = `${this.state.uri}${target.value}`;
return ( return (
<InstallBridgeWrapper> <Wrapper>
<TitleHeader>TREZOR Bridge.<BridgeVersion>{this.state.currentVersion}</BridgeVersion></TitleHeader> <Top>
<P>New communication tool to facilitate the connection between your TREZOR and your internet browser.</P> <TitleHeader>TREZOR Bridge<Version>{this.state.currentVersion}</Version></TitleHeader>
<DownloadBridgeWrapper> <P>New communication tool to facilitate the connection between your TREZOR and your internet browser.</P>
<SelectWrapper <Download>
isSearchable={false} <SelectWrapper
isClearable={false} isSearchable={false}
value={target} isClearable={false}
onChange={v => this.onChange(v)} value={target}
options={this.state.installers} onChange={v => this.onChange(v)}
/> options={this.state.installers}
<Link href={url}> />
<DownloadBridgeButton> <Link href={`${this.state.uri}${target.value}`}>
<Icon <DownloadBridgeButton>
icon={ICONS.DOWNLOAD} <Icon
color={colors.WHITE} icon={ICONS.DOWNLOAD}
size={30} color={colors.WHITE}
/> size={30}
/>
Download latest Bridge {this.state.latestVersion} Download latest Bridge {this.state.latestVersion}
</DownloadBridgeButton> </DownloadBridgeButton>
</Link> </Link>
</DownloadBridgeWrapper> </Download>
{target.signature && ( <Ol>
<P> {this.props.transport.bridge.changelog.map(entry => (
<Li key={entry}>{entry}</Li>
))}
</Ol>
<P isSmaller>
<LearnMoreText>Learn more about latest versions in</LearnMoreText>
<Link <Link
href={this.state.uri + target.signature} href="https://github.com/trezor/trezord-go/blob/master/CHANGELOG.md"
target="_blank" target="_blank"
rel="noreferrer noopener" rel="noreferrer noopener"
isGreen isGreen
>Check PGP signature >Changelog
</Link> </Link>
</P> </P>
)} <P>
<P> {target.signature && (
{ changelog } <Link
<LearnMoreText>Learn more about latest versions in</LearnMoreText> href={this.state.uri + target.signature}
<Link target="_blank"
href="https://github.com/trezor/trezord-go/blob/master/CHANGELOG.md" rel="noreferrer noopener"
target="_blank" isGreen
rel="noreferrer noopener" >Check PGP signature
isGreen </Link>
>Changelog )}
</Link> </P>
</P> </Top>
{this.props.transport.type && ( <Bottom>
<React.Fragment> {this.props.transport.type && (
<P> <P>
No, i dont want to upgrade Bridge now, No, i dont want to upgrade Bridge now<br />
Take me <GoBack onClick={() => this.props.selectFirstAvailableDevice()}>back to the wallet</GoBack>
</P> </P>
<P> )}
Take me <Link href="#/">back to the wallet</Link> </Bottom>
</P> </Wrapper>
</React.Fragment>
)}
</InstallBridgeWrapper>
); );
} }
} }
export default InstallBridge;

View File

@ -36,7 +36,6 @@ const LandingWrapper = styled.div`
const LandingContent = styled.div` const LandingContent = styled.div`
flex: 1; flex: 1;
display: flex; display: flex;
align-items: center;
justify-content: center; justify-content: center;
`; `;
@ -85,6 +84,7 @@ export default (props: Props) => {
const shouldShowUnsupportedBrowser = browserState.supported === false; const shouldShowUnsupportedBrowser = browserState.supported === false;
const isLoading = !shouldShowInitializationError && !shouldShowInstallBridge && !shouldShowConnectDevice && !shouldShowUnsupportedBrowser && !localStorageError; const isLoading = !shouldShowInitializationError && !shouldShowInstallBridge && !shouldShowConnectDevice && !shouldShowUnsupportedBrowser && !localStorageError;
return ( return (
<LandingWrapper> <LandingWrapper>
{isLoading && <LandingLoader text="Loading" size={100} />} {isLoading && <LandingLoader text="Loading" size={100} />}
@ -103,7 +103,7 @@ export default (props: Props) => {
<Log /> <Log />
<LandingContent> <LandingContent>
{shouldShowUnsupportedBrowser && <BrowserNotSupported />} {shouldShowUnsupportedBrowser && <BrowserNotSupported />}
{shouldShowInstallBridge && <InstallBridge transport={transport} />} {shouldShowInstallBridge && <InstallBridge selectFirstAvailableDevice={props.selectFirstAvailableDevice} transport={transport} />}
{(shouldShowConnectDevice || shouldShowDisconnectDevice) && ( {(shouldShowConnectDevice || shouldShowDisconnectDevice) && (
<div> <div>