From 1238871cd6a7d24a39c9e08e92e5f51416b5928d Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Tue, 20 Sep 2016 10:40:23 +0200 Subject: [PATCH 01/11] examples(webui): convert to react --- examples/webui/.eslintrc | 4 + examples/webui/package.json | 44 ++++++- examples/webui/src/app/actions/accounts.js | 43 +++++++ examples/webui/src/app/actions/blocks.js | 17 +++ examples/webui/src/app/actions/errors.js | 5 + examples/webui/src/app/actions/home.js | 51 ++++++++ examples/webui/src/app/actions/index.js | 24 ++++ examples/webui/src/app/actions/pages.js | 3 + examples/webui/src/app/actions/peers.js | 5 + examples/webui/src/app/actions/router.js | 3 + .../webui/src/app/actions/transactions.js | 17 +++ examples/webui/src/app/actions/utils.js | 39 ++++++ examples/webui/src/app/components/accounts.js | 58 +++++++++ examples/webui/src/app/components/blocks.js | 69 ++++++++++ examples/webui/src/app/components/feed.js | 67 ++++++++++ examples/webui/src/app/components/hash.js | 9 ++ examples/webui/src/app/components/notfound.js | 15 +++ examples/webui/src/app/components/peers.js | 52 ++++++++ .../src/app/components/processing-status.js | 17 +++ .../webui/src/app/components/transactions.js | 57 +++++++++ examples/webui/src/app/containers/app.js | 39 ++++++ examples/webui/src/app/containers/home.js | 53 ++++++++ examples/webui/src/app/containers/root.js | 27 ++++ examples/webui/src/app/index 2.js | 29 +++++ examples/webui/src/app/index.js | 42 +++--- examples/webui/src/app/reducers/accounts.js | 35 +++++ examples/webui/src/app/reducers/blocks.js | 43 +++++++ examples/webui/src/app/reducers/errors.js | 15 +++ examples/webui/src/app/reducers/index.js | 19 +++ examples/webui/src/app/reducers/peers.js | 11 ++ .../webui/src/app/reducers/transactions.js | 16 +++ examples/webui/src/app/routes.js | 16 +++ examples/webui/src/app/services/api.js | 1 + examples/webui/src/app/services/index.js | 5 + .../src/app/store/configure-store.dev.js | 30 +++++ .../webui/src/app/store/configure-store.js | 5 + .../src/app/store/configure-store.prod.js | 16 +++ .../webui/src/app/utils/file-extension.js | 13 ++ examples/webui/src/app/utils/promise.js | 5 + examples/webui/src/app/utils/pure.js | 6 + examples/webui/src/app/utils/saga-helpers.js | 30 +++++ examples/webui/src/app/utils/shallow-eql.js | 27 ++++ examples/webui/src/styles/accounts.less | 4 + examples/webui/src/styles/app.less | 8 ++ examples/webui/src/styles/base.less | 34 +++++ examples/webui/src/styles/blocks.less | 4 + examples/webui/src/styles/feed.less | 15 +++ examples/webui/src/styles/nav.less | 86 +++++++++++++ examples/webui/src/styles/peers.less | 8 ++ examples/webui/src/styles/transactions.less | 3 + examples/webui/src/views/index.pug | 41 +----- examples/webui/src/views/layout.pug | 7 +- examples/webui/webpack.config.js | 121 ++++++++++++++++++ 53 files changed, 1343 insertions(+), 70 deletions(-) create mode 100644 examples/webui/.eslintrc create mode 100644 examples/webui/src/app/actions/accounts.js create mode 100644 examples/webui/src/app/actions/blocks.js create mode 100644 examples/webui/src/app/actions/errors.js create mode 100644 examples/webui/src/app/actions/home.js create mode 100644 examples/webui/src/app/actions/index.js create mode 100644 examples/webui/src/app/actions/pages.js create mode 100644 examples/webui/src/app/actions/peers.js create mode 100644 examples/webui/src/app/actions/router.js create mode 100644 examples/webui/src/app/actions/transactions.js create mode 100644 examples/webui/src/app/actions/utils.js create mode 100644 examples/webui/src/app/components/accounts.js create mode 100644 examples/webui/src/app/components/blocks.js create mode 100644 examples/webui/src/app/components/feed.js create mode 100644 examples/webui/src/app/components/hash.js create mode 100644 examples/webui/src/app/components/notfound.js create mode 100644 examples/webui/src/app/components/peers.js create mode 100644 examples/webui/src/app/components/processing-status.js create mode 100644 examples/webui/src/app/components/transactions.js create mode 100644 examples/webui/src/app/containers/app.js create mode 100644 examples/webui/src/app/containers/home.js create mode 100644 examples/webui/src/app/containers/root.js create mode 100644 examples/webui/src/app/index 2.js create mode 100644 examples/webui/src/app/reducers/accounts.js create mode 100644 examples/webui/src/app/reducers/blocks.js create mode 100644 examples/webui/src/app/reducers/errors.js create mode 100644 examples/webui/src/app/reducers/index.js create mode 100644 examples/webui/src/app/reducers/peers.js create mode 100644 examples/webui/src/app/reducers/transactions.js create mode 100644 examples/webui/src/app/routes.js create mode 100644 examples/webui/src/app/services/api.js create mode 100644 examples/webui/src/app/services/index.js create mode 100644 examples/webui/src/app/store/configure-store.dev.js create mode 100644 examples/webui/src/app/store/configure-store.js create mode 100644 examples/webui/src/app/store/configure-store.prod.js create mode 100644 examples/webui/src/app/utils/file-extension.js create mode 100644 examples/webui/src/app/utils/promise.js create mode 100644 examples/webui/src/app/utils/pure.js create mode 100644 examples/webui/src/app/utils/saga-helpers.js create mode 100644 examples/webui/src/app/utils/shallow-eql.js create mode 100644 examples/webui/src/styles/accounts.less create mode 100644 examples/webui/src/styles/app.less create mode 100644 examples/webui/src/styles/base.less create mode 100644 examples/webui/src/styles/blocks.less create mode 100644 examples/webui/src/styles/feed.less create mode 100644 examples/webui/src/styles/nav.less create mode 100644 examples/webui/src/styles/peers.less create mode 100644 examples/webui/src/styles/transactions.less create mode 100644 examples/webui/webpack.config.js diff --git a/examples/webui/.eslintrc b/examples/webui/.eslintrc new file mode 100644 index 0000000..9b09463 --- /dev/null +++ b/examples/webui/.eslintrc @@ -0,0 +1,4 @@ +{ + "parser": "babel-eslint", + "extends": ["standard", "standard-react"] +} diff --git a/examples/webui/package.json b/examples/webui/package.json index a015d48..9aec0ca 100644 --- a/examples/webui/package.json +++ b/examples/webui/package.json @@ -7,14 +7,14 @@ "build-clean": "rm -r build", "build-assets": "cp -r src/assets build", "build-views": "pug src/views -o build --pretty", - "build-js": "aegir-build", - "build-css": "lessc --clean-css src/styles/page.less build/css/page.min.css", - "build": "npm run build-assets && npm run build-views && npm run build-js && npm run build-css", + "build-js": "webpack", + "build": "npm run build-assets && npm run build-views && npm run build-js", "release": "npm run build && mv build release", "serve": "static -p 9001 build", "mon": "nodemon --exec 'npm run build && npm run serve' --watch src -e js,pug,less", "test": "echo \"Error: no test specified\" && exit 1", - "sig": "star-sig --port=20000" + "sig": "star-sig --port=20000", + "lint": "eslint src/app/**/*.js" }, "keywords": [ "libp2p", @@ -24,13 +24,45 @@ "author": "David Dias ", "license": "MIT", "devDependencies": { - "aegir": "diasdavid/aegir#f655e4ac670bbec6542f7ed561f925b07778cc6c", + "babel-eslint": "^6.1.2", + "babel-loader": "^6.2.5", + "babel-polyfill": "^6.13.0", + "babel-preset-es2015": "^6.14.0", + "babel-preset-react": "^6.11.1", + "babel-preset-stage-0": "^6.5.0", + "brfs": "^1.4.3", + "css-loader": "^0.25.0", + "eslint": "^3.5.0", + "eslint-config-standard": "^6.0.1", + "eslint-config-standard-react": "^4.0.2", + "https-browserify": "0.0.1", + "json-loader": "^0.5.4", "less": "^2.7.1", + "less-loader": "^2.2.3", "less-plugin-clean-css": "^1.5.1", "libp2p-webrtc-star": "^0.4.4", "node-static": "^0.7.8", "nodemon": "^1.10.2", "pug": "^2.0.0-beta6", - "pug-cli": "^1.0.0-alpha6" + "pug-cli": "^1.0.0-alpha6", + "redux-logger": "^2.6.1", + "stream-http": "^2.4.0", + "style-loader": "^0.13.1", + "transform-loader": "^0.2.3", + "webpack": "^2.1.0-beta.23" + }, + "dependencies": { + "elemental": "^0.6.1", + "react": "^15.3.2", + "react-addons-css-transition-group": "^15.3.2", + "react-addons-shallow-compare": "^15.3.2", + "react-dom": "^15.3.2", + "react-redux": "^4.4.5", + "react-router": "^2.8.1", + "react-router-redux": "^4.0.5", + "react-tap-event-plugin": "^1.0.0", + "react-virtualized": "^8.0.5", + "redux": "^3.6.0", + "redux-thunk": "^2.1.0" } } diff --git a/examples/webui/src/app/actions/accounts.js b/examples/webui/src/app/actions/accounts.js new file mode 100644 index 0000000..9d9e0ab --- /dev/null +++ b/examples/webui/src/app/actions/accounts.js @@ -0,0 +1,43 @@ +const Account = require('ethereumjs-account') + +export const ADD_OR_UPDATE_ACCOUNT = 'ADD_OR_UPDATE_ACCOUNT' + +export function received (coinbase, account) { + return { + type: ADD_OR_UPDATE_ACCOUNT, + id: coinbase, + account: account, + status: 'received' + } +} + +export function processed (coinbase, account) { + return { + type: ADD_OR_UPDATE_ACCOUNT, + id: coinbase, + account: account, + status: 'processed' + } +} + +export function before (node, coinbase) { + return (dispatch) => { + node.vm.trie.get(coinbase, (err, account) => { + if (err) { + return console.error(err) + } + dispatch(received(coinbase, new Account(account))) + }) + } +} + +export function after (node, coinbase) { + return (dispatch) => { + node.vm.trie.get(coinbase, (err, account) => { + if (err) { + return console.error(err) + } + dispatch(processed(new Account(coinbase, account))) + }) + } +} diff --git a/examples/webui/src/app/actions/blocks.js b/examples/webui/src/app/actions/blocks.js new file mode 100644 index 0000000..d77538f --- /dev/null +++ b/examples/webui/src/app/actions/blocks.js @@ -0,0 +1,17 @@ +export const ADD_BLOCK = 'ADD_BLOCK' + +export function addBefore (block) { + return { + type: ADD_BLOCK, + block: block, + status: 'received' + } +} + +export function addAfter (block) { + return { + type: ADD_BLOCK, + block: block, + status: 'processed' + } +} diff --git a/examples/webui/src/app/actions/errors.js b/examples/webui/src/app/actions/errors.js new file mode 100644 index 0000000..b0856ee --- /dev/null +++ b/examples/webui/src/app/actions/errors.js @@ -0,0 +1,5 @@ +import {action} from './utils' + +export const RESET_ERROR_MESSAGE = 'RESET_ERROR_MESSAGE' + +export const resetErrorMessage = () => action(RESET_ERROR_MESSAGE) diff --git a/examples/webui/src/app/actions/home.js b/examples/webui/src/app/actions/home.js new file mode 100644 index 0000000..7fefeab --- /dev/null +++ b/examples/webui/src/app/actions/home.js @@ -0,0 +1,51 @@ +import ethereum from '../../../../../src' +import * as blocks from './blocks' +import * as accounts from './accounts' +import * as peers from './peers' +let node + +function startNode () { + const _node = new ethereum.Node() + return new Promise((resolve, reject) => { + _node.start((err) => { + if (err) { + return reject(err) + } + resolve(_node) + }) + }) +} + +export function start () { + return (dispatch, getState) => { + return startNode().then((_node) => { + node = _node + + node.vm.on('beforeBlock', (block, cb) => { + dispatch(blocks.addBefore(block)) + dispatch(accounts.before(node, block.header.coinbase)) + cb() + }) + + node.vm.on('afterBlock', (block, cb) => { + dispatch(blocks.addAfter(block)) + dispatch(accounts.after(node, block.header.coinbase)) + cb() + }) + + // TODO: connect to peer-connected and peer-disconnected + const onPeerConnected = (peer) => { + dispatch(peers.add(peer)) + } + const onPeerDisconnected = (peer) => { + dispatch(peers.remove(peer)) + } + }) + } +} + +export function stop () { + node.stop() + + return Promise.resolve() +} diff --git a/examples/webui/src/app/actions/index.js b/examples/webui/src/app/actions/index.js new file mode 100644 index 0000000..c22f9aa --- /dev/null +++ b/examples/webui/src/app/actions/index.js @@ -0,0 +1,24 @@ +// Broken because of https://phabricator.babeljs.io/T2877 +// export * from './pages' +// export * from './errors' + +// export * from './home' + +// Workaround + +import * as errors from './errors' +import * as router from './router' + +import * as home from './home' +import * as accounts from './accounts' +import * as blocks from './blocks' +import * as peers from './peers' +import * as transactions from './transactions' + +export {errors} +export {router} +export {home} +export {accounts} +export {blocks} +export {peers} +export {transactions} diff --git a/examples/webui/src/app/actions/pages.js b/examples/webui/src/app/actions/pages.js new file mode 100644 index 0000000..1fc30c1 --- /dev/null +++ b/examples/webui/src/app/actions/pages.js @@ -0,0 +1,3 @@ +import {createPage} from './utils' + +export const {HOME, home} = createPage('home') diff --git a/examples/webui/src/app/actions/peers.js b/examples/webui/src/app/actions/peers.js new file mode 100644 index 0000000..9f4f31c --- /dev/null +++ b/examples/webui/src/app/actions/peers.js @@ -0,0 +1,5 @@ +export function add (peer) { +} + +export function remove (peer) { +} diff --git a/examples/webui/src/app/actions/router.js b/examples/webui/src/app/actions/router.js new file mode 100644 index 0000000..dd91c14 --- /dev/null +++ b/examples/webui/src/app/actions/router.js @@ -0,0 +1,3 @@ +import {push, replace, go, goBack, goForward} from 'react-router-redux' + +export {push, replace, go, goBack, goForward} diff --git a/examples/webui/src/app/actions/transactions.js b/examples/webui/src/app/actions/transactions.js new file mode 100644 index 0000000..f4b9f84 --- /dev/null +++ b/examples/webui/src/app/actions/transactions.js @@ -0,0 +1,17 @@ +export const ADD_OR_UPDATE_TRANSACTION = 'ADD_OR_UPDATE_TRANSACTION' + +export function add (tx) { + return { + type: ADD_OR_UPDATE_TRANSACTION, + tx: tx, + status: 'received' + } +} + +export function processed (tx) { + return { + type: ADD_OR_UPDATE_TRANSACTION, + tx: tx, + status: 'processed' + } +} diff --git a/examples/webui/src/app/actions/utils.js b/examples/webui/src/app/actions/utils.js new file mode 100644 index 0000000..e2c9d7d --- /dev/null +++ b/examples/webui/src/app/actions/utils.js @@ -0,0 +1,39 @@ +const REQUEST = 'REQUEST' +const SUCCESS = 'SUCCESS' +const FAILURE = 'FAILURE' + +export function createRequestTypes (base) { + const res = {} + const types = [REQUEST, SUCCESS, FAILURE] + types.forEach((type) => { + res[type] = `${base}_${type}` + }) + + return res +} + +export function action (type, payload = {}) { + return {type, ...payload} +} + +function createPageConstants (name) { + return { + LOAD: `LOAD_${name.toUpperCase()}_PAGE`, + LEAVE: `LEAVE_${name.toUpperCase()}_PAGE` + } +} + +function createPageActions (name, consts) { + return { + load: () => action(consts.LOAD), + leave: () => action(consts.LEAVE) + } +} + +export function createPage (name) { + const consts = createPageConstants(name) + return { + [name.toUpperCase()]: consts, + [name]: createPageActions(name, consts) + } +} diff --git a/examples/webui/src/app/components/accounts.js b/examples/webui/src/app/components/accounts.js new file mode 100644 index 0000000..ceabf23 --- /dev/null +++ b/examples/webui/src/app/components/accounts.js @@ -0,0 +1,58 @@ +import React, {Component, PropTypes} from 'react' +import {Col, Glyph, Spinner} from 'elemental' +import {AutoSizer, List} from 'react-virtualized' + +import ProcessingStatus from './processing-status' + +export default class Accounts extends Component { + static propTypes = { + feed: PropTypes.object.isRequired + }; + + _renderAccount = ({key, index}) => { + const hash = this._feedValues[index] + const item = this.props.feed[hash] + + return ( +
+ {hash}: {item.account.balance}Ether
+ Status: +
+ ) + } + + render () { + let feed = ( +
+ +
+ Loading your accounts +
+ ) + + this._feedValues = Object.keys(this.props.feed) + if (this._feedValues && this._feedValues.length > 0) { + feed = ( + + {({ height, width }) => ( + + )} + + ) + } + return ( + +

Accounts

+
+ {feed} +
+ + ) + } +} diff --git a/examples/webui/src/app/components/blocks.js b/examples/webui/src/app/components/blocks.js new file mode 100644 index 0000000..52b099f --- /dev/null +++ b/examples/webui/src/app/components/blocks.js @@ -0,0 +1,69 @@ +import React, {Component, PropTypes} from 'react' +import {Col, Glyph, Spinner} from 'elemental' +import {AutoSizer, List} from 'react-virtualized' +import {bufferToInt} from 'ethereumjs-util' + +import ProcessingStatus from './processing-status' +import Hash from './hash' + +function formatDate (buf) { + const ts = bufferToInt(buf) + const date = new Date(ts) + return date.toLocaleString() +} + +export default class Blocks extends Component { + static propTypes = { + feed: PropTypes.object.isRequired + }; + + _renderBlock = ({key, index, style}) => { + const hash = this._feedValues[index] + const item = this.props.feed[hash] + const block = item.block + + return ( +
+ Number: {block.header.number}
+ Parent:
+ Time: {formatDate(block.header.timestamp)}
+ Status: +
+ ) + } + + render () { + let feed = ( +
+ +
+ Loading your blocks +
+ ) + + this._feedValues = Object.keys(this.props.feed) + if (this._feedValues && this._feedValues.length > 0) { + feed = ( + + {({ height, width }) => ( + + )} + + ) + } + return ( + +

Blocks

+
+ {feed} +
+ + ) + } +} diff --git a/examples/webui/src/app/components/feed.js b/examples/webui/src/app/components/feed.js new file mode 100644 index 0000000..715ec55 --- /dev/null +++ b/examples/webui/src/app/components/feed.js @@ -0,0 +1,67 @@ +import React, {Component, PropTypes} from 'react' +import {Card, Row, Col, Button, Glyph, Spinner} from 'elemental' +import {Link} from 'react-router' + +export default class Feed extends Component { + static propTypes = { + feed: PropTypes.array.isRequired + }; + + _renderCard = (item) => { + return ( + + + + + + {item.title} + {item.paper ? : ''} + + + + + by {item.author} + + + {item.year ? ( + + + published in {item.year} + + + ) : ''} + + +