Initial new UI source code import (#2607)
* address -> name mappings * expanding, loading all coin details * send use only actual BasicCoin tokens registered (any reg) * sending token & accounts * form styling updates * send form layout in place * coin send working as expected * api subscriptions on multiple addresses * bring in events * simplify * basic events display in-place, functionally complete * basic functionality in-place * fix horrible event address issue * rwork display of events slightly * test TLA availability * table for owner -> tokens * fix signature lookup address * fix signature lookup address * basic overview styling * txhash links * page layout adjustments * background import * adjust colors * no global registration, simplify color selection * updated styling * connection dialog for "busy connecting" * initial token connection - WIP * init token updates take place * basic test for manual token * rework connection display * allow updates of the secure token * first stab at making the build build * update runner tags * fix linting issues * skip tests requiring network (should be e2e, TODO) * re-enable javascript tag/runner * release push does the trick * push to any branch, CI name * javscript-test runner as well * swap dependencies build requires test * revert stages swap * retrieve images associated with tokens * remove js build deps order * null image when hash = 0x0 * 6x64 images (hashes for registries) * don't pass tokens as prop to IdentityIcon * check images against content hash pictures * cleanup signer after connection changes * fix naming typo * display unknownImages for balances (not available as content hash) * unknownImage for transfer dialog * basic githubhint layout * single input for commit/filename * ethcore_hashContent call * lookup hash * registration in place * fixes * events is using a proper table * pass value through as-is * stop wrongly using main app IdentityIcon * NEVER export class instance functions * alignment back to normal * typo in definition * set & get images working (mostly) * show content retrieval info * set exitcode via || * use javascript:latest images * disable npm progress bar * rename phase I * rename phase II * only send build output to GitHub on major branches * also run the build step as part of the test (until comprehensive) * ci-specific build (no webpack progress) * allow for account creation via recovery phrase * display account uuid (where available), closes #2546 * connection dialog now shows up in dapps as well, closes #2538 * token images show up as expected * IdentityName component added and deployed * fix padding tests * adjust tests to map to stricter 0x-prefixed hex * render names via common component for the address -> name * split lint into seperate script (early exit) * test phases changed to lint, test & pack * pack part of test phase * remove files marked for deletion (cleanup) * Signer cleanups, start moving in the direction of the rest * add personal signer methods * basic signer request subscription * don't poll blockNumber when not connected * missing return, creating massive ws queue backlogs * ΞTH -> ETH * fix failing tests * registry uses setAddress to actually set addresses now * bytes mapping operates on lowerCase hex strings * sha3 ids for each application * add dappreg to list of contracts * adjust alignment of queries * show gas estimation log * abi with payable for register function * add key as required * image retrieval from dappreg * use proper Image urls * embed and link apps from Parity, retrieved via /api/apps * filter apps that has been replaced * proxy entry for parity-utils * add basiccoin abi * add support for fallback abi type * capture constructor paramaters * merge master into js * move images to assets/images/ * add font assets * import fonts as part of build * don't inline woff files * Revert "merge master into js" This reverts commit cfcfa81bd26f1b3cbc748d3afa1eb5c670b363fe. * remove unused npm packages * information on gas estimates (like almost everywhere else) * don't pass gas & gasPrice to estimation * display account passwordhint when available * signer subscriptions based on polling & function trapping * pending requests retrieved via jsapi * update signer middleware * remove all web3 instances * remove web3 package * last web3 dependencies removed * no need to toChecksumAddress - api takes care of it * expand description for personal_confirmRequest * Signer conversion from web3 -> parity.js completed * explicit in no return * green circle background * remove generated background * convert /api/* paths to localhost:8080/api/* paths (hard-coded, temporary) * change dapps to load from localhost:8080/ui/* * remove dangling web3 files * update manager test for signer * /api/ping -> / * additional token images * additional token images * add missing styles.css for 8180 error pages * cater for txhash returning null/empty object * adjust output directories * Release merge with origin with ours strategy * additional token images * cater for development server * s/localhost/127.0.0.1/ (cater for origin) * Fix address selection for contract deployment * Adjust z-index for error overlay * better text on unique background pattern * fix signer rejections * Don't allow gavcoin transfer with no balance * fix txhash rendering in signer * remove unnecessary ParityBackground * script to update js-precompiled * Redirect from :8080 to :8180 * Remove extra return * Dapp logo images
This commit is contained in:
44
js/src/views/Status/components/AutoComplete/AutoComplete.js
Normal file
44
js/src/views/Status/components/AutoComplete/AutoComplete.js
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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 AutoComplete from 'material-ui/AutoComplete';
|
||||
|
||||
export default class WrappedAutoComplete extends Component {
|
||||
|
||||
render () {
|
||||
return (
|
||||
<AutoComplete { ...this.props } />
|
||||
);
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
openOnFocus: true,
|
||||
filter: (searchText, key) => searchText === '' || key.toLowerCase().indexOf(searchText.toLowerCase()) !== -1
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
dataSource: PropTypes.array.isRequired,
|
||||
filter: PropTypes.func,
|
||||
name: PropTypes.string.isRequired,
|
||||
openOnFocus: PropTypes.bool
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
muiTheme: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// 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 from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import getMuiTheme from 'material-ui/styles/getMuiTheme';
|
||||
|
||||
import WrappedAutoComplete from './AutoComplete';
|
||||
|
||||
describe('components/AutoComplete', () => {
|
||||
describe('rendering', () => {
|
||||
let rendered;
|
||||
|
||||
beforeEach(() => {
|
||||
const dataSource = ['abc', 'def', 'ghi'];
|
||||
const component =
|
||||
<WrappedAutoComplete
|
||||
dataSource={ dataSource }
|
||||
name='testComponent'
|
||||
/>;
|
||||
|
||||
rendered = shallow(component, { context: { muiTheme: getMuiTheme({}) } });
|
||||
});
|
||||
|
||||
it('renders the material AutoComplete component', () => {
|
||||
expect(rendered).to.be.ok;
|
||||
expect(rendered).to.have.exactly(1).descendants('AutoComplete');
|
||||
});
|
||||
});
|
||||
});
|
||||
17
js/src/views/Status/components/AutoComplete/index.js
Normal file
17
js/src/views/Status/components/AutoComplete/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 './AutoComplete';
|
||||
47
js/src/views/Status/components/Box/Box.js
Normal file
47
js/src/views/Status/components/Box/Box.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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';
|
||||
|
||||
export default class Box extends Component {
|
||||
|
||||
renderValue () {
|
||||
if (!this.props.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<h1>{ this.props.value }</h1>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='dapp-box'>
|
||||
<h2>{ this.props.title }</h2>
|
||||
{ this.renderValue() }
|
||||
{ this.props.children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
value: PropTypes.string,
|
||||
children: PropTypes.element
|
||||
}
|
||||
|
||||
}
|
||||
70
js/src/views/Status/components/Box/Box.spec.js
Normal file
70
js/src/views/Status/components/Box/Box.spec.js
Normal file
@@ -0,0 +1,70 @@
|
||||
// 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 from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Box from './Box';
|
||||
|
||||
describe('components/Box', () => {
|
||||
describe('rendering', () => {
|
||||
const title = 'test title';
|
||||
let rendered;
|
||||
|
||||
beforeEach(() => {
|
||||
rendered = shallow(<Box title={ title } />);
|
||||
});
|
||||
|
||||
it('renders the component', () => {
|
||||
expect(rendered).to.be.ok;
|
||||
expect(rendered).to.have.className('dapp-box');
|
||||
});
|
||||
|
||||
it('renders the title', () => {
|
||||
expect(rendered.find('h2')).to.have.text(title);
|
||||
});
|
||||
|
||||
it('renders no default value', () => {
|
||||
expect(rendered).to.not.have.descendants('h1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('contents', () => {
|
||||
const value = 'test value';
|
||||
const child = 'this is the child value';
|
||||
|
||||
let rendered;
|
||||
|
||||
beforeEach(() => {
|
||||
rendered = shallow(
|
||||
<Box
|
||||
title='title'
|
||||
value={ value }
|
||||
>
|
||||
<pre>{ child }</pre>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
it('renders the value', () => {
|
||||
expect(rendered.find('h1')).to.have.text(value);
|
||||
});
|
||||
|
||||
it('wraps the children', () => {
|
||||
expect(rendered.find('pre')).to.have.text(child);
|
||||
});
|
||||
});
|
||||
});
|
||||
17
js/src/views/Status/components/Box/index.js
Normal file
17
js/src/views/Status/components/Box/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 './Box';
|
||||
40
js/src/views/Status/components/Call/Call.css
Normal file
40
js/src/views/Status/components/Call/Call.css
Normal file
@@ -0,0 +1,40 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.call {
|
||||
position: relative;
|
||||
border-bottom: 2px solid #CCC6C6;
|
||||
margin-bottom: 18.4px;
|
||||
background: #f5f4f2;
|
||||
}
|
||||
|
||||
.call:first-child {
|
||||
border-color: #6691C2;
|
||||
}
|
||||
|
||||
.call pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.call pre:nth-child(3) {
|
||||
padding-top: 0;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.callNo {
|
||||
float: right;
|
||||
color: #ccc;
|
||||
}
|
||||
69
js/src/views/Status/components/Call/Call.js
Normal file
69
js/src/views/Status/components/Call/Call.js
Normal file
@@ -0,0 +1,69 @@
|
||||
// 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 Response from '../Response';
|
||||
import styles from './Call.css';
|
||||
|
||||
export default class Call extends Component {
|
||||
|
||||
render () {
|
||||
let { callNo, name, params, response } = this.props.call;
|
||||
params = this.formatParams(params);
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={ this.setActiveCall }
|
||||
ref={ this.setElement }
|
||||
className={ styles.call }
|
||||
{ ...this._test(`call-${callNo}`) }
|
||||
>
|
||||
<span className={ styles.callNo } { ...this._test('callNo') }>#{ callNo }</span>
|
||||
<pre { ...this._test('name') }>{ name }({ params })</pre>
|
||||
<Response response={ response } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
setElement = el => {
|
||||
this.element = el;
|
||||
}
|
||||
|
||||
setActiveCall = () => {
|
||||
this.props.setActiveCall(this.props.call, this.element);
|
||||
}
|
||||
|
||||
formatParams (params) {
|
||||
return params.reduce((str, p) => {
|
||||
if (str !== '') {
|
||||
str += ', ';
|
||||
}
|
||||
if (p === undefined) {
|
||||
return str;
|
||||
}
|
||||
if (typeof p === 'object' || typeof p === 'string') {
|
||||
p = JSON.stringify(p);
|
||||
}
|
||||
return str + p;
|
||||
}, '');
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
call: PropTypes.object.isRequired,
|
||||
setActiveCall: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
}
|
||||
92
js/src/views/Status/components/Call/Call.spec.js
Normal file
92
js/src/views/Status/components/Call/Call.spec.js
Normal file
@@ -0,0 +1,92 @@
|
||||
// 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 from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import '../../../../environment/tests';
|
||||
|
||||
import Call from './Call';
|
||||
|
||||
describe('components/Call', () => {
|
||||
const call = { callIdx: 123, callNo: 456, name: 'eth_call', params: [{ name: '123' }], response: '' };
|
||||
const element = 'dummyElement';
|
||||
|
||||
let rendered;
|
||||
let instance;
|
||||
let setActiveCall = sinon.stub();
|
||||
|
||||
beforeEach(() => {
|
||||
rendered = shallow(
|
||||
<Call
|
||||
call={ call }
|
||||
setActiveCall={ setActiveCall }
|
||||
/>
|
||||
);
|
||||
instance = rendered.instance();
|
||||
});
|
||||
|
||||
describe('rendering', () => {
|
||||
it('renders the component', () => {
|
||||
expect(rendered).to.be.ok;
|
||||
expect(rendered).to.have.exactly(1).descendants(`div[data-test="Call-call-${call.callNo}"]`);
|
||||
});
|
||||
|
||||
it('adds onMouseEnter to setActiveElement', () => {
|
||||
expect(rendered.find('div').first()).to.have.prop('onMouseEnter', instance.setActiveCall);
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions', () => {
|
||||
it('sets the element via setElement', () => {
|
||||
expect(instance.element).to.not.be.ok;
|
||||
instance.setElement(element);
|
||||
expect(instance.element).to.equal(element);
|
||||
});
|
||||
|
||||
it('calls parent setActive call on setActiveCall', () => {
|
||||
instance.setElement(element);
|
||||
instance.setActiveCall();
|
||||
|
||||
expect(setActiveCall).to.be.calledWith(call, element);
|
||||
});
|
||||
});
|
||||
|
||||
describe('utility', () => {
|
||||
describe('.formatParams', () => {
|
||||
it('correctly returns a single parameter', () => {
|
||||
expect(instance.formatParams([1])).to.equal('1');
|
||||
});
|
||||
|
||||
it('correctly joins 2 parameters', () => {
|
||||
expect(instance.formatParams([1, 2])).to.equal('1, 2');
|
||||
});
|
||||
|
||||
it('stringifies a string object', () => {
|
||||
expect(instance.formatParams(['1'])).to.equal('"1"');
|
||||
});
|
||||
|
||||
it('stringifies an object object', () => {
|
||||
expect(instance.formatParams([{ name: '1' }])).to.equal('{"name":"1"}');
|
||||
});
|
||||
|
||||
it('skips an undefined value', () => {
|
||||
expect(instance.formatParams(['1', undefined, 3])).to.equal('"1", , 3');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
17
js/src/views/Status/components/Call/index.js
Normal file
17
js/src/views/Status/components/Call/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 './Call';
|
||||
44
js/src/views/Status/components/Calls/Calls.css
Normal file
44
js/src/views/Status/components/Calls/Calls.css
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.historyInfo {
|
||||
margin-top: 0;
|
||||
text-transform: initial;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.removeIcon {
|
||||
float: right;
|
||||
color: #bbb;
|
||||
cursor: pointer;
|
||||
transition: opacity ease-in-out 0.2s;
|
||||
transition-delay: 0.2s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
div:hover > .removeIcon {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.history {
|
||||
margin-top: calc(1em + 18.4px);
|
||||
padding-top: 0;
|
||||
overflow: auto;
|
||||
max-height: 60vh;
|
||||
}
|
||||
132
js/src/views/Status/components/Calls/Calls.js
Normal file
132
js/src/views/Status/components/Calls/Calls.js
Normal file
@@ -0,0 +1,132 @@
|
||||
// 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 AnimateChildren from '../../components-compositors/Animated/children';
|
||||
import Call from '../Call';
|
||||
import CallsToolbar from '../CallsToolbar';
|
||||
import styles from './Calls.css';
|
||||
|
||||
export default class Calls extends Component {
|
||||
|
||||
state = {
|
||||
activeCall: null,
|
||||
activeChild: null
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div
|
||||
className='calls-container'
|
||||
onMouseLeave={ this.clearActiveCall }
|
||||
{ ...this._test('container') }
|
||||
>
|
||||
{ this.renderClear() }
|
||||
<h2 className={ styles.header }>History</h2>
|
||||
<div className={ `${styles.history} row` } ref={ this.setCallsHistory }>
|
||||
{ this.renderNoCallsMsg() }
|
||||
{ this.renderCalls() }
|
||||
</div>
|
||||
<CallsToolbar
|
||||
call={ this.state.activeCall }
|
||||
callEl={ this.state.activeChild }
|
||||
containerEl={ this._callsHistory }
|
||||
actions={ this.props.actions }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderClear () {
|
||||
if (!this.props.calls.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
{ ...this._test('remove') }
|
||||
title='Clear RPC calls history'
|
||||
onClick={ this.clearHistory }
|
||||
className={ styles.removeIcon }
|
||||
>
|
||||
<i className='icon-trash'></i>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
renderNoCallsMsg () {
|
||||
if (this.props.calls.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<AnimateChildren>
|
||||
<div { ...this._test('empty-wrapper') }>
|
||||
<h3 className={ styles.historyInfo } { ...this._test('empty') }>
|
||||
Fire up some calls and the results will be here.
|
||||
</h3>
|
||||
</div>
|
||||
</AnimateChildren>
|
||||
);
|
||||
}
|
||||
|
||||
renderCalls () {
|
||||
const { calls } = this.props;
|
||||
|
||||
if (!calls.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<AnimateChildren>
|
||||
{ calls.map((call, idx) => (
|
||||
<Call
|
||||
key={ calls.length - idx }
|
||||
call={ call }
|
||||
setActiveCall={ this.setActiveCall }
|
||||
/>
|
||||
)) }
|
||||
</AnimateChildren>
|
||||
);
|
||||
}
|
||||
|
||||
clearActiveCall = () => {
|
||||
this.setState({ activeCall: null, activeChild: null });
|
||||
}
|
||||
|
||||
setActiveCall = (call, el) => {
|
||||
this.setState({ activeCall: call, activeChild: el });
|
||||
}
|
||||
|
||||
setCallsHistory = el => {
|
||||
this._callsHistory = el;
|
||||
}
|
||||
|
||||
clearHistory = () => {
|
||||
this.props.reset();
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
calls: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
actions: PropTypes.shape({
|
||||
fireRpc: PropTypes.func.isRequired,
|
||||
copyToClipboard: PropTypes.func.isRequired,
|
||||
selectRpcMethod: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
reset: PropTypes.func
|
||||
}
|
||||
|
||||
}
|
||||
135
js/src/views/Status/components/Calls/Calls.spec.js
Normal file
135
js/src/views/Status/components/Calls/Calls.spec.js
Normal file
@@ -0,0 +1,135 @@
|
||||
// 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 from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import '../../../../environment/tests';
|
||||
|
||||
import Calls from './Calls';
|
||||
|
||||
describe('components/Calls', () => {
|
||||
describe('rendering (no calls)', () => {
|
||||
let rendered;
|
||||
|
||||
before(() => {
|
||||
const calls = [];
|
||||
|
||||
rendered = shallow(<Calls calls={ calls } />);
|
||||
});
|
||||
|
||||
it('renders the component and container', () => {
|
||||
expect(rendered).to.be.ok;
|
||||
expect(rendered).to.have.className('calls-container');
|
||||
});
|
||||
|
||||
it('renders no calls', () => {
|
||||
expect(rendered.find('div[data-test="Calls-empty-wrapper"]')).to.have.exactly(1).descendants('h3');
|
||||
});
|
||||
|
||||
it('renders no clear button', () => {
|
||||
expect(rendered.find('a[data-test="Calls-remove"]')).to.not.exist;
|
||||
});
|
||||
|
||||
it('renders an attached CallsToolbar', () => {
|
||||
expect(rendered).to.have.exactly(1).descendants('CallsToolbar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('rendering (calls supplied)', () => {
|
||||
const calls = [
|
||||
{ callNo: 0, name: 'eth_call', params: '', response: '' },
|
||||
{ callNo: 1, name: 'eth_sendTransaction', params: '', response: '' }
|
||||
];
|
||||
const actions = { action1: true, action2: true };
|
||||
|
||||
let rendered;
|
||||
let instance;
|
||||
|
||||
before(() => {
|
||||
rendered = shallow(<Calls calls={ calls } actions={ actions } />);
|
||||
instance = rendered.instance();
|
||||
});
|
||||
|
||||
it('renders the clear button', () => {
|
||||
expect(rendered).to.have.exactly(1).descendants('a[data-test="Calls-remove"]');
|
||||
});
|
||||
|
||||
it('renders calls', () => {
|
||||
expect(rendered.find('div[data-test="Calls-empty-wrapper"]')).to.not.exist;
|
||||
expect(rendered.find('div.row div')).to.have.exactly(2).descendants('Call');
|
||||
});
|
||||
|
||||
it('passes the correct properties to Call', () => {
|
||||
const call = rendered.find('Call').first();
|
||||
|
||||
expect(call).to.have.prop('setActiveCall', instance.setActiveCall);
|
||||
expect(call).to.have.prop('call').deep.equal(calls[0]);
|
||||
});
|
||||
|
||||
it('passes the correct properties to CallsToolbar', () => {
|
||||
const child = { offsetTop: 0 };
|
||||
const container = { scrollTop: 0 };
|
||||
|
||||
instance.setCallsHistory(container);
|
||||
rendered.setState({ activeCall: 'dummyActiveCall', activeChild: child });
|
||||
|
||||
const toolbar = rendered.find('CallsToolbar').first();
|
||||
|
||||
expect(toolbar).to.have.prop('call', 'dummyActiveCall');
|
||||
expect(toolbar).to.have.prop('actions').deep.equal(actions);
|
||||
expect(toolbar).to.have.prop('callEl').deep.equal(child);
|
||||
expect(toolbar).to.have.prop('containerEl').deep.equal(container);
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions', () => {
|
||||
let rendered;
|
||||
let instance;
|
||||
|
||||
before(() => {
|
||||
const calls = [
|
||||
{ callNo: 0, name: 'eth_call', params: '', response: '' },
|
||||
{ callNo: 1, name: 'eth_sendTransaction', params: '', response: '' }
|
||||
];
|
||||
|
||||
rendered = shallow(<Calls calls={ calls } />);
|
||||
instance = rendered.instance();
|
||||
});
|
||||
|
||||
it('sets the element via setCallsHistory', () => {
|
||||
instance.setCallsHistory('dummyElement');
|
||||
|
||||
expect(instance._callsHistory).to.equal('dummyElement');
|
||||
});
|
||||
|
||||
it('sets state via setActiveCall', () => {
|
||||
instance.setActiveCall('dummyActiveCall', 'dummyActiveChild');
|
||||
|
||||
expect(rendered).to.have.state('activeCall', 'dummyActiveCall');
|
||||
expect(rendered).to.have.state('activeChild', 'dummyActiveChild');
|
||||
});
|
||||
|
||||
it('clears state via clearActiveCall', () => {
|
||||
instance.setActiveCall('dummyActiveCall', 'dummyActiveChild');
|
||||
expect(rendered).to.have.state('activeCall', 'dummyActiveCall');
|
||||
instance.clearActiveCall();
|
||||
|
||||
expect(rendered).to.have.state('activeCall', null);
|
||||
expect(rendered).to.have.state('activeChild', null);
|
||||
});
|
||||
});
|
||||
});
|
||||
17
js/src/views/Status/components/Calls/index.js
Normal file
17
js/src/views/Status/components/Calls/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 './Calls';
|
||||
66
js/src/views/Status/components/CallsToolbar/CallsToolbar.css
Normal file
66
js/src/views/Status/components/CallsToolbar/CallsToolbar.css
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.callActionsWrap {
|
||||
position: absolute;
|
||||
animation: fadein .5s;
|
||||
right: 0;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.callActionsButton {
|
||||
padding: 0 !important;
|
||||
height: 24px !important;
|
||||
}
|
||||
|
||||
.callActionsWrap:hover .callActionsButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.callActions {
|
||||
display: none;
|
||||
height: 100%;
|
||||
margin-top: 1px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.callActionsWrap:hover .callActions {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.callAction {
|
||||
float: right;
|
||||
transition: opacity ease-in-out .2s;
|
||||
transition-delay: .2s;
|
||||
opacity: 0;
|
||||
padding: 3px !important;
|
||||
height: 22px !important;
|
||||
width: 22px !important;
|
||||
}
|
||||
|
||||
.callActions:hover .callAction {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.callActionIcon {
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
132
js/src/views/Status/components/CallsToolbar/CallsToolbar.js
Normal file
132
js/src/views/Status/components/CallsToolbar/CallsToolbar.js
Normal file
@@ -0,0 +1,132 @@
|
||||
// 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 CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { sortBy, find, extend } from 'lodash';
|
||||
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import MoreHorizIcon from 'material-ui/svg-icons/navigation/more-horiz';
|
||||
import CallIcon from 'material-ui/svg-icons/communication/call';
|
||||
import AssignmentIcon from 'material-ui/svg-icons/action/assignment';
|
||||
import InputIcon from 'material-ui/svg-icons/action/input';
|
||||
|
||||
import { SCROLLBAR_WIDTH } from '../../constants';
|
||||
import styles from './CallsToolbar.css';
|
||||
import rpcData from '../../data/rpc.json';
|
||||
const rpcMethods = sortBy(rpcData.methods, 'name');
|
||||
|
||||
export default class CallsToolbar extends Component {
|
||||
|
||||
render () {
|
||||
const { call, callEl, containerEl } = this.props;
|
||||
|
||||
if (!call) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const wrapStyle = { top: callEl.offsetTop - SCROLLBAR_WIDTH - containerEl.scrollTop };
|
||||
if (this.hasScrollbar(containerEl)) {
|
||||
wrapStyle.right = 13;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ styles.callActionsWrap }
|
||||
style={ wrapStyle }
|
||||
>
|
||||
<IconButton
|
||||
className={ styles.callActionsButton }
|
||||
{ ...this._test('button-more') }
|
||||
>
|
||||
<MoreHorizIcon />
|
||||
</IconButton>
|
||||
<div className={ styles.callActions } { ...this._test('button-container') }>
|
||||
<IconButton
|
||||
className={ styles.callAction }
|
||||
onClick={ this.setCall }
|
||||
tooltip='Set'
|
||||
tooltipPosition='top-left'
|
||||
{ ...this._test('button-setCall') }
|
||||
>
|
||||
<InputIcon className={ styles.callActionIcon } />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
className={ styles.callAction }
|
||||
onClick={ this.makeCall }
|
||||
tooltip='Fire again'
|
||||
tooltipPosition='top-left'
|
||||
{ ...this._test('button-makeCall') }
|
||||
>
|
||||
<CallIcon className={ styles.callActionIcon } />
|
||||
</IconButton>
|
||||
<CopyToClipboard
|
||||
text={ JSON.stringify(call) }
|
||||
onCopy={ this.copyToClipboard }
|
||||
>
|
||||
<IconButton
|
||||
className={ styles.callAction }
|
||||
tooltip='Copy to clipboard'
|
||||
tooltipPosition='top-left'
|
||||
{ ...this._test('copyCallToClipboard') }
|
||||
>
|
||||
<AssignmentIcon className={ styles.callActionIcon } />
|
||||
</IconButton>
|
||||
</CopyToClipboard>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
setCall = () => {
|
||||
const { call } = this.props;
|
||||
let method = find(rpcMethods, { name: call.name });
|
||||
|
||||
this.props.actions.selectRpcMethod(extend({}, method, { paramsValues: call.params }));
|
||||
}
|
||||
|
||||
makeCall = () => {
|
||||
const { call } = this.props;
|
||||
let method = find(rpcMethods, { name: call.name });
|
||||
|
||||
this.setCall();
|
||||
this.props.actions.fireRpc({
|
||||
method: method.name,
|
||||
outputFormatter: method.outputFormatter,
|
||||
inputFormatters: method.inputFormatters,
|
||||
params: call.params
|
||||
});
|
||||
}
|
||||
|
||||
copyToClipboard = () => {
|
||||
this.props.actions.copyToClipboard('method copied to clipboard');
|
||||
}
|
||||
|
||||
hasScrollbar (el) {
|
||||
return el.clientHeight < el.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
CallsToolbar.propTypes = {
|
||||
call: PropTypes.object.isRequired,
|
||||
callEl: PropTypes.node.isRequired,
|
||||
containerEl: PropTypes.node.isRequired,
|
||||
actions: PropTypes.shape({
|
||||
fireRpc: PropTypes.func.isRequired,
|
||||
copyToClipboard: PropTypes.func.isRequired,
|
||||
selectRpcMethod: PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
};
|
||||
118
js/src/views/Status/components/CallsToolbar/CallsToolbar.spec.js
Normal file
118
js/src/views/Status/components/CallsToolbar/CallsToolbar.spec.js
Normal file
@@ -0,0 +1,118 @@
|
||||
// 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 from 'react';
|
||||
import sinon from 'sinon';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import '../../../../environment/tests';
|
||||
|
||||
import CallsToolbar from './CallsToolbar';
|
||||
|
||||
describe('components/CallsToolbar', () => {
|
||||
const callEl = { offsetTop: 0 };
|
||||
const containerEl = { scrollTop: 0, clientHeight: 0, scrollHeight: 999 };
|
||||
|
||||
describe('rendering (no call)', () => {
|
||||
let rendered;
|
||||
|
||||
before(() => {
|
||||
const call = null;
|
||||
|
||||
rendered = shallow(<CallsToolbar call={ call } callEl={ callEl } containerEl={ containerEl } />);
|
||||
});
|
||||
|
||||
it('does not render the component', () => {
|
||||
expect(rendered).to.not.have.descendants('[data-test="CallsToolbar-button-more"]');
|
||||
});
|
||||
});
|
||||
|
||||
describe('rendering', () => {
|
||||
const call = { callNo: 456, name: 'eth_call', params: '', response: '' };
|
||||
let rendered;
|
||||
let btncontainer;
|
||||
|
||||
before(() => {
|
||||
rendered = shallow(<CallsToolbar call={ call } callEl={ callEl } containerEl={ containerEl } />);
|
||||
btncontainer = rendered.find('[data-test="CallsToolbar-button-container"]');
|
||||
});
|
||||
|
||||
it('renders the More button', () => {
|
||||
expect(rendered).to.have.descendants('[data-test="CallsToolbar-button-more"]');
|
||||
});
|
||||
|
||||
it('renders the Set button', () => {
|
||||
expect(btncontainer).to.have.descendants('[data-test="CallsToolbar-button-setCall"]');
|
||||
});
|
||||
|
||||
it('renders the Fire button', () => {
|
||||
expect(btncontainer).to.have.descendants('[data-test="CallsToolbar-button-makeCall"]');
|
||||
});
|
||||
|
||||
it('renders the Copy button', () => {
|
||||
expect(btncontainer).to.have.descendants('[data-test="CallsToolbar-copyCallToClipboard"]');
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions', () => {
|
||||
const call = { callNo: 456, name: 'eth_call', params: '', response: '' };
|
||||
const actions = { fireRpc: sinon.stub(), copyToClipboard: sinon.stub(), selectRpcMethod: sinon.stub() };
|
||||
|
||||
let rendered;
|
||||
let instance;
|
||||
|
||||
before(() => {
|
||||
rendered = shallow(<CallsToolbar call={ call } callEl={ callEl } containerEl={ containerEl } actions={ actions } />);
|
||||
instance = rendered.instance();
|
||||
});
|
||||
|
||||
it('calls copyToClipboard with action copyToClipboard', () => {
|
||||
instance.copyToClipboard();
|
||||
expect(actions.copyToClipboard).to.be.calledOnce;
|
||||
});
|
||||
|
||||
it('calls setCall with action selectRpcMethod', () => {
|
||||
instance.setCall();
|
||||
expect(actions.selectRpcMethod).to.be.calledOnce;
|
||||
});
|
||||
|
||||
it('calls makeCall with action fireRpc', () => {
|
||||
instance.makeCall();
|
||||
expect(actions.fireRpc).to.be.calledOnce;
|
||||
});
|
||||
});
|
||||
|
||||
describe('utility', () => {
|
||||
const call = { callNo: 456, name: 'eth_call', params: '', response: '' };
|
||||
let rendered;
|
||||
let instance;
|
||||
|
||||
before(() => {
|
||||
rendered = shallow(<CallsToolbar call={ call } callEl={ callEl } containerEl={ containerEl } />);
|
||||
instance = rendered.instance();
|
||||
});
|
||||
|
||||
describe('.hasScrollbar', () => {
|
||||
it('correctly returns true when scrollbar', () => {
|
||||
expect(instance.hasScrollbar({ clientHeight: 123, scrollHeight: 456 })).to.be.true;
|
||||
});
|
||||
|
||||
it('correctly returns false when no scrollbar', () => {
|
||||
expect(instance.hasScrollbar({ clientHeight: 456, scrollHeight: 123 })).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
17
js/src/views/Status/components/CallsToolbar/index.js
Normal file
17
js/src/views/Status/components/CallsToolbar/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 './CallsToolbar';
|
||||
67
js/src/views/Status/components/Debug/Debug.css
Normal file
67
js/src/views/Status/components/Debug/Debug.css
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.subheader {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.inputTrigger {
|
||||
display: none;
|
||||
left: 310px;
|
||||
bottom: 4px;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
animation: fadein .3s;
|
||||
}
|
||||
|
||||
*:hover > .inputTrigger {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
.logs {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stopped {
|
||||
color: #aaa;
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
.log {
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
overflow: visible;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.actions {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.actions a {
|
||||
margin-left: 5px;
|
||||
cursor: pointer;
|
||||
color: #bbb;
|
||||
}
|
||||
114
js/src/views/Status/components/Debug/Debug.js
Normal file
114
js/src/views/Status/components/Debug/Debug.js
Normal file
@@ -0,0 +1,114 @@
|
||||
// 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 AvPause from 'material-ui/svg-icons/av/pause';
|
||||
import AvPlay from 'material-ui/svg-icons/av/play-arrow';
|
||||
import AvReplay from 'material-ui/svg-icons/av/replay';
|
||||
|
||||
import { Container, ContainerTitle } from '../../../../ui';
|
||||
|
||||
import styles from './Debug.css';
|
||||
|
||||
export default class Debug extends Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
clearStatusLogs: PropTypes.func.isRequired,
|
||||
toggleStatusLogs: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
nodeStatus: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
render () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { devLogsLevels } = nodeStatus;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<ContainerTitle
|
||||
title='Node Logs' />
|
||||
{ this.renderActions() }
|
||||
<h2 className={ styles.subheader }>
|
||||
{ devLogsLevels || '-' }
|
||||
</h2>
|
||||
{ this.renderToggle() }
|
||||
{ this.renderLogs() }
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
renderToggle () {
|
||||
const { devLogsEnabled } = this.props.nodeStatus;
|
||||
|
||||
if (devLogsEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.stopped }>
|
||||
Refresh and display of logs from Parity is currently stopped via the UI, start it to see the latest updates.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderLogs () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { devLogs } = nodeStatus;
|
||||
|
||||
if (!devLogs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const logs = devLogs.map((log, idx) => (
|
||||
<pre className={ styles.log } key={ idx }>
|
||||
{ log }
|
||||
</pre>
|
||||
));
|
||||
|
||||
return (
|
||||
<div className={ styles.logs }>
|
||||
{ logs }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderActions () {
|
||||
const { devLogsEnabled } = this.props.nodeStatus;
|
||||
const toggleButton = devLogsEnabled
|
||||
? <AvPause />
|
||||
: <AvPlay />;
|
||||
|
||||
return (
|
||||
<div className={ styles.actions }>
|
||||
<a onClick={ this.toggle }>{ toggleButton }</a>
|
||||
<a onClick={ this.clear }><AvReplay /></a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
clear = () => {
|
||||
const { clearStatusLogs } = this.props.actions;
|
||||
|
||||
clearStatusLogs();
|
||||
}
|
||||
|
||||
toggle = () => {
|
||||
const { devLogsEnabled } = this.props.nodeStatus;
|
||||
const { toggleStatusLogs } = this.props.actions;
|
||||
|
||||
toggleStatusLogs(!devLogsEnabled);
|
||||
}
|
||||
}
|
||||
17
js/src/views/Status/components/Debug/index.js
Normal file
17
js/src/views/Status/components/Debug/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 './Debug';
|
||||
@@ -0,0 +1,74 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.input {
|
||||
margin-top: 0;
|
||||
width: 100%;
|
||||
padding-left: 10px;
|
||||
padding-right: 50px;
|
||||
}
|
||||
|
||||
.icon, .iconSuccess, .firstIcon {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
margin: 3px 3px;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.success, .iconSuccess {
|
||||
color: #8bc34a;
|
||||
}
|
||||
|
||||
.icon i, .iconSuccess i, .firstIcon i {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.icons, .iconsVisible, .firstIcon {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
opacity: 0;
|
||||
transition: opacity ease-in-out .2s;
|
||||
transition-delay: 0.2s;
|
||||
}
|
||||
|
||||
.iconsVisible {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.container:hover .icons, .container:hover .firstIcon {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.firstIcon {
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
right: auto;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: 3px 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.autocomplete input {
|
||||
margin-top: 0;
|
||||
padding-left: 10px !important;
|
||||
padding-right: 50px !important;
|
||||
}
|
||||
192
js/src/views/Status/components/EditableValue/EditableValue.js
Normal file
192
js/src/views/Status/components/EditableValue/EditableValue.js
Normal file
@@ -0,0 +1,192 @@
|
||||
// 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 AutoComplete from 'material-ui/AutoComplete';
|
||||
|
||||
import styles from './EditableValue.css';
|
||||
import valueStyles from '../Value/Value.css';
|
||||
|
||||
export default class EditableValue extends Component {
|
||||
|
||||
state = {
|
||||
value: this.props.value,
|
||||
inEditMode: false
|
||||
}
|
||||
|
||||
componentWillReceiveProps (newProps) {
|
||||
if (newProps.value === this.state.value || this.state.inEditMode) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
value: newProps.value
|
||||
});
|
||||
}
|
||||
|
||||
onChange = value => {
|
||||
this.setState({
|
||||
value: value
|
||||
});
|
||||
}
|
||||
|
||||
onOpenEdit = evt => {
|
||||
this.setState({
|
||||
inEditMode: true
|
||||
});
|
||||
|
||||
if (!this._input) {
|
||||
return;
|
||||
}
|
||||
this._input.focus();
|
||||
}
|
||||
|
||||
onCancel = evt => {
|
||||
this.setState({
|
||||
inEditMode: false,
|
||||
value: this.props.value
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit = () => {
|
||||
this.setState({
|
||||
inEditMode: false
|
||||
});
|
||||
this.props.onSubmit(this.state.value, false);
|
||||
}
|
||||
|
||||
onResetToDefault = () => {
|
||||
this.props.onSubmit(this.props.defaultValue, true);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<form
|
||||
className={ `${valueStyles.valueContainer} ${styles.container}` }
|
||||
onSubmit={ this.onSubmit }
|
||||
{ ...this._testInherit() }
|
||||
>
|
||||
{ this.renderResetButton() }
|
||||
<div className={ this.state.inEditMode ? styles.iconsVisible : styles.icons }>
|
||||
{ this.props.children }
|
||||
{ this.renderButtons() }
|
||||
</div>
|
||||
{ this.renderInput() }
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
renderInput () {
|
||||
const { inEditMode, value } = this.state;
|
||||
|
||||
const setInput = el => { this._input = el; };
|
||||
const onChange = evt => this.onChange(evt.target.value);
|
||||
|
||||
if (!inEditMode || !this.props.autocomplete) {
|
||||
return (
|
||||
<input
|
||||
className={ inEditMode ? styles.input : valueStyles.value }
|
||||
type='text'
|
||||
value={ value }
|
||||
onClick={ this.onOpenEdit }
|
||||
ref={ setInput }
|
||||
onChange={ onChange }
|
||||
readOnly={ !inEditMode }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
name='EditableValueAutoComplete' // avoid Material Ui warning
|
||||
className={ styles.autocomplete }
|
||||
fullWidth
|
||||
searchText={ value }
|
||||
dataSource={ this.props.dataSource }
|
||||
onUpdateInput={ this.onChange }
|
||||
onNewRequest={ this.onChange }
|
||||
openOnFocus
|
||||
filter={ AutoComplete.noFilter }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderResetButton () {
|
||||
if (this.state.inEditMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.props.defaultValue || this.state.value === this.props.defaultValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
key={ 'reset' }
|
||||
className={ `${styles.icon} ${styles.firstIcon}` }
|
||||
onClick={ this.onResetToDefault }
|
||||
title={ `Reset to ${this.props.defaultValue}` }
|
||||
{ ...this._testInherit('reset') }
|
||||
>
|
||||
<i className='icon-anchor'></i>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
renderButtons () {
|
||||
if (this.state.inEditMode) {
|
||||
return [
|
||||
<a
|
||||
key={ 'submit' }
|
||||
className={ styles.iconSuccess }
|
||||
onClick={ this.onSubmit }
|
||||
{ ...this._testInherit('submit') }
|
||||
>
|
||||
<i className='icon-check'></i>
|
||||
</a>,
|
||||
<a
|
||||
key={ 'cancel' }
|
||||
className={ styles.icon }
|
||||
onClick={ this.onCancel }
|
||||
{ ...this._testInherit('cancel') }
|
||||
>
|
||||
<i className='icon-close'></i>
|
||||
</a>
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
key={ 'edit' }
|
||||
className={ styles.icon }
|
||||
onClick={ this.onOpenEdit }
|
||||
title='Edit'
|
||||
{ ...this._testInherit('edit') }
|
||||
>
|
||||
<i className='icon-pencil'></i>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
value: PropTypes.string,
|
||||
defaultValue: PropTypes.string,
|
||||
children: PropTypes.element,
|
||||
autocomplete: PropTypes.bool,
|
||||
dataSource: PropTypes.arrayOf(PropTypes.string)
|
||||
}
|
||||
|
||||
}
|
||||
17
js/src/views/Status/components/EditableValue/index.js
Normal file
17
js/src/views/Status/components/EditableValue/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 './EditableValue';
|
||||
28
js/src/views/Status/components/JsonEditor/JsonEditor.css
Normal file
28
js/src/views/Status/components/JsonEditor/JsonEditor.css
Normal file
@@ -0,0 +1,28 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.editor {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.error {
|
||||
border: 1px solid red !important;
|
||||
}
|
||||
|
||||
.errorMsg {
|
||||
color: red;
|
||||
}
|
||||
98
js/src/views/Status/components/JsonEditor/JsonEditor.js
Normal file
98
js/src/views/Status/components/JsonEditor/JsonEditor.js
Normal file
@@ -0,0 +1,98 @@
|
||||
// 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 { isEqual } from 'lodash';
|
||||
import formatJson from 'format-json';
|
||||
|
||||
import styles from './JsonEditor.css';
|
||||
|
||||
export default class JsonEditor extends Component {
|
||||
|
||||
constructor (...args) {
|
||||
super(...args);
|
||||
let { value } = this.props;
|
||||
value = formatJson.plain(value);
|
||||
this.state = { value };
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const mockedEvt = { target: { value: this.state.value } };
|
||||
this.onChange(mockedEvt);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
let { value } = nextProps;
|
||||
|
||||
if (!isEqual(value, this.props.value)) {
|
||||
value = formatJson.plain(value);
|
||||
this.setState({ value });
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
let errorClass = this.state.error ? styles.error : '';
|
||||
|
||||
return (
|
||||
<div className='row'>
|
||||
<textarea
|
||||
onChange={ this.onChange }
|
||||
className={ `${styles.editor} ${errorClass}` }
|
||||
value={ this.state.value }
|
||||
/>
|
||||
{ this.renderError() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderError () {
|
||||
const { error } = this.state;
|
||||
if (!error) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.errorMsg }>{ error }</div>
|
||||
);
|
||||
}
|
||||
|
||||
onChange = evt => {
|
||||
const { value } = evt.target;
|
||||
let parsed;
|
||||
let error;
|
||||
|
||||
try {
|
||||
parsed = JSON.parse(value);
|
||||
error = null;
|
||||
} catch (err) {
|
||||
parsed = null;
|
||||
error = 'invalid json';
|
||||
}
|
||||
|
||||
this.setState({
|
||||
value,
|
||||
error
|
||||
});
|
||||
|
||||
this.props.onChange(parsed, error);
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
value: PropTypes.object
|
||||
}
|
||||
|
||||
}
|
||||
17
js/src/views/Status/components/JsonEditor/index.js
Normal file
17
js/src/views/Status/components/JsonEditor/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 './JsonEditor';
|
||||
20
js/src/views/Status/components/Markdown/Markdown.css
Normal file
20
js/src/views/Status/components/Markdown/Markdown.css
Normal file
@@ -0,0 +1,20 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.container li {
|
||||
display: list-item;
|
||||
line-height: 1.6;
|
||||
}
|
||||
58
js/src/views/Status/components/Markdown/Markdown.js
Normal file
58
js/src/views/Status/components/Markdown/Markdown.js
Normal file
@@ -0,0 +1,58 @@
|
||||
// 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 marked from 'marked';
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import styles from './Markdown.css';
|
||||
|
||||
export default class Marked extends Component {
|
||||
|
||||
state = {}
|
||||
|
||||
render () {
|
||||
let { parsed } = this.state;
|
||||
if (!parsed) {
|
||||
return null;
|
||||
}
|
||||
return <div className={ styles.container } style={ this.props.style } dangerouslySetInnerHTML={ { __html: parsed } } />;
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
this.setState({ parsed: this.parse(this.props.val) });
|
||||
}
|
||||
|
||||
componentWillReceiveProps (newProps) {
|
||||
if (newProps.val === this.props.val) {
|
||||
return;
|
||||
}
|
||||
this.setState({ parsed: this.parse(newProps.val) });
|
||||
}
|
||||
|
||||
parse (val) {
|
||||
try {
|
||||
val = marked(val);
|
||||
} catch (err) {
|
||||
console.error(`Marked error when parsing ${val}: ${err}`);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
val: PropTypes.any,
|
||||
style: PropTypes.object
|
||||
}
|
||||
|
||||
}
|
||||
17
js/src/views/Status/components/Markdown/index.js
Normal file
17
js/src/views/Status/components/Markdown/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 './Markdown';
|
||||
@@ -0,0 +1,99 @@
|
||||
// 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 formatNumber from 'format-number';
|
||||
|
||||
import { ContainerTitle, Input } from '../../../../ui';
|
||||
|
||||
import { numberFromString } from './numberFromString';
|
||||
import { decodeExtraData } from './decodeExtraData';
|
||||
|
||||
const toNiceNumber = formatNumber();
|
||||
|
||||
export default class MiningSettings extends Component {
|
||||
static contextTypes = {
|
||||
api: PropTypes.object
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
nodeStatus: PropTypes.object
|
||||
}
|
||||
|
||||
render () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { coinbase, defaultExtraData, extraData, gasFloorTarget, minGasPrice } = nodeStatus;
|
||||
|
||||
return (
|
||||
<div { ...this._testInherit() }>
|
||||
<ContainerTitle title='mining settings' />
|
||||
<Input
|
||||
label='author'
|
||||
hint='the mining author'
|
||||
value={ coinbase }
|
||||
onSubmit={ this.onAuthorChange }
|
||||
{ ...this._test('author') } />
|
||||
<Input
|
||||
label='extradata'
|
||||
hint='extra data for mined blocks'
|
||||
value={ decodeExtraData(extraData) }
|
||||
onSubmit={ this.onExtraDataChange }
|
||||
defaultValue={ decodeExtraData(defaultExtraData) }
|
||||
{ ...this._test('extra-data') } />
|
||||
<Input
|
||||
label='minimal gas price'
|
||||
hint='the minimum gas price for mining'
|
||||
value={ toNiceNumber(minGasPrice) }
|
||||
onSubmit={ this.onMinGasPriceChange }
|
||||
{ ...this._test('min-gas-price') } />
|
||||
<Input
|
||||
label='gas floor target'
|
||||
hint='the gas floor target for mining'
|
||||
value={ toNiceNumber(gasFloorTarget) }
|
||||
onSubmit={ this.onGasFloorTargetChange }
|
||||
{ ...this._test('gas-floor-target') } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onMinGasPriceChange = (newVal) => {
|
||||
const { api } = this.context;
|
||||
|
||||
api.ethcore.setMinGasPrice(numberFromString(newVal));
|
||||
};
|
||||
|
||||
onExtraDataChange = (newVal, isResetToDefault) => {
|
||||
const { api } = this.context;
|
||||
const { nodeStatus } = this.props;
|
||||
|
||||
// In case of resetting to default we are just using raw bytes from defaultExtraData
|
||||
// When user sets new value we can safely send a string that will be converted to hex by formatter.
|
||||
const val = isResetToDefault ? nodeStatus.defaultExtraData : newVal;
|
||||
api.ethcore.setExtraData(val);
|
||||
};
|
||||
|
||||
onAuthorChange = (newVal) => {
|
||||
const { api } = this.context;
|
||||
|
||||
api.ethcore.setAuthor(newVal);
|
||||
};
|
||||
|
||||
onGasFloorTargetChange = (newVal) => {
|
||||
const { api } = this.context;
|
||||
|
||||
api.ethcore.setGasFloorTarget(numberFromString(newVal));
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// 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 rlp from 'rlp';
|
||||
|
||||
export function decodeExtraData (str) {
|
||||
try {
|
||||
// Try decoding as RLP
|
||||
const decoded = rlp.decode(str);
|
||||
const v = decoded[0];
|
||||
decoded[0] = decoded[1];
|
||||
decoded[1] = `${v[0]}.${v[1]}.${v[2]}`;
|
||||
return decoded.join('/');
|
||||
} catch (err) {
|
||||
// hex -> str
|
||||
return str.match(/.{1,2}/g).map(v => {
|
||||
return String.fromCharCode(parseInt(v, 16));
|
||||
}).join('');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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 { decodeExtraData } from './decodeExtraData';
|
||||
|
||||
describe('MINING SETTINGS', () => {
|
||||
describe('EXTRA DATA', () => {
|
||||
const str = 'parity/1.0.0/1.0.0-beta2';
|
||||
const encoded = '0xd783010000867061726974798b312e302e302d6265746132';
|
||||
|
||||
it('should decode encoded to str', () => {
|
||||
expect(decodeExtraData(encoded)).to.equal(str);
|
||||
});
|
||||
});
|
||||
});
|
||||
17
js/src/views/Status/components/MiningSettings/index.js
Normal file
17
js/src/views/Status/components/MiningSettings/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 './MiningSettings';
|
||||
@@ -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/>.
|
||||
|
||||
export function numberFromString (val) {
|
||||
return parseInt(
|
||||
val
|
||||
.replace(/m/ig, 'k')
|
||||
.replace(/k/ig, '000')
|
||||
.replace(/[^0-9]/g, '')
|
||||
, 10
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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 { numberFromString } from './numberFromString';
|
||||
|
||||
describe('NUMBER FROM STRING', () => {
|
||||
it('should convert string to number', () => {
|
||||
expect(numberFromString('12345'), 12345);
|
||||
});
|
||||
|
||||
it('should handle special characters "k" and "m"', () => {
|
||||
expect(numberFromString('10kk'), 10000000);
|
||||
expect(numberFromString('10K'), 1000);
|
||||
expect(numberFromString('10Mmk'), 1000000000000000);
|
||||
});
|
||||
|
||||
it('should ignore any non-numeric characters', () => {
|
||||
expect(numberFromString('10.000.000'), 10000000);
|
||||
expect(numberFromString('10_000_000'), 10000000);
|
||||
expect(numberFromString('10_k_k'), 10000000);
|
||||
expect(numberFromString('-5'), 5);
|
||||
});
|
||||
});
|
||||
20
js/src/views/Status/components/Response/Response.css
Normal file
20
js/src/views/Status/components/Response/Response.css
Normal file
@@ -0,0 +1,20 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.response {
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
}
|
||||
65
js/src/views/Status/components/Response/Response.js
Normal file
65
js/src/views/Status/components/Response/Response.js
Normal file
@@ -0,0 +1,65 @@
|
||||
// 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 { isArray, isPlainObject } from 'lodash';
|
||||
|
||||
import styles from './Response.css';
|
||||
|
||||
export default class Response extends Component {
|
||||
|
||||
render () {
|
||||
let { response } = this.props;
|
||||
let formatted;
|
||||
|
||||
if (isArray(response)) {
|
||||
formatted = this.renderArray();
|
||||
}
|
||||
if (isPlainObject(response)) {
|
||||
formatted = this.renderObject();
|
||||
}
|
||||
|
||||
return <pre className={ styles.response }>{ formatted || response }</pre>;
|
||||
}
|
||||
|
||||
renderArray () {
|
||||
let { response } = this.props;
|
||||
return response.map((r, idx) => (
|
||||
<span key={ idx }>
|
||||
{ idx === 0 ? '[' : ',' }
|
||||
{ idx === 0 ? '' : <br /> }
|
||||
{ r }
|
||||
{ idx === response.length - 1 ? ']' : '' }
|
||||
</span>
|
||||
));
|
||||
}
|
||||
|
||||
renderObject () {
|
||||
let { response } = this.props;
|
||||
const arr = JSON.stringify(response, null, 1).split('\n');
|
||||
return arr.map((any, idx) => (
|
||||
<span key={ idx }>
|
||||
{ any }
|
||||
{ idx !== 0 && idx !== arr.length - 1 ? <br /> : '' }
|
||||
</span>
|
||||
));
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
response: PropTypes.any.isRequired
|
||||
}
|
||||
|
||||
}
|
||||
47
js/src/views/Status/components/Response/Response.spec.js
Normal file
47
js/src/views/Status/components/Response/Response.spec.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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 from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import '../../../../environment/tests';
|
||||
|
||||
import Response from './Response';
|
||||
|
||||
describe('components/Response', () => {
|
||||
describe('rendering', () => {
|
||||
it('renders non-arrays/non-objects exactly as received', () => {
|
||||
const TEST = '1234567890';
|
||||
const rendered = shallow(<Response response={ TEST } />);
|
||||
|
||||
expect(rendered).to.have.html(`<pre>${TEST}</pre>`);
|
||||
});
|
||||
|
||||
it('renders arrays properly with index and value', () => {
|
||||
const TEST = ['123', '456'];
|
||||
const rendered = shallow(<Response response={ TEST } />);
|
||||
|
||||
expect(rendered).to.have.html('<pre><span>[123</span><span>,<br/>456]</span></pre>');
|
||||
});
|
||||
|
||||
it('renders objects properly with key and value', () => {
|
||||
const TEST = { foo: '123', bar: '456' };
|
||||
const rendered = shallow(<Response response={ TEST } />);
|
||||
|
||||
expect(rendered).to.have.html('<pre><span>{</span><span> "foo": "123",<br/></span><span> "bar": "456"<br/></span><span>}</span></pre>');
|
||||
});
|
||||
});
|
||||
});
|
||||
17
js/src/views/Status/components/Response/index.js
Normal file
17
js/src/views/Status/components/Response/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 './Response';
|
||||
32
js/src/views/Status/components/RpcCalls/RpcCalls.css
Normal file
32
js/src/views/Status/components/RpcCalls/RpcCalls.css
Normal file
@@ -0,0 +1,32 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.header {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h3 + label > input {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.jsonToggle {
|
||||
width: auto !important;
|
||||
float: right;
|
||||
}
|
||||
337
js/src/views/Status/components/RpcCalls/RpcCalls.js
Normal file
337
js/src/views/Status/components/RpcCalls/RpcCalls.js
Normal file
@@ -0,0 +1,337 @@
|
||||
// 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 _ from 'lodash';
|
||||
|
||||
import Toggle from 'material-ui/Toggle/Toggle';
|
||||
import TextField from 'material-ui/TextField';
|
||||
import { RpcAutoComplete } from 'dapps-react-components';
|
||||
import { formatRpcMd } from '../../util/rpc-md';
|
||||
import AnimateChildren from '../../components-compositors/Animated/children';
|
||||
import JsonEditor from '../JsonEditor';
|
||||
import Calls from '../Calls';
|
||||
import Markdown from '../Markdown';
|
||||
import styles from './RpcCalls.css';
|
||||
import rpcData from '../../data/rpc.json';
|
||||
import RpcNav from '../RpcNav';
|
||||
|
||||
const rpcMethods = _.sortBy(rpcData.methods, 'name');
|
||||
|
||||
export default class RpcCalls extends Component {
|
||||
|
||||
state = {};
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
const { paramsValues, params } = nextProps.rpc.selectedMethod;
|
||||
if (paramsValues) {
|
||||
params.map((p, idx) => {
|
||||
// todo [adgo] 01.05.2016 - make sure this works
|
||||
// not sure idx is the same for paramsValues and params
|
||||
this.setState({
|
||||
[this.paramKey(p)]: paramsValues[idx]
|
||||
});
|
||||
});
|
||||
|
||||
if (this.state.jsonMode) {
|
||||
this.setJsonEditorValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='dapp-flex-content'>
|
||||
<main className='dapp-content'>
|
||||
<div className='dapp-container'>
|
||||
<div className='row'>
|
||||
<div className='col col-6'>
|
||||
<h1><span>RPC</span> Requests</h1>
|
||||
</div>
|
||||
<div className='col col-6'>
|
||||
<RpcNav />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={ { clear: 'both' } }></div>
|
||||
<div className='dapp-container'>
|
||||
<div className='row'>
|
||||
<div className='col col-6 mobile-full'>
|
||||
{ this.renderForm() }
|
||||
</div>
|
||||
<div className='col col-6 mobile-full'>
|
||||
<Calls
|
||||
calls={ this.props.rpc.prevCalls }
|
||||
reset={ this.props.actions.resetRpcPrevCalls }
|
||||
actions={ this.props.actions }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderForm () {
|
||||
return (
|
||||
<div>
|
||||
<Toggle
|
||||
className={ styles.jsonToggle }
|
||||
onToggle={ this.onJsonToggle }
|
||||
label='JSON'
|
||||
/>
|
||||
<h2 className={ styles.header }>
|
||||
<label htmlFor='selectedMethod'>
|
||||
Call Method
|
||||
</label>
|
||||
</h2>
|
||||
<AnimateChildren absolute>
|
||||
{ this.renderJsonForm() }
|
||||
{ this.renderInputForm() }
|
||||
</AnimateChildren>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderInputForm () {
|
||||
if (this.state.jsonMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { returns } = this.props.rpc.selectedMethod;
|
||||
return (
|
||||
<div className='row'>
|
||||
{ this.renderMethodList() }
|
||||
<h3>Parameters</h3>
|
||||
{ this.renderInputs() }
|
||||
<h3>Returns</h3>
|
||||
<Markdown val={ formatRpcMd(returns) } />
|
||||
{ this.renderFormButton() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderMethodList () {
|
||||
const { desc } = this.props.rpc.selectedMethod;
|
||||
return (
|
||||
<div>
|
||||
<RpcAutoComplete
|
||||
style={ { marginTop: 0 } }
|
||||
onNewRequest={ this.handleMethodChange }
|
||||
{ ...this._test('rpcAutoComplete') }
|
||||
/>
|
||||
<div>
|
||||
<Markdown val={ desc } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
handleMethodChange = name => {
|
||||
const method = rpcMethods.find(m => m.name === name);
|
||||
this.props.actions.selectRpcMethod(method);
|
||||
}
|
||||
|
||||
onRpcFire = () => {
|
||||
if (this.state.jsonMode) {
|
||||
return this.onCustomRpcFire();
|
||||
}
|
||||
|
||||
let { name, params, outputFormatter, inputFormatters } = this.props.rpc.selectedMethod;
|
||||
params = params.map(this.jsonParamValue);
|
||||
|
||||
this.props.actions.fireRpc({
|
||||
method: name,
|
||||
outputFormatter,
|
||||
inputFormatters,
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
onCustomRpcFire () {
|
||||
const { method, params } = this.state.jsonEditorParsedValue;
|
||||
this.props.actions.fireRpc({ method, params });
|
||||
}
|
||||
|
||||
renderInputs () {
|
||||
let { params, name } = this.props.rpc.selectedMethod;
|
||||
|
||||
if (!params || !params.length) {
|
||||
return (
|
||||
<span>none</span>
|
||||
);
|
||||
}
|
||||
|
||||
return _.find(rpcMethods, { name })
|
||||
.params.map(
|
||||
p => {
|
||||
const onChange = evt => this.setState({
|
||||
[this.paramKey(p)]: evt.target.value
|
||||
});
|
||||
|
||||
if (_.isPlainObject(p)) {
|
||||
return this.renderObjInputs(p);
|
||||
}
|
||||
|
||||
return (
|
||||
<TextField
|
||||
key={ p }
|
||||
inputStyle={ { marginTop: 0 } }
|
||||
fullWidth
|
||||
hintText={ p }
|
||||
title={ p }
|
||||
hintStyle={ { maxWidth: '100%', overflow: 'hidden', whiteSpace: 'nowrap' } }
|
||||
value={ this.paramValue(p) }
|
||||
onChange={ onChange }
|
||||
{ ...this._test(this.paramKey(p)) }
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
renderObjInputs (param) {
|
||||
const { description, details } = param;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Markdown val={ description } />
|
||||
<ul>
|
||||
{ Object.keys(details).map(k => {
|
||||
const onChange = evt => this.setState({
|
||||
[this.paramKey(`${description}.${k}`)]: evt.target.value
|
||||
});
|
||||
|
||||
return (
|
||||
<li key={ k }>
|
||||
<TextField
|
||||
inputStyle={ { marginTop: 0 } }
|
||||
fullWidth
|
||||
title={ `${k}: ${details[k]}` }
|
||||
hintText={ `${k}: ${details[k]}` }
|
||||
hintStyle={ { maxWidth: '100%', overflow: 'hidden', whiteSpace: 'nowrap' } }
|
||||
value={ this.paramValue(`${description}.${k}`) }
|
||||
onChange={ onChange }
|
||||
{ ...this._test(this.paramKey(k)) }
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}) }
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
setJsonEditorValue () {
|
||||
const { name, params } = this.props.rpc.selectedMethod;
|
||||
const json = {
|
||||
method: name,
|
||||
params: params.map(this.jsonParamValue)
|
||||
};
|
||||
this.setState({
|
||||
jsonEditorValue: json
|
||||
});
|
||||
}
|
||||
|
||||
onJsonToggle = () => {
|
||||
if (!this.state.jsonMode) {
|
||||
this.setJsonEditorValue();
|
||||
}
|
||||
this.setState({ jsonMode: !this.state.jsonMode });
|
||||
}
|
||||
|
||||
renderJsonForm () {
|
||||
if (!this.state.jsonMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<JsonEditor
|
||||
onChange={ this.onJsonEditorChange }
|
||||
value={ this.state.jsonEditorValue }
|
||||
/>
|
||||
{ this.renderFormButton() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderFormButton () {
|
||||
return (
|
||||
<button
|
||||
{ ...this._test('fireRpc') }
|
||||
className={ 'dapp-block-button' }
|
||||
disabled={ this.state.jsonEditorError }
|
||||
onClick={ this.onRpcFire }
|
||||
>
|
||||
Fire!
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
onJsonEditorChange = (jsonEditorParsedValue, jsonEditorError) => {
|
||||
this.setState({
|
||||
jsonEditorParsedValue,
|
||||
jsonEditorError
|
||||
});
|
||||
}
|
||||
|
||||
jsonParamValue = p => {
|
||||
if (_.isPlainObject(p)) {
|
||||
const { description, details } = p;
|
||||
return Object.keys(details).reduce((obj, key) => {
|
||||
obj[key] = this.paramValue(`${description}.${key}`);
|
||||
return obj;
|
||||
}, {});
|
||||
}
|
||||
|
||||
return this.paramValue(p);
|
||||
}
|
||||
|
||||
paramValue (p) {
|
||||
return this.state[this.paramKey(p)];
|
||||
}
|
||||
|
||||
paramKey (p) {
|
||||
return `params_${p}`;
|
||||
}
|
||||
|
||||
selectedMethodChanged (nextProps) {
|
||||
return nextProps.rpc.selectedMethod.name !== this.props.rpc.selectedMethod.name;
|
||||
}
|
||||
|
||||
stateChanged (nextState) {
|
||||
return !_.isEqual(nextState, this.state);
|
||||
}
|
||||
|
||||
prevCallsChanged (nextProps) {
|
||||
return nextProps.rpc.prevCalls.length !== this.props.rpc.prevCalls.length;
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
rpc: PropTypes.shape({
|
||||
prevCalls: PropTypes.array.isRequired,
|
||||
selectedMethod: PropTypes.object.isRequired
|
||||
}).isRequired,
|
||||
actions: PropTypes.shape({
|
||||
fireRpc: PropTypes.func.isRequired,
|
||||
selectRpcMethod: PropTypes.func.isRequired,
|
||||
resetRpcPrevCalls: PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
}
|
||||
17
js/src/views/Status/components/RpcCalls/index.js
Normal file
17
js/src/views/Status/components/RpcCalls/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 './RpcCalls';
|
||||
35
js/src/views/Status/components/RpcDocs/RpcDocs.css
Normal file
35
js/src/views/Status/components/RpcDocs/RpcDocs.css
Normal file
@@ -0,0 +1,35 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.autocomplete {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.headline {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.returnsTitle {
|
||||
display: 'inline';
|
||||
}
|
||||
|
||||
.returnsDesc {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
104
js/src/views/Status/components/RpcDocs/RpcDocs.js
Normal file
104
js/src/views/Status/components/RpcDocs/RpcDocs.js
Normal file
@@ -0,0 +1,104 @@
|
||||
// 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 } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { sortBy } from 'lodash';
|
||||
import List from 'material-ui/List/List';
|
||||
import ListItem from 'material-ui/List/ListItem';
|
||||
import AutoComplete from '../AutoComplete';
|
||||
|
||||
import { formatRpcMd } from '../../util/rpc-md';
|
||||
import ScrollTopButton from '../ScrollTopButton';
|
||||
import styles from './RpcDocs.css';
|
||||
import Markdown from '../Markdown';
|
||||
import rpcData from '../../data/rpc.json';
|
||||
import RpcNav from '../RpcNav';
|
||||
|
||||
const rpcMethods = sortBy(rpcData.methods, 'name');
|
||||
|
||||
class RpcDocs extends Component {
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='dapp-flex-content'>
|
||||
<main className='dapp-content'>
|
||||
<div className='dapp-container'>
|
||||
<div className='row'>
|
||||
<div className='col col-6'>
|
||||
<h1><span>RPC</span> Docs</h1>
|
||||
</div>
|
||||
<div className='col col-6'>
|
||||
<RpcNav />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={ { clear: 'both' } }></div>
|
||||
<div className='dapp-container'>
|
||||
<div className='row'>
|
||||
<div className='col col-12'>
|
||||
<AutoComplete
|
||||
floatingLabelText='Method name'
|
||||
className={ styles.autocomplete }
|
||||
dataSource={ rpcMethods.map(m => m.name) }
|
||||
onNewRequest={ this.handleMethodChange }
|
||||
{ ...this._test('autocomplete') }
|
||||
/>
|
||||
{ this.renderData() }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ScrollTopButton />
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderData () {
|
||||
const methods = rpcMethods.map((m, idx) => {
|
||||
const setMethod = el => { this[`_method-${m.name}`] = el; };
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
key={ m.name }
|
||||
disabled
|
||||
ref={ setMethod }
|
||||
>
|
||||
<h3 className={ styles.headline }>{ m.name }</h3>
|
||||
<Markdown val={ m.desc } />
|
||||
<p><strong>Params</strong>{ !m.params.length ? ' - none' : '' }</p>
|
||||
{ m.params.map((p, idx) => <Markdown key={ `${m.name}-${idx}` } val={ formatRpcMd(p) } />) }
|
||||
<p className={ styles.returnsTitle }><strong>Returns</strong> - </p>
|
||||
<Markdown className={ styles.returnsDesc } val={ formatRpcMd(m.returns) } />
|
||||
{ idx !== rpcMethods.length - 1 ? <hr /> : '' }
|
||||
</ListItem>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<List>
|
||||
{ methods }
|
||||
</List>
|
||||
);
|
||||
}
|
||||
|
||||
handleMethodChange = name => {
|
||||
ReactDOM.findDOMNode(this[`_method-${name}`]).scrollIntoViewIfNeeded();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default RpcDocs;
|
||||
17
js/src/views/Status/components/RpcDocs/index.js
Normal file
17
js/src/views/Status/components/RpcDocs/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 './RpcDocs';
|
||||
28
js/src/views/Status/components/RpcNav/RpcNav.css
Normal file
28
js/src/views/Status/components/RpcNav/RpcNav.css
Normal file
@@ -0,0 +1,28 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.nav {
|
||||
font-size: 20px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.activeNav {
|
||||
color: #b7a6a6 !important;
|
||||
}
|
||||
|
||||
.nav a:not(:first-child) {
|
||||
margin-left: 30px;
|
||||
}
|
||||
35
js/src/views/Status/components/RpcNav/RpcNav.js
Normal file
35
js/src/views/Status/components/RpcNav/RpcNav.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// 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 } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import styles from './RpcNav.css';
|
||||
|
||||
export default class RpcNav extends Component {
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className={ styles.nav }>
|
||||
<Link to={ '/rpc/calls' } activeClassName={ styles.activeNav } { ...this._test('rpc-calls-link') }>
|
||||
<i className='icon-call-out'></i>
|
||||
</Link>
|
||||
<Link to={ '/rpc/docs' } activeClassName={ styles.activeNav } { ...this._test('rpc-docs-link') }>
|
||||
<i className='icon-docs'></i>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
17
js/src/views/Status/components/RpcNav/index.js
Normal file
17
js/src/views/Status/components/RpcNav/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 './RpcNav';
|
||||
@@ -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/>.
|
||||
*/
|
||||
.scrollButton {
|
||||
position: fixed !important;
|
||||
bottom: 35px !important;
|
||||
right: 0;
|
||||
left: 0;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
animation: fadein .5s;
|
||||
background: #eee !important;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #6691C2 !important;
|
||||
z-index: 10;
|
||||
padding: 5px !important;
|
||||
width: 34px !important;
|
||||
height: 34px !important;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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 } from 'react';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import ArrowUpwardIcon from 'material-ui/svg-icons/navigation/arrow-upward';
|
||||
|
||||
import { scrollTo } from './util';
|
||||
import styles from './ScrollTopButton.css';
|
||||
|
||||
const scrollTopThreshold = 600;
|
||||
|
||||
export default class ScrollTopButton extends Component {
|
||||
|
||||
state = {}
|
||||
|
||||
componentDidMount () {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
_scrollToTop () {
|
||||
scrollTo(document.body, 0, 500);
|
||||
}
|
||||
|
||||
render () {
|
||||
let hiddenClass = !this.state.showScrollButton ? styles.hidden : '';
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
className={ `${styles.scrollButton} ${hiddenClass}` }
|
||||
onClick={ this._scrollToTop }>
|
||||
<ArrowUpwardIcon />
|
||||
</IconButton>
|
||||
);
|
||||
}
|
||||
|
||||
handleScroll = event => {
|
||||
let { scrollTop } = event.srcElement.body;
|
||||
let { showScrollButton } = this.state;
|
||||
|
||||
if (!showScrollButton && scrollTop > scrollTopThreshold) {
|
||||
this.setState({
|
||||
showScrollButton: true
|
||||
});
|
||||
}
|
||||
|
||||
if (showScrollButton && scrollTop < scrollTopThreshold) {
|
||||
this.setState({
|
||||
showScrollButton: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
17
js/src/views/Status/components/ScrollTopButton/index.js
Normal file
17
js/src/views/Status/components/ScrollTopButton/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 './ScrollTopButton';
|
||||
47
js/src/views/Status/components/ScrollTopButton/util.js
Normal file
47
js/src/views/Status/components/ScrollTopButton/util.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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 function scrollTo (element, to, duration) {
|
||||
let start = element.scrollTop;
|
||||
let change = to - start;
|
||||
let increment = 50;
|
||||
|
||||
let animateScroll = elapsedTime => {
|
||||
elapsedTime += increment;
|
||||
let position = easeInOut(elapsedTime, start, change, duration);
|
||||
element.scrollTop = position;
|
||||
if (elapsedTime < duration) {
|
||||
setTimeout(() => {
|
||||
// stop if user scrolled
|
||||
if (element.scrollTop !== parseInt(position, 10)) {
|
||||
return;
|
||||
}
|
||||
animateScroll(elapsedTime);
|
||||
}, increment);
|
||||
}
|
||||
};
|
||||
|
||||
animateScroll(0);
|
||||
}
|
||||
|
||||
export function easeInOut (currentTime, start, change, duration) {
|
||||
currentTime /= duration / 2;
|
||||
if (currentTime < 1) {
|
||||
return change / 2 * currentTime * currentTime + start;
|
||||
}
|
||||
currentTime -= 1;
|
||||
return -change / 2 * (currentTime * (currentTime - 2) - 1) + start;
|
||||
}
|
||||
74
js/src/views/Status/components/Status/Status.css
Normal file
74
js/src/views/Status/components/Status/Status.css
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
.container {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin: 0 -1em;
|
||||
}
|
||||
|
||||
.row::after {
|
||||
display: table;
|
||||
clear: both;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.blockinfo {
|
||||
font-size: 24px;
|
||||
color: #aaa;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.col,
|
||||
.col1, .col2, .col3, .col4, .col5, .col6, .col7, .col8, .col9, .col10, .col11, .col12 {
|
||||
float: left;
|
||||
padding: 0 1em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.col3 {
|
||||
width: 25%;
|
||||
width: -webkit-calc(100% / 12 * 3);
|
||||
width: -moz-calc(100% / 12 * 3);
|
||||
width: calc(100% / 12 * 3);
|
||||
}
|
||||
|
||||
.col4 {
|
||||
width: 33.33333%;
|
||||
width: -webkit-calc(100% / 12 * 4);
|
||||
width: -moz-calc(100% / 12 * 4);
|
||||
width: calc(100% / 12 * 4);
|
||||
}
|
||||
|
||||
.col5 {
|
||||
width: 41.66665%;
|
||||
width: -webkit-calc(100% / 12 * 5);
|
||||
width: -moz-calc(100% / 12 * 5);
|
||||
width: calc(100% / 12 * 5);
|
||||
}
|
||||
|
||||
.col6 {
|
||||
width: 50%;
|
||||
width: -webkit-calc(100% / 12 * 6);
|
||||
width: -moz-calc(100% / 12 * 6);
|
||||
width: calc(100% / 12 * 6);
|
||||
}
|
||||
|
||||
.col12 {
|
||||
width: 100%;
|
||||
}
|
||||
145
js/src/views/Status/components/Status/Status.js
Normal file
145
js/src/views/Status/components/Status/Status.js
Normal file
@@ -0,0 +1,145 @@
|
||||
// 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 bytes from 'bytes';
|
||||
|
||||
import { Container, ContainerTitle, Input } from '../../../../ui';
|
||||
|
||||
import styles from './Status.css';
|
||||
import MiningSettings from '../MiningSettings';
|
||||
|
||||
export default class Status extends Component {
|
||||
static propTypes = {
|
||||
nodeStatus: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
render () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { netPeers } = nodeStatus;
|
||||
|
||||
if (!netPeers || !nodeStatus.blockNumber) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hashrate = bytes(nodeStatus.hashrate.toNumber()) || 0;
|
||||
const peers = `${netPeers.active}/${netPeers.connected}/${netPeers.max}`;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className={ styles.container }>
|
||||
<div className={ styles.row }>
|
||||
<div className={ styles.col3 }>
|
||||
<div className={ styles.col12 }>
|
||||
<ContainerTitle title='best block' />
|
||||
<h2 { ...this._test('best-block') } className={ styles.blockinfo }>
|
||||
#{ nodeStatus.blockNumber.toFormat() }
|
||||
</h2>
|
||||
</div>
|
||||
<div className={ styles.col12 }>
|
||||
<ContainerTitle title='peers' />
|
||||
<h2 { ...this._test('peers') } className={ styles.blockinfo }>
|
||||
{ peers }
|
||||
</h2>
|
||||
</div>
|
||||
<div className={ styles.col12 }>
|
||||
<ContainerTitle title='hash rate' />
|
||||
<h2 { ...this._test('hashrate') } className={ styles.blockinfo }>
|
||||
{ `${hashrate} H/s` }
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className={ styles.col5 }>
|
||||
<MiningSettings
|
||||
{ ...this._test('mining') }
|
||||
nodeStatus={ nodeStatus }
|
||||
actions={ this.props.actions } />
|
||||
</div>
|
||||
<div className={ styles.col4 }>
|
||||
{ this.renderSettings() }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
renderNodeName () {
|
||||
const { nodeStatus } = this.props;
|
||||
|
||||
return (
|
||||
<span>
|
||||
{ nodeStatus.nodeName || 'Node' }
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
renderSettings () {
|
||||
const { nodeStatus } = this.props;
|
||||
const { rpcSettings, netPeers } = nodeStatus;
|
||||
const peers = `${netPeers.active}/${netPeers.connected}/${netPeers.max}`;
|
||||
|
||||
return (
|
||||
<div { ...this._test('settings') }>
|
||||
<ContainerTitle title='network settings' />
|
||||
<Input
|
||||
disabled
|
||||
label='chain'
|
||||
value={ nodeStatus.netChain }
|
||||
{ ...this._test('chain') } />
|
||||
<div className={ styles.row }>
|
||||
<div className={ styles.col6 }>
|
||||
<Input
|
||||
disabled
|
||||
label='peers'
|
||||
value={ peers }
|
||||
{ ...this._test('peers') } />
|
||||
</div>
|
||||
<div className={ styles.col6 }>
|
||||
<Input
|
||||
disabled
|
||||
label='network port'
|
||||
value={ nodeStatus.netPort.toString() }
|
||||
{ ...this._test('network-port') } />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
disabled
|
||||
label='rpc enabled'
|
||||
value={ rpcSettings.enabled ? 'yes' : 'no' }
|
||||
{ ...this._test('rpc-enabled') } />
|
||||
<div className={ styles.row }>
|
||||
<div className={ styles.col6 }>
|
||||
<Input
|
||||
disabled
|
||||
label='rpc interface'
|
||||
value={ rpcSettings.interface }
|
||||
{ ...this._test('rpc-interface') } />
|
||||
</div>
|
||||
<div className={ styles.col6 }>
|
||||
<Input
|
||||
disabled
|
||||
label='rpc port'
|
||||
value={ rpcSettings.port.toString() }
|
||||
{ ...this._test('rpc-port') } />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
17
js/src/views/Status/components/Status/index.js
Normal file
17
js/src/views/Status/components/Status/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 './Status';
|
||||
Reference in New Issue
Block a user