Extension installation overlay (#4423)

* Extension installation overlay

* Pr gumbles

* Spelling

* Update Chrome URL
This commit is contained in:
Jaco Greeff 2017-02-03 20:01:49 +01:00 committed by GitHub
parent cd4d489b57
commit f48d8b0ef6
6 changed files with 235 additions and 0 deletions

View File

@ -193,6 +193,7 @@
"scryptsy": "2.0.0", "scryptsy": "2.0.0",
"solc": "ngotchac/solc-js", "solc": "ngotchac/solc-js",
"store": "1.3.20", "store": "1.3.20",
"useragent.js": "0.5.6",
"utf8": "2.1.2", "utf8": "2.1.2",
"valid-url": "1.0.9", "valid-url": "1.0.9",
"validator": "6.2.0", "validator": "6.2.0",

View File

@ -0,0 +1,52 @@
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.body {
background: #f80;
color: white;
opacity: 1;
max-width: 500px;
padding: 1em 4em 1em 2em;
position: fixed;
right: 1.5em;
top: 1.5em;
z-index: 1000;
.button {
background: rgba(0, 0, 0, 0.5);
color: white !important;
svg {
fill: white !important;
}
}
.buttonrow {
text-align: right;
}
p {
color: white;
}
.close {
cursor: pointer;
position: absolute;
right: 1em;
top: 1em;
}
}

View File

@ -0,0 +1,74 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { FormattedMessage } from 'react-intl';
import { Button } from '~/ui';
import { CloseIcon, CheckIcon } from '~/ui/Icons';
import Store from './store';
import styles from './extension.css';
@observer
export default class Extension extends Component {
store = new Store();
render () {
const { showWarning } = this.store;
if (!showWarning) {
return null;
}
return (
<div className={ styles.body }>
<CloseIcon
className={ styles.close }
onClick={ this.onClose }
/>
<p>
<FormattedMessage
id='extension.intro'
defaultMessage='Parity now has an extension available for Chrome that allows safe browsing of Ethereum-enabled distributed applications. It is highly recommended that you install this extension to further enhance your Parity experience.'
/>
</p>
<p className={ styles.buttonrow }>
<Button
className={ styles.button }
icon={ <CheckIcon /> }
label={
<FormattedMessage
id='extension.install'
defaultMessage='Install the extension now'
/>
}
onClick={ this.onInstallClick }
/>
</p>
</div>
);
}
onClose = () => {
this.store.snoozeWarning();
}
onInstallClick = () => {
this.store.installExtension();
}
}

View File

@ -0,0 +1,17 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './extension';

View File

@ -0,0 +1,89 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
/* global chrome */
import { action, computed, observable } from 'mobx';
import store from 'store';
import browser from 'useragent.js/lib/browser';
const A_DAY = 24 * 60 * 60 * 1000;
const NEXT_DISPLAY = '_parity::extensionWarning::nextDisplay';
// 'https://chrome.google.com/webstore/detail/parity-ethereum-integrati/himekenlppkgeaoeddcliojfddemadig';
const EXTENSION_PAGE = 'https://chrome.google.com/webstore/detail/himekenlppkgeaoeddcliojfddemadig';
export default class Store {
@observable isInstalling = false;
@observable nextDisplay = 0;
@observable shouldInstall = false;
constructor () {
this.nextDisplay = store.get(NEXT_DISPLAY) || 0;
this.testInstall();
}
@computed get showWarning () {
return !this.isInstalling && this.shouldInstall && (Date.now() > this.nextDisplay);
}
@action setInstalling = (isInstalling) => {
this.isInstalling = isInstalling;
}
@action snoozeWarning = (sleep = A_DAY) => {
this.nextDisplay = Date.now() + sleep;
store.set(NEXT_DISPLAY, this.nextDisplay);
}
@action testInstall = () => {
this.shouldInstall = this.readStatus();
}
readStatus = () => {
const hasExtension = Symbol.for('parity.extension') in window;
const ua = browser.analyze(navigator.userAgent || '');
if (hasExtension) {
return false;
}
return (ua || {}).name.toLowerCase() === 'chrome';
}
installExtension = () => {
this.setInstalling(true);
return new Promise((resolve, reject) => {
const link = document.createElement('link');
link.setAttribute('rel', 'chrome-webstore-item');
link.setAttribute('href', EXTENSION_PAGE);
document.querySelector('head').appendChild(link);
if (chrome && chrome.webstore && chrome.webstore.install) {
chrome.webstore.install(EXTENSION_PAGE, resolve, reject);
} else {
reject(new Error('Direct installation failed.'));
}
})
.catch((error) => {
console.warn('Unable to perform direct install', error);
window.open(EXTENSION_PAGE, '_blank');
});
}
}

View File

@ -26,6 +26,7 @@ import ParityBar from '../ParityBar';
import Snackbar from './Snackbar'; import Snackbar from './Snackbar';
import Container from './Container'; import Container from './Container';
import DappContainer from './DappContainer'; import DappContainer from './DappContainer';
import Extension from './Extension';
import FrameError from './FrameError'; import FrameError from './FrameError';
import Status from './Status'; import Status from './Status';
import Store from './store'; import Store from './store';
@ -106,6 +107,7 @@ class Application extends Component {
? <Status upgradeStore={ this.upgradeStore } /> ? <Status upgradeStore={ this.upgradeStore } />
: null : null
} }
<Extension />
<Snackbar /> <Snackbar />
</Container> </Container>
); );