From 9f01f2ff479f2def9b863a6d2ad82e33fb20bd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 19 Jan 2017 16:47:06 +0100 Subject: [PATCH 1/5] Embeddable ParityBar --- js/src/embed.js | 118 ++++++++++++++++++++++++++++ js/src/index.ejs | 2 +- js/src/redux/middleware.js | 50 +++++++----- js/src/redux/store.js | 4 +- js/src/secureApi.js | 18 +++-- js/src/ui/Tooltips/reducers.js | 6 +- js/src/util/storage.js | 40 ++++++++++ js/src/views/Application/store.js | 5 +- js/src/views/ParityBar/parityBar.js | 64 +++++++++++---- js/src/views/Settings/middleware.js | 9 ++- js/webpack/app.js | 14 +++- 11 files changed, 280 insertions(+), 50 deletions(-) create mode 100644 js/src/embed.js create mode 100644 js/src/util/storage.js diff --git a/js/src/embed.js b/js/src/embed.js new file mode 100644 index 00000000000..cff5f800c74 --- /dev/null +++ b/js/src/embed.js @@ -0,0 +1,118 @@ +// Copyright 2015, 2016 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 . + +import 'babel-polyfill'; +import 'whatwg-fetch'; + +import es6Promise from 'es6-promise'; +es6Promise.polyfill(); + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { AppContainer } from 'react-hot-loader'; + +import injectTapEventPlugin from 'react-tap-event-plugin'; + +import SecureApi from './secureApi'; +import ContractInstances from '~/contracts'; + +import { initStore } from './redux'; +import ContextProvider from '~/ui/ContextProvider'; +import muiTheme from '~/ui/Theme'; + +import { patchApi } from '~/util/tx'; +import { setApi } from '~/redux/providers/apiActions'; + +import './environment'; + +import '../assets/fonts/Roboto/font.css'; +import '../assets/fonts/RobotoMono/font.css'; + +injectTapEventPlugin(); + +import ParityBar from './views/ParityBar'; + +// Cleanup Loading +const $container = document.querySelector('#container'); +$container.parentNode.removeChild($container); + +// Test transport (std transport should be provided as global object) +class FakeTransport { + constructor () { + console.warn('Secure Transport not provided. Falling back to FakeTransport'); + } + + execute (method, ...params) { + console.log('Calling', method, params); + return Promise.reject('not connected'); + } + on () {} +} + +class FrameSecureApi extends SecureApi { + constructor (transport) { + super('', null, () => { + return transport; + }); + } + + connect () { + // Do nothing - this API does not need connecting + this.emit('connecting'); + // Fire connected event with some delay. + setTimeout(() => { + this.emit('connected'); + }); + } + + needsToken () { + return false; + } + + isConnecting () { + return false; + } + + isConnected () { + return true; + } +} + +const api = new FrameSecureApi(window.secureTransport || new FakeTransport()); +patchApi(api); +ContractInstances.create(api); + +const store = initStore(api, null, true); +store.dispatch({ type: 'initAll', api }); +store.dispatch(setApi(api)); + +window.secureApi = api; + +const app = ( + +); + +const container = document.createElement('div'); +document.body.appendChild(container); + +ReactDOM.render( + + + { app } + + , + container +); diff --git a/js/src/index.ejs b/js/src/index.ejs index 48cd5c0c0dd..590070e8b0b 100644 --- a/js/src/index.ejs +++ b/js/src/index.ejs @@ -27,7 +27,7 @@
-
Loading +
Loading
diff --git a/js/src/redux/middleware.js b/js/src/redux/middleware.js index bffeddc98f1..65848133238 100644 --- a/js/src/redux/middleware.js +++ b/js/src/redux/middleware.js @@ -25,24 +25,38 @@ import CertificationsMiddleware from './providers/certifications/middleware'; import ChainMiddleware from './providers/chainMiddleware'; import RegistryMiddleware from './providers/registry/middleware'; -export default function (api, browserHistory) { - const errors = new ErrorsMiddleware(); - const signer = new SignerMiddleware(api); - const settings = new SettingsMiddleware(); - const status = statusMiddleware(); - const certifications = new CertificationsMiddleware(); - const routeMiddleware = routerMiddleware(browserHistory); - const chain = new ChainMiddleware(); - const registry = new RegistryMiddleware(api); - - const middleware = [ - settings.toMiddleware(), - signer.toMiddleware(), - errors.toMiddleware(), - certifications.toMiddleware(), - chain.toMiddleware(), - registry - ]; +export default function (api, browserHistory, forEmbed = false) { + let middleware; + if (forEmbed) { + const errors = new ErrorsMiddleware(); + const signer = new SignerMiddleware(api); + const settings = new SettingsMiddleware(); + const chain = new ChainMiddleware(); + middleware = [ + settings.toMiddleware(), + signer.toMiddleware(), + errors.toMiddleware(), + chain.toMiddleware() + ]; + } else { + const errors = new ErrorsMiddleware(); + const signer = new SignerMiddleware(api); + const settings = new SettingsMiddleware(); + const certifications = new CertificationsMiddleware(); + const chain = new ChainMiddleware(); + const registry = new RegistryMiddleware(api); + + middleware = [ + settings.toMiddleware(), + signer.toMiddleware(), + errors.toMiddleware(), + certifications.toMiddleware(), + chain.toMiddleware(), + registry + ]; + } + const status = statusMiddleware(); + const routeMiddleware = browserHistory ? routerMiddleware(browserHistory) : []; return middleware.concat(status, routeMiddleware, thunk); } diff --git a/js/src/redux/store.js b/js/src/redux/store.js index 132375784fc..dff56bd20eb 100644 --- a/js/src/redux/store.js +++ b/js/src/redux/store.js @@ -33,9 +33,9 @@ const storeCreation = window.devToolsExtension ? window.devToolsExtension()(createStore) : createStore; -export default function (api, browserHistory) { +export default function (api, browserHistory, forEmbed = false) { const reducers = initReducers(); - const middleware = initMiddleware(api, browserHistory); + const middleware = initMiddleware(api, browserHistory, forEmbed); const store = applyMiddleware(...middleware)(storeCreation)(reducers); BalancesProvider.instantiate(store, api); diff --git a/js/src/secureApi.js b/js/src/secureApi.js index b39ecaf3b96..9f81dce8fd2 100644 --- a/js/src/secureApi.js +++ b/js/src/secureApi.js @@ -18,9 +18,9 @@ import { uniq } from 'lodash'; import Api from './api'; import { LOG_KEYS, getLogger } from '~/config'; +import storage from '~/util/storage'; const log = getLogger(LOG_KEYS.Signer); -const sysuiToken = window.localStorage.getItem('sysuiToken'); export default class SecureApi extends Api { _isConnecting = false; @@ -31,8 +31,14 @@ export default class SecureApi extends Api { _dappsPort = 8080; _signerPort = 8180; - constructor (url, nextToken) { - const transport = new Api.Transport.Ws(url, sysuiToken, false); + static getTransport (url, sysuiToken) { + return new Api.Transport.Ws(url, sysuiToken, false); + } + + constructor (url, nextToken, getTransport = SecureApi.getTransport) { + let sysuiToken = storage.getItem('sysuiToken'); + + const transport = getTransport(url, sysuiToken); super(transport); this._url = url; @@ -56,8 +62,8 @@ export default class SecureApi extends Api { } get hostname () { - if (window.location.hostname === 'home.parity') { - return 'dapps.parity'; + if (window.location.hostname === 'home.ethlink.io') { + return 'dapps.ethlink.io'; } if (!this._dappsInterface || this._dappsInterface === '0.0.0.0') { @@ -308,7 +314,7 @@ export default class SecureApi extends Api { } _saveToken (token) { - window.localStorage.setItem('sysuiToken', token); + storage.setItem('sysuiToken', token); } /** diff --git a/js/src/ui/Tooltips/reducers.js b/js/src/ui/Tooltips/reducers.js index cc0ebf926fa..d43d1609560 100644 --- a/js/src/ui/Tooltips/reducers.js +++ b/js/src/ui/Tooltips/reducers.js @@ -14,13 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import storage from '~/util/storage'; + const LS_KEY = 'tooltips'; let currentId = -1; let maxId = 0; function closeTooltips (state, action) { - window.localStorage.setItem(LS_KEY, '{"state":"off"}'); + storage.setItem(LS_KEY, '{"state":"off"}'); currentId = -1; @@ -41,7 +43,7 @@ function newTooltip (state, action) { } function nextTooltip (state, action) { - const hideTips = window.localStorage.getItem(LS_KEY); + const hideTips = storage.getItem(LS_KEY); currentId = hideTips ? -1 diff --git a/js/src/util/storage.js b/js/src/util/storage.js new file mode 100644 index 00000000000..bed2810de01 --- /dev/null +++ b/js/src/util/storage.js @@ -0,0 +1,40 @@ +// Copyright 2015, 2016 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 . + +/** + * A safe localStorage wrapper + */ +class Storage { + storage = window.localStorage; + + setItem (val, key) { + try { + this.storage.setItem(val, key); + } catch (e) { + console.warn('Error saving to storage', e); + } + } + + getItem (val) { + try { + return this.storage.getItem(val); + } catch (e) { + console.warn('Error reading from storage', e); + } + } +} + +export default new Storage(); diff --git a/js/src/views/Application/store.js b/js/src/views/Application/store.js index 535d0942b8d..831ab7f0572 100644 --- a/js/src/views/Application/store.js +++ b/js/src/views/Application/store.js @@ -15,6 +15,7 @@ // along with Parity. If not, see . import { action, observable } from 'mobx'; +import storage from '~/util/storage'; export default class Store { @observable firstrunVisible = false; @@ -22,7 +23,7 @@ export default class Store { constructor (api) { this._api = api; - const value = window.localStorage.getItem('showFirstRun'); + const value = storage.getItem('showFirstRun'); if (value) { this.firstrunVisible = JSON.parse(value); } @@ -36,7 +37,7 @@ export default class Store { @action toggleFirstrun = (visible = false) => { this.firstrunVisible = visible; - window.localStorage.setItem('showFirstRun', JSON.stringify(!!visible)); + storage.setItem('showFirstRun', JSON.stringify(!!visible)); } _checkAccounts () { diff --git a/js/src/views/ParityBar/parityBar.js b/js/src/views/ParityBar/parityBar.js index af97e565517..57458dbbbc0 100644 --- a/js/src/views/ParityBar/parityBar.js +++ b/js/src/views/ParityBar/parityBar.js @@ -29,7 +29,8 @@ import styles from './parityBar.css'; class ParityBar extends Component { static propTypes = { pending: PropTypes.array, - dapp: PropTypes.bool + dapp: PropTypes.bool, + externalLink: PropTypes.string } state = { @@ -45,12 +46,31 @@ class ParityBar extends Component { } if (count < newCount) { - this.setState({ opened: true }); + this.setOpened(true); } else if (newCount === 0 && count === 1) { - this.setState({ opened: false }); + this.setOpened(false); } } + setOpened (opened) { + this.setState({ opened }); + + if (!this.bar) { + return; + } + + // Fire up custom even to support having parity bar iframed. + const event = new CustomEvent('parity.bar.visibility', { + bubbles: true, + detail: { opened } + }); + this.bar.dispatchEvent(event); + } + + onRef = (el) => { + this.bar = el; + } + render () { const { opened } = this.state; @@ -72,18 +92,19 @@ class ParityBar extends Component { className={ styles.parityIcon } /> ); + const parityButton = ( +
- -======= -
- -
+ ); + } + + renderDrag () { + if (this.props.externalLink) { + return; + } + + return ( +
-
-
->>>>>>> master + className={ dragButtonClasses.join(' ') } + ref='dragButton' + />
); } renderLink (button) { const { externalLink } = this.props; + if (!externalLink) { return ( @@ -256,7 +251,10 @@ class ParityBar extends Component { } return ( - + { button } ); diff --git a/js/src/views/Settings/middleware.js b/js/src/views/Settings/middleware.js index 0ec546d11b4..76bd48d19f9 100644 --- a/js/src/views/Settings/middleware.js +++ b/js/src/views/Settings/middleware.js @@ -14,9 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import defaultViews from './Views/defaults'; import store from 'store'; +import defaultViews from './Views/defaults'; + function initBackground (store, api) { const backgroundSeed = loadBackground() || api.util.sha3(`${Date.now()}`); From b22967efbbb9cda3f7e9d6913f5648fa32c46fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 23 Jan 2017 12:08:54 +0100 Subject: [PATCH 5/5] Supporting parity background --- js/src/views/ParityBar/parityBar.js | 14 +++++++------- js/src/views/Settings/middleware.js | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/js/src/views/ParityBar/parityBar.js b/js/src/views/ParityBar/parityBar.js index 2afe2d12cd1..1c7fdaeb3fc 100644 --- a/js/src/views/ParityBar/parityBar.js +++ b/js/src/views/ParityBar/parityBar.js @@ -26,7 +26,7 @@ import { Badge, Button, ContainerTitle, ParityBackground } from '~/ui'; import { Embedded as Signer } from '../Signer'; import DappsStore from '~/views/Dapps/dappsStore'; -import imagesEthcoreBlock from '../../../assets/images/parity-logo-white-no-text.svg'; +import imagesEthcoreBlock from '!url-loader!../../../assets/images/parity-logo-white-no-text.svg'; import styles from './parityBar.css'; const LS_STORE_KEY = '_parity::parityBar'; @@ -197,12 +197,6 @@ class ParityBar extends Component { /> ); - const dragButtonClasses = [ styles.dragButton ]; - - if (this.state.moving) { - dragButtonClasses.push(styles.moving); - } - return (