Merge branch 'master' into jg-signer-api-queries-2
This commit is contained in:
commit
59f4252011
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1263,7 +1263,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-ui-precompiled"
|
name = "parity-ui-precompiled"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "git+https://github.com/ethcore/js-precompiled.git#f46188126257e03c775e76a3cea82b5f70549400"
|
source = "git+https://github.com/ethcore/js-precompiled.git#f8dba85e17d32860d4070fb444fa5cf13bcc6b3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "parity.js",
|
"name": "parity.js",
|
||||||
"version": "0.2.61",
|
"version": "0.2.63",
|
||||||
"main": "release/index.js",
|
"main": "release/index.js",
|
||||||
"jsnext:main": "src/index.js",
|
"jsnext:main": "src/index.js",
|
||||||
"author": "Parity Team <admin@parity.io>",
|
"author": "Parity Team <admin@parity.io>",
|
||||||
@ -102,6 +102,7 @@
|
|||||||
"postcss-nested": "^1.0.0",
|
"postcss-nested": "^1.0.0",
|
||||||
"postcss-simple-vars": "^3.0.0",
|
"postcss-simple-vars": "^3.0.0",
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
|
"react-addons-perf": "~15.3.2",
|
||||||
"react-addons-test-utils": "~15.3.2",
|
"react-addons-test-utils": "~15.3.2",
|
||||||
"react-copy-to-clipboard": "^4.2.3",
|
"react-copy-to-clipboard": "^4.2.3",
|
||||||
"react-dom": "~15.3.2",
|
"react-dom": "~15.3.2",
|
||||||
|
17
js/src/dapps/dappreg.html
Normal file
17
js/src/dapps/dappreg.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<link rel="icon" href="/parity-logo-black-no-text.png" type="image/png">
|
||||||
|
<title>Dapp Registry</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container"></div>
|
||||||
|
<script src="vendor.js"></script>
|
||||||
|
<script src="commons.js"></script>
|
||||||
|
<script src="/parity-utils/parity.js"></script>
|
||||||
|
<script src="dappreg.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
35
js/src/dapps/dappreg.js
Normal file
35
js/src/dapps/dappreg.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 from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import injectTapEventPlugin from 'react-tap-event-plugin';
|
||||||
|
import { useStrict } from 'mobx';
|
||||||
|
|
||||||
|
injectTapEventPlugin();
|
||||||
|
useStrict(true);
|
||||||
|
|
||||||
|
import Application from './dappreg/Application';
|
||||||
|
|
||||||
|
import '../../assets/fonts/Roboto/font.css';
|
||||||
|
import '../../assets/fonts/RobotoMono/font.css';
|
||||||
|
import './style.css';
|
||||||
|
import './dappreg.html';
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<Application />,
|
||||||
|
document.querySelector('#container')
|
||||||
|
);
|
58
js/src/dapps/dappreg/Application/application.css
Normal file
58
js/src/dapps/dappreg/Application/application.css
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.body {
|
||||||
|
color: #333;
|
||||||
|
background: #eee;
|
||||||
|
padding: 4.5em 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.apps {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 980px;
|
||||||
|
padding: 1.5em;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
font-size: 0.75em;
|
||||||
|
margin: 1em;
|
||||||
|
padding: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background: #44e;
|
||||||
|
border-radius: 0 0 0.25em 0.25em;
|
||||||
|
color: #fff;
|
||||||
|
left: 0;
|
||||||
|
padding: 1em;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 5em;
|
||||||
|
font-size: 2em;
|
||||||
|
color: #999;
|
||||||
|
}
|
64
js/src/dapps/dappreg/Application/application.js
Normal file
64
js/src/dapps/dappreg/Application/application.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import DappsStore from '../dappsStore';
|
||||||
|
|
||||||
|
import ButtonBar from '../ButtonBar';
|
||||||
|
import Dapp from '../Dapp';
|
||||||
|
import ModalDelete from '../ModalDelete';
|
||||||
|
import ModalRegister from '../ModalRegister';
|
||||||
|
import ModalUpdate from '../ModalUpdate';
|
||||||
|
import SelectDapp from '../SelectDapp';
|
||||||
|
import Warning from '../Warning';
|
||||||
|
import styles from './application.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Application extends Component {
|
||||||
|
dappsStore = DappsStore.instance();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (this.dappsStore.isLoading) {
|
||||||
|
return (
|
||||||
|
<div className={ styles.loading }>
|
||||||
|
Loading application
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.body }>
|
||||||
|
<div className={ styles.header }>
|
||||||
|
DAPP REGISTRY, a global view of distributed applications available on the network. Putting the puzzle together.
|
||||||
|
</div>
|
||||||
|
<div className={ styles.apps }>
|
||||||
|
<SelectDapp />
|
||||||
|
<ButtonBar />
|
||||||
|
<Dapp />
|
||||||
|
</div>
|
||||||
|
<div className={ styles.footer }>
|
||||||
|
{ this.dappsStore.count } applications registered, { this.dappsStore.ownedCount } owned by user
|
||||||
|
</div>
|
||||||
|
<Warning />
|
||||||
|
<ModalDelete />
|
||||||
|
<ModalRegister />
|
||||||
|
<ModalUpdate />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/Application/index.js
Normal file
17
js/src/dapps/dappreg/Application/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 './application';
|
38
js/src/dapps/dappreg/Button/button.css
Normal file
38
js/src/dapps/dappreg/Button/button.css
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.button {
|
||||||
|
background: #44e;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1em;
|
||||||
|
margin: 1em 0.375em;
|
||||||
|
opacity: 0.85;
|
||||||
|
padding: 0.75em 2em;
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: default;
|
||||||
|
background: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-warning="true"] {
|
||||||
|
background: #e44;
|
||||||
|
}
|
||||||
|
}
|
52
js/src/dapps/dappreg/Button/button.js
Normal file
52
js/src/dapps/dappreg/Button/button.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
|
import styles from './button.css';
|
||||||
|
|
||||||
|
export default class Button extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
label: PropTypes.string.isRequired,
|
||||||
|
warning: PropTypes.bool,
|
||||||
|
onClick: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { className, disabled, label, warning } = this.props;
|
||||||
|
const classes = `${styles.button} ${className}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={ classes }
|
||||||
|
data-warning={ warning }
|
||||||
|
disabled={ disabled }
|
||||||
|
onClick={ this.onClick }>
|
||||||
|
{ label }
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick = (event) => {
|
||||||
|
if (this.props.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onClick(event);
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/Button/index.js
Normal file
17
js/src/dapps/dappreg/Button/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 './button';
|
21
js/src/dapps/dappreg/ButtonBar/buttonBar.css
Normal file
21
js/src/dapps/dappreg/ButtonBar/buttonBar.css
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.buttonbar {
|
||||||
|
text-align: center;
|
||||||
|
margin: 1em 0 0 0;
|
||||||
|
}
|
101
js/src/dapps/dappreg/ButtonBar/buttonBar.js
Normal file
101
js/src/dapps/dappreg/ButtonBar/buttonBar.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import DappsStore from '../dappsStore';
|
||||||
|
import ModalStore from '../modalStore';
|
||||||
|
|
||||||
|
import Button from '../Button';
|
||||||
|
import styles from './buttonBar.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class ButtonBar extends Component {
|
||||||
|
dappsStore = DappsStore.instance();
|
||||||
|
modalStore = ModalStore.instance();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
let buttons = [];
|
||||||
|
|
||||||
|
if (this.dappsStore.isEditing || this.dappsStore.isNew) {
|
||||||
|
buttons = [
|
||||||
|
<Button
|
||||||
|
key='cancel'
|
||||||
|
label='Cancel'
|
||||||
|
warning
|
||||||
|
onClick={ this.onCancelClick } />,
|
||||||
|
<Button
|
||||||
|
key='save'
|
||||||
|
label={ this.dappsStore.isNew ? 'Register' : 'Update' }
|
||||||
|
disabled={ !this.dappsStore.canSave }
|
||||||
|
onClick={ this.onSaveClick } />
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
buttons = [
|
||||||
|
<Button
|
||||||
|
key='delete'
|
||||||
|
label='Delete'
|
||||||
|
warning
|
||||||
|
disabled={ !this.dappsStore.currentApp.isOwner && !this.dappsStore.isContractOwner }
|
||||||
|
onClick={ this.onDeleteClick } />,
|
||||||
|
<Button
|
||||||
|
key='edit'
|
||||||
|
label='Edit'
|
||||||
|
disabled={ !this.dappsStore.currentApp.isOwner }
|
||||||
|
onClick={ this.onEditClick } />,
|
||||||
|
<Button
|
||||||
|
key='new'
|
||||||
|
label='New'
|
||||||
|
onClick={ this.onNewClick } />
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.buttonbar }>
|
||||||
|
{ buttons }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick = () => {
|
||||||
|
if (this.dappsStore.isEditing) {
|
||||||
|
this.dappsStore.setEditing(false);
|
||||||
|
} else {
|
||||||
|
this.dappsStore.setNew(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteClick = () => {
|
||||||
|
this.modalStore.showDelete();
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditClick = () => {
|
||||||
|
this.dappsStore.setEditing(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onNewClick = () => {
|
||||||
|
this.dappsStore.setNew(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick = () => {
|
||||||
|
if (this.dappsStore.isEditing) {
|
||||||
|
this.modalStore.showUpdate();
|
||||||
|
} else {
|
||||||
|
this.modalStore.showRegister();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/ButtonBar/index.js
Normal file
17
js/src/dapps/dappreg/ButtonBar/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 './buttonBar';
|
19
js/src/dapps/dappreg/Dapp/dapp.css
Normal file
19
js/src/dapps/dappreg/Dapp/dapp.css
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.app {
|
||||||
|
}
|
162
js/src/dapps/dappreg/Dapp/dapp.js
Normal file
162
js/src/dapps/dappreg/Dapp/dapp.js
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import { api } from '../parity';
|
||||||
|
import DappsStore from '../dappsStore';
|
||||||
|
|
||||||
|
import Input from '../Input';
|
||||||
|
import SelectAccount from '../SelectAccount';
|
||||||
|
import styles from './dapp.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Dapp extends Component {
|
||||||
|
dappsStore = DappsStore.instance();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const app = this.dappsStore.isNew || this.dappsStore.isEditing
|
||||||
|
? this.dappsStore.wipApp
|
||||||
|
: this.dappsStore.currentApp;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.app }>
|
||||||
|
{ this.dappsStore.isNew ? this.renderOwnerSelect(app) : this.renderOwnerStatic(app) }
|
||||||
|
{ this.renderInputs(app) }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderInputs (app) {
|
||||||
|
if (this.dappsStore.isNew) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
this.renderHashInput(app, 'image', 'Image hash, as generated by Githubhint', true),
|
||||||
|
this.renderHashInput(app, 'manifest', 'Manifest hash, as generated by Githubhint'),
|
||||||
|
this.renderHashInput(app, 'content', 'Content hash, as generated by Githubhint')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
renderOwnerSelect (app) {
|
||||||
|
const overlayImage = (
|
||||||
|
<img
|
||||||
|
className={ styles.overlayImage }
|
||||||
|
src={ api.util.createIdentityImg(this.dappsStore.currentAccount.address, 4) } />
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
hint={ this.dappsStore.currentAccount.address }
|
||||||
|
label='Owner, select the application owner and editor'
|
||||||
|
overlay={ overlayImage }>
|
||||||
|
<SelectAccount />
|
||||||
|
</Input>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderOwnerStatic (app) {
|
||||||
|
const overlayImage = (
|
||||||
|
<img
|
||||||
|
className={ styles.overlayImage }
|
||||||
|
src={ api.util.createIdentityImg(app.owner, 4) } />
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
hint={ app.owner }
|
||||||
|
label='Owner, the application owner and editor'
|
||||||
|
overlay={ overlayImage }>
|
||||||
|
<input value={ app.ownerName } readOnly />
|
||||||
|
</Input>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHashInput (app, type, label, withImage = false) {
|
||||||
|
const onChange = (event) => this.onChangeHash(event, type);
|
||||||
|
const hash = app[`${type}Hash`];
|
||||||
|
|
||||||
|
let overlayImage = null;
|
||||||
|
if (withImage && hash) {
|
||||||
|
overlayImage = (
|
||||||
|
<img
|
||||||
|
className={ styles.overlayImage }
|
||||||
|
src={ `/api/content/${hash.substr(2)}` } />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
hint={ app[`${type}Error`] || app[`${type}Url`] || '...' }
|
||||||
|
label={ label }
|
||||||
|
key={ `${type}Edit` }
|
||||||
|
overlay={ overlayImage }>
|
||||||
|
<input
|
||||||
|
value={ app[`${type}Hash`] || '' }
|
||||||
|
data-dirty={ app[`${type}Changed`] }
|
||||||
|
data-error={ !!app[`${type}Error`] }
|
||||||
|
readOnly={ !this.dappsStore.isEditing && !this.dappsStore.isNew }
|
||||||
|
onChange={ onChange } />
|
||||||
|
</Input>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeHash (event, type) {
|
||||||
|
if (!this.dappsStore.isNew && !this.dappsStore.isEditing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hash = event.target.value;
|
||||||
|
let changed = false;
|
||||||
|
let url = null;
|
||||||
|
|
||||||
|
if (this.dappsStore.isNew) {
|
||||||
|
if (hash && hash.length) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.dappsStore.currentApp[`${type}Hash`] !== hash) {
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
url = this.dappsStore.currentApp[`${type}Url`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dappsStore.editWip({
|
||||||
|
[`${type}Changed`]: changed,
|
||||||
|
[`${type}Error`]: null,
|
||||||
|
[`${type}Hash`]: hash,
|
||||||
|
[`${type}Url`]: changed ? 'Resolving url from hash' : url
|
||||||
|
});
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
if (hash.length) {
|
||||||
|
this.dappsStore
|
||||||
|
.lookupHash(hash)
|
||||||
|
.then((url) => {
|
||||||
|
this.dappsStore.editWip({
|
||||||
|
[`${type}Error`]: url ? null : 'Unable to resolve url',
|
||||||
|
[`${type}Url`]: url
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.dappsStore.editWip({ [`${type}Url`]: null });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/Dapp/index.js
Normal file
17
js/src/dapps/dappreg/Dapp/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 './dapp';
|
17
js/src/dapps/dappreg/Input/index.js
Normal file
17
js/src/dapps/dappreg/Input/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 './input';
|
92
js/src/dapps/dappreg/Input/input.css
Normal file
92
js/src/dapps/dappreg/Input/input.css
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.input {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
input, select {
|
||||||
|
background: rgba(255, 255, 255, 0.85);
|
||||||
|
border: 4px solid rgba(223, 223, 223, 0.85);
|
||||||
|
border-radius: 0.25em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #333;
|
||||||
|
font-size: 1em;
|
||||||
|
margin: 0.25em 0 0.25em 0;
|
||||||
|
padding: 0.5em 0.5em 1.5em 0.5em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding-bottom: 1.5em;
|
||||||
|
|
||||||
|
&[data-dirty="true"] {
|
||||||
|
background: rgba(255, 255, 203, 0.85);
|
||||||
|
border-color: rgba(203, 203, 151, 0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-error="true"] {
|
||||||
|
background: rgba(255, 223, 223, 0.85) !important;
|
||||||
|
border-color: rgba(223, 191, 191, 0.85) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[readonly] {
|
||||||
|
background: rgba(239, 239, 239, 0.85);
|
||||||
|
border-color: rgba(223, 223, 223, 0.85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
color: #888;
|
||||||
|
display: block;
|
||||||
|
font-size: 0.75em;
|
||||||
|
margin-top: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
-moz-appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
height: 58px;
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
background: rgba(239, 239, 239, 0.85);
|
||||||
|
border-color: rgba(223, 223, 223, 0.85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
color: #888;
|
||||||
|
display: block;
|
||||||
|
font-size: 0.75em;
|
||||||
|
position: absolute;
|
||||||
|
right: 52px;
|
||||||
|
text-align: right;
|
||||||
|
top: 52px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
right: 10px;
|
||||||
|
position: absolute;
|
||||||
|
top: 30px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
js/src/dapps/dappreg/Input/input.js
Normal file
47
js/src/dapps/dappreg/Input/input.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';
|
||||||
|
|
||||||
|
import styles from './input.css';
|
||||||
|
|
||||||
|
export default class Input extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
hint: PropTypes.string,
|
||||||
|
label: PropTypes.string.isRequired,
|
||||||
|
overlay: PropTypes.node
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { children, hint, label, overlay } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.input }>
|
||||||
|
<label>
|
||||||
|
{ label }
|
||||||
|
</label>
|
||||||
|
{ children }
|
||||||
|
<div className={ styles.hint }>
|
||||||
|
{ hint }
|
||||||
|
</div>
|
||||||
|
<div className={ styles.overlay }>
|
||||||
|
{ overlay }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/Modal/index.js
Normal file
17
js/src/dapps/dappreg/Modal/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 './modal';
|
116
js/src/dapps/dappreg/Modal/modal.css
Normal file
116
js/src/dapps/dappreg/Modal/modal.css
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
.body {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 50;
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0 0 0.25em 0.25em;
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 840px;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
line-height: 1.5em;
|
||||||
|
padding: 2em;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.section {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
color: #f44;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section+.section {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
padding: 0.5em 1.625em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background: #44e;
|
||||||
|
color: #fff;
|
||||||
|
opacity: 0.85;
|
||||||
|
padding: 1em;
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
background: #e44;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
background: rgba(204, 204, 204, 0.7);
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 49;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.account {
|
||||||
|
div {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
display: block !important;
|
||||||
|
color: #888;
|
||||||
|
font-size: 0.75em;
|
||||||
|
margin-top: -0.5em;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
color: #888;
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light {
|
||||||
|
color: #888;
|
||||||
|
}
|
66
js/src/dapps/dappreg/Modal/modal.js
Normal file
66
js/src/dapps/dappreg/Modal/modal.js
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/>.
|
||||||
|
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
|
import styles from './modal.css';
|
||||||
|
|
||||||
|
export default class Modal extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
buttons: PropTypes.node,
|
||||||
|
children: PropTypes.node,
|
||||||
|
error: PropTypes.object,
|
||||||
|
header: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { children, buttons, error, header } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.modal }>
|
||||||
|
<div className={ styles.overlay } />
|
||||||
|
<div className={ styles.body }>
|
||||||
|
<div className={ styles.dialog }>
|
||||||
|
<div className={ `${styles.header} ${error ? styles.error : ''}` }>
|
||||||
|
{ header }
|
||||||
|
</div>
|
||||||
|
<div className={ styles.content }>
|
||||||
|
{ error ? this.renderError() : children }
|
||||||
|
</div>
|
||||||
|
<div className={ styles.footer }>
|
||||||
|
{ buttons }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderError () {
|
||||||
|
const { error } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
Your operation failed to complete sucessfully. The following error was returned:
|
||||||
|
</div>
|
||||||
|
<div className={ `${styles.section} ${styles.error}` }>
|
||||||
|
{ error.toString() }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/ModalDelete/index.js
Normal file
17
js/src/dapps/dappreg/ModalDelete/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 './modalDelete';
|
159
js/src/dapps/dappreg/ModalDelete/modalDelete.js
Normal file
159
js/src/dapps/dappreg/ModalDelete/modalDelete.js
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import { api } from '../parity';
|
||||||
|
import DappsStore from '../dappsStore';
|
||||||
|
import ModalStore from '../modalStore';
|
||||||
|
|
||||||
|
import Button from '../Button';
|
||||||
|
import Modal from '../Modal';
|
||||||
|
|
||||||
|
import styles from '../Modal/modal.css';
|
||||||
|
|
||||||
|
const HEADERS = [
|
||||||
|
'Error During Deletion',
|
||||||
|
'Confirm Application Deletion',
|
||||||
|
'Waiting for Signer Confirmation',
|
||||||
|
'Waiting for Transaction Receipt',
|
||||||
|
'Deletion Completed'
|
||||||
|
];
|
||||||
|
const STEP_ERROR = 0;
|
||||||
|
const STEP_CONFIRM = 1;
|
||||||
|
const STEP_SIGNER = 2;
|
||||||
|
const STEP_TXRECEIPT = 3;
|
||||||
|
const STEP_DONE = 4;
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class ModalDelete extends Component {
|
||||||
|
dappsStore = DappsStore.instance();
|
||||||
|
modalStore = ModalStore.instance();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (!this.modalStore.showingDelete) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
buttons={ this.renderButtons() }
|
||||||
|
error={ this.modalStore.errorDelete }
|
||||||
|
header={ HEADERS[this.modalStore.stepDelete] }>
|
||||||
|
{ this.renderStep() }
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderButtons () {
|
||||||
|
switch (this.modalStore.stepDelete) {
|
||||||
|
case STEP_ERROR:
|
||||||
|
case STEP_DONE:
|
||||||
|
return [
|
||||||
|
<Button
|
||||||
|
key='close'
|
||||||
|
label='Close'
|
||||||
|
onClick={ this.onClickClose } />
|
||||||
|
];
|
||||||
|
case STEP_CONFIRM:
|
||||||
|
return [
|
||||||
|
<Button
|
||||||
|
key='cancel'
|
||||||
|
label='No, Cancel'
|
||||||
|
onClick={ this.onClickClose } />,
|
||||||
|
<Button
|
||||||
|
key='delete'
|
||||||
|
label='Yes, Delete'
|
||||||
|
warning
|
||||||
|
onClick={ this.onClickYes } />
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStep () {
|
||||||
|
switch (this.modalStore.stepDelete) {
|
||||||
|
case STEP_CONFIRM:
|
||||||
|
return this.renderStepConfirm();
|
||||||
|
case STEP_SIGNER:
|
||||||
|
return this.renderStepWait('Waiting for transaction confirmation in the Parity secure signer');
|
||||||
|
case STEP_TXRECEIPT:
|
||||||
|
return this.renderStepWait('Waiting for the transaction receipt from the network');
|
||||||
|
case STEP_DONE:
|
||||||
|
return this.renderStepCompleted();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepCompleted () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
Your application has been removed from the registry.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepConfirm () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
You are about to remove a distributed application from the registry, the details of this application is given below. Removal does not return any fees, however the application will not be available to users anymore.
|
||||||
|
</div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
<div className={ styles.heading }>
|
||||||
|
Owner account
|
||||||
|
</div>
|
||||||
|
<div className={ styles.account }>
|
||||||
|
<img src={ api.util.createIdentityImg(this.dappsStore.currentApp.owner, 3) } />
|
||||||
|
<div>{ this.dappsStore.currentApp.ownerName }</div>
|
||||||
|
<div className={ styles.address }>{ this.dappsStore.currentApp.owner }</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
<div className={ styles.heading }>
|
||||||
|
Application identifier
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{ this.dappsStore.currentApp.id }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepWait (waitingFor) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
{ waitingFor }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickClose = () => {
|
||||||
|
this.modalStore.hideDelete();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickYes = () => {
|
||||||
|
this.modalStore.doDelete();
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/ModalRegister/index.js
Normal file
17
js/src/dapps/dappreg/ModalRegister/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 './modalRegister';
|
159
js/src/dapps/dappreg/ModalRegister/modalRegister.js
Normal file
159
js/src/dapps/dappreg/ModalRegister/modalRegister.js
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import { api } from '../parity';
|
||||||
|
import DappsStore from '../dappsStore';
|
||||||
|
import ModalStore from '../modalStore';
|
||||||
|
|
||||||
|
import Button from '../Button';
|
||||||
|
import Modal from '../Modal';
|
||||||
|
|
||||||
|
import styles from '../Modal/modal.css';
|
||||||
|
|
||||||
|
const HEADERS = [
|
||||||
|
'Error During Registration',
|
||||||
|
'Confirm Application Registration',
|
||||||
|
'Waiting for Signer Confirmation',
|
||||||
|
'Waiting for Transaction Receipt',
|
||||||
|
'Registration Completed'
|
||||||
|
];
|
||||||
|
const STEP_ERROR = 0;
|
||||||
|
const STEP_CONFIRM = 1;
|
||||||
|
const STEP_SIGNER = 2;
|
||||||
|
const STEP_TXRECEIPT = 3;
|
||||||
|
const STEP_DONE = 4;
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class ModalRegister extends Component {
|
||||||
|
dappsStore = DappsStore.instance();
|
||||||
|
modalStore = ModalStore.instance();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (!this.modalStore.showingRegister) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
buttons={ this.renderButtons() }
|
||||||
|
error={ this.modalStore.errorRegister }
|
||||||
|
header={ HEADERS[this.modalStore.stepRegister] }>
|
||||||
|
{ this.renderStep() }
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderButtons () {
|
||||||
|
switch (this.modalStore.stepRegister) {
|
||||||
|
case STEP_ERROR:
|
||||||
|
case STEP_DONE:
|
||||||
|
return [
|
||||||
|
<Button
|
||||||
|
key='close'
|
||||||
|
label='Close'
|
||||||
|
onClick={ this.onClickClose } />
|
||||||
|
];
|
||||||
|
case STEP_CONFIRM:
|
||||||
|
return [
|
||||||
|
<Button
|
||||||
|
key='cancel'
|
||||||
|
label='No, Cancel'
|
||||||
|
onClick={ this.onClickClose } />,
|
||||||
|
<Button
|
||||||
|
key='register'
|
||||||
|
label='Yes, Register'
|
||||||
|
warning
|
||||||
|
onClick={ this.onClickConfirmYes } />
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStep () {
|
||||||
|
switch (this.modalStore.stepRegister) {
|
||||||
|
case STEP_CONFIRM:
|
||||||
|
return this.renderStepConfirm();
|
||||||
|
case STEP_SIGNER:
|
||||||
|
return this.renderStepWait('Waiting for transaction confirmation in the Parity secure signer');
|
||||||
|
case STEP_TXRECEIPT:
|
||||||
|
return this.renderStepWait('Waiting for the transaction receipt from the network');
|
||||||
|
case STEP_DONE:
|
||||||
|
return this.renderStepCompleted();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepCompleted () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
Your application has been registered in the registry.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepConfirm () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
You are about to register a new distributed application on the network, the details of this application is given below. This will require a non-refundable fee of { api.util.fromWei(this.dappsStore.fee).toFormat(3) }<small>ETH</small>.
|
||||||
|
</div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
<div className={ styles.heading }>
|
||||||
|
Selected owner account
|
||||||
|
</div>
|
||||||
|
<div className={ styles.account }>
|
||||||
|
<img src={ api.util.createIdentityImg(this.dappsStore.currentAccount.address, 3) } />
|
||||||
|
<div>{ this.dappsStore.currentAccount.name }</div>
|
||||||
|
<div className={ styles.hint }>{ this.dappsStore.currentAccount.address }</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
<div className={ styles.heading }>
|
||||||
|
Unique assigned application identifier
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{ this.dappsStore.wipApp.id }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepWait (waitingFor) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
{ waitingFor }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickClose = () => {
|
||||||
|
this.modalStore.hideRegister();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickConfirmYes = () => {
|
||||||
|
this.modalStore.doRegister();
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/ModalUpdate/index.js
Normal file
17
js/src/dapps/dappreg/ModalUpdate/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 './modalUpdate';
|
169
js/src/dapps/dappreg/ModalUpdate/modalUpdate.js
Normal file
169
js/src/dapps/dappreg/ModalUpdate/modalUpdate.js
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import DappsStore from '../dappsStore';
|
||||||
|
import ModalStore from '../modalStore';
|
||||||
|
|
||||||
|
import Button from '../Button';
|
||||||
|
import Modal from '../Modal';
|
||||||
|
|
||||||
|
import styles from '../Modal/modal.css';
|
||||||
|
|
||||||
|
const HEADERS = [
|
||||||
|
'Error During Update',
|
||||||
|
'Confirm Application Update',
|
||||||
|
'Waiting for Signer Confirmation',
|
||||||
|
'Waiting for Transaction Receipt',
|
||||||
|
'Update Completed'
|
||||||
|
];
|
||||||
|
const STEP_ERROR = 0;
|
||||||
|
const STEP_CONFIRM = 1;
|
||||||
|
const STEP_SIGNER = 2;
|
||||||
|
const STEP_TXRECEIPT = 3;
|
||||||
|
const STEP_DONE = 4;
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class ModalUpdate extends Component {
|
||||||
|
dappsStore = DappsStore.instance();
|
||||||
|
modalStore = ModalStore.instance();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (!this.modalStore.showingUpdate) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
buttons={ this.renderButtons() }
|
||||||
|
error={ this.modalStore.errorUpdate }
|
||||||
|
header={ HEADERS[this.modalStore.stepUpdate] }>
|
||||||
|
{ this.renderStep() }
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderButtons () {
|
||||||
|
switch (this.modalStore.stepUpdate) {
|
||||||
|
case STEP_ERROR:
|
||||||
|
case STEP_DONE:
|
||||||
|
return [
|
||||||
|
<Button
|
||||||
|
key='close'
|
||||||
|
label='Close'
|
||||||
|
onClick={ this.onClickClose } />
|
||||||
|
];
|
||||||
|
case STEP_CONFIRM:
|
||||||
|
return [
|
||||||
|
<Button
|
||||||
|
key='cancel'
|
||||||
|
label='No, Cancel'
|
||||||
|
onClick={ this.onClickClose } />,
|
||||||
|
<Button
|
||||||
|
key='delete'
|
||||||
|
label='Yes, Update'
|
||||||
|
warning
|
||||||
|
onClick={ this.onClickYes } />
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStep () {
|
||||||
|
switch (this.modalStore.stepUpdate) {
|
||||||
|
case STEP_CONFIRM:
|
||||||
|
return this.renderStepConfirm();
|
||||||
|
case STEP_SIGNER:
|
||||||
|
return this.renderStepWait('Waiting for transaction confirmation in the Parity secure signer');
|
||||||
|
case STEP_TXRECEIPT:
|
||||||
|
return this.renderStepWait('Waiting for the transaction receipt from the network');
|
||||||
|
case STEP_DONE:
|
||||||
|
return this.renderStepCompleted();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepCompleted () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
Your application metadata has been updated in the registry.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepConfirm () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
You are about to update the application details in the registry, the details of these updates are given below. Please note that each update will generate a seperate transaction.
|
||||||
|
</div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
<div className={ styles.heading }>
|
||||||
|
Application identifier
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{ this.dappsStore.wipApp.id }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{ this.renderChanges() }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderChanges () {
|
||||||
|
return ['content', 'image', 'manifest']
|
||||||
|
.filter((type) => this.dappsStore.wipApp[`${type}Changed`])
|
||||||
|
.map((type) => {
|
||||||
|
return (
|
||||||
|
<div className={ styles.section } key={ `${type}Update` }>
|
||||||
|
<div className={ styles.heading }>
|
||||||
|
Updates to { type } hash
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>{ this.dappsStore.wipApp[`${type}Hash`] || '(removed)' }</div>
|
||||||
|
<div className={ styles.hint }>
|
||||||
|
{ this.dappsStore.wipApp[`${type}Url`] || 'current url to be removed from registry' }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepWait (waitingFor) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={ styles.section }>
|
||||||
|
{ waitingFor }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickClose = () => {
|
||||||
|
this.modalStore.hideUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickYes = () => {
|
||||||
|
this.modalStore.doUpdate();
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/SelectAccount/index.js
Normal file
17
js/src/dapps/dappreg/SelectAccount/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 './selectAccount';
|
49
js/src/dapps/dappreg/SelectAccount/selectAccount.js
Normal file
49
js/src/dapps/dappreg/SelectAccount/selectAccount.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import DappsStore from '../dappsStore';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class SelectAccount extends Component {
|
||||||
|
dappsStore = DappsStore.instance();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
value={ this.dappsStore.currentAccount.address }
|
||||||
|
onChange={ this.onSelect }>
|
||||||
|
{ this.renderOptions() }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderOptions () {
|
||||||
|
return this.dappsStore.accounts.map((account) => {
|
||||||
|
return (
|
||||||
|
<option value={ account.address } key={ account.address }>
|
||||||
|
{ account.name }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect = (event) => {
|
||||||
|
this.dappsStore.setCurrentAccount(event.target.value);
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/SelectDapp/index.js
Normal file
17
js/src/dapps/dappreg/SelectDapp/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 './selectDapp';
|
76
js/src/dapps/dappreg/SelectDapp/selectDapp.js
Normal file
76
js/src/dapps/dappreg/SelectDapp/selectDapp.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import DappsStore from '../dappsStore';
|
||||||
|
|
||||||
|
import Input from '../Input';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class SelectDapp extends Component {
|
||||||
|
dappsStore = DappsStore.instance();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (this.dappsStore.isNew) {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
hint='...'
|
||||||
|
label='Application Id, the unique assigned identifier'>
|
||||||
|
<input value={ this.dappsStore.wipApp.id } readOnly />
|
||||||
|
</Input>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let overlayImg = null;
|
||||||
|
if (this.dappsStore.currentApp.imageHash) {
|
||||||
|
overlayImg = (
|
||||||
|
<img src={ `/api/content/${this.dappsStore.currentApp.imageHash.substr(2)}` } />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
hint={ this.dappsStore.currentApp.id }
|
||||||
|
label='Application, the actual application details to show below'
|
||||||
|
overlay={ overlayImg }>
|
||||||
|
<select
|
||||||
|
disabled={ this.dappsStore.isEditing }
|
||||||
|
value={ this.dappsStore.currentApp.id }
|
||||||
|
onChange={ this.onSelect }>
|
||||||
|
{ this.renderOptions() }
|
||||||
|
</select>
|
||||||
|
</Input>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderOptions () {
|
||||||
|
return this.dappsStore.apps.map((app) => {
|
||||||
|
return (
|
||||||
|
<option
|
||||||
|
value={ app.id }
|
||||||
|
key={ app.id }>
|
||||||
|
{ app.name }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect = (event) => {
|
||||||
|
this.dappsStore.setCurrentApp(event.target.value);
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/dappreg/Warning/index.js
Normal file
17
js/src/dapps/dappreg/Warning/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 './warning';
|
36
js/src/dapps/dappreg/Warning/warning.css
Normal file
36
js/src/dapps/dappreg/Warning/warning.css
Normal file
@ -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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
background: #f44;
|
||||||
|
border-top-right-radius: 0.25em;
|
||||||
|
bottom: 0;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.75em;
|
||||||
|
left: 0;
|
||||||
|
line-height: 1.5em;
|
||||||
|
opacity: 1;
|
||||||
|
padding: 1.5em;
|
||||||
|
position: fixed;
|
||||||
|
max-width: 540px;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
div+div {
|
||||||
|
margin-top: 1.5em;
|
||||||
|
}
|
||||||
|
}
|
51
js/src/dapps/dappreg/Warning/warning.js
Normal file
51
js/src/dapps/dappreg/Warning/warning.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
|
||||||
|
import { api } from '../parity';
|
||||||
|
import DappsStore from '../dappsStore';
|
||||||
|
import ModalStore from '../modalStore';
|
||||||
|
|
||||||
|
import styles from './warning.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Warning extends Component {
|
||||||
|
dappsStore = DappsStore.instance();
|
||||||
|
modalStore = ModalStore.instance();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (!this.modalStore.showingWarning) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.warning } onClick={ this.onClose }>
|
||||||
|
<div>
|
||||||
|
WARNING: Registering a dapp is for developers only. Please ensure you understand the steps needed to develop and deploy applications, should you wish to use this dapp for anything apart from queries.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
A non-refundable fee of { api.util.fromWei(this.dappsStore.fee).toFormat(3) }<small>ETH</small> is required for any registration.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose = () => {
|
||||||
|
this.modalStore.hideWarning();
|
||||||
|
}
|
||||||
|
}
|
482
js/src/dapps/dappreg/dappsStore.js
Normal file
482
js/src/dapps/dappreg/dappsStore.js
Normal file
@ -0,0 +1,482 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import BigNumber from 'bignumber.js';
|
||||||
|
import { action, computed, observable, transaction } from 'mobx';
|
||||||
|
|
||||||
|
import * as abis from '../../contracts/abi';
|
||||||
|
import builtins from '../../views/Dapps/builtin.json';
|
||||||
|
|
||||||
|
import { api } from './parity';
|
||||||
|
|
||||||
|
let instance = null;
|
||||||
|
|
||||||
|
export default class DappsStore {
|
||||||
|
@observable accounts = [];
|
||||||
|
@observable addresses = [];
|
||||||
|
@observable apps = [];
|
||||||
|
@observable contractOwner = null;
|
||||||
|
@observable currentAccount = null;
|
||||||
|
@observable currentApp = null;
|
||||||
|
@observable count = 0;
|
||||||
|
@observable fee = new BigNumber(0);
|
||||||
|
@observable isContractOwner = false;
|
||||||
|
@observable isEditing = false;
|
||||||
|
@observable isLoading = true;
|
||||||
|
@observable isNew = false;
|
||||||
|
@observable wipApp = null;
|
||||||
|
|
||||||
|
_startTime = Date.now();
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
this._loadDapps();
|
||||||
|
}
|
||||||
|
|
||||||
|
static instance () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new DappsStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get canSave () {
|
||||||
|
const app = this.wipApp;
|
||||||
|
|
||||||
|
const hasError = app.contentError || app.imageError || app.manifestError;
|
||||||
|
const isDirty = this.isNew || app.contentChanged || app.imageChanged || app.manifestChanged;
|
||||||
|
const isEditMode = this.isEditing || this.isNew;
|
||||||
|
|
||||||
|
return isEditMode && isDirty && !hasError;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get isCurrentEditable () {
|
||||||
|
return !!this.accounts.find((account) => account.address === this.currentApp.owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get ownedCount () {
|
||||||
|
return (this.apps.filter((app) => app.isOwner) || []).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action copyToWip = () => {
|
||||||
|
let wipApp;
|
||||||
|
|
||||||
|
if (this.isNew) {
|
||||||
|
wipApp = {
|
||||||
|
id: api.util.sha3(`${this._startTime}_${Date.now()}`),
|
||||||
|
contentHash: null,
|
||||||
|
contentUrl: null,
|
||||||
|
imageHash: null,
|
||||||
|
imageUrl: null,
|
||||||
|
manifestHash: null,
|
||||||
|
manifestUrl: null
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const app = this.currentApp;
|
||||||
|
|
||||||
|
wipApp = {
|
||||||
|
id: app.id,
|
||||||
|
contentHash: app.contentHash,
|
||||||
|
contentUrl: app.contentUrl,
|
||||||
|
imageHash: app.imageHash,
|
||||||
|
imageUrl: app.imageUrl,
|
||||||
|
manifestHash: app.manifestHash,
|
||||||
|
manifestUrl: app.manifestUrl,
|
||||||
|
owner: app.owner,
|
||||||
|
ownerName: app.ownerName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.wipApp = Object.assign(wipApp, {
|
||||||
|
contentChanged: false,
|
||||||
|
contentError: null,
|
||||||
|
imageChanged: false,
|
||||||
|
imageError: null,
|
||||||
|
manifestChanged: false,
|
||||||
|
manifestError: null
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.wipApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action editWip = (details) => {
|
||||||
|
if (this.isNew || this.isEditing) {
|
||||||
|
transaction(() => {
|
||||||
|
Object
|
||||||
|
.keys(details)
|
||||||
|
.forEach((key) => {
|
||||||
|
this.wipApp[key] = details[key];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.wipApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action sortApps = (apps = this.apps) => {
|
||||||
|
transaction(() => {
|
||||||
|
const ownApps = apps
|
||||||
|
.filter((app) => app.isOwner)
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
const otherApps = apps
|
||||||
|
.filter((app) => !app.isOwner)
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
|
this.apps = ownApps.concat(otherApps);
|
||||||
|
this.currentApp = this.apps[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setApps = (apps) => {
|
||||||
|
this.sortApps(apps.filter((app) => {
|
||||||
|
const bnid = new BigNumber(app.id);
|
||||||
|
return bnid.gt(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
return this.apps;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action _addApp = (app) => {
|
||||||
|
transaction(() => {
|
||||||
|
this.setApps(this.apps.concat([app]));
|
||||||
|
this.setCurrentApp(app.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action addApp = (appId, account) => {
|
||||||
|
this
|
||||||
|
._loadDapp({
|
||||||
|
id: appId,
|
||||||
|
isOwner: true,
|
||||||
|
name: `- ${appId}`,
|
||||||
|
owner: account.address,
|
||||||
|
ownerName: account.name
|
||||||
|
})
|
||||||
|
.then(this._addApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action refreshApp = (appId) => {
|
||||||
|
this._loadDapp(this.apps.find((app) => app.id === appId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@action removeApp = (appId) => {
|
||||||
|
this.setApps(this.apps.filter((app) => app.id !== appId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setAppInfo = (app, info) => {
|
||||||
|
transaction(() => {
|
||||||
|
Object.keys(info).forEach((key) => {
|
||||||
|
app[key] = info[key];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setAccounts = (accountsInfo) => {
|
||||||
|
transaction(() => {
|
||||||
|
this.addresses = Object
|
||||||
|
.keys(accountsInfo)
|
||||||
|
.map((address) => {
|
||||||
|
const account = accountsInfo[address];
|
||||||
|
account.address = address;
|
||||||
|
return account;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.accounts = this.addresses.filter((account) => account.uuid);
|
||||||
|
this.currentAccount = this.accounts[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setContractOwner = (contractOwner) => {
|
||||||
|
transaction(() => {
|
||||||
|
this.contractOwner = contractOwner;
|
||||||
|
this.isContractOwner = !!this.accounts.find((account) => account.address === contractOwner);
|
||||||
|
});
|
||||||
|
return contractOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setCurrentApp = (id) => {
|
||||||
|
this.currentApp = this.apps.find((app) => app.id === id);
|
||||||
|
return this.currentApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setCurrentAccount = (address) => {
|
||||||
|
this.currentAccount = this.accounts.find((account) => account.address === address);
|
||||||
|
return this.currentAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setCount = (count) => {
|
||||||
|
this.count = count;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setEditing = (mode) => {
|
||||||
|
transaction(() => {
|
||||||
|
this.isEditing = mode;
|
||||||
|
this.copyToWip();
|
||||||
|
});
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setFee = (fee) => {
|
||||||
|
this.fee = fee;
|
||||||
|
return fee;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setLoading = (loading) => {
|
||||||
|
this.isLoading = loading;
|
||||||
|
return loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setNew = (mode) => {
|
||||||
|
transaction(() => {
|
||||||
|
this.isNew = mode;
|
||||||
|
this.copyToWip();
|
||||||
|
});
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
lookupHash (hash) {
|
||||||
|
return this._retrieveUrl(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getCount () {
|
||||||
|
return this._instanceReg
|
||||||
|
.count.call()
|
||||||
|
.then((count) => {
|
||||||
|
this.setCount(count.toNumber());
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:getCount', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_getFee () {
|
||||||
|
return this._instanceReg
|
||||||
|
.fee.call()
|
||||||
|
.then(this.setFee)
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:getFee', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_getOwner () {
|
||||||
|
return this._instanceReg
|
||||||
|
.owner.call()
|
||||||
|
.then(this.setContractOwner)
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:getOwner', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadDapps () {
|
||||||
|
return this._loadRegistry()
|
||||||
|
.then(() => Promise.all([
|
||||||
|
this._attachContracts(),
|
||||||
|
this._loadAccounts()
|
||||||
|
]))
|
||||||
|
.then(() => Promise.all([
|
||||||
|
this._getCount(),
|
||||||
|
this._getFee(),
|
||||||
|
this._getOwner()
|
||||||
|
]))
|
||||||
|
.then(() => {
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
for (let index = 0; index < this.count; index++) {
|
||||||
|
promises.push(this._instanceReg.at.call({}, [index]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
|
})
|
||||||
|
.then((appsInfo) => {
|
||||||
|
return Promise.all(
|
||||||
|
this
|
||||||
|
.setApps(appsInfo.map(([appId, owner]) => {
|
||||||
|
const isOwner = !!this.accounts.find((account) => account.address === owner);
|
||||||
|
const account = this.addresses.find((account) => account.address === owner);
|
||||||
|
const id = api.util.bytesToHex(appId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
owner,
|
||||||
|
ownerName: account ? account.name : owner,
|
||||||
|
isOwner,
|
||||||
|
name: `- ${id}`
|
||||||
|
};
|
||||||
|
}))
|
||||||
|
.map(this._loadDapp)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.sortApps();
|
||||||
|
this.setLoading(this.count === 0);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:loadDapps', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadDapp = (app) => {
|
||||||
|
return Promise
|
||||||
|
.all([
|
||||||
|
this._loadMeta(app.id, 'CONTENT'),
|
||||||
|
this._loadMeta(app.id, 'IMG'),
|
||||||
|
this._loadMeta(app.id, 'MANIFEST')
|
||||||
|
])
|
||||||
|
.then(([contentHash, imageHash, manifestHash]) => {
|
||||||
|
return Promise
|
||||||
|
.all([
|
||||||
|
this._retrieveUrl(contentHash),
|
||||||
|
this._retrieveUrl(imageHash),
|
||||||
|
this._retrieveUrl(manifestHash)
|
||||||
|
])
|
||||||
|
.then(([contentUrl, imageUrl, manifestUrl]) => {
|
||||||
|
return this
|
||||||
|
._loadManifest(app.id, manifestHash)
|
||||||
|
.then((manifest) => {
|
||||||
|
this.setAppInfo(app, {
|
||||||
|
manifest,
|
||||||
|
manifestHash,
|
||||||
|
manifestUrl,
|
||||||
|
contentHash,
|
||||||
|
contentUrl,
|
||||||
|
imageHash,
|
||||||
|
imageUrl,
|
||||||
|
name: (manifest && manifest.name) || `- ${app.id}`
|
||||||
|
});
|
||||||
|
|
||||||
|
return app;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:loadDapp', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadMeta (appId, key) {
|
||||||
|
return this._instanceReg
|
||||||
|
.meta.call({}, [appId, key])
|
||||||
|
.then((meta) => {
|
||||||
|
const hash = api.util.bytesToHex(meta);
|
||||||
|
const bnhash = new BigNumber(hash);
|
||||||
|
|
||||||
|
return bnhash.gt(0)
|
||||||
|
? hash
|
||||||
|
: null;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:loadMeta', error);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadManifest (appId, manifestHash) {
|
||||||
|
const builtin = builtins.find((app) => app.id === appId);
|
||||||
|
|
||||||
|
if (builtin) {
|
||||||
|
return Promise.resolve(builtin);
|
||||||
|
} else if (!manifestHash) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(`/api/content/${manifestHash.substr(2)}/`, { redirect: 'follow', mode: 'cors' })
|
||||||
|
.then((response) => {
|
||||||
|
return response.ok
|
||||||
|
? response.json()
|
||||||
|
: null;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:loadManifest', error);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_retrieveUrl (urlHash) {
|
||||||
|
if (!urlHash) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._instanceGhh
|
||||||
|
.entries.call({}, [urlHash])
|
||||||
|
.then(([repo, _commit, owner]) => {
|
||||||
|
const bnowner = new BigNumber(owner);
|
||||||
|
|
||||||
|
if (bnowner.eq(0)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const commit = api.util.bytesToHex(_commit);
|
||||||
|
const bncommit = new BigNumber(commit);
|
||||||
|
|
||||||
|
if (bncommit.eq(0)) {
|
||||||
|
return repo;
|
||||||
|
} else {
|
||||||
|
return `https://codeload.github.com/${repo}/zip/${commit.substr(2)}`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:retriveUrl', error);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadAccounts () {
|
||||||
|
return api.parity
|
||||||
|
.accounts()
|
||||||
|
.then(this.setAccounts)
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:loadAccounts', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadRegistry () {
|
||||||
|
return api.parity
|
||||||
|
.registryAddress()
|
||||||
|
.then((registryAddress) => {
|
||||||
|
console.log(`the registry was found at ${registryAddress}`);
|
||||||
|
this._registry = api.newContract(abis.registry, registryAddress).instance;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:loadRegistry', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_attachContracts () {
|
||||||
|
return Promise
|
||||||
|
.all([
|
||||||
|
this._registry.getAddress.call({}, [api.util.sha3('dappreg'), 'A']),
|
||||||
|
this._registry.getAddress.call({}, [api.util.sha3('githubhint'), 'A'])
|
||||||
|
])
|
||||||
|
.then(([dappregAddress, ghhAddress]) => {
|
||||||
|
console.log(`dappreg was found at ${dappregAddress}`);
|
||||||
|
this._contractReg = api.newContract(abis.dappreg, dappregAddress);
|
||||||
|
this._instanceReg = this._contractReg.instance;
|
||||||
|
console.log(`githubhint was found at ${ghhAddress}`);
|
||||||
|
this._contractGhh = api.newContract(abis.githubhint, ghhAddress);
|
||||||
|
this._instanceGhh = this._contractGhh.instance;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Store:attachContract', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
266
js/src/dapps/dappreg/modalStore.js
Normal file
266
js/src/dapps/dappreg/modalStore.js
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { action, observable, transaction } from 'mobx';
|
||||||
|
|
||||||
|
import { trackRequest } from './parity';
|
||||||
|
import DappsStore from './dappsStore';
|
||||||
|
|
||||||
|
let instance = null;
|
||||||
|
|
||||||
|
export default class ModalStore {
|
||||||
|
@observable errorDelete = null;
|
||||||
|
@observable errorRegister = null;
|
||||||
|
@observable errorUpdate = null;
|
||||||
|
@observable stepDelete = 0;
|
||||||
|
@observable stepRegister = 0;
|
||||||
|
@observable stepUpdate = 0;
|
||||||
|
@observable showingDelete = false;
|
||||||
|
@observable showingRegister = false;
|
||||||
|
@observable showingUpdate = false;
|
||||||
|
@observable showingWarning = true;
|
||||||
|
|
||||||
|
_dappsStore = DappsStore.instance();
|
||||||
|
|
||||||
|
static instance () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new ModalStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setDeleteError (error) {
|
||||||
|
transaction(() => {
|
||||||
|
this.setDeleteStep(0);
|
||||||
|
this.errorDelete = error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setDeleteStep (step) {
|
||||||
|
this.stepDelete = step;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action showDelete () {
|
||||||
|
transaction(() => {
|
||||||
|
this.setDeleteStep(1);
|
||||||
|
this.errorDelete = null;
|
||||||
|
this.showingDelete = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action hideDelete () {
|
||||||
|
this.showingDelete = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setRegisterError (error) {
|
||||||
|
transaction(() => {
|
||||||
|
this.setRegisterStep(0);
|
||||||
|
this.errorRegister = error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setRegisterStep (step) {
|
||||||
|
this.stepRegister = step;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action showRegister () {
|
||||||
|
transaction(() => {
|
||||||
|
this.setRegisterStep(1);
|
||||||
|
this.errorRegister = null;
|
||||||
|
this.showingRegister = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action hideRegister () {
|
||||||
|
transaction(() => {
|
||||||
|
this._dappsStore.setEditing(false);
|
||||||
|
this._dappsStore.setNew(false);
|
||||||
|
this.showingRegister = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setUpdateError (error) {
|
||||||
|
transaction(() => {
|
||||||
|
this.setUpdateStep(0);
|
||||||
|
this.errorUpdate = error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setUpdateStep (step) {
|
||||||
|
this.stepUpdate = step;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action showUpdate () {
|
||||||
|
transaction(() => {
|
||||||
|
this.setUpdateStep(1);
|
||||||
|
this.errorUpdate = null;
|
||||||
|
this.showingUpdate = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action hideUpdate () {
|
||||||
|
transaction(() => {
|
||||||
|
this._dappsStore.setEditing(false);
|
||||||
|
this._dappsStore.setNew(false);
|
||||||
|
this.showingUpdate = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action hideWarning () {
|
||||||
|
this.showingWarning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
doDelete () {
|
||||||
|
this.setDeleteStep(2);
|
||||||
|
|
||||||
|
const appId = this._dappsStore.currentApp.id;
|
||||||
|
const values = [appId];
|
||||||
|
const options = {
|
||||||
|
from: this._dappsStore.currentApp.isOwner ? this._dappsStore.currentApp.owner : this._dappsStore.contractOwner
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('ModalStore:doDelete', `performing deletion for ${appId} from ${options.from}`);
|
||||||
|
|
||||||
|
this._dappsStore._instanceReg
|
||||||
|
.unregister.estimateGas(options, values)
|
||||||
|
.then((gas) => {
|
||||||
|
const newGas = gas.mul(1.2);
|
||||||
|
|
||||||
|
console.log('ModalStore:doDelete', `gas estimated as ${gas.toFormat(0)}, setting to ${newGas.toFormat(0)}`);
|
||||||
|
|
||||||
|
options.gas = newGas.toFixed(0);
|
||||||
|
|
||||||
|
const request = this._dappsStore._instanceReg.unregister.postTransaction(options, values);
|
||||||
|
const statusCallback = (error, status) => {
|
||||||
|
if (error) {
|
||||||
|
} else if (status.signerRequestId) {
|
||||||
|
} else if (status.transactionHash) {
|
||||||
|
this.setDeleteStep(3);
|
||||||
|
} else if (status.transactionReceipt) {
|
||||||
|
this.setDeleteStep(4);
|
||||||
|
this._dappsStore.removeApp(appId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return trackRequest(request, statusCallback);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('ModalStore:doDelete', error);
|
||||||
|
this.setDeleteError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
doRegister () {
|
||||||
|
this.setRegisterStep(2);
|
||||||
|
|
||||||
|
const appId = this._dappsStore.wipApp.id;
|
||||||
|
const values = [appId];
|
||||||
|
const options = {
|
||||||
|
from: this._dappsStore.currentAccount.address,
|
||||||
|
value: this._dappsStore.fee
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('ModalStore:doRegister', `performing registration for ${appId} from ${this._dappsStore.currentAccount.address}`);
|
||||||
|
|
||||||
|
this._dappsStore._instanceReg
|
||||||
|
.register.estimateGas(options, values)
|
||||||
|
.then((gas) => {
|
||||||
|
const newGas = gas.mul(1.2);
|
||||||
|
|
||||||
|
console.log('ModalStore:doRegister', `gas estimated as ${gas.toFormat(0)}, setting to ${newGas.toFormat(0)}`);
|
||||||
|
|
||||||
|
options.gas = newGas.toFixed(0);
|
||||||
|
|
||||||
|
const request = this._dappsStore._instanceReg.register.postTransaction(options, values);
|
||||||
|
const statusCallback = (error, status) => {
|
||||||
|
if (error) {
|
||||||
|
} else if (status.signerRequestId) {
|
||||||
|
} else if (status.transactionHash) {
|
||||||
|
this.setRegisterStep(3);
|
||||||
|
} else if (status.transactionReceipt) {
|
||||||
|
this.setRegisterStep(4);
|
||||||
|
this._dappsStore.addApp(appId, this._dappsStore.currentAccount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return trackRequest(request, statusCallback);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('ModalStore:doRegister', error);
|
||||||
|
this.setRegisterError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
doUpdate () {
|
||||||
|
this.setUpdateStep(2);
|
||||||
|
|
||||||
|
const appId = this._dappsStore.wipApp.id;
|
||||||
|
const options = {
|
||||||
|
from: this._dappsStore.wipApp.owner
|
||||||
|
};
|
||||||
|
const types = {
|
||||||
|
'content': 'CONTENT',
|
||||||
|
'image': 'IMG',
|
||||||
|
'manifest': 'MANIFEST'
|
||||||
|
};
|
||||||
|
const values = Object
|
||||||
|
.keys(types)
|
||||||
|
.filter((type) => this._dappsStore.wipApp[`${type}Changed`])
|
||||||
|
.map((type) => {
|
||||||
|
return [appId, types[type], this._dappsStore.wipApp[`${type}Hash`] || '0x0'];
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('ModalStore:doUpdate', `performing updates for ${appId} from ${options.from}`);
|
||||||
|
|
||||||
|
Promise
|
||||||
|
.all(values.map((value) => this._dappsStore._instanceReg.setMeta.estimateGas(options, value)))
|
||||||
|
.then((gas) => {
|
||||||
|
const newGas = gas.map((gas) => gas.mul(1.2));
|
||||||
|
|
||||||
|
gas.forEach((gas, index) => {
|
||||||
|
console.log('ModalStore:doUpdate', `${values[index][1]} gas estimated as ${gas.toFormat(0)}, setting to ${newGas[index].toFormat(0)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const statusCallback = (error, status) => {
|
||||||
|
if (error) {
|
||||||
|
} else if (status.signerRequestId) {
|
||||||
|
} else if (status.transactionHash) {
|
||||||
|
this.setUpdateStep(3);
|
||||||
|
} else if (status.transactionReceipt) {
|
||||||
|
this.setUpdateStep(4);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Promise.all(
|
||||||
|
newGas.map((gas, index) => {
|
||||||
|
return trackRequest(
|
||||||
|
this._dappsStore._instanceReg.setMeta.postTransaction(
|
||||||
|
Object.assign(options, { gas: gas.toFixed(0) }), values[index]
|
||||||
|
), statusCallback
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this._dappsStore.refreshApp(appId);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('ModalStore:doUpdate', error);
|
||||||
|
this.setUpdateError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
53
js/src/dapps/dappreg/parity.js
Normal file
53
js/src/dapps/dappreg/parity.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const { api } = window.parity;
|
||||||
|
|
||||||
|
function trackRequest (requestPromise, statusCallback) {
|
||||||
|
return requestPromise
|
||||||
|
.then((signerRequestId) => {
|
||||||
|
console.log('trackRequest', `posted to signer with requestId ${signerRequestId.toString()}`);
|
||||||
|
statusCallback(null, { signerRequestId });
|
||||||
|
|
||||||
|
return api.pollMethod('parity_checkRequest', signerRequestId);
|
||||||
|
})
|
||||||
|
.then((transactionHash) => {
|
||||||
|
console.log('trackRequest', `received transaction hash ${transactionHash}`);
|
||||||
|
statusCallback(null, { transactionHash });
|
||||||
|
|
||||||
|
return api.pollMethod('eth_getTransactionReceipt', transactionHash, (receipt) => {
|
||||||
|
if (!receipt || !receipt.blockNumber || receipt.blockNumber.eq(0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then((transactionReceipt) => {
|
||||||
|
console.log('trackRequest', 'received transaction receipt', transactionReceipt);
|
||||||
|
statusCallback(null, { transactionReceipt });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('trackRequest', error);
|
||||||
|
statusCallback(error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
api,
|
||||||
|
trackRequest
|
||||||
|
};
|
@ -46,6 +46,12 @@ import './index.html';
|
|||||||
|
|
||||||
injectTapEventPlugin();
|
injectTapEventPlugin();
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
// Expose the React Performance Tools on the`window` object
|
||||||
|
const Perf = require('react-addons-perf');
|
||||||
|
window.Perf = Perf;
|
||||||
|
}
|
||||||
|
|
||||||
const AUTH_HASH = '#/auth?';
|
const AUTH_HASH = '#/auth?';
|
||||||
const parityUrl = process.env.PARITY_URL ||
|
const parityUrl = process.env.PARITY_URL ||
|
||||||
(
|
(
|
||||||
|
@ -36,6 +36,7 @@ export default class DetailsStep extends Component {
|
|||||||
onFuncChange: PropTypes.func,
|
onFuncChange: PropTypes.func,
|
||||||
values: PropTypes.array.isRequired,
|
values: PropTypes.array.isRequired,
|
||||||
valuesError: PropTypes.array.isRequired,
|
valuesError: PropTypes.array.isRequired,
|
||||||
|
warning: PropTypes.string,
|
||||||
onValueChange: PropTypes.func.isRequired
|
onValueChange: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +45,7 @@ export default class DetailsStep extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Form>
|
<Form>
|
||||||
|
{ this.renderWarning() }
|
||||||
<AddressSelect
|
<AddressSelect
|
||||||
label='from account'
|
label='from account'
|
||||||
hint='the account to transact with'
|
hint='the account to transact with'
|
||||||
@ -178,6 +180,20 @@ export default class DetailsStep extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderWarning () {
|
||||||
|
const { warning } = this.props;
|
||||||
|
|
||||||
|
if (!warning) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.warning }>
|
||||||
|
{ warning }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
onFuncChange = (event, index, signature) => {
|
onFuncChange = (event, index, signature) => {
|
||||||
const { contract, onFuncChange } = this.props;
|
const { contract, onFuncChange } = this.props;
|
||||||
|
|
||||||
|
@ -33,3 +33,12 @@
|
|||||||
.txhash {
|
.txhash {
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
border-radius: 0.5em;
|
||||||
|
background: #f80;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.75em;
|
||||||
|
padding: 0.75em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
@ -15,17 +15,21 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
||||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||||
|
|
||||||
import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '../../ui';
|
import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '../../ui';
|
||||||
|
import { MAX_GAS_ESTIMATION } from '../../util/constants';
|
||||||
import { validateAddress, validateUint } from '../../util/validation';
|
import { validateAddress, validateUint } from '../../util/validation';
|
||||||
|
|
||||||
import DetailsStep from './DetailsStep';
|
import DetailsStep from './DetailsStep';
|
||||||
|
|
||||||
|
import ERRORS from '../Transfer/errors';
|
||||||
import { ERROR_CODES } from '../../api/transport/error';
|
import { ERROR_CODES } from '../../api/transport/error';
|
||||||
|
|
||||||
export default class ExecuteContract extends Component {
|
class ExecuteContract extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
api: PropTypes.object.isRequired,
|
api: PropTypes.object.isRequired,
|
||||||
store: PropTypes.object.isRequired
|
store: PropTypes.object.isRequired
|
||||||
@ -36,6 +40,7 @@ export default class ExecuteContract extends Component {
|
|||||||
fromAddress: PropTypes.string,
|
fromAddress: PropTypes.string,
|
||||||
accounts: PropTypes.object,
|
accounts: PropTypes.object,
|
||||||
contract: PropTypes.object,
|
contract: PropTypes.object,
|
||||||
|
gasLimit: PropTypes.object.isRequired,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
onFromAddressChange: PropTypes.func.isRequired
|
onFromAddressChange: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
@ -46,6 +51,8 @@ export default class ExecuteContract extends Component {
|
|||||||
fromAddressError: null,
|
fromAddressError: null,
|
||||||
func: null,
|
func: null,
|
||||||
funcError: null,
|
funcError: null,
|
||||||
|
gas: null,
|
||||||
|
gasLimitError: null,
|
||||||
values: [],
|
values: [],
|
||||||
valuesError: [],
|
valuesError: [],
|
||||||
step: 0,
|
step: 0,
|
||||||
@ -64,6 +71,12 @@ export default class ExecuteContract extends Component {
|
|||||||
this.onFuncChange(null, functions[0]);
|
this.onFuncChange(null, functions[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (newProps) {
|
||||||
|
if (newProps.fromAddress !== this.props.fromAddress) {
|
||||||
|
this.estimateGas(newProps.fromAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { sending } = this.state;
|
const { sending } = this.state;
|
||||||
|
|
||||||
@ -119,7 +132,7 @@ export default class ExecuteContract extends Component {
|
|||||||
|
|
||||||
renderStep () {
|
renderStep () {
|
||||||
const { onFromAddressChange } = this.props;
|
const { onFromAddressChange } = this.props;
|
||||||
const { step, busyState, txhash, rejected } = this.state;
|
const { step, busyState, gasLimitError, txhash, rejected } = this.state;
|
||||||
|
|
||||||
if (rejected) {
|
if (rejected) {
|
||||||
return (
|
return (
|
||||||
@ -135,6 +148,7 @@ export default class ExecuteContract extends Component {
|
|||||||
<DetailsStep
|
<DetailsStep
|
||||||
{ ...this.props }
|
{ ...this.props }
|
||||||
{ ...this.state }
|
{ ...this.state }
|
||||||
|
warning={ gasLimitError }
|
||||||
onAmountChange={ this.onAmountChange }
|
onAmountChange={ this.onAmountChange }
|
||||||
onFromAddressChange={ onFromAddressChange }
|
onFromAddressChange={ onFromAddressChange }
|
||||||
onFuncChange={ this.onFuncChange }
|
onFuncChange={ this.onFuncChange }
|
||||||
@ -156,7 +170,7 @@ export default class ExecuteContract extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onAmountChange = (amount) => {
|
onAmountChange = (amount) => {
|
||||||
this.setState({ amount });
|
this.setState({ amount }, this.estimateGas);
|
||||||
}
|
}
|
||||||
|
|
||||||
onFuncChange = (event, func) => {
|
onFuncChange = (event, func) => {
|
||||||
@ -182,7 +196,7 @@ export default class ExecuteContract extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
func,
|
func,
|
||||||
values
|
values
|
||||||
});
|
}, this.estimateGas);
|
||||||
}
|
}
|
||||||
|
|
||||||
onValueChange = (event, index, _value) => {
|
onValueChange = (event, index, _value) => {
|
||||||
@ -211,6 +225,46 @@ export default class ExecuteContract extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
values: [].concat(values),
|
values: [].concat(values),
|
||||||
valuesError: [].concat(valuesError)
|
valuesError: [].concat(valuesError)
|
||||||
|
}, () => {
|
||||||
|
if (!valueError) {
|
||||||
|
this.estimateGas();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
estimateGas = (_fromAddress) => {
|
||||||
|
const { api } = this.context;
|
||||||
|
const { fromAddress, gasLimit } = this.props;
|
||||||
|
const { amount, func, values } = this.state;
|
||||||
|
const options = {
|
||||||
|
gas: MAX_GAS_ESTIMATION,
|
||||||
|
from: _fromAddress || fromAddress,
|
||||||
|
value: api.util.toWei(amount || 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!func) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
.estimateGas(options, values)
|
||||||
|
.then((gasEst) => {
|
||||||
|
const gas = gasEst.mul(1.2);
|
||||||
|
let gasLimitError = null;
|
||||||
|
|
||||||
|
if (gas.gte(MAX_GAS_ESTIMATION)) {
|
||||||
|
gasLimitError = ERRORS.gasException;
|
||||||
|
} else if (gas.gt(gasLimit)) {
|
||||||
|
gasLimitError = ERRORS.gasBlockLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
gas,
|
||||||
|
gasLimitError
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn('estimateGas', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +273,7 @@ export default class ExecuteContract extends Component {
|
|||||||
const { fromAddress } = this.props;
|
const { fromAddress } = this.props;
|
||||||
const { amount, func, values } = this.state;
|
const { amount, func, values } = this.state;
|
||||||
const options = {
|
const options = {
|
||||||
|
gas: MAX_GAS_ESTIMATION,
|
||||||
from: fromAddress,
|
from: fromAddress,
|
||||||
value: api.util.toWei(amount || 0)
|
value: api.util.toWei(amount || 0)
|
||||||
};
|
};
|
||||||
@ -237,13 +292,13 @@ export default class ExecuteContract extends Component {
|
|||||||
|
|
||||||
return api
|
return api
|
||||||
.pollMethod('parity_checkRequest', requestId)
|
.pollMethod('parity_checkRequest', requestId)
|
||||||
.catch((e) => {
|
.catch((error) => {
|
||||||
if (e.code === ERROR_CODES.REQUEST_REJECTED) {
|
if (error.code === ERROR_CODES.REQUEST_REJECTED) {
|
||||||
this.setState({ rejected: true });
|
this.setState({ rejected: true });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e;
|
throw error;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then((txhash) => {
|
.then((txhash) => {
|
||||||
@ -255,3 +310,18 @@ export default class ExecuteContract extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
const { gasLimit } = state.nodeStatus;
|
||||||
|
|
||||||
|
return { gasLimit };
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps (dispatch) {
|
||||||
|
return bindActionCreators({}, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(ExecuteContract);
|
||||||
|
@ -19,7 +19,9 @@ const ERRORS = {
|
|||||||
invalidAddress: 'the supplied address is an invalid network address',
|
invalidAddress: 'the supplied address is an invalid network address',
|
||||||
invalidAmount: 'the supplied amount should be a valid positive number',
|
invalidAmount: 'the supplied amount should be a valid positive number',
|
||||||
invalidDecimals: 'the supplied amount exceeds the allowed decimals',
|
invalidDecimals: 'the supplied amount exceeds the allowed decimals',
|
||||||
largeAmount: 'the transaction total is higher than the available balance'
|
largeAmount: 'the transaction total is higher than the available balance',
|
||||||
|
gasException: 'the transaction will throw an exception with the current values',
|
||||||
|
gasBlockLimit: 'the transaction execution will exceed the block gas limit'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ERRORS;
|
export default ERRORS;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
line-height: 1.618em;
|
line-height: 1.618em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -151,3 +152,13 @@
|
|||||||
.gasPriceDesc {
|
.gasPriceDesc {
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
border-radius: 0.5em;
|
||||||
|
background: #f80;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.75em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding: 0.75em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
@ -16,12 +16,15 @@
|
|||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
||||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||||
import NavigationArrowBack from 'material-ui/svg-icons/navigation/arrow-back';
|
import NavigationArrowBack from 'material-ui/svg-icons/navigation/arrow-back';
|
||||||
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
|
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
|
||||||
|
|
||||||
import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '../../ui';
|
import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '../../ui';
|
||||||
|
import { DEFAULT_GAS, DEFAULT_GASPRICE, MAX_GAS_ESTIMATION } from '../../util/constants';
|
||||||
|
|
||||||
import Details from './Details';
|
import Details from './Details';
|
||||||
import Extras from './Extras';
|
import Extras from './Extras';
|
||||||
@ -30,8 +33,6 @@ import styles from './transfer.css';
|
|||||||
|
|
||||||
import { ERROR_CODES } from '../../api/transport/error';
|
import { ERROR_CODES } from '../../api/transport/error';
|
||||||
|
|
||||||
const DEFAULT_GAS = '21000';
|
|
||||||
const DEFAULT_GASPRICE = '20000000000';
|
|
||||||
const TITLES = {
|
const TITLES = {
|
||||||
transfer: 'transfer details',
|
transfer: 'transfer details',
|
||||||
sending: 'sending',
|
sending: 'sending',
|
||||||
@ -42,7 +43,7 @@ const TITLES = {
|
|||||||
const STAGES_BASIC = [TITLES.transfer, TITLES.sending, TITLES.complete];
|
const STAGES_BASIC = [TITLES.transfer, TITLES.sending, TITLES.complete];
|
||||||
const STAGES_EXTRA = [TITLES.transfer, TITLES.extras, TITLES.sending, TITLES.complete];
|
const STAGES_EXTRA = [TITLES.transfer, TITLES.extras, TITLES.sending, TITLES.complete];
|
||||||
|
|
||||||
export default class Transfer extends Component {
|
class Transfer extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
api: PropTypes.object.isRequired,
|
api: PropTypes.object.isRequired,
|
||||||
store: PropTypes.object.isRequired
|
store: PropTypes.object.isRequired
|
||||||
@ -52,6 +53,7 @@ export default class Transfer extends Component {
|
|||||||
account: PropTypes.object,
|
account: PropTypes.object,
|
||||||
balance: PropTypes.object,
|
balance: PropTypes.object,
|
||||||
balances: PropTypes.object,
|
balances: PropTypes.object,
|
||||||
|
gasLimit: PropTypes.object.isRequired,
|
||||||
images: PropTypes.object.isRequired,
|
images: PropTypes.object.isRequired,
|
||||||
onClose: PropTypes.func
|
onClose: PropTypes.func
|
||||||
}
|
}
|
||||||
@ -64,6 +66,7 @@ export default class Transfer extends Component {
|
|||||||
gas: DEFAULT_GAS,
|
gas: DEFAULT_GAS,
|
||||||
gasEst: '0',
|
gasEst: '0',
|
||||||
gasError: null,
|
gasError: null,
|
||||||
|
gasLimitError: null,
|
||||||
gasPrice: DEFAULT_GASPRICE,
|
gasPrice: DEFAULT_GASPRICE,
|
||||||
gasPriceHistogram: {},
|
gasPriceHistogram: {},
|
||||||
gasPriceError: null,
|
gasPriceError: null,
|
||||||
@ -103,6 +106,7 @@ export default class Transfer extends Component {
|
|||||||
visible
|
visible
|
||||||
scroll
|
scroll
|
||||||
>
|
>
|
||||||
|
{ this.renderWarning() }
|
||||||
{ this.renderPage() }
|
{ this.renderPage() }
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
@ -264,6 +268,20 @@ export default class Transfer extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderWarning () {
|
||||||
|
const { gasLimitError } = this.state;
|
||||||
|
|
||||||
|
if (!gasLimitError) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.warning }>
|
||||||
|
{ gasLimitError }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
isValid () {
|
isValid () {
|
||||||
const detailsValid = !this.state.recipientError && !this.state.valueError && !this.state.totalError;
|
const detailsValid = !this.state.recipientError && !this.state.valueError && !this.state.totalError;
|
||||||
const extrasValid = !this.state.gasError && !this.state.gasPriceError && !this.state.totalError;
|
const extrasValid = !this.state.gasError && !this.state.gasPriceError && !this.state.totalError;
|
||||||
@ -519,6 +537,7 @@ export default class Transfer extends Component {
|
|||||||
|
|
||||||
return token.contract.instance.transfer
|
return token.contract.instance.transfer
|
||||||
.estimateGas({
|
.estimateGas({
|
||||||
|
gas: MAX_GAS_ESTIMATION,
|
||||||
from: account.address,
|
from: account.address,
|
||||||
to: token.address
|
to: token.address
|
||||||
}, [
|
}, [
|
||||||
@ -532,6 +551,7 @@ export default class Transfer extends Component {
|
|||||||
const { account } = this.props;
|
const { account } = this.props;
|
||||||
const { data, recipient, value } = this.state;
|
const { data, recipient, value } = this.state;
|
||||||
const options = {
|
const options = {
|
||||||
|
gas: MAX_GAS_ESTIMATION,
|
||||||
from: account.address,
|
from: account.address,
|
||||||
to: recipient,
|
to: recipient,
|
||||||
value: api.util.toWei(value || 0)
|
value: api.util.toWei(value || 0)
|
||||||
@ -552,19 +572,29 @@ export default class Transfer extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { gasLimit } = this.props;
|
||||||
|
|
||||||
(this.state.isEth
|
(this.state.isEth
|
||||||
? this._estimateGasEth()
|
? this._estimateGasEth()
|
||||||
: this._estimateGasToken()
|
: this._estimateGasToken()
|
||||||
).then((_value) => {
|
).then((gasEst) => {
|
||||||
let gas = _value;
|
let gas = gasEst;
|
||||||
|
let gasLimitError = null;
|
||||||
|
|
||||||
if (gas.gt(DEFAULT_GAS)) {
|
if (gas.gt(DEFAULT_GAS)) {
|
||||||
gas = gas.mul(1.2);
|
gas = gas.mul(1.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gas.gte(MAX_GAS_ESTIMATION)) {
|
||||||
|
gasLimitError = ERRORS.gasException;
|
||||||
|
} else if (gas.gt(gasLimit)) {
|
||||||
|
gasLimitError = ERRORS.gasBlockLimit;
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
gas: gas.toFixed(0),
|
gas: gas.toFixed(0),
|
||||||
gasEst: _value.toFormat()
|
gasEst: gasEst.toFormat(),
|
||||||
|
gasLimitError
|
||||||
}, this.recalculate);
|
}, this.recalculate);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -649,3 +679,18 @@ export default class Transfer extends Component {
|
|||||||
store.dispatch({ type: 'newError', error });
|
store.dispatch({ type: 'newError', error });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
const { gasLimit } = state.nodeStatus;
|
||||||
|
|
||||||
|
return { gasLimit };
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps (dispatch) {
|
||||||
|
return bindActionCreators({}, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(Transfer);
|
||||||
|
@ -16,26 +16,17 @@
|
|||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
|
|
||||||
class ParityBackground extends Component {
|
class ParityBackground extends Component {
|
||||||
static contextTypes = {
|
|
||||||
muiTheme: PropTypes.object.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
style: PropTypes.object.isRequired,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
gradient: PropTypes.string,
|
|
||||||
seed: PropTypes.any,
|
|
||||||
settings: PropTypes.object.isRequired,
|
|
||||||
onClick: PropTypes.func
|
onClick: PropTypes.func
|
||||||
}
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { muiTheme } = this.context;
|
const { children, className, style, onClick } = this.props;
|
||||||
const { children, className, gradient, seed, settings, onClick } = this.props;
|
|
||||||
const style = muiTheme.parity.getBackgroundStyle(gradient, seed || settings.backgroundSeed);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -48,17 +39,29 @@ class ParityBackground extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (_, initProps) {
|
||||||
const { settings } = state;
|
const { gradient, seed, muiTheme } = initProps;
|
||||||
|
|
||||||
return { settings };
|
let _seed = seed;
|
||||||
|
let _props = { style: muiTheme.parity.getBackgroundStyle(gradient, seed) };
|
||||||
|
|
||||||
|
return (state, props) => {
|
||||||
|
const { backgroundSeed } = state.settings;
|
||||||
|
const { seed } = props;
|
||||||
|
|
||||||
|
const newSeed = seed || backgroundSeed;
|
||||||
|
|
||||||
|
if (newSeed === _seed) {
|
||||||
|
return _props;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
_seed = newSeed;
|
||||||
return bindActionCreators({}, dispatch);
|
_props = { style: muiTheme.parity.getBackgroundStyle(gradient, newSeed) };
|
||||||
|
|
||||||
|
return _props;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps
|
||||||
mapDispatchToProps
|
|
||||||
)(ParityBackground);
|
)(ParityBackground);
|
||||||
|
26
js/src/util/constants.js
Normal file
26
js/src/util/constants.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const DEFAULT_GAS = '21000';
|
||||||
|
const DEFAULT_GASPRICE = '20000000000';
|
||||||
|
|
||||||
|
const MAX_GAS_ESTIMATION = '50000000';
|
||||||
|
|
||||||
|
export {
|
||||||
|
DEFAULT_GAS,
|
||||||
|
DEFAULT_GASPRICE,
|
||||||
|
MAX_GAS_ESTIMATION
|
||||||
|
};
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
import { isEqual } from 'lodash';
|
||||||
|
|
||||||
import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName, Tags, Input } from '../../../ui';
|
import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName, Tags, Input } from '../../../ui';
|
||||||
|
|
||||||
@ -30,7 +31,6 @@ export default class Summary extends Component {
|
|||||||
link: PropTypes.string,
|
link: PropTypes.string,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
noLink: PropTypes.bool,
|
noLink: PropTypes.bool,
|
||||||
children: PropTypes.node,
|
|
||||||
handleAddSearchToken: PropTypes.func
|
handleAddSearchToken: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,8 +42,42 @@ export default class Summary extends Component {
|
|||||||
name: 'Unnamed'
|
name: 'Unnamed'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
shouldComponentUpdate (nextProps) {
|
||||||
|
const prev = {
|
||||||
|
link: this.props.link, name: this.props.name,
|
||||||
|
noLink: this.props.noLink,
|
||||||
|
meta: this.props.account.meta, address: this.props.account.address
|
||||||
|
};
|
||||||
|
|
||||||
|
const next = {
|
||||||
|
link: nextProps.link, name: nextProps.name,
|
||||||
|
noLink: nextProps.noLink,
|
||||||
|
meta: nextProps.account.meta, address: nextProps.account.address
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isEqual(next, prev)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prevTokens = this.props.balance.tokens || [];
|
||||||
|
const nextTokens = nextProps.balance.tokens || [];
|
||||||
|
|
||||||
|
if (prevTokens.length !== nextTokens.length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prevValues = prevTokens.map((t) => t.value.toNumber());
|
||||||
|
const nextValues = nextTokens.map((t) => t.value.toNumber());
|
||||||
|
|
||||||
|
if (!isEqual(prevValues, nextValues)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { account, children, handleAddSearchToken } = this.props;
|
const { account, handleAddSearchToken } = this.props;
|
||||||
const { tags } = account.meta;
|
const { tags } = account.meta;
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
@ -71,7 +105,6 @@ export default class Summary extends Component {
|
|||||||
byline={ addressComponent } />
|
byline={ addressComponent } />
|
||||||
|
|
||||||
{ this.renderBalance() }
|
{ this.renderBalance() }
|
||||||
{ children }
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -30,3 +30,25 @@
|
|||||||
right: 1em;
|
right: 1em;
|
||||||
top: 4em;
|
top: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loadings {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
flex: 0 1 50%;
|
||||||
|
width: 50%;
|
||||||
|
height: 150px;
|
||||||
|
display: flex;
|
||||||
|
padding: 0.25em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -42,17 +42,48 @@ class Accounts extends Component {
|
|||||||
newDialog: false,
|
newDialog: false,
|
||||||
sortOrder: '',
|
sortOrder: '',
|
||||||
searchValues: [],
|
searchValues: [],
|
||||||
searchTokens: []
|
searchTokens: [],
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
window.setTimeout(() => {
|
||||||
|
this.setState({ show: true });
|
||||||
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { accounts, hasAccounts, balances } = this.props;
|
|
||||||
const { searchValues, sortOrder } = this.state;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.accounts }>
|
<div className={ styles.accounts }>
|
||||||
{ this.renderNewDialog() }
|
{ this.renderNewDialog() }
|
||||||
{ this.renderActionbar() }
|
{ this.renderActionbar() }
|
||||||
|
|
||||||
|
{ this.state.show ? this.renderAccounts() : this.renderLoading() }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLoading () {
|
||||||
|
const { accounts } = this.props;
|
||||||
|
|
||||||
|
const loadings = ((accounts && Object.keys(accounts)) || []).map((_, idx) => (
|
||||||
|
<div key={ idx } className={ styles.loading }>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.loadings }>
|
||||||
|
{ loadings }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAccounts () {
|
||||||
|
const { accounts, hasAccounts, balances } = this.props;
|
||||||
|
const { searchValues, sortOrder } = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<List
|
<List
|
||||||
search={ searchValues }
|
search={ searchValues }
|
||||||
@ -65,7 +96,6 @@ class Accounts extends Component {
|
|||||||
className={ styles.accountTooltip }
|
className={ styles.accountTooltip }
|
||||||
text='your accounts are visible for easy access, allowing you to edit the meta information, make transfers, view transactions and fund the account' />
|
text='your accounts are visible for easy access, allowing you to edit the meta information, make transfers, view transactions and fund the account' />
|
||||||
</Page>
|
</Page>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,10 @@ import { Errors, ParityBackground, Tooltips } from '../../../ui';
|
|||||||
import styles from '../application.css';
|
import styles from '../application.css';
|
||||||
|
|
||||||
export default class Container extends Component {
|
export default class Container extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
muiTheme: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.node.isRequired,
|
children: PropTypes.node.isRequired,
|
||||||
showFirstRun: PropTypes.bool,
|
showFirstRun: PropTypes.bool,
|
||||||
@ -30,9 +34,10 @@ export default class Container extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { children, showFirstRun, onCloseFirstRun } = this.props;
|
const { children, showFirstRun, onCloseFirstRun } = this.props;
|
||||||
|
const { muiTheme } = this.context;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ParityBackground className={ styles.container }>
|
<ParityBackground className={ styles.container } muiTheme={ muiTheme }>
|
||||||
<FirstRun
|
<FirstRun
|
||||||
visible={ showFirstRun }
|
visible={ showFirstRun }
|
||||||
onClose={ onCloseFirstRun } />
|
onClose={ onCloseFirstRun } />
|
||||||
|
@ -23,6 +23,11 @@
|
|||||||
.tabs {
|
.tabs {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs button,
|
.tabs button,
|
||||||
@ -38,6 +43,7 @@
|
|||||||
|
|
||||||
button.tabactive,
|
button.tabactive,
|
||||||
button.tabactive:hover {
|
button.tabactive:hover {
|
||||||
|
color: white !important;
|
||||||
background: rgba(0, 0, 0, 0.25) !important;
|
background: rgba(0, 0, 0, 0.25) !important;
|
||||||
border-radius: 4px 4px 0 0;
|
border-radius: 4px 4px 0 0;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
||||||
import { Tabs, Tab } from 'material-ui/Tabs';
|
import { Tab as MUITab } from 'material-ui/Tabs';
|
||||||
|
|
||||||
import { Badge, Tooltip } from '../../../ui';
|
import { Badge, Tooltip } from '../../../ui';
|
||||||
|
|
||||||
@ -33,20 +33,138 @@ const TABMAP = {
|
|||||||
deploy: 'contract'
|
deploy: 'contract'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Tab extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
active: PropTypes.bool,
|
||||||
|
view: PropTypes.object,
|
||||||
|
children: PropTypes.node,
|
||||||
|
pendings: PropTypes.number,
|
||||||
|
onChange: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
shouldComponentUpdate (nextProps) {
|
||||||
|
return nextProps.active !== this.props.active ||
|
||||||
|
(nextProps.view.id === 'signer' && nextProps.pendings !== this.props.pendings);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { active, view, children } = this.props;
|
||||||
|
|
||||||
|
const label = this.getLabel(view);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MUITab
|
||||||
|
className={ active ? styles.tabactive : '' }
|
||||||
|
selected={ active }
|
||||||
|
icon={ view.icon }
|
||||||
|
label={ label }
|
||||||
|
onClick={ this.handleClick }
|
||||||
|
>
|
||||||
|
{ children }
|
||||||
|
</MUITab>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLabel (view) {
|
||||||
|
const { label } = view;
|
||||||
|
|
||||||
|
if (view.id === 'signer') {
|
||||||
|
return this.renderSignerLabel(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view.id === 'status') {
|
||||||
|
return this.renderStatusLabel(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.renderLabel(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLabel (name, bubble) {
|
||||||
|
return (
|
||||||
|
<div className={ styles.label }>
|
||||||
|
{ name }
|
||||||
|
{ bubble }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSignerLabel (label) {
|
||||||
|
const { pendings } = this.props;
|
||||||
|
|
||||||
|
if (pendings) {
|
||||||
|
const bubble = (
|
||||||
|
<Badge
|
||||||
|
color='red'
|
||||||
|
className={ styles.labelBubble }
|
||||||
|
value={ pendings } />
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.renderLabel(label, bubble);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.renderLabel(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStatusLabel (label) {
|
||||||
|
// const { isTest, netChain } = this.props;
|
||||||
|
// const bubble = (
|
||||||
|
// <Badge
|
||||||
|
// color={ isTest ? 'red' : 'default' }
|
||||||
|
// className={ styles.labelBubble }
|
||||||
|
// value={ isTest ? 'TEST' : netChain } />
|
||||||
|
// );
|
||||||
|
|
||||||
|
return this.renderLabel(label, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick = () => {
|
||||||
|
const { onChange, view } = this.props;
|
||||||
|
onChange(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TabBar extends Component {
|
class TabBar extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
router: PropTypes.object.isRequired
|
router: PropTypes.object.isRequired
|
||||||
}
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
views: PropTypes.array.isRequired,
|
||||||
|
hash: PropTypes.string.isRequired,
|
||||||
pending: PropTypes.array,
|
pending: PropTypes.array,
|
||||||
isTest: PropTypes.bool,
|
isTest: PropTypes.bool,
|
||||||
netChain: PropTypes.string,
|
netChain: PropTypes.string
|
||||||
settings: PropTypes.object.isRequired
|
};
|
||||||
}
|
|
||||||
|
static defaultProps = {
|
||||||
|
pending: []
|
||||||
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
activeRoute: '/accounts'
|
activeViewId: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
setActiveView (props = this.props) {
|
||||||
|
const { hash, views } = props;
|
||||||
|
const view = views.find((view) => view.value === hash);
|
||||||
|
|
||||||
|
this.setState({ activeViewId: view.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
this.setActiveView();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
if (nextProps.hash !== this.props.hash) {
|
||||||
|
this.setActiveView(nextProps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate (nextProps, nextState) {
|
||||||
|
return (nextProps.hash !== this.props.hash) ||
|
||||||
|
(nextProps.pending.length !== this.props.pending.length) ||
|
||||||
|
(nextState.activeViewId !== this.state.activeViewId);
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
@ -81,100 +199,64 @@ class TabBar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderTabs () {
|
renderTabs () {
|
||||||
const { settings } = this.props;
|
const { views, pending } = this.props;
|
||||||
const windowHash = (window.location.hash || '').split('?')[0].split('/')[1];
|
const { activeViewId } = this.state;
|
||||||
const hash = TABMAP[windowHash] || windowHash;
|
|
||||||
|
|
||||||
const items = Object.keys(settings.views)
|
const items = views
|
||||||
.filter((id) => settings.views[id].fixed || settings.views[id].active)
|
.map((view, index) => {
|
||||||
.map((id) => {
|
const body = (view.id === 'accounts')
|
||||||
const view = settings.views[id];
|
? (
|
||||||
let label = this.renderLabel(view.label);
|
|
||||||
let body = null;
|
|
||||||
|
|
||||||
if (id === 'accounts') {
|
|
||||||
body = (
|
|
||||||
<Tooltip className={ styles.tabbarTooltip } text='navigate between the different parts and views of the application, switching between an account view, token view and distributed application view' />
|
<Tooltip className={ styles.tabbarTooltip } text='navigate between the different parts and views of the application, switching between an account view, token view and distributed application view' />
|
||||||
);
|
)
|
||||||
} else if (id === 'signer') {
|
: null;
|
||||||
label = this.renderSignerLabel(label);
|
|
||||||
} else if (id === 'status') {
|
const active = activeViewId === view.id;
|
||||||
label = this.renderStatusLabel(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tab
|
<Tab
|
||||||
className={ hash === view.value ? styles.tabactive : '' }
|
active={ active }
|
||||||
value={ view.value }
|
view={ view }
|
||||||
icon={ view.icon }
|
onChange={ this.onChange }
|
||||||
key={ id }
|
key={ index }
|
||||||
label={ label }
|
pendings={ pending.length }
|
||||||
onActive={ this.onActivate(view.route) }>
|
>
|
||||||
{ body }
|
{ body }
|
||||||
</Tab>
|
</Tab>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<div
|
||||||
className={ styles.tabs }
|
className={ styles.tabs }
|
||||||
value={ hash }>
|
onChange={ this.onChange }>
|
||||||
{ items }
|
{ items }
|
||||||
</Tabs>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderLabel = (name, bubble) => {
|
|
||||||
return (
|
|
||||||
<div className={ styles.label }>
|
|
||||||
{ name }
|
|
||||||
{ bubble }
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSignerLabel = (label) => {
|
onChange = (view) => {
|
||||||
const { pending } = this.props;
|
|
||||||
let bubble = null;
|
|
||||||
|
|
||||||
if (pending && pending.length) {
|
|
||||||
bubble = (
|
|
||||||
<Badge
|
|
||||||
color='red'
|
|
||||||
className={ styles.labelBubble }
|
|
||||||
value={ pending.length } />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.renderLabel(label, bubble);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderStatusLabel = (label) => {
|
|
||||||
// const { isTest, netChain } = this.props;
|
|
||||||
// const bubble = (
|
|
||||||
// <Badge
|
|
||||||
// color={ isTest ? 'red' : 'default' }
|
|
||||||
// className={ styles.labelBubble }
|
|
||||||
// value={ isTest ? 'TEST' : netChain } />
|
|
||||||
// );
|
|
||||||
|
|
||||||
return this.renderLabel(label, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
onActivate = (activeRoute) => {
|
|
||||||
const { router } = this.context;
|
const { router } = this.context;
|
||||||
|
|
||||||
return (event) => {
|
router.push(view.route);
|
||||||
router.push(activeRoute);
|
this.setState({ activeViewId: view.id });
|
||||||
this.setState({ activeRoute });
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const { settings } = state;
|
const { views } = state.settings;
|
||||||
|
|
||||||
return { settings };
|
const filteredViews = Object
|
||||||
|
.keys(views)
|
||||||
|
.filter((id) => views[id].fixed || views[id].active)
|
||||||
|
.map((id) => ({
|
||||||
|
...views[id],
|
||||||
|
id
|
||||||
|
}));
|
||||||
|
|
||||||
|
const windowHash = (window.location.hash || '').split('?')[0].split('/')[1];
|
||||||
|
const hash = TABMAP[windowHash] || windowHash;
|
||||||
|
|
||||||
|
return { views: filteredViews, hash };
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
function mapDispatchToProps (dispatch) {
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
"description": "Have a peak on internals of transaction queue of your node.",
|
"description": "Have a peak on internals of transaction queue of your node.",
|
||||||
"author": "Parity Team <admin@ethcore.io>",
|
"author": "Parity Team <admin@ethcore.io>",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"visible": true,
|
||||||
"secure": true
|
"secure": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -28,6 +28,10 @@ import imagesEthcoreBlock from '../../../assets/images/parity-logo-white-no-text
|
|||||||
import styles from './parityBar.css';
|
import styles from './parityBar.css';
|
||||||
|
|
||||||
class ParityBar extends Component {
|
class ParityBar extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
muiTheme: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
pending: PropTypes.array,
|
pending: PropTypes.array,
|
||||||
dapp: PropTypes.bool
|
dapp: PropTypes.bool
|
||||||
@ -62,6 +66,7 @@ class ParityBar extends Component {
|
|||||||
|
|
||||||
renderBar () {
|
renderBar () {
|
||||||
const { dapp } = this.props;
|
const { dapp } = this.props;
|
||||||
|
const { muiTheme } = this.context;
|
||||||
|
|
||||||
if (!dapp) {
|
if (!dapp) {
|
||||||
return null;
|
return null;
|
||||||
@ -75,7 +80,7 @@ class ParityBar extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.bar }>
|
<div className={ styles.bar }>
|
||||||
<ParityBackground className={ styles.corner }>
|
<ParityBackground className={ styles.corner } muiTheme={ muiTheme }>
|
||||||
<div className={ styles.cornercolor }>
|
<div className={ styles.cornercolor }>
|
||||||
<Link to='/apps'>
|
<Link to='/apps'>
|
||||||
<Button
|
<Button
|
||||||
@ -95,9 +100,11 @@ class ParityBar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderExpanded () {
|
renderExpanded () {
|
||||||
|
const { muiTheme } = this.context;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.overlay }>
|
<div className={ styles.overlay }>
|
||||||
<ParityBackground className={ styles.expanded }>
|
<ParityBackground className={ styles.expanded } muiTheme={ muiTheme }>
|
||||||
<div className={ styles.header }>
|
<div className={ styles.header }>
|
||||||
<div className={ styles.title }>
|
<div className={ styles.title }>
|
||||||
<ContainerTitle title='Parity Signer: Pending' />
|
<ContainerTitle title='Parity Signer: Pending' />
|
||||||
|
@ -81,6 +81,7 @@ class Background extends Component {
|
|||||||
renderBackgrounds () {
|
renderBackgrounds () {
|
||||||
const { settings } = this.props;
|
const { settings } = this.props;
|
||||||
const { seeds } = this.state;
|
const { seeds } = this.state;
|
||||||
|
const { muiTheme } = this.context;
|
||||||
|
|
||||||
return seeds.map((seed, index) => {
|
return seeds.map((seed, index) => {
|
||||||
return (
|
return (
|
||||||
@ -89,7 +90,9 @@ class Background extends Component {
|
|||||||
<ParityBackground
|
<ParityBackground
|
||||||
className={ settings.backgroundSeed === seed ? styles.seedactive : styles.seed }
|
className={ settings.backgroundSeed === seed ? styles.seedactive : styles.seed }
|
||||||
seed={ seed }
|
seed={ seed }
|
||||||
onClick={ this.onSelect(seed) } />
|
onClick={ this.onSelect(seed) }
|
||||||
|
muiTheme={ muiTheme }
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -37,6 +37,7 @@ module.exports = {
|
|||||||
entry: {
|
entry: {
|
||||||
// dapps
|
// dapps
|
||||||
'basiccoin': ['./dapps/basiccoin.js'],
|
'basiccoin': ['./dapps/basiccoin.js'],
|
||||||
|
'dappreg': ['./dapps/dappreg.js'],
|
||||||
'githubhint': ['./dapps/githubhint.js'],
|
'githubhint': ['./dapps/githubhint.js'],
|
||||||
'registry': ['./dapps/registry.js'],
|
'registry': ['./dapps/registry.js'],
|
||||||
'signaturereg': ['./dapps/signaturereg.js'],
|
'signaturereg': ['./dapps/signaturereg.js'],
|
||||||
|
Loading…
Reference in New Issue
Block a user