Merge remote-tracking branch 'origin/master' into fix-tx-rpc
This commit is contained in:
commit
63c28253d8
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1263,7 +1263,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-ui-precompiled"
|
name = "parity-ui-precompiled"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "git+https://github.com/ethcore/js-precompiled.git#7cb42b0c636f76eb478c9270a1e507ac3c3ba434"
|
source = "git+https://github.com/ethcore/js-precompiled.git#cb6836dddf8c9951e056283dcd9e105e97923d07"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
use endpoint::EndpointInfo;
|
use endpoint::EndpointInfo;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -54,6 +55,7 @@ impl Into<EndpointInfo> for App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ApiError {
|
pub struct ApiError {
|
||||||
pub code: String,
|
pub code: String,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
@ -3,6 +3,7 @@ WORKDIR /build
|
|||||||
# install tools and dependencies
|
# install tools and dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y \
|
apt-get install -y \
|
||||||
|
build-essential \
|
||||||
g++ \
|
g++ \
|
||||||
curl \
|
curl \
|
||||||
git \
|
git \
|
||||||
|
@ -4,6 +4,7 @@ WORKDIR /build
|
|||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y \
|
apt-get install -y \
|
||||||
g++ \
|
g++ \
|
||||||
|
build-essential \
|
||||||
curl \
|
curl \
|
||||||
git \
|
git \
|
||||||
file \
|
file \
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"presets": ["es2017", "es2016", "es2015", "stage-0", "react"],
|
"presets": [
|
||||||
|
"es2017", "es2016", "es2015",
|
||||||
|
"stage-0", "react"
|
||||||
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"transform-runtime",
|
"transform-runtime",
|
||||||
"transform-decorators-legacy",
|
"transform-decorators-legacy",
|
||||||
@ -10,6 +13,9 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"production": {
|
"production": {
|
||||||
"plugins": ["transform-react-remove-prop-types"]
|
"plugins": ["transform-react-remove-prop-types"]
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"plugins": ["react-hot-loader/babel"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
"no-debugger": "error",
|
"no-debugger": "error",
|
||||||
"no-alert": "error",
|
"no-alert": "error",
|
||||||
"jsx-quotes": ["error", "prefer-single"],
|
"jsx-quotes": ["error", "prefer-single"],
|
||||||
"react/jsx-curly-spacing": ["error", "always"]
|
"react/jsx-curly-spacing": ["error", "always"],
|
||||||
|
"object-property-newline": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
227
js/package.json
227
js/package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "parity.js",
|
"name": "parity.js",
|
||||||
"version": "0.2.74",
|
"version": "0.2.78",
|
||||||
"main": "release/index.js",
|
"main": "release/index.js",
|
||||||
"jsnext:main": "src/index.js",
|
"jsnext:main": "src/index.js",
|
||||||
"author": "Parity Team <admin@parity.io>",
|
"author": "Parity Team <admin@parity.io>",
|
||||||
@ -26,16 +26,16 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run build:lib && npm run build:dll && npm run build:app",
|
"build": "npm run build:lib && npm run build:dll && npm run build:app",
|
||||||
"build:app": "webpack --progress",
|
"build:app": "webpack --config webpack/app --progress",
|
||||||
"build:lib": "webpack --config webpack.libraries --progress",
|
"build:lib": "webpack --config webpack/libraries --progress",
|
||||||
"build:dll": "webpack --config webpack.vendor --progress",
|
"build:dll": "webpack --config webpack/vendor --progress",
|
||||||
"ci:build": "npm run ci:build:lib && npm run ci:build:dll && npm run ci:build:app",
|
"ci:build": "npm run ci:build:lib && npm run ci:build:dll && npm run ci:build:app",
|
||||||
"ci:build:app": "NODE_ENV=production webpack",
|
"ci:build:app": "NODE_ENV=production webpack --config webpack/app",
|
||||||
"ci:build:lib": "NODE_ENV=production webpack --config webpack.libraries",
|
"ci:build:lib": "NODE_ENV=production webpack --config webpack/libraries",
|
||||||
"ci:build:dll": "NODE_ENV=production webpack --config webpack.vendor",
|
"ci:build:dll": "NODE_ENV=production webpack --config webpack/vendor",
|
||||||
"ci:build:npm": "NODE_ENV=production webpack --config webpack.npm",
|
"ci:build:npm": "NODE_ENV=production webpack --config webpack/npm",
|
||||||
"start": "npm install && npm run build:lib && npm run build:dll && npm run start:app",
|
"start": "npm install && npm run build:lib && npm run build:dll && npm run start:app",
|
||||||
"start:app": "webpack-dev-server -d --history-api-fallback --open --hot --inline --progress --colors --port 3000",
|
"start:app": "node webpack/dev.server",
|
||||||
"clean": "rm -rf ./build ./coverage",
|
"clean": "rm -rf ./build ./coverage",
|
||||||
"coveralls": "npm run testCoverage && coveralls < coverage/lcov.info",
|
"coveralls": "npm run testCoverage && coveralls < coverage/lcov.info",
|
||||||
"lint": "eslint --ignore-path .gitignore ./src/",
|
"lint": "eslint --ignore-path .gitignore ./src/",
|
||||||
@ -47,127 +47,132 @@
|
|||||||
"prepush": "npm run lint:cached"
|
"prepush": "npm run lint:cached"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.10.1",
|
"babel-cli": "~6.18.0",
|
||||||
"babel-core": "^6.10.4",
|
"babel-core": "~6.18.2",
|
||||||
"babel-eslint": "^7.1.0",
|
"babel-eslint": "~7.1.0",
|
||||||
"babel-loader": "^6.2.3",
|
"babel-loader": "~6.2.3",
|
||||||
"babel-plugin-lodash": "^3.2.2",
|
"babel-plugin-lodash": "~3.2.2",
|
||||||
"babel-plugin-transform-class-properties": "^6.11.5",
|
"babel-plugin-transform-class-properties": "~6.19.0",
|
||||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
"babel-plugin-transform-decorators-legacy": "~1.3.4",
|
||||||
"babel-plugin-transform-react-remove-prop-types": "^0.2.9",
|
"babel-plugin-transform-react-remove-prop-types": "~0.2.9",
|
||||||
"babel-plugin-transform-runtime": "^6.9.0",
|
"babel-plugin-transform-runtime": "~6.15.0",
|
||||||
"babel-polyfill": "^6.13.0",
|
"babel-polyfill": "~6.16.0",
|
||||||
"babel-preset-es2015": "^6.9.0",
|
"babel-preset-es2015": "~6.18.0",
|
||||||
"babel-preset-es2015-rollup": "^1.1.1",
|
"babel-preset-es2015-rollup": "~1.2.0",
|
||||||
"babel-preset-es2016": "^6.11.3",
|
"babel-preset-es2016": "~6.16.0",
|
||||||
"babel-preset-es2017": "^6.14.0",
|
"babel-preset-es2017": "~6.16.0",
|
||||||
"babel-preset-react": "^6.5.0",
|
"babel-preset-react": "~6.16.0",
|
||||||
"babel-preset-stage-0": "^6.5.0",
|
"babel-preset-stage-0": "~6.16.0",
|
||||||
"babel-register": "6.9.0",
|
"babel-register": "6.18.0",
|
||||||
"babel-runtime": "^6.9.2",
|
"babel-runtime": "~6.18.0",
|
||||||
"chai": "^3.5.0",
|
"chai": "~3.5.0",
|
||||||
"chai-enzyme": "0.4.2",
|
"chai-enzyme": "0.4.2",
|
||||||
"cheerio": "0.20.0",
|
"cheerio": "0.20.0",
|
||||||
"copy-webpack-plugin": "^4.0.0",
|
"copy-webpack-plugin": "~4.0.0",
|
||||||
"core-js": "^2.4.1",
|
"core-js": "~2.4.1",
|
||||||
"coveralls": "^2.11.11",
|
"coveralls": "~2.11.11",
|
||||||
"css-loader": "^0.23.1",
|
"css-loader": "~0.26.0",
|
||||||
"enzyme": "2.3.0",
|
"enzyme": "2.3.0",
|
||||||
"eslint": "^3.1.0",
|
"eslint": "~3.10.2",
|
||||||
"eslint-config-semistandard": "^6.0.2",
|
"eslint-config-semistandard": "~7.0.0",
|
||||||
"eslint-config-standard": "^5.3.5",
|
"eslint-config-standard": "~6.2.1",
|
||||||
"eslint-config-standard-react": "^3.0.0",
|
"eslint-config-standard-react": "~4.2.0",
|
||||||
"eslint-plugin-promise": "^2.0.0",
|
"eslint-plugin-promise": "~3.4.0",
|
||||||
"eslint-plugin-react": "^5.1.1",
|
"eslint-plugin-react": "~6.7.1",
|
||||||
"eslint-plugin-standard": "^2.0.0",
|
"eslint-plugin-standard": "~2.0.0",
|
||||||
"extract-loader": "0.0.2",
|
"express": "~4.14.0",
|
||||||
"extract-text-webpack-plugin": "^1.0.1",
|
"extract-loader": "0.1.0",
|
||||||
"file-loader": "^0.8.5",
|
"extract-text-webpack-plugin": "~2.0.0-beta.4",
|
||||||
"fs-extra": "^0.30.0",
|
"file-loader": "~0.9.0",
|
||||||
"happypack": "^2.2.1",
|
"fs-extra": "~0.30.0",
|
||||||
"history": "^2.0.0",
|
"happypack": "~3.0.0",
|
||||||
"html-loader": "^0.4.4",
|
"history": "~2.0.0",
|
||||||
"husky": "^0.11.9",
|
"html-loader": "~0.4.4",
|
||||||
|
"html-webpack-plugin": "~2.24.1",
|
||||||
|
"http-proxy-middleware": "~0.17.2",
|
||||||
|
"husky": "~0.11.9",
|
||||||
"ignore-styles": "2.0.0",
|
"ignore-styles": "2.0.0",
|
||||||
"image-webpack-loader": "^1.8.0",
|
"image-webpack-loader": "~3.0.0",
|
||||||
"istanbul": "^1.0.0-alpha.2",
|
"istanbul": "~1.0.0-alpha.2",
|
||||||
"jsdom": "9.2.1",
|
"jsdom": "9.2.1",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "~0.5.4",
|
||||||
"mocha": "^3.0.0-1",
|
"mocha": "~3.0.0-1",
|
||||||
"mock-local-storage": "1.0.2",
|
"mock-local-storage": "1.0.2",
|
||||||
"mock-socket": "^3.0.1",
|
"mock-socket": "~3.0.1",
|
||||||
"nock": "^8.0.0",
|
"nock": "~8.0.0",
|
||||||
"postcss-import": "^8.1.2",
|
"postcss-import": "8.1.0",
|
||||||
"postcss-loader": "^0.8.1",
|
"postcss-loader": "~1.1.1",
|
||||||
"postcss-nested": "^1.0.0",
|
"postcss-nested": "~1.0.0",
|
||||||
"postcss-simple-vars": "^3.0.0",
|
"postcss-simple-vars": "~3.0.0",
|
||||||
"raw-loader": "^0.5.1",
|
"progress": "~1.1.8",
|
||||||
|
"raw-loader": "~0.5.1",
|
||||||
"react-addons-perf": "~15.3.2",
|
"react-addons-perf": "~15.3.2",
|
||||||
"react-addons-test-utils": "~15.3.2",
|
"react-addons-test-utils": "~15.3.2",
|
||||||
"react-copy-to-clipboard": "^4.2.3",
|
|
||||||
"react-dom": "~15.3.2",
|
"react-dom": "~15.3.2",
|
||||||
"react-hot-loader": "~1.3.0",
|
"react-hot-loader": "~3.0.0-beta.6",
|
||||||
"rucksack-css": "^0.8.6",
|
"rucksack-css": "~0.8.6",
|
||||||
"sinon": "^1.17.4",
|
"sinon": "~1.17.4",
|
||||||
"sinon-as-promised": "^4.0.2",
|
"sinon-as-promised": "~4.0.2",
|
||||||
"sinon-chai": "^2.8.0",
|
"sinon-chai": "~2.8.0",
|
||||||
"style-loader": "^0.13.0",
|
"style-loader": "~0.13.0",
|
||||||
"url-loader": "^0.5.7",
|
"url-loader": "~0.5.7",
|
||||||
"webpack": "^1.13.2",
|
"webpack": "~2.1.0-beta.27",
|
||||||
"webpack-dev-server": "^1.15.2",
|
"webpack-dev-middleware": "~1.8.4",
|
||||||
"webpack-error-notification": "0.1.6",
|
"webpack-error-notification": "0.1.6",
|
||||||
"webpack-hot-middleware": "~2.13.2",
|
"webpack-hot-middleware": "~2.13.2",
|
||||||
"websocket": "^1.0.23"
|
"websocket": "~1.0.23"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bignumber.js": "^2.3.0",
|
"bignumber.js": "~2.3.0",
|
||||||
"blockies": "0.0.2",
|
"blockies": "0.0.2",
|
||||||
"brace": "^0.9.0",
|
"brace": "~0.9.0",
|
||||||
"bytes": "^2.4.0",
|
"bytes": "~2.4.0",
|
||||||
"chart.js": "^2.3.0",
|
"chart.js": "~2.3.0",
|
||||||
"es6-error": "^4.0.0",
|
"es6-error": "~4.0.0",
|
||||||
"es6-promise": "^3.2.1",
|
"es6-promise": "~3.2.1",
|
||||||
"ethereumjs-tx": "^1.1.2",
|
"ethereumjs-tx": "~1.1.2",
|
||||||
"file-saver": "^1.3.3",
|
"eventemitter3": "~2.0.2",
|
||||||
"format-json": "^1.0.3",
|
"file-saver": "~1.3.3",
|
||||||
"format-number": "^2.0.1",
|
"format-json": "~1.0.3",
|
||||||
"geopattern": "^1.2.3",
|
"format-number": "~2.0.1",
|
||||||
"isomorphic-fetch": "^2.2.1",
|
"geopattern": "~1.2.3",
|
||||||
"js-sha3": "^0.5.2",
|
"isomorphic-fetch": "~2.2.1",
|
||||||
"lodash": "^4.11.1",
|
"js-sha3": "~0.5.2",
|
||||||
"marked": "^0.3.6",
|
"lodash": "~4.11.1",
|
||||||
|
"marked": "~0.3.6",
|
||||||
"material-ui": "0.16.1",
|
"material-ui": "0.16.1",
|
||||||
"material-ui-chip-input": "^0.8.0",
|
"material-ui-chip-input": "~0.8.0",
|
||||||
"mobx": "^2.6.1",
|
"mobx": "~2.6.1",
|
||||||
"mobx-react": "^3.5.8",
|
"mobx-react": "~3.5.8",
|
||||||
"mobx-react-devtools": "^4.2.9",
|
"mobx-react-devtools": "~4.2.9",
|
||||||
"moment": "^2.14.1",
|
"moment": "~2.14.1",
|
||||||
"phoneformat.js": "^1.0.3",
|
"phoneformat.js": "~1.0.3",
|
||||||
"qs": "^6.3.0",
|
"qs": "~6.3.0",
|
||||||
"react": "~15.3.2",
|
"react": "~15.3.2",
|
||||||
"react-ace": "^4.0.0",
|
"react-ace": "~4.0.0",
|
||||||
"react-addons-css-transition-group": "~15.3.2",
|
"react-addons-css-transition-group": "~15.3.2",
|
||||||
"react-chartjs-2": "^1.5.0",
|
"react-chartjs-2": "~1.5.0",
|
||||||
|
"react-copy-to-clipboard": "~4.2.3",
|
||||||
"react-dom": "~15.3.2",
|
"react-dom": "~15.3.2",
|
||||||
"react-dropzone": "^3.7.3",
|
"react-dropzone": "~3.7.3",
|
||||||
"react-redux": "^4.4.5",
|
"react-redux": "~4.4.5",
|
||||||
"react-router": "^2.6.1",
|
"react-router": "~2.6.1",
|
||||||
"react-router-redux": "^4.0.5",
|
"react-router-redux": "~4.0.5",
|
||||||
"react-tap-event-plugin": "~1.0.0",
|
"react-tap-event-plugin": "~1.0.0",
|
||||||
"react-tooltip": "^2.0.3",
|
"react-tooltip": "~2.0.3",
|
||||||
"recharts": "^0.15.2",
|
"recharts": "~0.15.2",
|
||||||
"redux": "^3.5.2",
|
"redux": "~3.5.2",
|
||||||
"redux-actions": "^0.10.1",
|
"redux-actions": "~0.10.1",
|
||||||
"redux-thunk": "^2.1.0",
|
"redux-thunk": "~2.1.0",
|
||||||
"rlp": "^2.0.0",
|
"rlp": "~2.0.0",
|
||||||
"scryptsy": "^2.0.0",
|
"scryptsy": "~2.0.0",
|
||||||
"solc": "ngotchac/solc-js",
|
"solc": "ngotchac/solc-js",
|
||||||
"store": "^1.3.20",
|
"store": "~1.3.20",
|
||||||
"utf8": "^2.1.1",
|
"utf8": "~2.1.1",
|
||||||
"valid-url": "^1.0.9",
|
"valid-url": "~1.0.9",
|
||||||
"validator": "^5.7.0",
|
"validator": "~5.7.0",
|
||||||
"web3": "^0.17.0-beta",
|
"web3": "~0.17.0-beta",
|
||||||
"whatwg-fetch": "^1.0.0",
|
"whatwg-fetch": "~1.0.0",
|
||||||
"worker-loader": "^0.7.1"
|
"worker-loader": "~0.7.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
js/src/3rdparty/sms-verification/index.js
vendored
5
js/src/3rdparty/sms-verification/index.js
vendored
@ -27,9 +27,10 @@ export const termsOfService = (
|
|||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const postToServer = (query) => {
|
export const postToServer = (query, isTestnet = false) => {
|
||||||
|
const port = isTestnet ? 8443 : 443;
|
||||||
query = stringify(query);
|
query = stringify(query);
|
||||||
return fetch('https://sms-verification.parity.io/?' + query, {
|
return fetch(`https://sms-verification.parity.io:${port}/?` + query, {
|
||||||
method: 'POST', mode: 'cors', cache: 'no-store'
|
method: 'POST', mode: 'cors', cache: 'no-store'
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@ -15,16 +15,16 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import Abi from '../../abi';
|
import Abi from '../../abi';
|
||||||
import Api from '../api';
|
|
||||||
import { isInstanceOf } from '../util/types';
|
|
||||||
|
|
||||||
let nextSubscriptionId = 0;
|
let nextSubscriptionId = 0;
|
||||||
|
|
||||||
export default class Contract {
|
export default class Contract {
|
||||||
constructor (api, abi) {
|
constructor (api, abi) {
|
||||||
if (!isInstanceOf(api, Api)) {
|
if (!api) {
|
||||||
throw new Error('API instance needs to be provided to Contract');
|
throw new Error('API instance needs to be provided to Contract');
|
||||||
} else if (!abi) {
|
}
|
||||||
|
|
||||||
|
if (!abi) {
|
||||||
throw new Error('ABI needs to be provided to Contract instance');
|
throw new Error('ABI needs to be provided to Contract instance');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
import { isArray, isHex, isInstanceOf, isString } from '../util/types';
|
import { isArray, isHex, isInstanceOf, isString } from '../util/types';
|
||||||
import { padLeft } from '../util/format';
|
import { padLeft, toHex } from '../util/format';
|
||||||
|
|
||||||
export function inAddress (address) {
|
export function inAddress (address) {
|
||||||
// TODO: address validation if we have upper-lower addresses
|
// TODO: address validation if we have upper-lower addresses
|
||||||
@ -100,15 +100,7 @@ export function inFilter (options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function inHex (str) {
|
export function inHex (str) {
|
||||||
if (str && str.toString) {
|
return toHex(str);
|
||||||
str = str.toString(16);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str && str.substr(0, 2) === '0x') {
|
|
||||||
return str.toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
return `0x${(str || '').toLowerCase()}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function inNumber10 (number) {
|
export function inNumber10 (number) {
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { range } from 'lodash';
|
import { range } from 'lodash';
|
||||||
import { inHex } from '../format/input';
|
|
||||||
|
|
||||||
export function bytesToHex (bytes) {
|
export function bytesToHex (bytes) {
|
||||||
return '0x' + bytes.map((b) => ('0' + b.toString(16)).slice(-2)).join('');
|
return '0x' + bytes.map((b) => ('0' + b.toString(16)).slice(-2)).join('');
|
||||||
@ -38,11 +37,23 @@ export function asciiToHex (string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function padRight (input, length) {
|
export function padRight (input, length) {
|
||||||
const value = inHex(input).substr(2, length * 2);
|
const value = toHex(input).substr(2, length * 2);
|
||||||
return '0x' + value + range(length * 2 - value.length).map(() => '0').join('');
|
return '0x' + value + range(length * 2 - value.length).map(() => '0').join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function padLeft (input, length) {
|
export function padLeft (input, length) {
|
||||||
const value = inHex(input).substr(2, length * 2);
|
const value = toHex(input).substr(2, length * 2);
|
||||||
return '0x' + range(length * 2 - value.length).map(() => '0').join('') + value;
|
return '0x' + range(length * 2 - value.length).map(() => '0').join('') + value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toHex (str) {
|
||||||
|
if (str && str.toString) {
|
||||||
|
str = str.toString(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str && str.substr(0, 2) === '0x') {
|
||||||
|
return str.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return `0x${(str || '').toLowerCase()}`;
|
||||||
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]
|
[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]
|
||||||
|
@ -19,7 +19,7 @@ import Registry from './registry';
|
|||||||
import SignatureReg from './signaturereg';
|
import SignatureReg from './signaturereg';
|
||||||
import TokenReg from './tokenreg';
|
import TokenReg from './tokenreg';
|
||||||
import GithubHint from './githubhint';
|
import GithubHint from './githubhint';
|
||||||
import smsVerification from './sms-verification';
|
import * as smsVerification from './sms-verification';
|
||||||
|
|
||||||
let instance = null;
|
let instance = null;
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import subscribeToEvent from '../util/subscribe-to-event';
|
||||||
|
|
||||||
export const checkIfVerified = (contract, account) => {
|
export const checkIfVerified = (contract, account) => {
|
||||||
return contract.instance.certified.call({}, [account]);
|
return contract.instance.certified.call({}, [account]);
|
||||||
};
|
};
|
||||||
@ -50,3 +52,36 @@ export const checkIfRequested = (contract, account) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const blockNumber = (api) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
api.subscribe('eth_blockNumber', (err, block) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
resolve(block);
|
||||||
|
})
|
||||||
|
.then((subscription) => {
|
||||||
|
api.unsubscribe(subscription);
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const awaitPuzzle = (api, contract, account) => {
|
||||||
|
return blockNumber(api)
|
||||||
|
.then((block) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const subscription = subscribeToEvent(contract, 'Puzzled', {
|
||||||
|
from: block.toNumber(),
|
||||||
|
filter: (log) => log.params.who.value === account
|
||||||
|
});
|
||||||
|
subscription.once('error', reject);
|
||||||
|
subscription.once('log', subscription.unsubscribe);
|
||||||
|
subscription.once('log', resolve);
|
||||||
|
subscription.once('timeout', () => {
|
||||||
|
reject(new Error('Timed out waiting for the puzzle.'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
|
||||||
<title>Basic Token Deployment</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container"></div>
|
|
||||||
<script src="vendor.js"></script>
|
|
||||||
<script src="commons.js"></script>
|
|
||||||
<script src="/parity-utils/parity.js"></script>
|
|
||||||
<script src="basiccoin.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -32,7 +32,6 @@ const routerHistory = useRouterHistory(createHashHistory)({});
|
|||||||
import '../../assets/fonts/Roboto/font.css';
|
import '../../assets/fonts/Roboto/font.css';
|
||||||
import '../../assets/fonts/RobotoMono/font.css';
|
import '../../assets/fonts/RobotoMono/font.css';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import './basiccoin.html';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Router history={ routerHistory }>
|
<Router history={ routerHistory }>
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
|
||||||
<title>Dapp Registry</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container"></div>
|
|
||||||
<script src="vendor.js"></script>
|
|
||||||
<script src="commons.js"></script>
|
|
||||||
<script src="/parity-utils/parity.js"></script>
|
|
||||||
<script src="dappreg.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -27,7 +27,6 @@ import Application from './dappreg/Application';
|
|||||||
import '../../assets/fonts/Roboto/font.css';
|
import '../../assets/fonts/Roboto/font.css';
|
||||||
import '../../assets/fonts/RobotoMono/font.css';
|
import '../../assets/fonts/RobotoMono/font.css';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import './dappreg.html';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Application />,
|
<Application />,
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
|
||||||
<title>GitHub Hint</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container"></div>
|
|
||||||
<script src="vendor.js"></script>
|
|
||||||
<script src="commons.js"></script>
|
|
||||||
<script src="githubhint.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -25,7 +25,6 @@ import Application from './githubhint/Application';
|
|||||||
import '../../assets/fonts/Roboto/font.css';
|
import '../../assets/fonts/Roboto/font.css';
|
||||||
import '../../assets/fonts/RobotoMono/font.css';
|
import '../../assets/fonts/RobotoMono/font.css';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import './githubhint.html';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Application />,
|
<Application />,
|
||||||
|
42
js/src/dapps/index.ejs
Normal file
42
js/src/dapps/index.ejs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
<style>
|
||||||
|
html, body, #container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
font-family: Roboto;
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<div class="loading-container">
|
||||||
|
<span class="loading">Loading...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="vendor.js"></script>
|
||||||
|
<% if (!htmlWebpackPlugin.options.secure) { %>
|
||||||
|
<script src="/parity-utils/parity.js"></script>
|
||||||
|
<% } %>
|
||||||
|
</body>
|
||||||
|
</html>
|
25
js/src/dapps/index.js
Normal file
25
js/src/dapps/index.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{ name: 'basiccoin', entry: 'basiccoin.js', title: 'Basic Token Deployment' },
|
||||||
|
{ name: 'dappreg', entry: 'dappreg.js', title: 'Dapp Registry' },
|
||||||
|
{ name: 'githubhint', entry: 'githubhint.js', title: 'GitHub Hint', secure: true },
|
||||||
|
{ name: 'localtx', entry: 'localtx.js', title: 'Local transactions Viewer', secure: true },
|
||||||
|
{ name: 'registry', entry: 'registry.js', title: 'Registry' },
|
||||||
|
{ name: 'signaturereg', entry: 'signaturereg.js', title: 'Method Signature Registry' },
|
||||||
|
{ name: 'tokenreg', entry: 'tokenreg.js', title: 'Token Registry' }
|
||||||
|
];
|
@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
|
||||||
<title>Local transactions Viewer</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container"></div>
|
|
||||||
<script src="vendor.js"></script>
|
|
||||||
<script src="commons.js"></script>
|
|
||||||
<script src="/parity-utils/parity.js"></script>
|
|
||||||
<script src="localtx.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -25,7 +25,6 @@ import Application from './localtx/Application';
|
|||||||
import '../../assets/fonts/Roboto/font.css';
|
import '../../assets/fonts/Roboto/font.css';
|
||||||
import '../../assets/fonts/RobotoMono/font.css';
|
import '../../assets/fonts/RobotoMono/font.css';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import './localtx.html';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Application />,
|
<Application />,
|
||||||
|
@ -110,7 +110,7 @@ export class Transaction extends BaseTransaction {
|
|||||||
static renderHeader () {
|
static renderHeader () {
|
||||||
return (
|
return (
|
||||||
<tr className={ styles.header }>
|
<tr className={ styles.header }>
|
||||||
<th></th>
|
<th />
|
||||||
<th>
|
<th>
|
||||||
Transaction
|
Transaction
|
||||||
</th>
|
</th>
|
||||||
@ -129,8 +129,7 @@ export class Transaction extends BaseTransaction {
|
|||||||
<th>
|
<th>
|
||||||
# Propagated
|
# Propagated
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th />
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -201,7 +200,7 @@ export class LocalTransaction extends BaseTransaction {
|
|||||||
static renderHeader () {
|
static renderHeader () {
|
||||||
return (
|
return (
|
||||||
<tr className={ styles.header }>
|
<tr className={ styles.header }>
|
||||||
<th></th>
|
<th />
|
||||||
<th>
|
<th>
|
||||||
Transaction
|
Transaction
|
||||||
</th>
|
</th>
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
|
||||||
<title>Token Registry</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container"></div>
|
|
||||||
<script src="vendor.js"></script>
|
|
||||||
<script src="commons.js"></script>
|
|
||||||
<script src="/parity-utils/parity.js"></script>
|
|
||||||
<script src="registry.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -27,7 +27,6 @@ import Container from './registry/Container';
|
|||||||
import '../../assets/fonts/Roboto/font.css';
|
import '../../assets/fonts/Roboto/font.css';
|
||||||
import '../../assets/fonts/RobotoMono/font.css';
|
import '../../assets/fonts/RobotoMono/font.css';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import './registry.html';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store={ store }>
|
<Provider store={ store }>
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
|
||||||
<title>Method Signature Registry</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container"></div>
|
|
||||||
<script src="vendor.js"></script>
|
|
||||||
<script src="commons.js"></script>
|
|
||||||
<script src="/parity-utils/parity.js"></script>
|
|
||||||
<script src="signaturereg.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -25,7 +25,6 @@ import Application from './signaturereg/Application';
|
|||||||
import '../../assets/fonts/Roboto/font.css';
|
import '../../assets/fonts/Roboto/font.css';
|
||||||
import '../../assets/fonts/RobotoMono/font.css';
|
import '../../assets/fonts/RobotoMono/font.css';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import './signaturereg.html';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Application />,
|
<Application />,
|
||||||
|
@ -73,7 +73,7 @@ export default class Import extends Component {
|
|||||||
Provide the ABI (Contract Interface) in the space provided below. Only non-constant functions (names & types) will be imported, while constant functions and existing signatures will be ignored.
|
Provide the ABI (Contract Interface) in the space provided below. Only non-constant functions (names & types) will be imported, while constant functions and existing signatures will be ignored.
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.info }>
|
<div className={ styles.info }>
|
||||||
<textarea rows='8' className={ styles.error } onChange={ this.onAbiEdit }></textarea>
|
<textarea rows='8' className={ styles.error } onChange={ this.onAbiEdit } />
|
||||||
<div className={ styles.error }>
|
<div className={ styles.error }>
|
||||||
{ abiError }
|
{ abiError }
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
|
||||||
<title>Token Registry</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container"></div>
|
|
||||||
<script src="vendor.js"></script>
|
|
||||||
<script src="commons.js"></script>
|
|
||||||
<script src="/parity-utils/parity.js"></script>
|
|
||||||
<script src="tokenreg.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -27,7 +27,6 @@ import Container from './tokenreg/Container';
|
|||||||
import '../../assets/fonts/Roboto/font.css';
|
import '../../assets/fonts/Roboto/font.css';
|
||||||
import '../../assets/fonts/RobotoMono/font.css';
|
import '../../assets/fonts/RobotoMono/font.css';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import './tokenreg.html';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
(
|
(
|
||||||
|
@ -147,7 +147,7 @@ export const loadToken = (index) => (dispatch, getState) => {
|
|||||||
dispatch(setTokenData(index, null));
|
dispatch(setTokenData(index, null));
|
||||||
dispatch(setTokenLoading(index, false));
|
dispatch(setTokenLoading(index, false));
|
||||||
|
|
||||||
if (!e instanceof TypeError) {
|
if (!(e instanceof TypeError)) {
|
||||||
console.error(`loadToken #${index} error`, e);
|
console.error(`loadToken #${index} error`, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
39
js/src/index.ejs
Normal file
39
js/src/index.ejs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
<style>
|
||||||
|
html, body, #container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
font-family: Roboto;
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<div class="loading-container">
|
||||||
|
<span class="loading">Loading...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="vendor.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,21 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
|
||||||
<title>Parity</title>
|
|
||||||
<style>
|
|
||||||
html, body, #container {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container"></div>
|
|
||||||
<script src="vendor.js"></script>
|
|
||||||
<script src="commons.js"></script>
|
|
||||||
<script src="index.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -22,17 +22,20 @@ es6Promise.polyfill();
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import { AppContainer } from 'react-hot-loader';
|
||||||
|
|
||||||
import injectTapEventPlugin from 'react-tap-event-plugin';
|
import injectTapEventPlugin from 'react-tap-event-plugin';
|
||||||
import { createHashHistory } from 'history';
|
import { createHashHistory } from 'history';
|
||||||
import { Redirect, Router, Route, useRouterHistory } from 'react-router';
|
import { useRouterHistory } from 'react-router';
|
||||||
import qs from 'querystring';
|
import qs from 'querystring';
|
||||||
|
|
||||||
import SecureApi from './secureApi';
|
import SecureApi from './secureApi';
|
||||||
import ContractInstances from './contracts';
|
import ContractInstances from './contracts';
|
||||||
|
|
||||||
import { initStore } from './redux';
|
import { initStore } from './redux';
|
||||||
import { ContextProvider, muiTheme } from './ui';
|
import ContextProvider from './ui/ContextProvider';
|
||||||
import { Accounts, Account, Addresses, Address, Application, Contract, Contracts, WriteContract, Dapp, Dapps, Settings, SettingsBackground, SettingsParity, SettingsProxy, SettingsViews, Signer, Status } from './views';
|
import muiTheme from './ui/Theme';
|
||||||
|
import MainApplication from './main';
|
||||||
|
|
||||||
import { setApi } from './redux/providers/apiActions';
|
import { setApi } from './redux/providers/apiActions';
|
||||||
|
|
||||||
@ -41,9 +44,6 @@ import './environment';
|
|||||||
import '../assets/fonts/Roboto/font.css';
|
import '../assets/fonts/Roboto/font.css';
|
||||||
import '../assets/fonts/RobotoMono/font.css';
|
import '../assets/fonts/RobotoMono/font.css';
|
||||||
|
|
||||||
import styles from './reset.css';
|
|
||||||
import './index.html';
|
|
||||||
|
|
||||||
injectTapEventPlugin();
|
injectTapEventPlugin();
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
@ -77,32 +77,47 @@ window.secureApi = api;
|
|||||||
const routerHistory = useRouterHistory(createHashHistory)({});
|
const routerHistory = useRouterHistory(createHashHistory)({});
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
|
<AppContainer>
|
||||||
<ContextProvider api={ api } muiTheme={ muiTheme } store={ store }>
|
<ContextProvider api={ api } muiTheme={ muiTheme } store={ store }>
|
||||||
<Router className={ styles.reset } history={ routerHistory }>
|
<MainApplication
|
||||||
<Redirect from='/' to='/accounts' />
|
routerHistory={ routerHistory }
|
||||||
<Redirect from='/auth' to='/accounts' query={ {} } />
|
/>
|
||||||
<Redirect from='/settings' to='/settings/views' />
|
</ContextProvider>
|
||||||
<Route path='/' component={ Application }>
|
</AppContainer>,
|
||||||
<Route path='accounts' component={ Accounts } />
|
|
||||||
<Route path='account/:address' component={ Account } />
|
|
||||||
<Route path='addresses' component={ Addresses } />
|
|
||||||
<Route path='address/:address' component={ Address } />
|
|
||||||
<Route path='apps' component={ Dapps } />
|
|
||||||
<Route path='app/:id' component={ Dapp } />
|
|
||||||
<Route path='contracts' component={ Contracts } />
|
|
||||||
<Route path='contracts/write' component={ WriteContract } />
|
|
||||||
<Route path='contract/:address' component={ Contract } />
|
|
||||||
<Route path='settings' component={ Settings }>
|
|
||||||
<Route path='background' component={ SettingsBackground } />
|
|
||||||
<Route path='proxy' component={ SettingsProxy } />
|
|
||||||
<Route path='views' component={ SettingsViews } />
|
|
||||||
<Route path='parity' component={ SettingsParity } />
|
|
||||||
</Route>
|
|
||||||
<Route path='signer' component={ Signer } />
|
|
||||||
<Route path='status' component={ Status } />
|
|
||||||
<Route path='status/:subpage' component={ Status } />
|
|
||||||
</Route>
|
|
||||||
</Router>
|
|
||||||
</ContextProvider>,
|
|
||||||
document.querySelector('#container')
|
document.querySelector('#container')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (module.hot) {
|
||||||
|
// module.hot.accept('./redux', () => {
|
||||||
|
// // redux store has a method replaceReducer
|
||||||
|
// // const newStore = initStore(api);
|
||||||
|
// console.warn('REDUX UPDATE');
|
||||||
|
// // store.replaceReducer(appReducer);
|
||||||
|
|
||||||
|
// // ReactDOM.render(
|
||||||
|
// // <AppContainer>
|
||||||
|
// // <ContextProvider api={ api } muiTheme={ muiTheme } store={ newStore }>
|
||||||
|
// // <MainApplication
|
||||||
|
// // routerHistory={ routerHistory }
|
||||||
|
// // />
|
||||||
|
// // </ContextProvider>
|
||||||
|
// // </AppContainer>,
|
||||||
|
// // document.querySelector('#container')
|
||||||
|
// // );
|
||||||
|
// });
|
||||||
|
|
||||||
|
module.hot.accept('./main.js', () => {
|
||||||
|
require('./main.js');
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<AppContainer>
|
||||||
|
<ContextProvider api={ api } muiTheme={ muiTheme } store={ store }>
|
||||||
|
<MainApplication
|
||||||
|
routerHistory={ routerHistory }
|
||||||
|
/>
|
||||||
|
</ContextProvider>
|
||||||
|
</AppContainer>,
|
||||||
|
document.querySelector('#container')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
60
js/src/main.js
Normal file
60
js/src/main.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 React, { Component, PropTypes } from 'react';
|
||||||
|
import { Redirect, Router, Route } from 'react-router';
|
||||||
|
|
||||||
|
import { Accounts, Account, Addresses, Address, Application, Contract, Contracts, WriteContract, Dapp, Dapps, Settings, SettingsBackground, SettingsParity, SettingsProxy, SettingsViews, Signer, Status } from './views';
|
||||||
|
|
||||||
|
import styles from './reset.css';
|
||||||
|
|
||||||
|
export default class MainApplication extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
routerHistory: PropTypes.any.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { routerHistory } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Router className={ styles.reset } history={ routerHistory }>
|
||||||
|
<Redirect from='/' to='/accounts' />
|
||||||
|
<Redirect from='/auth' to='/accounts' query={ {} } />
|
||||||
|
<Redirect from='/settings' to='/settings/views' />
|
||||||
|
<Route path='/' component={ Application }>
|
||||||
|
<Route path='accounts' component={ Accounts } />
|
||||||
|
<Route path='account/:address' component={ Account } />
|
||||||
|
<Route path='addresses' component={ Addresses } />
|
||||||
|
<Route path='address/:address' component={ Address } />
|
||||||
|
<Route path='apps' component={ Dapps } />
|
||||||
|
<Route path='app/:id' component={ Dapp } />
|
||||||
|
<Route path='contracts' component={ Contracts } />
|
||||||
|
<Route path='contracts/write' component={ WriteContract } />
|
||||||
|
<Route path='contract/:address' component={ Contract } />
|
||||||
|
<Route path='settings' component={ Settings }>
|
||||||
|
<Route path='background' component={ SettingsBackground } />
|
||||||
|
<Route path='proxy' component={ SettingsProxy } />
|
||||||
|
<Route path='views' component={ SettingsViews } />
|
||||||
|
<Route path='parity' component={ SettingsParity } />
|
||||||
|
</Route>
|
||||||
|
<Route path='signer' component={ Signer } />
|
||||||
|
<Route path='status' component={ Status } />
|
||||||
|
<Route path='status/:subpage' component={ Status } />
|
||||||
|
</Route>
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -128,7 +128,7 @@ export default class DeployContract extends Component {
|
|||||||
title={ title }
|
title={ title }
|
||||||
waiting={ waiting }
|
waiting={ waiting }
|
||||||
visible
|
visible
|
||||||
scroll>
|
>
|
||||||
{ this.renderStep() }
|
{ this.renderStep() }
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -62,7 +62,6 @@ export default class LoadContract extends Component {
|
|||||||
title={ title }
|
title={ title }
|
||||||
actions={ this.renderDialogActions() }
|
actions={ this.renderDialogActions() }
|
||||||
visible
|
visible
|
||||||
scroll
|
|
||||||
>
|
>
|
||||||
{ this.renderBody() }
|
{ this.renderBody() }
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -22,6 +22,10 @@ import SendIcon from 'material-ui/svg-icons/content/send';
|
|||||||
import { Tabs, Tab } from 'material-ui/Tabs';
|
import { Tabs, Tab } from 'material-ui/Tabs';
|
||||||
import Paper from 'material-ui/Paper';
|
import Paper from 'material-ui/Paper';
|
||||||
|
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import { showSnackbar } from '../../redux/providers/snackbarActions';
|
||||||
|
|
||||||
import Form, { Input } from '../../ui/Form';
|
import Form, { Input } from '../../ui/Form';
|
||||||
import { Button, Modal, IdentityName, IdentityIcon } from '../../ui';
|
import { Button, Modal, IdentityName, IdentityIcon } from '../../ui';
|
||||||
|
|
||||||
@ -30,13 +34,14 @@ import styles from './passwordManager.css';
|
|||||||
const TEST_ACTION = 'TEST_ACTION';
|
const TEST_ACTION = 'TEST_ACTION';
|
||||||
const CHANGE_ACTION = 'CHANGE_ACTION';
|
const CHANGE_ACTION = 'CHANGE_ACTION';
|
||||||
|
|
||||||
export default class PasswordManager extends Component {
|
class PasswordManager extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
api: PropTypes.object.isRequired
|
api: PropTypes.object.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
account: PropTypes.object.isRequired,
|
account: PropTypes.object.isRequired,
|
||||||
|
showSnackbar: PropTypes.func.isRequired,
|
||||||
onClose: PropTypes.func
|
onClose: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +338,7 @@ export default class PasswordManager extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleChangePassword = () => {
|
handleChangePassword = () => {
|
||||||
const { account } = this.props;
|
const { account, showSnackbar, onClose } = this.props;
|
||||||
const { currentPass, newPass, repeatNewPass, passwordHint } = this.state;
|
const { currentPass, newPass, repeatNewPass, passwordHint } = this.state;
|
||||||
|
|
||||||
if (repeatNewPass !== newPass) {
|
if (repeatNewPass !== newPass) {
|
||||||
@ -371,12 +376,9 @@ export default class PasswordManager extends Component {
|
|||||||
.changePassword(account.address, currentPass, newPass)
|
.changePassword(account.address, currentPass, newPass)
|
||||||
])
|
])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const message = {
|
showSnackbar(<div>Your password has been successfully changed.</div>);
|
||||||
value: 'Your password has been successfully changed',
|
this.setState({ waiting: false, showMessage: false });
|
||||||
success: true
|
onClose();
|
||||||
};
|
|
||||||
|
|
||||||
this.setState({ waiting: false, message, showMessage: true });
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
@ -385,3 +387,14 @@ export default class PasswordManager extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps (dispatch) {
|
||||||
|
return bindActionCreators({
|
||||||
|
showSnackbar
|
||||||
|
}, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
null,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(PasswordManager);
|
||||||
|
@ -53,7 +53,7 @@ export default class GatherData extends Component {
|
|||||||
{ this.renderCertified() }
|
{ this.renderCertified() }
|
||||||
{ this.renderRequested() }
|
{ this.renderRequested() }
|
||||||
<Input
|
<Input
|
||||||
label={ 'phone number' }
|
label={ 'phone number in international format' }
|
||||||
hint={ 'the SMS will be sent to this number' }
|
hint={ 'the SMS will be sent to this number' }
|
||||||
error={ isNumberValid ? null : 'invalid number' }
|
error={ isNumberValid ? null : 'invalid number' }
|
||||||
disabled={ isVerified }
|
disabled={ isVerified }
|
||||||
|
@ -25,7 +25,7 @@ import {
|
|||||||
LOADING,
|
LOADING,
|
||||||
QUERY_DATA,
|
QUERY_DATA,
|
||||||
POSTING_REQUEST, POSTED_REQUEST,
|
POSTING_REQUEST, POSTED_REQUEST,
|
||||||
REQUESTING_SMS, REQUESTED_SMS,
|
REQUESTING_SMS, QUERY_CODE,
|
||||||
POSTING_CONFIRMATION, POSTED_CONFIRMATION,
|
POSTING_CONFIRMATION, POSTED_CONFIRMATION,
|
||||||
DONE
|
DONE
|
||||||
} from './store';
|
} from './store';
|
||||||
@ -48,7 +48,7 @@ export default class SMSVerification extends Component {
|
|||||||
[LOADING]: 0,
|
[LOADING]: 0,
|
||||||
[QUERY_DATA]: 1,
|
[QUERY_DATA]: 1,
|
||||||
[POSTING_REQUEST]: 2, [POSTED_REQUEST]: 2, [REQUESTING_SMS]: 2,
|
[POSTING_REQUEST]: 2, [POSTED_REQUEST]: 2, [REQUESTING_SMS]: 2,
|
||||||
[REQUESTED_SMS]: 3,
|
[QUERY_CODE]: 3,
|
||||||
[POSTING_CONFIRMATION]: 4, [POSTED_CONFIRMATION]: 4,
|
[POSTING_CONFIRMATION]: 4, [POSTED_CONFIRMATION]: 4,
|
||||||
[DONE]: 5
|
[DONE]: 5
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ export default class SMSVerification extends Component {
|
|||||||
<Modal
|
<Modal
|
||||||
actions={ this.renderDialogActions(phase, error, isStepValid) }
|
actions={ this.renderDialogActions(phase, error, isStepValid) }
|
||||||
title='verify your account via SMS'
|
title='verify your account via SMS'
|
||||||
visible scroll
|
visible
|
||||||
current={ phase }
|
current={ phase }
|
||||||
steps={ ['Prepare', 'Enter Data', 'Request', 'Enter Code', 'Confirm', 'Done!'] }
|
steps={ ['Prepare', 'Enter Data', 'Request', 'Enter Code', 'Confirm', 'Done!'] }
|
||||||
waiting={ error ? [] : [ 0, 2, 4 ] }
|
waiting={ error ? [] : [ 0, 2, 4 ] }
|
||||||
@ -137,7 +137,7 @@ export default class SMSVerification extends Component {
|
|||||||
step,
|
step,
|
||||||
fee, number, isNumberValid, isVerified, hasRequested,
|
fee, number, isNumberValid, isVerified, hasRequested,
|
||||||
requestTx, isCodeValid, confirmationTx,
|
requestTx, isCodeValid, confirmationTx,
|
||||||
setNumber, setConsentGiven, setCode
|
setCode
|
||||||
} = this.props.store;
|
} = this.props.store;
|
||||||
|
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
|
@ -47,7 +47,7 @@ export default class SendRequest extends Component {
|
|||||||
|
|
||||||
case REQUESTING_SMS:
|
case REQUESTING_SMS:
|
||||||
return (
|
return (
|
||||||
<p>Requesting an SMS from the Parity server.</p>
|
<p>Requesting an SMS from the Parity server and waiting for the puzzle to be put into the contract.</p>
|
||||||
);
|
);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -20,19 +20,16 @@ import { sha3 } from '../../api/util/sha3';
|
|||||||
|
|
||||||
import Contracts from '../../contracts';
|
import Contracts from '../../contracts';
|
||||||
|
|
||||||
import { checkIfVerified, checkIfRequested } from '../../contracts/sms-verification';
|
import { checkIfVerified, checkIfRequested, awaitPuzzle } from '../../contracts/sms-verification';
|
||||||
import { postToServer } from '../../3rdparty/sms-verification';
|
import { postToServer } from '../../3rdparty/sms-verification';
|
||||||
import checkIfTxFailed from '../../util/check-if-tx-failed';
|
import checkIfTxFailed from '../../util/check-if-tx-failed';
|
||||||
import waitForConfirmations from '../../util/wait-for-block-confirmations';
|
import waitForConfirmations from '../../util/wait-for-block-confirmations';
|
||||||
|
|
||||||
const validCode = /^[A-Z\s]+$/i;
|
|
||||||
|
|
||||||
export const LOADING = 'fetching-contract';
|
export const LOADING = 'fetching-contract';
|
||||||
export const QUERY_DATA = 'query-data';
|
export const QUERY_DATA = 'query-data';
|
||||||
export const POSTING_REQUEST = 'posting-request';
|
export const POSTING_REQUEST = 'posting-request';
|
||||||
export const POSTED_REQUEST = 'posted-request';
|
export const POSTED_REQUEST = 'posted-request';
|
||||||
export const REQUESTING_SMS = 'requesting-sms';
|
export const REQUESTING_SMS = 'requesting-sms';
|
||||||
export const REQUESTED_SMS = 'requested-sms';
|
|
||||||
export const QUERY_CODE = 'query-code';
|
export const QUERY_CODE = 'query-code';
|
||||||
export const POSTING_CONFIRMATION = 'posting-confirmation';
|
export const POSTING_CONFIRMATION = 'posting-confirmation';
|
||||||
export const POSTED_CONFIRMATION = 'posted-confirmation';
|
export const POSTED_CONFIRMATION = 'posted-confirmation';
|
||||||
@ -50,11 +47,9 @@ export default class VerificationStore {
|
|||||||
@observable number = '';
|
@observable number = '';
|
||||||
@observable requestTx = null;
|
@observable requestTx = null;
|
||||||
@observable code = '';
|
@observable code = '';
|
||||||
|
@observable isCodeValid = null;
|
||||||
@observable confirmationTx = null;
|
@observable confirmationTx = null;
|
||||||
|
|
||||||
@computed get isCodeValid () {
|
|
||||||
return validCode.test(this.code);
|
|
||||||
}
|
|
||||||
@computed get isNumberValid () {
|
@computed get isNumberValid () {
|
||||||
return phone.isValidNumber(this.number);
|
return phone.isValidNumber(this.number);
|
||||||
}
|
}
|
||||||
@ -72,20 +67,19 @@ export default class VerificationStore {
|
|||||||
return this.contract && this.fee && this.isVerified !== null && this.hasRequested !== null;
|
return this.contract && this.fee && this.isVerified !== null && this.hasRequested !== null;
|
||||||
case QUERY_DATA:
|
case QUERY_DATA:
|
||||||
return this.isNumberValid && this.consentGiven;
|
return this.isNumberValid && this.consentGiven;
|
||||||
case REQUESTED_SMS:
|
|
||||||
return this.requestTx;
|
|
||||||
case QUERY_CODE:
|
case QUERY_CODE:
|
||||||
return this.isCodeValid;
|
return this.requestTx && this.isCodeValid === true;
|
||||||
case POSTED_CONFIRMATION:
|
case POSTED_CONFIRMATION:
|
||||||
return this.confirmationTx;
|
return !!this.confirmationTx;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (api, account) {
|
constructor (api, account, isTestnet) {
|
||||||
this.api = api;
|
this.api = api;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
|
this.isTestnet = isTestnet;
|
||||||
|
|
||||||
this.step = LOADING;
|
this.step = LOADING;
|
||||||
Contracts.create(api).registry.getContract('smsverification')
|
Contracts.create(api).registry.getContract('smsverification')
|
||||||
@ -151,7 +145,26 @@ export default class VerificationStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action setCode = (code) => {
|
@action setCode = (code) => {
|
||||||
|
const { contract, account } = this;
|
||||||
|
if (!contract || !account || code.length === 0) return;
|
||||||
|
|
||||||
|
const confirm = contract.functions.find((fn) => fn.name === 'confirm');
|
||||||
|
const options = { from: account };
|
||||||
|
const values = [ sha3(code) ];
|
||||||
|
|
||||||
this.code = code;
|
this.code = code;
|
||||||
|
this.isCodeValid = null;
|
||||||
|
confirm.estimateGas(options, values)
|
||||||
|
.then((gas) => {
|
||||||
|
options.gas = gas.mul(1.2).toFixed(0);
|
||||||
|
return confirm.call(options, values);
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
this.isCodeValid = result === true;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.error = 'Failed to check if the code is valid: ' + err.message;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@action sendRequest = () => {
|
@action sendRequest = () => {
|
||||||
@ -188,11 +201,15 @@ export default class VerificationStore {
|
|||||||
|
|
||||||
chain
|
chain
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.step = REQUESTING_SMS;
|
return api.parity.netChain();
|
||||||
return postToServer({ number, address: account });
|
|
||||||
})
|
})
|
||||||
|
.then((chain) => {
|
||||||
|
this.step = REQUESTING_SMS;
|
||||||
|
return postToServer({ number, address: account }, this.isTestnet);
|
||||||
|
})
|
||||||
|
.then(() => awaitPuzzle(api, contract, account))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.step = REQUESTED_SMS;
|
this.step = QUERY_CODE;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.error = 'Failed to request a confirmation SMS: ' + err.message;
|
this.error = 'Failed to request a confirmation SMS: ' + err.message;
|
||||||
|
@ -104,7 +104,6 @@ class Transfer extends Component {
|
|||||||
steps={ steps }
|
steps={ steps }
|
||||||
waiting={ extras ? [2] : [1] }
|
waiting={ extras ? [2] : [1] }
|
||||||
visible
|
visible
|
||||||
scroll
|
|
||||||
>
|
>
|
||||||
{ this.renderWarning() }
|
{ this.renderWarning() }
|
||||||
{ this.renderPage() }
|
{ this.renderPage() }
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import { newError } from '../ui/Errors/actions';
|
import { newError } from '../ui/Errors/actions';
|
||||||
import { setAddressImage } from './providers/imagesActions';
|
import { setAddressImage } from './providers/imagesActions';
|
||||||
import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from './providers/statusActions';
|
import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from './providers/statusActions';
|
||||||
import { toggleView } from '../views/Settings';
|
import { toggleView } from '../views/Settings/actions';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
newError,
|
newError,
|
||||||
|
@ -19,9 +19,9 @@ import { routerReducer } from 'react-router-redux';
|
|||||||
|
|
||||||
import { apiReducer, balancesReducer, blockchainReducer, compilerReducer, imagesReducer, personalReducer, signerReducer, statusReducer as nodeStatusReducer, snackbarReducer } from './providers';
|
import { apiReducer, balancesReducer, blockchainReducer, compilerReducer, imagesReducer, personalReducer, signerReducer, statusReducer as nodeStatusReducer, snackbarReducer } from './providers';
|
||||||
|
|
||||||
import { errorReducer } from '../ui/Errors';
|
import errorReducer from '../ui/Errors/reducers';
|
||||||
import { settingsReducer } from '../views/Settings';
|
import settingsReducer from '../views/Settings/reducers';
|
||||||
import { tooltipReducer } from '../ui/Tooltips';
|
import tooltipReducer from '../ui/Tooltips/reducers';
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return combineReducers({
|
return combineReducers({
|
||||||
|
@ -19,7 +19,7 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
import FileDownloadIcon from 'material-ui/svg-icons/file/file-download';
|
import FileDownloadIcon from 'material-ui/svg-icons/file/file-download';
|
||||||
|
|
||||||
import { Button } from '../../';
|
import Button from '../../Button';
|
||||||
|
|
||||||
class ActionbarExport extends Component {
|
class ActionbarExport extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -20,7 +20,8 @@ import FileUploadIcon from 'material-ui/svg-icons/file/file-upload';
|
|||||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||||
import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
||||||
|
|
||||||
import { Modal, Button } from '../../';
|
import Button from '../../Button';
|
||||||
|
import Modal from '../../Modal';
|
||||||
|
|
||||||
import styles from './import.css';
|
import styles from './import.css';
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import ActionSearch from 'material-ui/svg-icons/action/search';
|
import ActionSearch from 'material-ui/svg-icons/action/search';
|
||||||
|
|
||||||
import { Button, InputChip } from '../../';
|
import Button from '../../Button';
|
||||||
|
import InputChip from '../../Form/InputChip';
|
||||||
|
|
||||||
import styles from './search.css';
|
import styles from './search.css';
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import MenuItem from 'material-ui/MenuItem';
|
|||||||
|
|
||||||
import SortIcon from 'material-ui/svg-icons/content/sort';
|
import SortIcon from 'material-ui/svg-icons/content/sort';
|
||||||
|
|
||||||
import { Button } from '../../';
|
import Button from '../../Button';
|
||||||
|
|
||||||
import SortStore from './sortStore';
|
import SortStore from './sortStore';
|
||||||
import styles from './sort.css';
|
import styles from './sort.css';
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { Card } from 'material-ui/Card';
|
import { Card } from 'material-ui/Card';
|
||||||
|
|
||||||
|
import Title from './Title';
|
||||||
|
|
||||||
import styles from './container.css';
|
import styles from './container.css';
|
||||||
|
|
||||||
export default class Container extends Component {
|
export default class Container extends Component {
|
||||||
@ -25,7 +27,10 @@ export default class Container extends Component {
|
|||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
compact: PropTypes.bool,
|
compact: PropTypes.bool,
|
||||||
light: PropTypes.bool,
|
light: PropTypes.bool,
|
||||||
style: PropTypes.object
|
style: PropTypes.object,
|
||||||
|
title: PropTypes.oneOfType([
|
||||||
|
PropTypes.string, PropTypes.node
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
@ -35,9 +40,22 @@ export default class Container extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className={ classes } style={ style }>
|
<div className={ classes } style={ style }>
|
||||||
<Card className={ compact ? styles.compact : styles.padded }>
|
<Card className={ compact ? styles.compact : styles.padded }>
|
||||||
|
{ this.renderTitle() }
|
||||||
{ children }
|
{ children }
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderTitle () {
|
||||||
|
const { title } = this.props;
|
||||||
|
|
||||||
|
if (!title) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Title title={ title } />
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,10 @@ import IconButton from 'material-ui/IconButton';
|
|||||||
import AddIcon from 'material-ui/svg-icons/content/add';
|
import AddIcon from 'material-ui/svg-icons/content/add';
|
||||||
import RemoveIcon from 'material-ui/svg-icons/content/remove';
|
import RemoveIcon from 'material-ui/svg-icons/content/remove';
|
||||||
|
|
||||||
import { Input, InputAddressSelect, Select } from '../../../ui';
|
import Input from '../../../ui/Form/Input';
|
||||||
|
import InputAddressSelect from '../../../ui/Form/InputAddressSelect';
|
||||||
|
import Select from '../../../ui/Form/Select';
|
||||||
|
|
||||||
import { ABI_TYPES } from '../../../util/abi';
|
import { ABI_TYPES } from '../../../util/abi';
|
||||||
|
|
||||||
import styles from './typedInput.css';
|
import styles from './typedInput.css';
|
||||||
|
@ -18,6 +18,8 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
|
|
||||||
|
import ShortenedHash from '../ShortenedHash';
|
||||||
|
|
||||||
const defaultName = 'UNNAMED';
|
const defaultName = 'UNNAMED';
|
||||||
|
|
||||||
class IdentityName extends Component {
|
class IdentityName extends Component {
|
||||||
@ -41,7 +43,7 @@ class IdentityName extends Component {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const addressFallback = shorten ? this.formatHash(address) : address;
|
const addressFallback = shorten ? (<ShortenedHash data={ address } />) : address;
|
||||||
const fallback = unknown ? defaultName : addressFallback;
|
const fallback = unknown ? defaultName : addressFallback;
|
||||||
const isUuid = hasAccount && account.name === account.uuid;
|
const isUuid = hasAccount && account.name === account.uuid;
|
||||||
const displayName = (name && name.toUpperCase().trim()) ||
|
const displayName = (name && name.toUpperCase().trim()) ||
|
||||||
@ -55,14 +57,6 @@ class IdentityName extends Component {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
formatHash (hash) {
|
|
||||||
if (!hash || hash.length <= 16) {
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
|
@ -41,7 +41,6 @@ class Modal extends Component {
|
|||||||
compact: PropTypes.bool,
|
compact: PropTypes.bool,
|
||||||
current: PropTypes.number,
|
current: PropTypes.number,
|
||||||
waiting: PropTypes.array,
|
waiting: PropTypes.array,
|
||||||
scroll: PropTypes.bool,
|
|
||||||
steps: PropTypes.array,
|
steps: PropTypes.array,
|
||||||
title: PropTypes.oneOfType([
|
title: PropTypes.oneOfType([
|
||||||
PropTypes.node, PropTypes.string
|
PropTypes.node, PropTypes.string
|
||||||
@ -52,7 +51,7 @@ class Modal extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { muiTheme } = this.context;
|
const { muiTheme } = this.context;
|
||||||
const { actions, busy, className, current, children, compact, scroll, steps, waiting, title, visible, settings } = this.props;
|
const { actions, busy, className, current, children, compact, steps, waiting, title, visible, settings } = this.props;
|
||||||
const contentStyle = muiTheme.parity.getBackgroundStyle(null, settings.backgroundSeed);
|
const contentStyle = muiTheme.parity.getBackgroundStyle(null, settings.backgroundSeed);
|
||||||
const header = (
|
const header = (
|
||||||
<Title
|
<Title
|
||||||
@ -70,7 +69,7 @@ class Modal extends Component {
|
|||||||
actions={ actions }
|
actions={ actions }
|
||||||
actionsContainerStyle={ ACTIONS_STYLE }
|
actionsContainerStyle={ ACTIONS_STYLE }
|
||||||
autoDetectWindowHeight={ false }
|
autoDetectWindowHeight={ false }
|
||||||
autoScrollBodyContent={ !!scroll }
|
autoScrollBodyContent
|
||||||
actionsContainerClassName={ styles.actions }
|
actionsContainerClassName={ styles.actions }
|
||||||
bodyClassName={ styles.body }
|
bodyClassName={ styles.body }
|
||||||
contentClassName={ styles.content }
|
contentClassName={ styles.content }
|
||||||
|
17
js/src/ui/ShortenedHash/index.js
Normal file
17
js/src/ui/ShortenedHash/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 './shortenedHash';
|
21
js/src/ui/ShortenedHash/shortenedHash.css
Normal file
21
js/src/ui/ShortenedHash/shortenedHash.css
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/* Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hash {
|
||||||
|
display: inline-block;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
41
js/src/ui/ShortenedHash/shortenedHash.js
Normal file
41
js/src/ui/ShortenedHash/shortenedHash.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
|
import styles from './shortenedHash.css';
|
||||||
|
|
||||||
|
export default class ShortenedHash extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
data: PropTypes.string.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { data } = this.props;
|
||||||
|
|
||||||
|
let shortened = data.toLowerCase();
|
||||||
|
if (shortened.slice(0, 2) === '0x') {
|
||||||
|
shortened = shortened.slice(2);
|
||||||
|
}
|
||||||
|
if (shortened.length > (6 + 6)) {
|
||||||
|
shortened = shortened.slice(0, 6) + '…' + shortened.slice(-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<abbr className={ styles.hash } title={ shortened }>{ shortened }</abbr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -15,19 +15,12 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.details {
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
}
|
|
||||||
|
|
||||||
.hash {
|
.hash {
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.confirm {
|
.confirm {
|
||||||
padding-top: 1em;
|
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,9 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { LinearProgress } from 'material-ui';
|
import { LinearProgress } from 'material-ui';
|
||||||
|
|
||||||
import { txLink } from '../../3rdparty/etherscan/links';
|
import { txLink } from '../../3rdparty/etherscan/links';
|
||||||
|
import ShortenedHash from '../ShortenedHash';
|
||||||
|
|
||||||
import styles from './txHash.css';
|
import styles from './txHash.css';
|
||||||
|
|
||||||
@ -62,22 +64,23 @@ class TxHash extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { hash, isTest, summary } = this.props;
|
const { hash, isTest, summary } = this.props;
|
||||||
let header = null;
|
|
||||||
|
|
||||||
if (!summary) {
|
const link = (
|
||||||
header = (
|
<a href={ txLink(hash, isTest) } target='_blank'>
|
||||||
<div className={ styles.header }>
|
<ShortenedHash data={ hash } />
|
||||||
The transaction has been posted to the network with a transaction hash of
|
</a>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let header = (
|
||||||
|
<p>The transaction has been posted to the network, with a hash of { link }.</p>
|
||||||
|
);
|
||||||
|
if (summary) {
|
||||||
|
header = (<p>{ link }</p>);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.details }>
|
<div>
|
||||||
{ header }
|
{ header }
|
||||||
<div className={ styles.hash }>
|
|
||||||
<a href={ txLink(hash, isTest) } target='_blank'>{ hash }</a>
|
|
||||||
</div>
|
|
||||||
{ this.renderConfirmations() }
|
{ this.renderConfirmations() }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -87,17 +90,29 @@ class TxHash extends Component {
|
|||||||
const { maxConfirmations } = this.props;
|
const { maxConfirmations } = this.props;
|
||||||
const { blockNumber, transaction } = this.state;
|
const { blockNumber, transaction } = this.state;
|
||||||
|
|
||||||
let txBlock = 'Pending';
|
if (!(transaction && transaction.blockNumber && transaction.blockNumber.gt(0))) {
|
||||||
let confirmations = 'No';
|
return (
|
||||||
let value = 0;
|
<div className={ styles.confirm }>
|
||||||
|
<LinearProgress
|
||||||
if (transaction && transaction.blockNumber && transaction.blockNumber.gt(0)) {
|
className={ styles.progressbar }
|
||||||
const num = blockNumber.minus(transaction.blockNumber).plus(1);
|
color='white'
|
||||||
txBlock = `#${transaction.blockNumber.toFormat(0)}`;
|
mode='indeterminate'
|
||||||
confirmations = num.toFormat(0);
|
/>
|
||||||
value = num.gt(maxConfirmations) ? maxConfirmations : num.toNumber();
|
<div className={ styles.progressinfo }>waiting for confirmations</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const confirmations = blockNumber.minus(transaction.blockNumber).plus(1);
|
||||||
|
const value = Math.min(confirmations.toNumber(), maxConfirmations);
|
||||||
|
let count;
|
||||||
|
if (confirmations.gt(maxConfirmations)) {
|
||||||
|
count = confirmations.toFormat(0);
|
||||||
|
} else {
|
||||||
|
count = confirmations.toFormat(0) + `/${maxConfirmations}`;
|
||||||
|
}
|
||||||
|
const unit = value === 1 ? 'confirmation' : 'confirmations';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.confirm }>
|
<div className={ styles.confirm }>
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
@ -106,9 +121,10 @@ class TxHash extends Component {
|
|||||||
max={ maxConfirmations }
|
max={ maxConfirmations }
|
||||||
value={ value }
|
value={ value }
|
||||||
color='white'
|
color='white'
|
||||||
mode='determinate' />
|
mode='determinate'
|
||||||
|
/>
|
||||||
<div className={ styles.progressinfo }>
|
<div className={ styles.progressinfo }>
|
||||||
{ txBlock } / { confirmations } confirmations
|
<abbr title={ `block #${blockNumber.toFormat(0)}` }>{ count } { unit }</abbr>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -14,4 +14,4 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export default from './transaction';
|
export default from './txList';
|
131
js/src/ui/TxList/store.js
Normal file
131
js/src/ui/TxList/store.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 { action, observable, transaction } from 'mobx';
|
||||||
|
import { uniq } from 'lodash';
|
||||||
|
|
||||||
|
export default class Store {
|
||||||
|
@observable blocks = {};
|
||||||
|
@observable sortedHashes = [];
|
||||||
|
@observable transactions = {};
|
||||||
|
|
||||||
|
constructor (api) {
|
||||||
|
this._api = api;
|
||||||
|
this._subscriptionId = 0;
|
||||||
|
this._pendingHashes = [];
|
||||||
|
|
||||||
|
this.subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action addBlocks = (blocks) => {
|
||||||
|
this.blocks = Object.assign({}, this.blocks, blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action addTransactions = (transactions) => {
|
||||||
|
transaction(() => {
|
||||||
|
this.transactions = Object.assign({}, this.transactions, transactions);
|
||||||
|
this.sortedHashes = Object
|
||||||
|
.keys(this.transactions)
|
||||||
|
.sort((ahash, bhash) => {
|
||||||
|
const bnA = this.transactions[ahash].blockNumber;
|
||||||
|
const bnB = this.transactions[bhash].blockNumber;
|
||||||
|
|
||||||
|
if (bnB.eq(0)) {
|
||||||
|
return bnB.eq(bnA) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bnB.comparedTo(bnA);
|
||||||
|
});
|
||||||
|
this._pendingHashes = this.sortedHashes.filter((hash) => this.transactions[hash].blockNumber.eq(0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action clearPending () {
|
||||||
|
this._pendingHashes = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe () {
|
||||||
|
this._api
|
||||||
|
.subscribe('eth_blockNumber', (error, blockNumber) => {
|
||||||
|
if (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._pendingHashes.length) {
|
||||||
|
this.loadTransactions(this._pendingHashes);
|
||||||
|
this.clearPending();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((subscriptionId) => {
|
||||||
|
this._subscriptionId = subscriptionId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribe () {
|
||||||
|
if (!this._subscriptionId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._api.unsubscribe(this._subscriptionId);
|
||||||
|
this._subscriptionId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadTransactions (_txhashes) {
|
||||||
|
const txhashes = _txhashes.filter((hash) => !this.transactions[hash] || this._pendingHashes.includes(hash));
|
||||||
|
|
||||||
|
if (!txhashes || !txhashes.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise
|
||||||
|
.all(txhashes.map((txhash) => this._api.eth.getTransactionByHash(txhash)))
|
||||||
|
.then((transactions) => {
|
||||||
|
this.addTransactions(
|
||||||
|
transactions.reduce((transactions, tx, index) => {
|
||||||
|
transactions[txhashes[index]] = tx;
|
||||||
|
return transactions;
|
||||||
|
}, {})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.loadBlocks(transactions.map((tx) => tx.blockNumber ? tx.blockNumber.toNumber() : 0));
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn('loadTransactions', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadBlocks (_blockNumbers) {
|
||||||
|
const blockNumbers = uniq(_blockNumbers).filter((bn) => !this.blocks[bn]);
|
||||||
|
|
||||||
|
if (!blockNumbers || !blockNumbers.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise
|
||||||
|
.all(blockNumbers.map((blockNumber) => this._api.eth.getBlockByNumber(blockNumber)))
|
||||||
|
.then((blocks) => {
|
||||||
|
this.addBlocks(
|
||||||
|
blocks.reduce((blocks, block, index) => {
|
||||||
|
blocks[blockNumbers[index]] = block;
|
||||||
|
return blocks;
|
||||||
|
}, {})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn('loadBlocks', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
81
js/src/ui/TxList/txList.css
Normal file
81
js/src/ui/TxList/txList.css
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/* Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.transactions {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
tr {
|
||||||
|
line-height: 32px;
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
|
&:nth-child(even) {
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
color: #aaa;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 0.75em 0.75em;
|
||||||
|
|
||||||
|
&.method {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.timestamp {
|
||||||
|
padding-top: 1.5em;
|
||||||
|
text-align: right;
|
||||||
|
line-height: 1.5em;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.transaction {
|
||||||
|
padding-top: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
& div {
|
||||||
|
line-height: 1.25em;
|
||||||
|
min-height: 1.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
178
js/src/ui/TxList/txList.js
Normal file
178
js/src/ui/TxList/txList.js
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 moment from 'moment';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import { txLink, addressLink } from '../../3rdparty/etherscan/links';
|
||||||
|
|
||||||
|
import IdentityIcon from '../IdentityIcon';
|
||||||
|
import IdentityName from '../IdentityName';
|
||||||
|
import MethodDecoding from '../MethodDecoding';
|
||||||
|
import Store from './store';
|
||||||
|
|
||||||
|
import styles from './txList.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class TxList extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
api: PropTypes.object.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
address: PropTypes.string.isRequired,
|
||||||
|
hashes: PropTypes.oneOfType([
|
||||||
|
PropTypes.array,
|
||||||
|
PropTypes.object
|
||||||
|
]).isRequired,
|
||||||
|
isTest: PropTypes.bool.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
store = new Store(this.context.api);
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
this.store.loadTransactions(this.props.hashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
this.store.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (newProps) {
|
||||||
|
this.store.loadTransactions(newProps.hashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<table className={ styles.transactions }>
|
||||||
|
<tbody>
|
||||||
|
{ this.renderRows() }
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRows () {
|
||||||
|
const { address, isTest } = this.props;
|
||||||
|
|
||||||
|
return this.store.sortedHashes.map((txhash) => {
|
||||||
|
const tx = this.store.transactions[txhash];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr key={ tx.hash }>
|
||||||
|
{ this.renderBlockNumber(tx.blockNumber) }
|
||||||
|
{ this.renderAddress(tx.from) }
|
||||||
|
<td className={ styles.transaction }>
|
||||||
|
{ this.renderEtherValue(tx.value) }
|
||||||
|
<div>⇒</div>
|
||||||
|
<div>
|
||||||
|
<a
|
||||||
|
className={ styles.link }
|
||||||
|
href={ txLink(tx.hash, isTest) }
|
||||||
|
target='_blank'>
|
||||||
|
{ `${tx.hash.substr(2, 6)}...${tx.hash.slice(-6)}` }
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
{ this.renderAddress(tx.to) }
|
||||||
|
<td className={ styles.method }>
|
||||||
|
<MethodDecoding
|
||||||
|
historic
|
||||||
|
address={ address }
|
||||||
|
transaction={ tx } />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAddress (address) {
|
||||||
|
const { isTest } = this.props;
|
||||||
|
|
||||||
|
let esLink = null;
|
||||||
|
if (address) {
|
||||||
|
esLink = (
|
||||||
|
<a
|
||||||
|
href={ addressLink(address, isTest) }
|
||||||
|
target='_blank'
|
||||||
|
className={ styles.link }>
|
||||||
|
<IdentityName address={ address } shorten />
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<td className={ styles.address }>
|
||||||
|
<div className={ styles.center }>
|
||||||
|
<IdentityIcon
|
||||||
|
center
|
||||||
|
className={ styles.icon }
|
||||||
|
address={ address } />
|
||||||
|
</div>
|
||||||
|
<div className={ styles.center }>
|
||||||
|
{ esLink || 'DEPLOY' }
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEtherValue (_value) {
|
||||||
|
const { api } = this.context;
|
||||||
|
const value = api.util.fromWei(_value);
|
||||||
|
|
||||||
|
if (value.eq(0)) {
|
||||||
|
return <div className={ styles.value }>{ ' ' }</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.value }>
|
||||||
|
{ value.toFormat(5) }<small>ETH</small>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderBlockNumber (_blockNumber) {
|
||||||
|
const blockNumber = _blockNumber.toNumber();
|
||||||
|
const block = this.store.blocks[blockNumber];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<td className={ styles.timestamp }>
|
||||||
|
<div>{ blockNumber && block ? moment(block.timestamp).fromNow() : null }</div>
|
||||||
|
<div>{ blockNumber ? _blockNumber.toFormat() : 'Pending' }</div>
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
const { isTest } = state.nodeStatus;
|
||||||
|
|
||||||
|
return {
|
||||||
|
isTest
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps (dispatch) {
|
||||||
|
return bindActionCreators({}, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(TxList);
|
@ -37,10 +37,12 @@ import Modal, { Busy as BusyStep, Completed as CompletedStep } from './Modal';
|
|||||||
import muiTheme from './Theme';
|
import muiTheme from './Theme';
|
||||||
import Page from './Page';
|
import Page from './Page';
|
||||||
import ParityBackground from './ParityBackground';
|
import ParityBackground from './ParityBackground';
|
||||||
|
import ShortenedHash from './ShortenedHash';
|
||||||
import SignerIcon from './SignerIcon';
|
import SignerIcon from './SignerIcon';
|
||||||
import Tags from './Tags';
|
import Tags from './Tags';
|
||||||
import Tooltips, { Tooltip } from './Tooltips';
|
import Tooltips, { Tooltip } from './Tooltips';
|
||||||
import TxHash from './TxHash';
|
import TxHash from './TxHash';
|
||||||
|
import TxList from './TxList';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Actionbar,
|
Actionbar,
|
||||||
@ -79,9 +81,11 @@ export {
|
|||||||
Page,
|
Page,
|
||||||
ParityBackground,
|
ParityBackground,
|
||||||
RadioButtons,
|
RadioButtons,
|
||||||
|
ShortenedHash,
|
||||||
SignerIcon,
|
SignerIcon,
|
||||||
Tags,
|
Tags,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Tooltips,
|
Tooltips,
|
||||||
TxHash
|
TxHash,
|
||||||
|
TxList
|
||||||
};
|
};
|
||||||
|
19
js/src/util/is-testnet.js
Normal file
19
js/src/util/is-testnet.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 (chain) => {
|
||||||
|
return chain === 'morden' || chain === 'ropsten' || chain === 'testnet';
|
||||||
|
};
|
77
js/src/util/subscribe-to-event.js
Normal file
77
js/src/util/subscribe-to-event.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 EventEmitter from 'eventemitter3';
|
||||||
|
|
||||||
|
const defaults = {
|
||||||
|
from: 0, // TODO
|
||||||
|
to: 'latest',
|
||||||
|
timeout: null,
|
||||||
|
filter: () => true
|
||||||
|
};
|
||||||
|
|
||||||
|
const subscribeToEvent = (contract, name, opt = {}) => {
|
||||||
|
opt = Object.assign({}, defaults, opt);
|
||||||
|
|
||||||
|
let subscription = null;
|
||||||
|
let timeout = null;
|
||||||
|
|
||||||
|
const unsubscribe = () => {
|
||||||
|
if (subscription) {
|
||||||
|
contract.unsubscribe(subscription);
|
||||||
|
subscription = null;
|
||||||
|
}
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const emitter = new EventEmitter();
|
||||||
|
emitter.unsubscribe = unsubscribe;
|
||||||
|
|
||||||
|
if (typeof opt.timeout === 'number') {
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
unsubscribe();
|
||||||
|
emitter.emit('timeout');
|
||||||
|
}, opt.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = (err, logs) => {
|
||||||
|
if (err) {
|
||||||
|
return emitter.emit('error', err);
|
||||||
|
}
|
||||||
|
for (let log of logs) {
|
||||||
|
if (opt.filter(log)) {
|
||||||
|
emitter.emit('log', log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
contract.subscribe(name, {
|
||||||
|
fromBlock: opt.from, toBlock: opt.to
|
||||||
|
}, callback)
|
||||||
|
.then((_subscription) => {
|
||||||
|
subscription = _subscription;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
emitter.emit('error', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
return emitter;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default subscribeToEvent;
|
@ -1,191 +0,0 @@
|
|||||||
// Copyright 2015, 2016 Ethcore (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 BigNumber from 'bignumber.js';
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
import { IdentityIcon, IdentityName, MethodDecoding } from '../../../../ui';
|
|
||||||
import { txLink, addressLink } from '../../../../3rdparty/etherscan/links';
|
|
||||||
|
|
||||||
import styles from '../transactions.css';
|
|
||||||
|
|
||||||
export default class Transaction extends Component {
|
|
||||||
static contextTypes = {
|
|
||||||
api: PropTypes.object.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
address: PropTypes.string.isRequired,
|
|
||||||
isTest: PropTypes.bool.isRequired,
|
|
||||||
transaction: PropTypes.object.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
state = {
|
|
||||||
isContract: false,
|
|
||||||
isReceived: false,
|
|
||||||
transaction: null,
|
|
||||||
block: null
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
this.lookup();
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { block } = this.state;
|
|
||||||
const { transaction } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
<td className={ styles.timestamp }>
|
|
||||||
<div>{ this.formatBlockTimestamp(block) }</div>
|
|
||||||
<div>{ this.formatNumber(transaction.blockNumber) }</div>
|
|
||||||
</td>
|
|
||||||
{ this.renderAddress(transaction.from) }
|
|
||||||
{ this.renderTransaction() }
|
|
||||||
{ this.renderAddress(transaction.to) }
|
|
||||||
<td className={ styles.method }>
|
|
||||||
{ this.renderMethod() }
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderMethod () {
|
|
||||||
const { address } = this.props;
|
|
||||||
const { transaction } = this.state;
|
|
||||||
|
|
||||||
if (!transaction) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MethodDecoding
|
|
||||||
historic
|
|
||||||
address={ address }
|
|
||||||
transaction={ transaction } />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTransaction () {
|
|
||||||
const { isTest } = this.props;
|
|
||||||
const { transaction } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<td className={ styles.transaction }>
|
|
||||||
{ this.renderEtherValue() }
|
|
||||||
<div>⇒</div>
|
|
||||||
<div>
|
|
||||||
<a
|
|
||||||
className={ styles.link }
|
|
||||||
href={ txLink(transaction.hash, isTest) }
|
|
||||||
target='_blank'
|
|
||||||
>
|
|
||||||
{ this.formatHash(transaction.hash) }
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderAddress (address) {
|
|
||||||
const { isTest } = this.props;
|
|
||||||
|
|
||||||
const eslink = address ? (
|
|
||||||
<a
|
|
||||||
href={ addressLink(address, isTest) }
|
|
||||||
target='_blank'
|
|
||||||
className={ styles.link }>
|
|
||||||
<IdentityName address={ address } shorten />
|
|
||||||
</a>
|
|
||||||
) : 'DEPLOY';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<td className={ styles.address }>
|
|
||||||
<div className={ styles.center }>
|
|
||||||
<IdentityIcon
|
|
||||||
center
|
|
||||||
className={ styles.icon }
|
|
||||||
address={ address } />
|
|
||||||
</div>
|
|
||||||
<div className={ styles.center }>
|
|
||||||
{ eslink }
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderEtherValue () {
|
|
||||||
const { api } = this.context;
|
|
||||||
const { transaction } = this.state;
|
|
||||||
|
|
||||||
if (!transaction) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = api.util.fromWei(transaction.value);
|
|
||||||
|
|
||||||
if (value.eq(0)) {
|
|
||||||
return <div className={ styles.value }>{ ' ' }</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={ styles.value }>
|
|
||||||
{ value.toFormat(5) }<small>ETH</small>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
formatHash (hash) {
|
|
||||||
if (!hash || hash.length <= 16) {
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
formatNumber (number) {
|
|
||||||
return new BigNumber(number).toFormat();
|
|
||||||
}
|
|
||||||
|
|
||||||
formatBlockTimestamp (block) {
|
|
||||||
if (!block) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return moment(block.timestamp).fromNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
lookup () {
|
|
||||||
const { api } = this.context;
|
|
||||||
const { transaction, address } = this.props;
|
|
||||||
|
|
||||||
this.setState({ isReceived: address === transaction.to });
|
|
||||||
|
|
||||||
Promise
|
|
||||||
.all([
|
|
||||||
api.eth.getBlockByNumber(transaction.blockNumber),
|
|
||||||
api.eth.getTransactionByHash(transaction.hash)
|
|
||||||
])
|
|
||||||
.then(([block, transaction]) => {
|
|
||||||
this.setState({ block, transaction });
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.warn('lookup', error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,49 +14,10 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
.right {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transactions {
|
.transactions {
|
||||||
}
|
}
|
||||||
|
|
||||||
.transactions table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transactions tr {
|
|
||||||
line-height: 32px;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transactions tr:nth-child(even) {
|
|
||||||
background: rgba(255, 255, 255, 0.04);
|
|
||||||
}
|
|
||||||
|
|
||||||
.transactions th {
|
|
||||||
color: #aaa;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transactions td {
|
|
||||||
vertical-align: top;
|
|
||||||
padding: 0.75em 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transactions .link {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.infonone {
|
.infonone {
|
||||||
opacity: 0.25;
|
opacity: 0.25;
|
||||||
}
|
}
|
||||||
@ -67,35 +28,3 @@
|
|||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.address {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transaction {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transactions td.transaction {
|
|
||||||
padding-top: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transaction div {
|
|
||||||
line-height: 1.25em;
|
|
||||||
min-height: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.method {
|
|
||||||
width: 40%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transactions td.timestamp {
|
|
||||||
padding-top: 1.5em;
|
|
||||||
text-align: right;
|
|
||||||
line-height: 1.5em;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
@ -17,12 +17,9 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import LinearProgress from 'material-ui/LinearProgress';
|
|
||||||
|
|
||||||
import etherscan from '../../../3rdparty/etherscan';
|
import etherscan from '../../../3rdparty/etherscan';
|
||||||
import { Container, ContainerTitle } from '../../../ui';
|
import { Container, TxList } from '../../../ui';
|
||||||
|
|
||||||
import Transaction from './Transaction';
|
|
||||||
|
|
||||||
import styles from './transactions.css';
|
import styles from './transactions.css';
|
||||||
|
|
||||||
@ -33,16 +30,12 @@ class Transactions extends Component {
|
|||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
address: PropTypes.string.isRequired,
|
address: PropTypes.string.isRequired,
|
||||||
accounts: PropTypes.object,
|
|
||||||
contacts: PropTypes.object,
|
|
||||||
contracts: PropTypes.object,
|
|
||||||
tokens: PropTypes.object,
|
|
||||||
isTest: PropTypes.bool,
|
isTest: PropTypes.bool,
|
||||||
traceMode: PropTypes.bool
|
traceMode: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
transactions: [],
|
hashes: [],
|
||||||
loading: true,
|
loading: true,
|
||||||
callInfo: {}
|
callInfo: {}
|
||||||
}
|
}
|
||||||
@ -67,38 +60,16 @@ class Transactions extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
const { address } = this.props;
|
||||||
<Container>
|
const { hashes } = this.state;
|
||||||
<ContainerTitle title='transactions' />
|
|
||||||
{ this.renderTransactions() }
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTransactions () {
|
|
||||||
const { loading, transactions } = this.state;
|
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return (
|
|
||||||
<LinearProgress mode='indeterminate' />
|
|
||||||
);
|
|
||||||
} else if (!transactions.length) {
|
|
||||||
return (
|
|
||||||
<div className={ styles.infonone }>
|
|
||||||
No transactions were found for this account
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.transactions }>
|
<Container title='transactions'>
|
||||||
<table>
|
<TxList
|
||||||
<tbody>
|
address={ address }
|
||||||
{ this.renderRows() }
|
hashes={ hashes } />
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{ this.renderEtherscanFooter() }
|
{ this.renderEtherscanFooter() }
|
||||||
</div>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,30 +87,6 @@ class Transactions extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRows () {
|
|
||||||
const { address, accounts, contacts, contracts, tokens, isTest } = this.props;
|
|
||||||
const { transactions } = this.state;
|
|
||||||
|
|
||||||
return (transactions || [])
|
|
||||||
.sort((tA, tB) => {
|
|
||||||
return tB.blockNumber.comparedTo(tA.blockNumber);
|
|
||||||
})
|
|
||||||
.slice(0, 25)
|
|
||||||
.map((transaction, index) => {
|
|
||||||
return (
|
|
||||||
<Transaction
|
|
||||||
key={ index }
|
|
||||||
transaction={ transaction }
|
|
||||||
address={ address }
|
|
||||||
accounts={ accounts }
|
|
||||||
contacts={ contacts }
|
|
||||||
contracts={ contracts }
|
|
||||||
tokens={ tokens }
|
|
||||||
isTest={ isTest } />
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactions = (props) => {
|
getTransactions = (props) => {
|
||||||
const { isTest, address, traceMode } = props;
|
const { isTest, address, traceMode } = props;
|
||||||
|
|
||||||
@ -151,9 +98,9 @@ class Transactions extends Component {
|
|||||||
|
|
||||||
return this
|
return this
|
||||||
.fetchTransactions(isTest, address, traceMode)
|
.fetchTransactions(isTest, address, traceMode)
|
||||||
.then(transactions => {
|
.then((transactions) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
transactions,
|
hashes: transactions.map((transaction) => transaction.hash),
|
||||||
loading: false
|
loading: false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -204,16 +151,10 @@ class Transactions extends Component {
|
|||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const { isTest, traceMode } = state.nodeStatus;
|
const { isTest, traceMode } = state.nodeStatus;
|
||||||
const { accounts, contacts, contracts } = state.personal;
|
|
||||||
const { tokens } = state.balances;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isTest,
|
isTest,
|
||||||
traceMode,
|
traceMode
|
||||||
accounts,
|
|
||||||
contacts,
|
|
||||||
contracts,
|
|
||||||
tokens
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ class Account extends Component {
|
|||||||
|
|
||||||
params: PropTypes.object,
|
params: PropTypes.object,
|
||||||
accounts: PropTypes.object,
|
accounts: PropTypes.object,
|
||||||
|
isTestnet: PropTypes.bool,
|
||||||
balances: PropTypes.object
|
balances: PropTypes.object
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +66,9 @@ class Account extends Component {
|
|||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { api } = this.context;
|
const { api } = this.context;
|
||||||
const { address } = this.props.params;
|
const { address } = this.props.params;
|
||||||
|
const { isTestnet } = this.props;
|
||||||
|
|
||||||
const verificationStore = new VerificationStore(api, address);
|
const verificationStore = new VerificationStore(api, address, isTestnet);
|
||||||
this.setState({ verificationStore });
|
this.setState({ verificationStore });
|
||||||
this.setVisibleAccounts();
|
this.setVisibleAccounts();
|
||||||
}
|
}
|
||||||
@ -326,11 +328,13 @@ class Account extends Component {
|
|||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const { accounts } = state.personal;
|
const { accounts } = state.personal;
|
||||||
|
const { isTest } = state.nodeStatus;
|
||||||
const { balances } = state.balances;
|
const { balances } = state.balances;
|
||||||
const { images } = state;
|
const { images } = state;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accounts,
|
accounts,
|
||||||
|
isTestnet: isTest,
|
||||||
balances,
|
balances,
|
||||||
images
|
images
|
||||||
};
|
};
|
||||||
|
@ -92,7 +92,7 @@ class Accounts extends Component {
|
|||||||
|
|
||||||
const loadings = ((accounts && Object.keys(accounts)) || []).map((_, idx) => (
|
const loadings = ((accounts && Object.keys(accounts)) || []).map((_, idx) => (
|
||||||
<div key={ idx } className={ styles.loading }>
|
<div key={ idx } className={ styles.loading }>
|
||||||
<div></div>
|
<div />
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import { connect } from 'react-redux';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
||||||
import { Tab as MUITab } from 'material-ui/Tabs';
|
import { Tab as MUITab } from 'material-ui/Tabs';
|
||||||
|
import { isEqual } from 'lodash';
|
||||||
|
|
||||||
import { Badge, Tooltip } from '../../../ui';
|
import { Badge, Tooltip } from '../../../ui';
|
||||||
|
|
||||||
@ -162,9 +163,13 @@ class TabBar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate (nextProps, nextState) {
|
shouldComponentUpdate (nextProps, nextState) {
|
||||||
|
const prevViews = this.props.views.map((v) => v.id).sort();
|
||||||
|
const nextViews = nextProps.views.map((v) => v.id).sort();
|
||||||
|
|
||||||
return (nextProps.hash !== this.props.hash) ||
|
return (nextProps.hash !== this.props.hash) ||
|
||||||
(nextProps.pending.length !== this.props.pending.length) ||
|
(nextProps.pending.length !== this.props.pending.length) ||
|
||||||
(nextState.activeViewId !== this.state.activeViewId);
|
(nextState.activeViewId !== this.state.activeViewId) ||
|
||||||
|
(!isEqual(prevViews, nextViews));
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
@ -192,7 +197,7 @@ class TabBar extends Component {
|
|||||||
return (
|
return (
|
||||||
<ToolbarGroup>
|
<ToolbarGroup>
|
||||||
<div className={ styles.last }>
|
<div className={ styles.last }>
|
||||||
<div></div>
|
<div />
|
||||||
</div>
|
</div>
|
||||||
</ToolbarGroup>
|
</ToolbarGroup>
|
||||||
);
|
);
|
||||||
@ -217,7 +222,7 @@ class TabBar extends Component {
|
|||||||
active={ active }
|
active={ active }
|
||||||
view={ view }
|
view={ view }
|
||||||
onChange={ this.onChange }
|
onChange={ this.onChange }
|
||||||
key={ index }
|
key={ view.id }
|
||||||
pendings={ pending.length }
|
pendings={ pending.length }
|
||||||
>
|
>
|
||||||
{ body }
|
{ body }
|
||||||
|
@ -19,6 +19,7 @@ import moment from 'moment';
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
import { IdentityIcon, IdentityName, Input, InputAddress } from '../../../../ui';
|
import { IdentityIcon, IdentityName, Input, InputAddress } from '../../../../ui';
|
||||||
|
import ShortenedHash from '../../../../ui/ShortenedHash';
|
||||||
import { txLink } from '../../../../3rdparty/etherscan/links';
|
import { txLink } from '../../../../3rdparty/etherscan/links';
|
||||||
|
|
||||||
import styles from '../../contract.css';
|
import styles from '../../contract.css';
|
||||||
@ -71,7 +72,7 @@ export default class Event extends Component {
|
|||||||
<div className={ styles.eventType }>
|
<div className={ styles.eventType }>
|
||||||
{ event.type }({ keys })
|
{ event.type }({ keys })
|
||||||
</div>
|
</div>
|
||||||
<a href={ url } target='_blank'>{ this.formatHash(event.transactionHash) }</a>
|
<a href={ url } target='_blank'><ShortenedHash data={ event.transactionHash } /></a>
|
||||||
</td>
|
</td>
|
||||||
<td className={ styles.eventDetails }>
|
<td className={ styles.eventDetails }>
|
||||||
<div className={ styles.eventParams }>
|
<div className={ styles.eventParams }>
|
||||||
@ -82,14 +83,6 @@ export default class Event extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
formatHash (hash) {
|
|
||||||
if (!hash || hash.length <= 16) {
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${hash.substr(2, 6)}...${hash.slice(-6)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderAddressName (address, withName = true) {
|
renderAddressName (address, withName = true) {
|
||||||
return (
|
return (
|
||||||
<span className={ styles.eventAddress }>
|
<span className={ styles.eventAddress }>
|
||||||
|
@ -165,7 +165,6 @@ class Contract extends Component {
|
|||||||
actions={ [ cancelBtn ] }
|
actions={ [ cancelBtn ] }
|
||||||
title={ 'contract details' }
|
title={ 'contract details' }
|
||||||
visible
|
visible
|
||||||
scroll
|
|
||||||
>
|
>
|
||||||
<div className={ styles.details }>
|
<div className={ styles.details }>
|
||||||
{ this.renderSource(contract) }
|
{ this.renderSource(contract) }
|
||||||
|
@ -65,8 +65,7 @@ export default class Dapp extends Component {
|
|||||||
name={ name }
|
name={ name }
|
||||||
sandbox='allow-forms allow-popups allow-same-origin allow-scripts'
|
sandbox='allow-forms allow-popups allow-same-origin allow-scripts'
|
||||||
scrolling='auto'
|
scrolling='auto'
|
||||||
src={ src }>
|
src={ src } />
|
||||||
</iframe>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,8 @@ export default class AddDapps extends Component {
|
|||||||
/>
|
/>
|
||||||
] }
|
] }
|
||||||
visible
|
visible
|
||||||
scroll>
|
>
|
||||||
<div className={ styles.warning }>
|
<div className={ styles.warning } />
|
||||||
</div>
|
|
||||||
{ this.renderList(store.sortedLocal, 'Applications locally available', 'All applications installed locally on the machine by the user for access by the Parity client.') }
|
{ this.renderList(store.sortedLocal, 'Applications locally available', 'All applications installed locally on the machine by the user for access by the Parity client.') }
|
||||||
{ this.renderList(store.sortedBuiltin, 'Applications bundled with Parity', 'Experimental applications developed by the Parity team to show off dapp capabilities, integration, experimental features and to control certain network-wide client behaviour.') }
|
{ this.renderList(store.sortedBuiltin, 'Applications bundled with Parity', 'Experimental applications developed by the Parity team to show off dapp capabilities, integration, experimental features and to control certain network-wide client behaviour.') }
|
||||||
{ this.renderList(store.sortedNetwork, 'Applications on the global network', 'These applications are not affiliated with Parity nor are they published by Parity. Each remain under the control of their respective authors. Please ensure that you understand the goals for each application before interacting.') }
|
{ this.renderList(store.sortedNetwork, 'Applications on the global network', 'These applications are not affiliated with Parity nor are they published by Parity. Each remain under the control of their respective authors. Please ensure that you understand the goals for each application before interacting.') }
|
||||||
|
@ -130,9 +130,15 @@ export default class DappsStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_getHost (api) {
|
_getHost (api) {
|
||||||
return process.env.NODE_ENV === 'production'
|
const host = process.env.DAPPS_URL || (process.env.NODE_ENV === 'production'
|
||||||
? this._api.dappsUrl
|
? this._api.dappsUrl
|
||||||
: '';
|
: '');
|
||||||
|
|
||||||
|
if (host === '/') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
_fetchBuiltinApps () {
|
_fetchBuiltinApps () {
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
.transaction {
|
.transaction {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.transaction > * {
|
.transaction > * {
|
||||||
|
@ -18,15 +18,17 @@ import BigNumber from 'bignumber.js';
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
|
||||||
import Store from '../../store';
|
import Store from '../../store';
|
||||||
import * as RequestsActions from '../../../../redux/providers/signerActions';
|
import * as RequestsActions from '../../../../redux/providers/signerActions';
|
||||||
import { Container, ContainerTitle } from '../../../../ui';
|
import { Container, Page, TxList } from '../../../../ui';
|
||||||
|
|
||||||
import { RequestPending, RequestFinished } from '../../components';
|
import { RequestPending, RequestFinished } from '../../components';
|
||||||
|
|
||||||
import styles from './RequestsPage.css';
|
import styles from './RequestsPage.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
class RequestsPage extends Component {
|
class RequestsPage extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
api: PropTypes.object.isRequired
|
api: PropTypes.object.isRequired
|
||||||
@ -44,20 +46,19 @@ class RequestsPage extends Component {
|
|||||||
isTest: PropTypes.bool.isRequired
|
isTest: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
store = new Store(this.context.api);
|
store = new Store(this.context.api, true);
|
||||||
|
|
||||||
render () {
|
componentWillUnmount () {
|
||||||
const { pending, finished } = this.props.signer;
|
this.store.unsubscribe();
|
||||||
|
|
||||||
if (!pending.length && !finished.length) {
|
|
||||||
return this.renderNoRequestsMsg();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
return (
|
return (
|
||||||
<div>
|
<Page>
|
||||||
{ this.renderPendingRequests() }
|
<div>{ this.renderPendingRequests() }</div>
|
||||||
{ this.renderFinishedRequests() }
|
<div>{ this.renderLocalQueue() }</div>
|
||||||
</div>
|
<div>{ this.renderFinishedRequests() }</div>
|
||||||
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,18 +66,39 @@ class RequestsPage extends Component {
|
|||||||
return new BigNumber(b.id).cmp(a.id);
|
return new BigNumber(b.id).cmp(a.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderLocalQueue () {
|
||||||
|
const { localHashes } = this.store;
|
||||||
|
|
||||||
|
if (!localHashes.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container title='Local Transactions'>
|
||||||
|
<TxList
|
||||||
|
address=''
|
||||||
|
hashes={ localHashes } />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
renderPendingRequests () {
|
renderPendingRequests () {
|
||||||
const { pending } = this.props.signer;
|
const { pending } = this.props.signer;
|
||||||
|
|
||||||
if (!pending.length) {
|
if (!pending.length) {
|
||||||
return;
|
return (
|
||||||
|
<Container>
|
||||||
|
<div className={ styles.noRequestsMsg }>
|
||||||
|
There are no requests requiring your confirmation.
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = pending.sort(this._sortRequests).map(this.renderPending);
|
const items = pending.sort(this._sortRequests).map(this.renderPending);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container title='Pending Requests'>
|
||||||
<ContainerTitle title='Pending Requests' />
|
|
||||||
<div className={ styles.items }>
|
<div className={ styles.items }>
|
||||||
{ items }
|
{ items }
|
||||||
</div>
|
</div>
|
||||||
@ -94,8 +116,7 @@ class RequestsPage extends Component {
|
|||||||
const items = finished.sort(this._sortRequests).map(this.renderFinished);
|
const items = finished.sort(this._sortRequests).map(this.renderFinished);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container title='Finished Requests'>
|
||||||
<ContainerTitle title='Finished Requests' />
|
|
||||||
<div className={ styles.items }>
|
<div className={ styles.items }>
|
||||||
{ items }
|
{ items }
|
||||||
</div>
|
</div>
|
||||||
@ -143,16 +164,6 @@ class RequestsPage extends Component {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoRequestsMsg () {
|
|
||||||
return (
|
|
||||||
<Container>
|
|
||||||
<div className={ styles.noRequestsMsg }>
|
|
||||||
There are no requests requiring your confirmation.
|
|
||||||
</div>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { Actionbar, Page } from '../../ui';
|
import { Actionbar } from '../../ui';
|
||||||
import RequestsPage from './containers/RequestsPage';
|
import RequestsPage from './containers/RequestsPage';
|
||||||
|
|
||||||
import styles from './signer.css';
|
import styles from './signer.css';
|
||||||
@ -27,9 +27,7 @@ export default class Signer extends Component {
|
|||||||
<div className={ styles.signer }>
|
<div className={ styles.signer }>
|
||||||
<Actionbar
|
<Actionbar
|
||||||
title='Trusted Signer' />
|
title='Trusted Signer' />
|
||||||
<Page>
|
|
||||||
<RequestsPage />
|
<RequestsPage />
|
||||||
</Page>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,26 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { isEqual } from 'lodash';
|
||||||
import { action, observable } from 'mobx';
|
import { action, observable } from 'mobx';
|
||||||
|
|
||||||
export default class Store {
|
export default class Store {
|
||||||
@observable balances = {};
|
@observable balances = {};
|
||||||
|
@observable localHashes = [];
|
||||||
|
|
||||||
constructor (api) {
|
constructor (api, withLocalTransactions = false) {
|
||||||
this._api = api;
|
this._api = api;
|
||||||
|
this._timeoutId = 0;
|
||||||
|
|
||||||
|
if (withLocalTransactions) {
|
||||||
|
this.fetchLocalTransactions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action unsubscribe () {
|
||||||
|
if (this._timeoutId) {
|
||||||
|
clearTimeout(this._timeoutId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@action setBalance = (address, balance) => {
|
@action setBalance = (address, balance) => {
|
||||||
@ -31,6 +44,12 @@ export default class Store {
|
|||||||
this.balances = Object.assign({}, this.balances, balances);
|
this.balances = Object.assign({}, this.balances, balances);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action setLocalHashes = (localHashes) => {
|
||||||
|
if (!isEqual(localHashes, this.localHashes)) {
|
||||||
|
this.localHashes = localHashes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fetchBalance (address) {
|
fetchBalance (address) {
|
||||||
this._api.eth
|
this._api.eth
|
||||||
.getBalance(address)
|
.getBalance(address)
|
||||||
@ -63,4 +82,18 @@ export default class Store {
|
|||||||
console.warn('Store:fetchBalances', error);
|
console.warn('Store:fetchBalances', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchLocalTransactions = () => {
|
||||||
|
const nextTimeout = () => {
|
||||||
|
this._timeoutId = setTimeout(this.fetchLocalTransactions, 1500);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._api.parity
|
||||||
|
.localTransactions()
|
||||||
|
.then((localTransactions) => {
|
||||||
|
this.setLocalHashes(Object.keys(localTransactions));
|
||||||
|
})
|
||||||
|
.then(nextTimeout)
|
||||||
|
.catch(nextTimeout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ export default class Calls extends Component {
|
|||||||
onClick={ this.clearHistory }
|
onClick={ this.clearHistory }
|
||||||
className={ styles.removeIcon }
|
className={ styles.removeIcon }
|
||||||
>
|
>
|
||||||
<i className='icon-trash'></i>
|
<i className='icon-trash' />
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ export default class EditableValue extends Component {
|
|||||||
title={ `Reset to ${this.props.defaultValue}` }
|
title={ `Reset to ${this.props.defaultValue}` }
|
||||||
{ ...this._testInherit('reset') }
|
{ ...this._testInherit('reset') }
|
||||||
>
|
>
|
||||||
<i className='icon-anchor'></i>
|
<i className='icon-anchor' />
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@ export default class EditableValue extends Component {
|
|||||||
onClick={ this.onSubmit }
|
onClick={ this.onSubmit }
|
||||||
{ ...this._testInherit('submit') }
|
{ ...this._testInherit('submit') }
|
||||||
>
|
>
|
||||||
<i className='icon-check'></i>
|
<i className='icon-check' />
|
||||||
</a>,
|
</a>,
|
||||||
<a
|
<a
|
||||||
key={ 'cancel' }
|
key={ 'cancel' }
|
||||||
@ -162,7 +162,7 @@ export default class EditableValue extends Component {
|
|||||||
onClick={ this.onCancel }
|
onClick={ this.onCancel }
|
||||||
{ ...this._testInherit('cancel') }
|
{ ...this._testInherit('cancel') }
|
||||||
>
|
>
|
||||||
<i className='icon-close'></i>
|
<i className='icon-close' />
|
||||||
</a>
|
</a>
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -175,7 +175,7 @@ export default class EditableValue extends Component {
|
|||||||
title='Edit'
|
title='Edit'
|
||||||
{ ...this._testInherit('edit') }
|
{ ...this._testInherit('edit') }
|
||||||
>
|
>
|
||||||
<i className='icon-pencil'></i>
|
<i className='icon-pencil' />
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ export default class RpcCalls extends Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={ { clear: 'both' } }></div>
|
<div style={ { clear: 'both' } } />
|
||||||
<div className='dapp-container'>
|
<div className='dapp-container'>
|
||||||
<div className='row'>
|
<div className='row'>
|
||||||
<div className='col col-6 mobile-full'>
|
<div className='col col-6 mobile-full'>
|
||||||
|
@ -46,7 +46,7 @@ class RpcDocs extends Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={ { clear: 'both' } }></div>
|
<div style={ { clear: 'both' } } />
|
||||||
<div className='dapp-container'>
|
<div className='dapp-container'>
|
||||||
<div className='row'>
|
<div className='row'>
|
||||||
<div className='col col-12'>
|
<div className='col col-12'>
|
||||||
|
@ -24,10 +24,10 @@ export default class RpcNav extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className={ styles.nav }>
|
<div className={ styles.nav }>
|
||||||
<Link to={ '/rpc/calls' } activeClassName={ styles.activeNav } { ...this._test('rpc-calls-link') }>
|
<Link to={ '/rpc/calls' } activeClassName={ styles.activeNav } { ...this._test('rpc-calls-link') }>
|
||||||
<i className='icon-call-out'></i>
|
<i className='icon-call-out' />
|
||||||
</Link>
|
</Link>
|
||||||
<Link to={ '/rpc/docs' } activeClassName={ styles.activeNav } { ...this._test('rpc-docs-link') }>
|
<Link to={ '/rpc/docs' } activeClassName={ styles.activeNav } { ...this._test('rpc-docs-link') }>
|
||||||
<i className='icon-docs'></i>
|
<i className='icon-docs' />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -118,8 +118,7 @@ class WriteContract extends Component {
|
|||||||
<span
|
<span
|
||||||
className={ styles.slider }
|
className={ styles.slider }
|
||||||
onMouseDown={ this.handleStartResize }
|
onMouseDown={ this.handleStartResize }
|
||||||
>
|
/>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -24,17 +24,17 @@ const SNIPPETS = {
|
|||||||
snippet0: {
|
snippet0: {
|
||||||
name: 'Token.sol',
|
name: 'Token.sol',
|
||||||
description: 'Standard ERP20 Token Contract',
|
description: 'Standard ERP20 Token Contract',
|
||||||
id: 'snippet0', sourcecode: require('raw!../../contracts/snippets/token.sol')
|
id: 'snippet0', sourcecode: require('raw-loader!../../contracts/snippets/token.sol')
|
||||||
},
|
},
|
||||||
snippet1: {
|
snippet1: {
|
||||||
name: 'StandardToken.sol',
|
name: 'StandardToken.sol',
|
||||||
description: 'Implementation of ERP20 Token Contract',
|
description: 'Implementation of ERP20 Token Contract',
|
||||||
id: 'snippet1', sourcecode: require('raw!../../contracts/snippets/standard-token.sol')
|
id: 'snippet1', sourcecode: require('raw-loader!../../contracts/snippets/standard-token.sol')
|
||||||
},
|
},
|
||||||
snippet2: {
|
snippet2: {
|
||||||
name: 'HumanStandardToken.sol',
|
name: 'HumanStandardToken.sol',
|
||||||
description: 'Implementation of the Human Token Contract',
|
description: 'Implementation of the Human Token Contract',
|
||||||
id: 'snippet2', sourcecode: require('raw!../../contracts/snippets/human-standard-token.sol')
|
id: 'snippet2', sourcecode: require('raw-loader!../../contracts/snippets/human-standard-token.sol')
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,238 +0,0 @@
|
|||||||
|
|
||||||
// Copyright 2015, 2016 Ethcore (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/>.
|
|
||||||
|
|
||||||
const HappyPack = require('happypack');
|
|
||||||
const path = require('path');
|
|
||||||
const postcssImport = require('postcss-import');
|
|
||||||
const postcssNested = require('postcss-nested');
|
|
||||||
const postcssVars = require('postcss-simple-vars');
|
|
||||||
const rucksack = require('rucksack-css');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const WebpackErrorNotificationPlugin = require('webpack-error-notification');
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|
||||||
|
|
||||||
const ENV = process.env.NODE_ENV || 'development';
|
|
||||||
const isProd = ENV === 'production';
|
|
||||||
const DEST = process.env.BUILD_DEST || '.build';
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
debug: !isProd,
|
|
||||||
cache: !isProd,
|
|
||||||
devtool: isProd ? '#eval' : '#cheap-module-eval-source-map',
|
|
||||||
context: path.join(__dirname, './src'),
|
|
||||||
entry: {
|
|
||||||
// dapps
|
|
||||||
'basiccoin': ['./dapps/basiccoin.js'],
|
|
||||||
'dappreg': ['./dapps/dappreg.js'],
|
|
||||||
'githubhint': ['./dapps/githubhint.js'],
|
|
||||||
'registry': ['./dapps/registry.js'],
|
|
||||||
'signaturereg': ['./dapps/signaturereg.js'],
|
|
||||||
'localtx': ['./dapps/localtx.js'],
|
|
||||||
'tokenreg': ['./dapps/tokenreg.js'],
|
|
||||||
// app
|
|
||||||
'index': ['./index.js']
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, DEST),
|
|
||||||
filename: '[name].js'
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
loaders: [
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loaders: [ 'happypack/loader?id=js' ]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
include: /node_modules\/material-ui-chip-input/,
|
|
||||||
loader: 'babel'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.json$/,
|
|
||||||
loaders: ['json']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.html$/,
|
|
||||||
loader: 'file?name=[name].[ext]!extract-loader!html-loader'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
include: [/src/],
|
|
||||||
loaders: [ 'happypack/loader?id=css' ]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
exclude: [/src/],
|
|
||||||
loader: 'style!css'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(png|jpg)$/,
|
|
||||||
loader: 'file-loader?name=[name].[hash].[ext]'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(woff(2)|ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
|
||||||
loader: 'file-loader'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
noParse: [
|
|
||||||
/node_modules\/sinon/
|
|
||||||
]
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
root: path.join(__dirname, 'node_modules'),
|
|
||||||
fallback: path.join(__dirname, 'node_modules'),
|
|
||||||
extensions: ['', '.js', '.jsx'],
|
|
||||||
unsafeCache: true
|
|
||||||
},
|
|
||||||
resolveLoaders: {
|
|
||||||
root: path.join(__dirname, 'node_modules'),
|
|
||||||
fallback: path.join(__dirname, 'node_modules')
|
|
||||||
},
|
|
||||||
|
|
||||||
htmlLoader: {
|
|
||||||
root: path.resolve(__dirname, 'assets/images'),
|
|
||||||
attrs: ['img:src', 'link:href']
|
|
||||||
},
|
|
||||||
|
|
||||||
postcss: [
|
|
||||||
postcssImport({
|
|
||||||
addDependencyTo: webpack
|
|
||||||
}),
|
|
||||||
postcssNested({}),
|
|
||||||
postcssVars({
|
|
||||||
unknown: function (node, name, result) {
|
|
||||||
node.warn(result, `Unknown variable ${name}`);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
rucksack({
|
|
||||||
autoprefixer: true
|
|
||||||
})
|
|
||||||
],
|
|
||||||
plugins: (function () {
|
|
||||||
const plugins = [
|
|
||||||
new HappyPack({
|
|
||||||
id: 'css',
|
|
||||||
threads: 4,
|
|
||||||
loaders: [
|
|
||||||
'style',
|
|
||||||
'css?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
|
|
||||||
'postcss'
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
new HappyPack({
|
|
||||||
id: 'js',
|
|
||||||
threads: 4,
|
|
||||||
loaders: isProd ? ['babel'] : [
|
|
||||||
'react-hot',
|
|
||||||
'babel?cacheDirectory=true'
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
new CopyWebpackPlugin([{ from: './error_pages.css', to: 'styles.css' }], {}),
|
|
||||||
new WebpackErrorNotificationPlugin(),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env': {
|
|
||||||
NODE_ENV: JSON.stringify(ENV),
|
|
||||||
RPC_ADDRESS: JSON.stringify(process.env.RPC_ADDRESS),
|
|
||||||
PARITY_URL: JSON.stringify(process.env.PARITY_URL),
|
|
||||||
LOGGING: JSON.stringify(!isProd)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
new webpack.DllReferencePlugin({
|
|
||||||
context: '.',
|
|
||||||
manifest: require(`./${DEST}/vendor-manifest.json`)
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!isProd) {
|
|
||||||
plugins.push(
|
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
|
||||||
filename: 'commons.js',
|
|
||||||
name: 'commons'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isProd) {
|
|
||||||
plugins.push(
|
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
|
||||||
chunks: ['index'],
|
|
||||||
name: 'commons'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
plugins.push(new webpack.optimize.OccurrenceOrderPlugin(false));
|
|
||||||
plugins.push(new webpack.optimize.DedupePlugin());
|
|
||||||
plugins.push(new webpack.optimize.UglifyJsPlugin({
|
|
||||||
screwIe8: true,
|
|
||||||
compress: {
|
|
||||||
warnings: false
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
comments: false
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return plugins;
|
|
||||||
}()),
|
|
||||||
devServer: {
|
|
||||||
contentBase: `./${DEST}`,
|
|
||||||
historyApiFallback: false,
|
|
||||||
quiet: false,
|
|
||||||
hot: !isProd,
|
|
||||||
proxy: [
|
|
||||||
{
|
|
||||||
context: (pathname, req) => {
|
|
||||||
return pathname === '/' && req.method === 'HEAD';
|
|
||||||
},
|
|
||||||
target: 'http://127.0.0.1:8180',
|
|
||||||
changeOrigin: true,
|
|
||||||
autoRewrite: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
context: '/api',
|
|
||||||
target: 'http://127.0.0.1:8080',
|
|
||||||
changeOrigin: true,
|
|
||||||
autoRewrite: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
context: '/app',
|
|
||||||
target: 'http://127.0.0.1:8080',
|
|
||||||
changeOrigin: true,
|
|
||||||
pathRewrite: {
|
|
||||||
'^/app': ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
context: '/parity-utils',
|
|
||||||
target: 'http://127.0.0.1:3000',
|
|
||||||
changeOrigin: true,
|
|
||||||
pathRewrite: {
|
|
||||||
'^/parity-utils': ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
context: '/rpc',
|
|
||||||
target: 'http://127.0.0.1:8080',
|
|
||||||
changeOrigin: true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
158
js/webpack/app.js
Normal file
158
js/webpack/app.js
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
|
||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const path = require('path');
|
||||||
|
const WebpackErrorNotificationPlugin = require('webpack-error-notification');
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
|
const Shared = require('./shared');
|
||||||
|
const DAPPS = require('../src/dapps');
|
||||||
|
|
||||||
|
const FAVICON = path.resolve(__dirname, '../assets/images/parity-logo-black-no-text.png');
|
||||||
|
|
||||||
|
const DEST = process.env.BUILD_DEST || '.build';
|
||||||
|
const ENV = process.env.NODE_ENV || 'development';
|
||||||
|
const isProd = ENV === 'production';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
cache: !isProd,
|
||||||
|
devtool: isProd ? '#eval' : '#cheap-module-eval-source-map',
|
||||||
|
|
||||||
|
context: path.join(__dirname, '../src'),
|
||||||
|
entry: Object.assign({}, Shared.dappsEntry, {
|
||||||
|
index: './index.js'
|
||||||
|
}),
|
||||||
|
output: {
|
||||||
|
publicPath: '/',
|
||||||
|
path: path.join(__dirname, '../', DEST),
|
||||||
|
filename: '[name].[hash].js'
|
||||||
|
},
|
||||||
|
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
// use: [ 'happypack/loader?id=js' ]
|
||||||
|
use: isProd ? ['babel-loader'] : [
|
||||||
|
'babel-loader?cacheDirectory=true'
|
||||||
|
],
|
||||||
|
options: Shared.getBabelrc()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
include: /node_modules\/material-ui-chip-input/,
|
||||||
|
use: [ 'babel-loader' ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.json$/,
|
||||||
|
use: [ 'json-loader' ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
use: [
|
||||||
|
'file-loader?name=[name].[ext]!extract-loader',
|
||||||
|
{
|
||||||
|
loader: 'html-loader',
|
||||||
|
options: {
|
||||||
|
root: path.resolve(__dirname, '../assets/images'),
|
||||||
|
attrs: ['img:src', 'link:href']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
include: [ /src/ ],
|
||||||
|
// use: [ 'happypack/loader?id=css' ]
|
||||||
|
use: [
|
||||||
|
'style-loader',
|
||||||
|
'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
|
||||||
|
'postcss-loader'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
exclude: [ /src/ ],
|
||||||
|
use: [ 'style-loader', 'css-loader' ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpg)$/,
|
||||||
|
use: [ 'file-loader?name=[name].[hash].[ext]' ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff(2)|ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||||
|
use: [ 'file-loader' ]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
noParse: [
|
||||||
|
/node_modules\/sinon/
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
resolve: {
|
||||||
|
modules: [
|
||||||
|
path.join(__dirname, '../node_modules')
|
||||||
|
],
|
||||||
|
extensions: ['.json', '.js', '.jsx'],
|
||||||
|
unsafeCache: true
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: (function () {
|
||||||
|
const plugins = Shared.getPlugins().concat([
|
||||||
|
new CopyWebpackPlugin([{ from: './error_pages.css', to: 'styles.css' }], {}),
|
||||||
|
new WebpackErrorNotificationPlugin(),
|
||||||
|
|
||||||
|
new webpack.DllReferencePlugin({
|
||||||
|
context: '.',
|
||||||
|
manifest: require(`../${DEST}/vendor-manifest.json`)
|
||||||
|
}),
|
||||||
|
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
title: 'Parity',
|
||||||
|
filename: 'index.html',
|
||||||
|
template: './index.ejs',
|
||||||
|
favicon: FAVICON,
|
||||||
|
chunks: [ isProd ? null : 'commons', 'index' ]
|
||||||
|
})
|
||||||
|
], DAPPS.map((dapp) => {
|
||||||
|
return new HtmlWebpackPlugin({
|
||||||
|
title: dapp.title,
|
||||||
|
filename: dapp.name + '.html',
|
||||||
|
template: './dapps/index.ejs',
|
||||||
|
favicon: FAVICON,
|
||||||
|
secure: dapp.secure,
|
||||||
|
chunks: [ isProd ? null : 'commons', dapp.name ]
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (!isProd) {
|
||||||
|
plugins.push(
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
filename: 'commons.[hash].js',
|
||||||
|
name: 'commons',
|
||||||
|
minChunks: Infinity
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugins;
|
||||||
|
}())
|
||||||
|
};
|
@ -15,7 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
// test only
|
// test only
|
||||||
/**
|
/**
|
||||||
* Run `PARITY_URL="127.0.0.1:8180" NODE_ENV="production" npm run build`
|
* Run `DAPPS_URL="/" PARITY_URL="127.0.0.1:8180" NODE_ENV="production" npm run build`
|
||||||
* to build the project ; use this server to test that the minifed
|
* to build the project ; use this server to test that the minifed
|
||||||
* version is working (this is a simple proxy server)
|
* version is working (this is a simple proxy server)
|
||||||
*/
|
*/
|
||||||
@ -23,39 +23,17 @@
|
|||||||
var express = require('express');
|
var express = require('express');
|
||||||
var proxy = require('http-proxy-middleware');
|
var proxy = require('http-proxy-middleware');
|
||||||
|
|
||||||
|
var Shared = require('./shared');
|
||||||
|
|
||||||
var app = express();
|
var app = express();
|
||||||
var wsProxy = proxy('ws://127.0.0.1:8180', { changeOrigin: true });
|
var wsProxy = proxy('ws://127.0.0.1:8180', { changeOrigin: true });
|
||||||
|
|
||||||
|
Shared.addProxies(app);
|
||||||
|
|
||||||
app.use(express.static('.build'));
|
app.use(express.static('.build'));
|
||||||
|
|
||||||
app.use('/api/*', proxy({
|
|
||||||
target: 'http://127.0.0.1:8080',
|
|
||||||
changeOrigin: true
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.use('/app/*', proxy({
|
|
||||||
target: 'http://127.0.0.1:8080',
|
|
||||||
changeOrigin: true,
|
|
||||||
pathRewrite: {
|
|
||||||
'^/app': ''
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.use('/parity-utils/*', proxy({
|
|
||||||
target: 'http://127.0.0.1:3000',
|
|
||||||
changeOrigin: true,
|
|
||||||
pathRewrite: {
|
|
||||||
'^/parity-utils': ''
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.use('/rpc/*', proxy({
|
|
||||||
target: 'http://127.0.0.1:8080',
|
|
||||||
changeOrigin: true
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.use(wsProxy);
|
app.use(wsProxy);
|
||||||
|
|
||||||
var server = app.listen(3000);
|
var server = app.listen(process.env.PORT || 3000, function () {
|
||||||
|
console.log('Listening on port', server.address().port);
|
||||||
|
});
|
||||||
server.on('upgrade', wsProxy.upgrade);
|
server.on('upgrade', wsProxy.upgrade);
|
80
js/webpack/dev.server.js
Normal file
80
js/webpack/dev.server.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const webpackDevMiddleware = require('webpack-dev-middleware');
|
||||||
|
const webpackHotMiddleware = require('webpack-hot-middleware');
|
||||||
|
|
||||||
|
const http = require('http');
|
||||||
|
const express = require('express');
|
||||||
|
const ProgressBar = require('progress');
|
||||||
|
|
||||||
|
const webpackConfig = require('./app');
|
||||||
|
const Shared = require('./shared');
|
||||||
|
|
||||||
|
let progressBar = { update: () => {} };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add webpack hot middleware to each entry in the config
|
||||||
|
* and HMR to the plugins
|
||||||
|
*/
|
||||||
|
(function updateWebpackConfig () {
|
||||||
|
Object.keys(webpackConfig.entry).forEach((key) => {
|
||||||
|
const entry = webpackConfig.entry[key];
|
||||||
|
|
||||||
|
webpackConfig.entry[key] = [].concat(
|
||||||
|
'react-hot-loader/patch',
|
||||||
|
'webpack-hot-middleware/client?reload=true',
|
||||||
|
entry
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
|
||||||
|
webpackConfig.plugins.push(new webpack.NamedModulesPlugin());
|
||||||
|
webpackConfig.plugins.push(new webpack.NoErrorsPlugin());
|
||||||
|
|
||||||
|
webpackConfig.plugins.push(new webpack.ProgressPlugin(
|
||||||
|
(percentage) => progressBar.update(percentage)
|
||||||
|
));
|
||||||
|
})();
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const compiler = webpack(webpackConfig);
|
||||||
|
|
||||||
|
app.use(webpackHotMiddleware(compiler, {
|
||||||
|
log: console.log
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use(webpackDevMiddleware(compiler, {
|
||||||
|
noInfo: false,
|
||||||
|
quiet: false,
|
||||||
|
progress: true,
|
||||||
|
publicPath: webpackConfig.output.publicPath,
|
||||||
|
stats: {
|
||||||
|
colors: true
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use(express.static(webpackConfig.output.path));
|
||||||
|
|
||||||
|
// Add the dev proxies in the express App
|
||||||
|
Shared.addProxies(app);
|
||||||
|
|
||||||
|
const server = http.createServer(app);
|
||||||
|
server.listen(process.env.PORT || 3000, function () {
|
||||||
|
console.log('Listening on port', server.address().port);
|
||||||
|
progressBar = new ProgressBar('[:bar] :percent :etas', { total: 50 });
|
||||||
|
});
|
@ -16,16 +16,16 @@
|
|||||||
|
|
||||||
// Run with `webpack --config webpack.libraries.js --progress`
|
// Run with `webpack --config webpack.libraries.js --progress`
|
||||||
|
|
||||||
const HappyPack = require('happypack');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
|
||||||
|
|
||||||
|
const Shared = require('./shared');
|
||||||
|
|
||||||
|
const DEST = process.env.BUILD_DEST || '.build';
|
||||||
const ENV = process.env.NODE_ENV || 'development';
|
const ENV = process.env.NODE_ENV || 'development';
|
||||||
const isProd = ENV === 'production';
|
const isProd = ENV === 'production';
|
||||||
const DEST = process.env.BUILD_DEST || '.build';
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
context: path.join(__dirname, './src'),
|
context: path.join(__dirname, '../src'),
|
||||||
entry: {
|
entry: {
|
||||||
// library
|
// library
|
||||||
'inject': ['./web3.js'],
|
'inject': ['./web3.js'],
|
||||||
@ -33,59 +33,31 @@ module.exports = {
|
|||||||
'parity': ['./parity.js']
|
'parity': ['./parity.js']
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, DEST),
|
path: path.join(__dirname, '../', DEST),
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
library: '[name].js',
|
library: '[name].js',
|
||||||
libraryTarget: 'umd'
|
libraryTarget: 'umd'
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'happypack/loader?id=js'
|
// use: [ 'happypack/loader?id=js' ]
|
||||||
|
use: isProd ? ['babel-loader'] : [
|
||||||
|
// 'react-hot-loader',
|
||||||
|
'babel-loader?cacheDirectory=true'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.json$/,
|
test: /\.json$/,
|
||||||
loaders: ['json']
|
use: [ 'json-loader' ]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.html$/,
|
test: /\.html$/,
|
||||||
loader: 'file?name=[name].[ext]'
|
use: [ 'file-loader?name=[name].[ext]' ]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
plugins: (function () {
|
plugins: Shared.getPlugins()
|
||||||
const plugins = [
|
|
||||||
new HappyPack({
|
|
||||||
id: 'js',
|
|
||||||
threads: 4,
|
|
||||||
loaders: [ 'babel' ]
|
|
||||||
}),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env': {
|
|
||||||
NODE_ENV: JSON.stringify(ENV),
|
|
||||||
RPC_ADDRESS: JSON.stringify(process.env.RPC_ADDRESS),
|
|
||||||
PARITY_URL: JSON.stringify(process.env.PARITY_URL),
|
|
||||||
LOGGING: JSON.stringify(!isProd)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
if (isProd) {
|
|
||||||
plugins.push(new webpack.optimize.OccurrenceOrderPlugin(false));
|
|
||||||
plugins.push(new webpack.optimize.DedupePlugin());
|
|
||||||
plugins.push(new webpack.optimize.UglifyJsPlugin({
|
|
||||||
screwIe8: true,
|
|
||||||
compress: {
|
|
||||||
warnings: false
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
comments: false
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return plugins;
|
|
||||||
}())
|
|
||||||
};
|
};
|
@ -15,19 +15,20 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const packageJson = require('./package.json');
|
const packageJson = require('../package.json');
|
||||||
|
|
||||||
|
const Shared = require('./shared');
|
||||||
|
|
||||||
const ENV = process.env.NODE_ENV || 'development';
|
const ENV = process.env.NODE_ENV || 'development';
|
||||||
const isProd = ENV === 'production';
|
const isProd = ENV === 'production';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
context: path.join(__dirname, './src'),
|
context: path.join(__dirname, '../src'),
|
||||||
target: 'node',
|
target: 'node',
|
||||||
entry: 'library.js',
|
entry: 'library.js',
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, '.npmjs'),
|
path: path.join(__dirname, '../.npmjs'),
|
||||||
filename: 'library.js',
|
filename: 'library.js',
|
||||||
library: 'Parity',
|
library: 'Parity',
|
||||||
libraryTarget: 'umd',
|
libraryTarget: 'umd',
|
||||||
@ -41,20 +42,28 @@ module.exports = {
|
|||||||
noParse: [
|
noParse: [
|
||||||
/babel-polyfill/
|
/babel-polyfill/
|
||||||
],
|
],
|
||||||
loaders: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /(\.jsx|\.js)$/,
|
test: /(\.jsx|\.js)$/,
|
||||||
loader: 'babel',
|
// use: [ 'happypack/loader?id=js' ],
|
||||||
|
use: isProd ? ['babel-loader'] : [
|
||||||
|
// 'react-hot-loader',
|
||||||
|
'babel-loader?cacheDirectory=true'
|
||||||
|
],
|
||||||
exclude: /node_modules/
|
exclude: /node_modules/
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
root: path.resolve('./src'),
|
modules: [
|
||||||
extensions: ['', '.js']
|
path.resolve('./src'),
|
||||||
|
path.join(__dirname, '../node_modules')
|
||||||
|
],
|
||||||
|
extensions: ['.json', '.js', '.jsx']
|
||||||
},
|
},
|
||||||
plugins: (function () {
|
|
||||||
const plugins = [
|
plugins: Shared.getPlugins().concat([
|
||||||
new CopyWebpackPlugin([
|
new CopyWebpackPlugin([
|
||||||
{
|
{
|
||||||
from: '../parity.package.json',
|
from: '../parity.package.json',
|
||||||
@ -73,20 +82,5 @@ module.exports = {
|
|||||||
to: 'README.md'
|
to: 'README.md'
|
||||||
}
|
}
|
||||||
], { copyUnmodified: true })
|
], { copyUnmodified: true })
|
||||||
];
|
])
|
||||||
|
|
||||||
if (isProd) {
|
|
||||||
plugins.push(new webpack.optimize.UglifyJsPlugin({
|
|
||||||
screwIe8: true,
|
|
||||||
compress: {
|
|
||||||
warnings: false
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
comments: false
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return plugins;
|
|
||||||
}())
|
|
||||||
};
|
};
|
176
js/webpack/shared.js
Normal file
176
js/webpack/shared.js
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
// const HappyPack = require('happypack');
|
||||||
|
|
||||||
|
const postcssImport = require('postcss-import');
|
||||||
|
const postcssNested = require('postcss-nested');
|
||||||
|
const postcssVars = require('postcss-simple-vars');
|
||||||
|
const rucksack = require('rucksack-css');
|
||||||
|
|
||||||
|
const ENV = process.env.NODE_ENV || 'development';
|
||||||
|
const isProd = ENV === 'production';
|
||||||
|
|
||||||
|
function getBabelrc () {
|
||||||
|
const babelrc = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../.babelrc')));
|
||||||
|
|
||||||
|
const es2015Index = babelrc.presets.findIndex((p) => p === 'es2015');
|
||||||
|
|
||||||
|
// [ "es2015", { "modules": false } ]
|
||||||
|
babelrc.presets[es2015Index] = [ 'es2015', { modules: false } ];
|
||||||
|
babelrc['babelrc'] = false;
|
||||||
|
return babelrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPlugins (_isProd = isProd) {
|
||||||
|
const postcss = [
|
||||||
|
postcssImport({
|
||||||
|
addDependencyTo: webpack
|
||||||
|
}),
|
||||||
|
postcssNested({}),
|
||||||
|
postcssVars({
|
||||||
|
unknown: function (node, name, result) {
|
||||||
|
node.warn(result, `Unknown variable ${name}`);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
rucksack({
|
||||||
|
autoprefixer: true
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
const plugins = [
|
||||||
|
// NB: HappyPack is not yet working with Webpack 2... (as of Nov. 26)
|
||||||
|
|
||||||
|
// new HappyPack({
|
||||||
|
// id: 'css',
|
||||||
|
// threads: 4,
|
||||||
|
// loaders: [
|
||||||
|
// 'style-loader',
|
||||||
|
// 'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
|
||||||
|
// 'postcss-loader'
|
||||||
|
// ]
|
||||||
|
// }),
|
||||||
|
|
||||||
|
// new HappyPack({
|
||||||
|
// id: 'js',
|
||||||
|
// threads: 4,
|
||||||
|
// loaders: _isProd ? ['babel'] : [
|
||||||
|
// 'react-hot-loader',
|
||||||
|
// 'babel-loader?cacheDirectory=true'
|
||||||
|
// ]
|
||||||
|
// }),
|
||||||
|
|
||||||
|
// new HappyPack({
|
||||||
|
// id: 'babel',
|
||||||
|
// threads: 4,
|
||||||
|
// loaders: ['babel-loader']
|
||||||
|
// }),
|
||||||
|
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': {
|
||||||
|
NODE_ENV: JSON.stringify(ENV),
|
||||||
|
RPC_ADDRESS: JSON.stringify(process.env.RPC_ADDRESS),
|
||||||
|
PARITY_URL: JSON.stringify(process.env.PARITY_URL),
|
||||||
|
DAPPS_URL: JSON.stringify(process.env.DAPPS_URL),
|
||||||
|
LOGGING: JSON.stringify(!isProd)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
minimize: isProd,
|
||||||
|
debug: !isProd,
|
||||||
|
options: {
|
||||||
|
context: path.join(__dirname, '../src'),
|
||||||
|
postcss: postcss,
|
||||||
|
babel: getBabelrc()
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
new webpack.optimize.OccurrenceOrderPlugin(!_isProd)
|
||||||
|
];
|
||||||
|
|
||||||
|
if (_isProd) {
|
||||||
|
plugins.push(new webpack.optimize.UglifyJsPlugin({
|
||||||
|
screwIe8: true,
|
||||||
|
compress: {
|
||||||
|
warnings: false
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
comments: false
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDappsEntry () {
|
||||||
|
const DAPPS = require('../src/dapps');
|
||||||
|
|
||||||
|
return DAPPS.reduce((_entry, dapp) => {
|
||||||
|
_entry[dapp.name] = './dapps/' + dapp.entry;
|
||||||
|
return _entry;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addProxies (app) {
|
||||||
|
const proxy = require('http-proxy-middleware');
|
||||||
|
|
||||||
|
app.use(proxy((pathname, req) => {
|
||||||
|
return pathname === '/' && req.method === 'HEAD';
|
||||||
|
}, {
|
||||||
|
target: 'http://127.0.0.1:8180',
|
||||||
|
changeOrigin: true,
|
||||||
|
autoRewrite: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use('/api', proxy({
|
||||||
|
target: 'http://127.0.0.1:8080',
|
||||||
|
changeOrigin: true,
|
||||||
|
autoRewrite: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use('/app', proxy({
|
||||||
|
target: 'http://127.0.0.1:8080',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: {
|
||||||
|
'^/app': ''
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use('/parity-utils', proxy({
|
||||||
|
target: 'http://127.0.0.1:3000',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: {
|
||||||
|
'^/parity-utils': ''
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use('/rpc', proxy({
|
||||||
|
target: 'http://127.0.0.1:8080',
|
||||||
|
changeOrigin: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getBabelrc: getBabelrc,
|
||||||
|
getPlugins: getPlugins,
|
||||||
|
dappsEntry: getDappsEntry(),
|
||||||
|
addProxies: addProxies
|
||||||
|
};
|
@ -14,11 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
const HappyPack = require('happypack');
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const Shared = require('./shared');
|
||||||
|
|
||||||
const ENV = process.env.NODE_ENV || 'development';
|
const ENV = process.env.NODE_ENV || 'development';
|
||||||
const isProd = ENV === 'production';
|
|
||||||
const DEST = process.env.BUILD_DEST || '.build';
|
const DEST = process.env.BUILD_DEST || '.build';
|
||||||
|
|
||||||
let modules = [
|
let modules = [
|
||||||
@ -45,69 +46,38 @@ let modules = [
|
|||||||
'scryptsy'
|
'scryptsy'
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!isProd) {
|
|
||||||
modules = modules.concat([
|
|
||||||
'webpack-dev-server/client?http://localhost:3000',
|
|
||||||
'react-hot-loader', 'core-js', 'core-js/library'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
vendor: modules
|
vendor: modules
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.json$/,
|
test: /\.json$/,
|
||||||
loaders: ['json']
|
use: [ 'json-loader' ]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
include: /(ethereumjs-tx)/,
|
include: /(ethereumjs-tx)/,
|
||||||
loaders: [ 'happypack/loader?id=js' ]
|
use: [ 'babel-loader' ]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
path: `${DEST}/`,
|
path: path.resolve(__dirname, '../', `${DEST}/`),
|
||||||
library: '[name]_lib'
|
library: '[name]_lib'
|
||||||
},
|
},
|
||||||
plugins: (function () {
|
plugins: Shared.getPlugins().concat([
|
||||||
const plugins = [
|
|
||||||
new webpack.DllPlugin({
|
new webpack.DllPlugin({
|
||||||
name: '[name]_lib',
|
name: '[name]_lib',
|
||||||
path: `${DEST}/[name]-manifest.json`
|
path: path.resolve(__dirname, '../', `${DEST}/[name]-manifest.json`)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': {
|
'process.env': {
|
||||||
NODE_ENV: JSON.stringify(ENV)
|
NODE_ENV: JSON.stringify(ENV)
|
||||||
}
|
}
|
||||||
}),
|
|
||||||
|
|
||||||
new HappyPack({
|
|
||||||
id: 'js',
|
|
||||||
threads: 4,
|
|
||||||
loaders: ['babel']
|
|
||||||
})
|
})
|
||||||
];
|
])
|
||||||
|
|
||||||
if (isProd) {
|
|
||||||
plugins.push(new webpack.optimize.OccurrenceOrderPlugin(false));
|
|
||||||
plugins.push(new webpack.optimize.DedupePlugin());
|
|
||||||
plugins.push(new webpack.optimize.UglifyJsPlugin({
|
|
||||||
screwIe8: true,
|
|
||||||
compress: {
|
|
||||||
warnings: false
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
comments: false
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return plugins;
|
|
||||||
}())
|
|
||||||
};
|
};
|
3
parity/cli/config.invalid3.toml
Normal file
3
parity/cli/config.invalid3.toml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[signer]
|
||||||
|
passwd = []
|
||||||
|
|
@ -649,11 +649,12 @@ mod tests {
|
|||||||
fn should_parse_config_and_return_errors() {
|
fn should_parse_config_and_return_errors() {
|
||||||
let config1 = Args::parse_config(include_str!("./config.invalid1.toml"));
|
let config1 = Args::parse_config(include_str!("./config.invalid1.toml"));
|
||||||
let config2 = Args::parse_config(include_str!("./config.invalid2.toml"));
|
let config2 = Args::parse_config(include_str!("./config.invalid2.toml"));
|
||||||
|
let config3 = Args::parse_config(include_str!("./config.invalid3.toml"));
|
||||||
|
|
||||||
match (config1, config2) {
|
match (config1, config2, config3) {
|
||||||
(Err(ArgsError::Parsing(_)), Err(ArgsError::Decode(_))) => {},
|
(Err(ArgsError::Parsing(_)), Err(ArgsError::Decode(_)), Err(ArgsError::UnknownFields(_))) => {},
|
||||||
(a, b) => {
|
(a, b, c) => {
|
||||||
assert!(false, "Got invalid error types: {:?}, {:?}", a, b);
|
assert!(false, "Got invalid error types: {:?}, {:?}, {:?}", a, b, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user