Unverified Commit 01147fa6 authored by Thibaut Sardan's avatar Thibaut Sardan Committed by GitHub
Browse files

Merge branch 'master' into luke-442-window-shrink-bug

parents 68877058 5ceb26dc
Pipeline #44434 canceled with stage
...@@ -68,7 +68,8 @@ ...@@ -68,7 +68,8 @@
"react-router-dom": "^4.2.2", "react-router-dom": "^4.2.2",
"react-scripts": "^2.1.3", "react-scripts": "^2.1.3",
"recompose": "^0.27.1", "recompose": "^0.27.1",
"rxjs": "^6.2.0" "rxjs": "^6.2.0",
"semver": "^5.6.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-decorators": "^7.2.0", "@babel/plugin-proposal-decorators": "^7.2.0",
......
...@@ -13,7 +13,10 @@ import { ...@@ -13,7 +13,10 @@ import {
} from 'react-router-dom'; } from 'react-router-dom';
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import isElectron from 'is-electron'; import isElectron from 'is-electron';
import { Modal } from 'fether-ui';
import ReactResizeDetector from 'react-resize-detector'; import ReactResizeDetector from 'react-resize-detector';
import semver from 'semver';
import { version } from '../../package.json';
import Accounts from '../Accounts'; import Accounts from '../Accounts';
import BackupAccount from '../BackupAccount'; import BackupAccount from '../BackupAccount';
...@@ -23,6 +26,8 @@ import Send from '../Send'; ...@@ -23,6 +26,8 @@ import Send from '../Send';
import Tokens from '../Tokens'; import Tokens from '../Tokens';
import Whitelist from '../Whitelist'; import Whitelist from '../Whitelist';
const currentVersion = version;
// Use MemoryRouter for production viewing in file:// protocol // Use MemoryRouter for production viewing in file:// protocol
// https://github.com/facebook/create-react-app/issues/3591 // https://github.com/facebook/create-react-app/issues/3591
const Router = const Router =
...@@ -40,6 +45,55 @@ class App extends Component { ...@@ -40,6 +45,55 @@ class App extends Component {
electron.ipcRenderer.send('asynchronous-message', 'app-resize', height); electron.ipcRenderer.send('asynchronous-message', 'app-resize', height);
}; };
state = {
newRelease: false // false | {name, url, ignore}
};
componentDidMount () {
window
.fetch('https://api.github.com/repos/paritytech/fether/releases/latest')
.then(j => j.json())
.then(({ name, html_url: url, tag_name: tag }) => {
const latestVersion = tag.match(/v(\d+\.\d+(\.\d+)?)/)[1];
if (semver.gt(latestVersion, currentVersion)) {
this.setState({
newRelease: {
name,
url,
ignore: false
}
});
}
})
.catch(e => {
console.error('Error while checking for a new version of Fether:', e);
});
}
renderModalLinks = () => {
return (
<nav className='form-nav -binary'>
<button className='button -back' onClick={this.hideNewReleaseModal}>
Remind me later
</button>
<button className='button' onClick={this.openNewReleaseUrl}>
Download
</button>
</nav>
);
};
hideNewReleaseModal = () => {
this.setState({
newRelease: { ...this.state.newRelease, ignore: true }
});
};
openNewReleaseUrl = () => {
window.open(this.state.newRelease.url, '_blank', 'noopener noreferrer');
};
/** /**
* Decide which screen to render. * Decide which screen to render.
*/ */
...@@ -49,6 +103,8 @@ class App extends Component { ...@@ -49,6 +103,8 @@ class App extends Component {
parityStore: { api } parityStore: { api }
} = this.props; } = this.props;
const { newRelease } = this.state;
if (isFirstRun) { if (isFirstRun) {
return ( return (
<div className='window'> <div className='window'>
...@@ -79,28 +135,35 @@ class App extends Component { ...@@ -79,28 +135,35 @@ class App extends Component {
<ReactResizeDetector handleHeight onResize={this.handleResize}> <ReactResizeDetector handleHeight onResize={this.handleResize}>
<div className='content'> <div className='content'>
<div className='window'> <div className='window'>
<Router> <Modal
<Switch> title='New version available'
{/* The next line is the homepage */} description={newRelease ? `${newRelease.name} was released!` : ''}
<Redirect exact from='/' to='/accounts' /> visible={newRelease && !newRelease.ignore}
<Route path='/accounts' component={Accounts} /> buttons={this.renderModalLinks()}
<Route path='/onboarding' component={Onboarding} /> >
<Route path='/tokens/:accountAddress' component={Tokens} /> <Router>
<Route <Switch>
path='/whitelist/:accountAddress' {/* The next line is the homepage */}
component={Whitelist} <Redirect exact from='/' to='/accounts' />
/> <Route path='/accounts' component={Accounts} />
<Route <Route path='/onboarding' component={Onboarding} />
path='/backup/:accountAddress' <Route path='/tokens/:accountAddress' component={Tokens} />
component={BackupAccount} <Route
/> path='/whitelist/:accountAddress'
<Route component={Whitelist}
path='/send/:tokenAddress/from/:accountAddress' />
component={Send} <Route
/> path='/backup/:accountAddress'
<Redirect from='*' to='/' /> component={BackupAccount}
</Switch> />
</Router> <Route
path='/send/:tokenAddress/from/:accountAddress'
component={Send}
/>
<Redirect from='*' to='/' />
</Switch>
</Router>
</Modal>
</div> </div>
</div> </div>
</ReactResizeDetector> </ReactResizeDetector>
......
...@@ -41,7 +41,7 @@ class HealthModal extends Component { ...@@ -41,7 +41,7 @@ class HealthModal extends Component {
<Modal <Modal
description={this.renderDescription()} description={this.renderDescription()}
fullscreen={fullscreen} fullscreen={fullscreen}
loading={loading} icon={loading}
title={this.renderTitle()} title={this.renderTitle()}
visible={visible} visible={visible}
> >
......
...@@ -57,8 +57,8 @@ class Sent extends Component { ...@@ -57,8 +57,8 @@ class Sent extends Component {
description={this.renderDescription()} description={this.renderDescription()}
fullscreen fullscreen
link={this.renderLink()} link={this.renderLink()}
loading={this.renderIcon()} icon={this.renderIcon()}
navigateTo={this.renderGoHomepage()} buttons={this.renderGoHomepage()}
title={this.renderTitle()} title={this.renderTitle()}
visible visible
/> />
......
...@@ -31,7 +31,7 @@ class TokensList extends Component { ...@@ -31,7 +31,7 @@ class TokensList extends Component {
<Modal <Modal
description='Please wait...' description='Please wait...'
fullscreen={false} fullscreen={false}
loading={loading} icon={loading}
title='Loading account tokens...' title='Loading account tokens...'
visible={isLoadingAccountTokens} visible={isLoadingAccountTokens}
/> />
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
} }
.alert-screen-content { .alert-screen-content {
width: 75%;
.alert-screen_image { .alert-screen_image {
display: flex; display: flex;
......
...@@ -8,12 +8,12 @@ import PropTypes from 'prop-types'; ...@@ -8,12 +8,12 @@ import PropTypes from 'prop-types';
import { Image as SUIImage, Modal as SUIModal } from 'semantic-ui-react'; import { Image as SUIImage, Modal as SUIModal } from 'semantic-ui-react';
export const Modal = ({ export const Modal = ({
buttons,
children, children,
description, description,
fullscreen, fullscreen,
icon,
link, link,
loading,
navigateTo,
title, title,
visible visible
}) => ( }) => (
...@@ -24,19 +24,21 @@ export const Modal = ({ ...@@ -24,19 +24,21 @@ export const Modal = ({
> >
<div className={`alert-screen ${fullscreen ? '-full-screen' : ''}`}> <div className={`alert-screen ${fullscreen ? '-full-screen' : ''}`}>
<SUIModal.Content image className='alert-screen-content'> <SUIModal.Content image className='alert-screen-content'>
<SUIImage {icon && (
wrapped <SUIImage
alt='loading' alt='loading'
size='medium' className='alert-screen_image'
src={loading} size='medium'
className='alert-screen_image' src={icon}
/> wrapped
/>
)}
<SUIModal.Description className='alert-screen_text'> <SUIModal.Description className='alert-screen_text'>
<h1>{title}</h1> <h1>{title}</h1>
<p>{description}</p> <p>{description}</p>
<p>{link || null}</p> <p>{link || null}</p>
</SUIModal.Description> </SUIModal.Description>
{navigateTo || null} {buttons || null}
</SUIModal.Content> </SUIModal.Content>
</div> </div>
</SUIModal> </SUIModal>
...@@ -45,12 +47,12 @@ export const Modal = ({ ...@@ -45,12 +47,12 @@ export const Modal = ({
); );
Modal.propTypes = { Modal.propTypes = {
buttons: PropTypes.node,
children: PropTypes.node, children: PropTypes.node,
description: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), description: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
fullscreen: PropTypes.bool, fullscreen: PropTypes.bool,
icon: PropTypes.string,
link: PropTypes.node, link: PropTypes.node,
loading: PropTypes.any.isRequired,
navigateTo: PropTypes.node,
title: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), title: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
visible: PropTypes.bool visible: PropTypes.bool
}; };
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment