Merge branch 'master' into delete-accounts
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "parity.js",
|
||||
"version": "0.2.56",
|
||||
"version": "0.2.62",
|
||||
"main": "release/index.js",
|
||||
"jsnext:main": "src/index.js",
|
||||
"author": "Parity Team <admin@parity.io>",
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { stringify } from 'querystring';
|
||||
import React from 'react';
|
||||
|
||||
export default (
|
||||
export const termsOfService = (
|
||||
<ul>
|
||||
<li>This privacy notice relates to your use of the Parity SMS verification service. We take your privacy seriously and deal in an honest, direct and transparent way when it comes to your data.</li>
|
||||
<li>We collect your phone number when you use this service. This is temporarily kept in memory, and then encrypted and stored in our EU servers. We only retain the cryptographic hash of the number to prevent duplicated accounts. You consent to this use.</li>
|
||||
@@ -25,3 +26,18 @@ export default (
|
||||
<li><i>Parity Technology Limited</i> is registered in England and Wales under company number <code>09760015</code> and complies with the Data Protection Act 1998 (UK). You may contact us via email at <a href={ 'mailto:admin@parity.io' }>admin@parity.io</a>. Our general privacy policy can be found here: <a href={ 'https://ethcore.io/legal.html' }>https://ethcore.io/legal.html</a>.</li>
|
||||
</ul>
|
||||
);
|
||||
|
||||
export const postToServer = (query) => {
|
||||
query = stringify(query);
|
||||
return fetch('https://sms-verification.parity.io/?' + query, {
|
||||
method: 'POST', mode: 'cors', cache: 'no-store'
|
||||
})
|
||||
.then((res) => {
|
||||
return res.json().then((data) => {
|
||||
if (res.ok) {
|
||||
return data.message;
|
||||
}
|
||||
throw new Error(data.message || 'unknown error');
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -14,8 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { stringify } from 'querystring';
|
||||
|
||||
export const checkIfVerified = (contract, account) => {
|
||||
return contract.instance.certified.call({}, [account]);
|
||||
};
|
||||
@@ -35,18 +33,3 @@ export const checkIfRequested = (contract, account) => {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const postToServer = (query) => {
|
||||
query = stringify(query);
|
||||
return fetch('https://sms-verification.parity.io/?' + query, {
|
||||
method: 'POST', mode: 'cors', cache: 'no-store'
|
||||
})
|
||||
.then((res) => {
|
||||
return res.json().then((data) => {
|
||||
if (res.ok) {
|
||||
return data.message;
|
||||
}
|
||||
throw new Error(data.message || 'unknown error');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -105,7 +105,7 @@ export function attachInstances () {
|
||||
])
|
||||
.then(([registryAddress, netChain]) => {
|
||||
const registry = api.newContract(abis.registry, registryAddress).instance;
|
||||
isTest = netChain === 'morden' || netChain === 'testnet';
|
||||
isTest = ['morden', 'ropsten', 'testnet'].includes(netChain);
|
||||
|
||||
console.log(`contract was found at registry=${registryAddress}`);
|
||||
console.log(`running on ${netChain}, isTest=${isTest}`);
|
||||
|
||||
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
|
||||
};
|
||||
@@ -77,7 +77,7 @@ export default class Lookup extends Component {
|
||||
label='Lookup'
|
||||
primary
|
||||
icon={ <SearchIcon /> }
|
||||
onClick={ this.onLookupClick }
|
||||
onTouchTap={ this.onLookupClick }
|
||||
/>
|
||||
</div>
|
||||
<CardText>{ output }</CardText>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { sha3, toWei } from '../parity.js';
|
||||
import { sha3, api } from '../parity.js';
|
||||
|
||||
const alreadyQueued = (queue, action, name) =>
|
||||
!!queue.find((entry) => entry.action === action && entry.name === name);
|
||||
@@ -29,6 +29,8 @@ export const reserve = (name) => (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const account = state.accounts.selected;
|
||||
const contract = state.contract;
|
||||
const fee = state.fee;
|
||||
|
||||
if (!contract || !account) return;
|
||||
if (alreadyQueued(state.names.queue, 'reserve', name)) return;
|
||||
const reserve = contract.functions.find((f) => f.name === 'reserve');
|
||||
@@ -36,19 +38,28 @@ export const reserve = (name) => (dispatch, getState) => {
|
||||
name = name.toLowerCase();
|
||||
const options = {
|
||||
from: account.address,
|
||||
value: toWei(1).toString()
|
||||
value: fee
|
||||
};
|
||||
const values = [ sha3(name) ];
|
||||
|
||||
dispatch(reserveStart(name));
|
||||
|
||||
reserve.estimateGas(options, values)
|
||||
.then((gas) => {
|
||||
options.gas = gas.mul(1.2).toFixed(0);
|
||||
return reserve.postTransaction(options, values);
|
||||
})
|
||||
.then((data) => {
|
||||
.then((requestId) => {
|
||||
return api.pollMethod('parity_checkRequest', requestId);
|
||||
})
|
||||
.then((txhash) => {
|
||||
dispatch(reserveSuccess(name));
|
||||
}).catch((err) => {
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err && err.type === 'REQUEST_REJECTED') {
|
||||
return dispatch(reserveFail(name));
|
||||
}
|
||||
|
||||
console.error(`could not reserve ${name}`);
|
||||
if (err) console.error(err.stack);
|
||||
dispatch(reserveFail(name));
|
||||
@@ -79,9 +90,17 @@ export const drop = (name) => (dispatch, getState) => {
|
||||
options.gas = gas.mul(1.2).toFixed(0);
|
||||
return drop.postTransaction(options, values);
|
||||
})
|
||||
.then((data) => {
|
||||
.then((requestId) => {
|
||||
return api.pollMethod('parity_checkRequest', requestId);
|
||||
})
|
||||
.then((txhash) => {
|
||||
dispatch(dropSuccess(name));
|
||||
}).catch((err) => {
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err && err.type === 'REQUEST_REJECTED') {
|
||||
dispatch(reserveFail(name));
|
||||
}
|
||||
|
||||
console.error(`could not drop ${name}`);
|
||||
if (err) console.error(err.stack);
|
||||
dispatch(reserveFail(name));
|
||||
|
||||
@@ -86,6 +86,22 @@ export default class Names extends Component {
|
||||
name: ''
|
||||
};
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
const nextQueue = nextProps.queue;
|
||||
const prevQueue = this.props.queue;
|
||||
|
||||
if (nextQueue.length > prevQueue.length) {
|
||||
const newQueued = nextQueue[nextQueue.length - 1];
|
||||
const newName = newQueued.name;
|
||||
|
||||
if (newName !== this.state.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ name: '' });
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { action, name } = this.state;
|
||||
const { fee, pending, queue } = this.props;
|
||||
@@ -120,7 +136,7 @@ export default class Names extends Component {
|
||||
label={ action === 'reserve' ? 'Reserve' : 'Drop' }
|
||||
primary
|
||||
icon={ <CheckIcon /> }
|
||||
onClick={ this.onSubmitClick }
|
||||
onTouchTap={ this.onSubmitClick }
|
||||
/>
|
||||
{ queue.length > 0
|
||||
? (<div>{ useSignerText }{ renderQueue(queue) }</div>)
|
||||
|
||||
@@ -52,7 +52,7 @@ export default class Records extends Component {
|
||||
label='Save'
|
||||
primary
|
||||
icon={ <SaveIcon /> }
|
||||
onClick={ this.onSaveClick }
|
||||
onTouchTap={ this.onSaveClick }
|
||||
/>
|
||||
</CardText>
|
||||
</Card>
|
||||
|
||||
@@ -174,7 +174,7 @@ export default class LoadContract extends Component {
|
||||
const secondaryText = description || `Saved ${moment(timestamp).fromNow()}`;
|
||||
const remove = removable
|
||||
? (
|
||||
<IconButton onClick={ onDelete }>
|
||||
<IconButton onTouchTap={ onDelete }>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ import ErrorIcon from 'material-ui/svg-icons/navigation/close';
|
||||
import { fromWei } from '../../../api/util/wei';
|
||||
import { Form, Input } from '../../../ui';
|
||||
|
||||
import terms from '../terms-of-service';
|
||||
import { termsOfService } from '../../../3rdparty/sms-verification';
|
||||
import styles from './gatherData.css';
|
||||
|
||||
export default class GatherData extends Component {
|
||||
@@ -66,7 +66,7 @@ export default class GatherData extends Component {
|
||||
disabled={ isVerified }
|
||||
onCheck={ this.consentOnChange }
|
||||
/>
|
||||
<div className={ styles.terms }>{ terms }</div>
|
||||
<div className={ styles.terms }>{ termsOfService }</div>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
@@ -123,8 +123,7 @@ export default class GatherData extends Component {
|
||||
<p className={ styles.message }>You already requested verification.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (hasRequested === false) {
|
||||
} else if (hasRequested === false) {
|
||||
return (
|
||||
<div className={ styles.container }>
|
||||
<SuccessIcon />
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
|
||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||
import DoneIcon from 'material-ui/svg-icons/action/done-all';
|
||||
import CancelIcon from 'material-ui/svg-icons/content/clear';
|
||||
|
||||
import { Button, IdentityIcon, Modal } from '../../ui';
|
||||
|
||||
@@ -77,7 +77,7 @@ export default class SMSVerification extends Component {
|
||||
const cancel = (
|
||||
<Button
|
||||
key='cancel' label='Cancel'
|
||||
icon={ <ContentClear /> }
|
||||
icon={ <CancelIcon /> }
|
||||
onClick={ onClose }
|
||||
/>
|
||||
);
|
||||
@@ -92,7 +92,7 @@ export default class SMSVerification extends Component {
|
||||
<Button
|
||||
key='done' label='Done'
|
||||
disabled={ !isStepValid }
|
||||
icon={ <ActionDoneAll /> }
|
||||
icon={ <DoneIcon /> }
|
||||
onClick={ onClose }
|
||||
/>
|
||||
</div>
|
||||
@@ -140,37 +140,47 @@ export default class SMSVerification extends Component {
|
||||
setNumber, setConsentGiven, setCode
|
||||
} = this.props.store;
|
||||
|
||||
if (phase === 5) {
|
||||
return (<Done />);
|
||||
}
|
||||
if (phase === 4) {
|
||||
return (<SendConfirmation step={ step } tx={ confirmationTx } />);
|
||||
}
|
||||
if (phase === 3) {
|
||||
return (
|
||||
<QueryCode
|
||||
number={ number } fee={ fee } isCodeValid={ isCodeValid }
|
||||
setCode={ setCode }
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (phase === 2) {
|
||||
return (<SendRequest step={ step } tx={ requestTx } />);
|
||||
}
|
||||
if (phase === 1) {
|
||||
const { setNumber, setConsentGiven } = this.props.store;
|
||||
return (
|
||||
<GatherData
|
||||
fee={ fee } isNumberValid={ isNumberValid }
|
||||
isVerified={ isVerified } hasRequested={ hasRequested }
|
||||
setNumber={ setNumber } setConsentGiven={ setConsentGiven }
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (phase === 0) {
|
||||
return (<p>Preparing awesomeness!</p>);
|
||||
}
|
||||
switch (phase) {
|
||||
case 0:
|
||||
return (
|
||||
<p>Loading SMS Verification.</p>
|
||||
);
|
||||
|
||||
return null;
|
||||
case 1:
|
||||
const { setNumber, setConsentGiven } = this.props.store;
|
||||
return (
|
||||
<GatherData
|
||||
fee={ fee } isNumberValid={ isNumberValid }
|
||||
isVerified={ isVerified } hasRequested={ hasRequested }
|
||||
setNumber={ setNumber } setConsentGiven={ setConsentGiven }
|
||||
/>
|
||||
);
|
||||
|
||||
case 2:
|
||||
return (
|
||||
<SendRequest step={ step } tx={ requestTx } />
|
||||
);
|
||||
|
||||
case 3:
|
||||
return (
|
||||
<QueryCode
|
||||
number={ number } fee={ fee } isCodeValid={ isCodeValid }
|
||||
setCode={ setCode }
|
||||
/>
|
||||
);
|
||||
|
||||
case 4:
|
||||
return (
|
||||
<SendConfirmation step={ step } tx={ confirmationTx } />
|
||||
);
|
||||
|
||||
case 5:
|
||||
return (
|
||||
<Done />
|
||||
);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ import { sha3 } from '../../api/util/sha3';
|
||||
|
||||
import Contracts from '../../contracts';
|
||||
|
||||
import { checkIfVerified, checkIfRequested, postToServer } from '../../contracts/sms-verification';
|
||||
import { checkIfVerified, checkIfRequested } from '../../contracts/sms-verification';
|
||||
import { postToServer } from '../../3rdparty/sms-verification';
|
||||
import checkIfTxFailed from '../../util/check-if-tx-failed';
|
||||
import waitForConfirmations from '../../util/wait-for-block-confirmations';
|
||||
|
||||
@@ -87,7 +88,7 @@ export default class VerificationStore {
|
||||
this.account = account;
|
||||
|
||||
this.step = LOADING;
|
||||
Contracts.create(api).registry.getContract('smsVerification')
|
||||
Contracts.create(api).registry.getContract('smsverification')
|
||||
.then((contract) => {
|
||||
this.contract = contract;
|
||||
this.load();
|
||||
|
||||
@@ -155,24 +155,20 @@ export default class Status {
|
||||
|
||||
const { refreshStatus } = this._store.getState().nodeStatus;
|
||||
|
||||
const statusPromises = [ this._api.eth.syncing() ];
|
||||
const statusPromises = [ this._api.eth.syncing(), this._api.parity.netPeers() ];
|
||||
|
||||
if (refreshStatus) {
|
||||
statusPromises.push(this._api.eth.hashrate());
|
||||
statusPromises.push(this._api.parity.netPeers());
|
||||
}
|
||||
|
||||
Promise
|
||||
.all(statusPromises)
|
||||
.then((statusResults) => {
|
||||
const status = statusResults.length === 1
|
||||
? {
|
||||
syncing: statusResults[0]
|
||||
}
|
||||
.then(([ syncing, netPeers, ...statusResults ]) => {
|
||||
const status = statusResults.length === 0
|
||||
? { syncing, netPeers }
|
||||
: {
|
||||
syncing: statusResults[0],
|
||||
hashrate: statusResults[1],
|
||||
netPeers: statusResults[2]
|
||||
syncing, netPeers,
|
||||
hashrate: statusResults[0]
|
||||
};
|
||||
|
||||
if (!isEqual(status, this._status)) {
|
||||
@@ -251,7 +247,7 @@ export default class Status {
|
||||
.then(([
|
||||
clientVersion, defaultExtraData, netChain, netPort, rpcSettings, enode
|
||||
]) => {
|
||||
const isTest = netChain === 'morden' || netChain === 'testnet';
|
||||
const isTest = netChain === 'morden' || netChain === 'ropsten' || netChain === 'testnet';
|
||||
|
||||
const longStatus = {
|
||||
clientVersion,
|
||||
|
||||
@@ -31,7 +31,7 @@ const initialState = {
|
||||
gasLimit: new BigNumber(0),
|
||||
hashrate: new BigNumber(0),
|
||||
minGasPrice: new BigNumber(0),
|
||||
netChain: 'morden',
|
||||
netChain: 'ropsten',
|
||||
netPeers: {
|
||||
active: new BigNumber(0),
|
||||
connected: new BigNumber(0),
|
||||
|
||||
@@ -96,7 +96,7 @@ export default class TypedInput extends Component {
|
||||
<IconButton
|
||||
iconStyle={ iconStyle }
|
||||
style={ style }
|
||||
onClick={ this.onAddField }
|
||||
onTouchTap={ this.onAddField }
|
||||
>
|
||||
<AddIcon />
|
||||
</IconButton>
|
||||
@@ -104,7 +104,7 @@ export default class TypedInput extends Component {
|
||||
<IconButton
|
||||
iconStyle={ iconStyle }
|
||||
style={ style }
|
||||
onClick={ this.onRemoveField }
|
||||
onTouchTap={ this.onRemoveField }
|
||||
>
|
||||
<RemoveIcon />
|
||||
</IconButton>
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"description": "Have a peak on internals of transaction queue of your node.",
|
||||
"author": "Parity Team <admin@ethcore.io>",
|
||||
"version": "1.0.0",
|
||||
"visible": true,
|
||||
"secure": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -67,7 +67,7 @@ export default class Dapps extends Component {
|
||||
label='edit'
|
||||
key='edit'
|
||||
icon={ <EyeIcon /> }
|
||||
onClick={ this.store.openModal }
|
||||
onTouchTap={ this.store.openModal }
|
||||
/>
|
||||
] }
|
||||
/>
|
||||
|
||||
@@ -25,7 +25,7 @@ export default class Account extends Component {
|
||||
static propTypes = {
|
||||
className: PropTypes.string,
|
||||
address: PropTypes.string.isRequired,
|
||||
chain: PropTypes.string.isRequired,
|
||||
isTest: PropTypes.bool.isRequired,
|
||||
balance: PropTypes.object // eth BigNumber, not required since it mght take time to fetch
|
||||
};
|
||||
|
||||
@@ -51,11 +51,13 @@ export default class Account extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { address, chain, className } = this.props;
|
||||
const { address, isTest, className } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ `${styles.acc} ${className}` }>
|
||||
<AccountLink address={ address } chain={ chain }>
|
||||
<AccountLink
|
||||
address={ address }
|
||||
isTest={ isTest }>
|
||||
<IdentityIcon
|
||||
center
|
||||
address={ address } />
|
||||
@@ -74,19 +76,23 @@ export default class Account extends Component {
|
||||
}
|
||||
|
||||
renderName () {
|
||||
const { address } = this.props;
|
||||
const { address, isTest } = this.props;
|
||||
const name = <IdentityName address={ address } empty />;
|
||||
|
||||
if (!name) {
|
||||
return (
|
||||
<AccountLink address={ address } chain={ this.props.chain }>
|
||||
<AccountLink
|
||||
address={ address }
|
||||
isTest={ isTest }>
|
||||
[{ this.shortAddress(address) }]
|
||||
</AccountLink>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AccountLink address={ address } chain={ this.props.chain } >
|
||||
<AccountLink
|
||||
address={ address }
|
||||
isTest={ isTest } >
|
||||
<span>
|
||||
<span className={ styles.name }>{ name }</span>
|
||||
<span className={ styles.address }>[{ this.tinyAddress(address) }]</span>
|
||||
|
||||
@@ -21,7 +21,7 @@ import styles from './AccountLink.css';
|
||||
|
||||
export default class AccountLink extends Component {
|
||||
static propTypes = {
|
||||
chain: PropTypes.string.isRequired,
|
||||
isTest: PropTypes.bool.isRequired,
|
||||
address: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node
|
||||
@@ -32,15 +32,15 @@ export default class AccountLink extends Component {
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
const { address, chain } = this.props;
|
||||
const { address, isTest } = this.props;
|
||||
|
||||
this.updateLink(address, chain);
|
||||
this.updateLink(address, isTest);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
const { address, chain } = nextProps;
|
||||
const { address, isTest } = nextProps;
|
||||
|
||||
this.updateLink(address, chain);
|
||||
this.updateLink(address, isTest);
|
||||
}
|
||||
|
||||
render () {
|
||||
@@ -56,8 +56,8 @@ export default class AccountLink extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
updateLink (address, chain) {
|
||||
const link = addressLink(address, chain === 'morden' || chain === 'testnet');
|
||||
updateLink (address, isTest) {
|
||||
const link = addressLink(address, isTest);
|
||||
|
||||
this.setState({
|
||||
link
|
||||
|
||||
@@ -31,14 +31,16 @@ export default class RequestFinishedWeb3 extends Component {
|
||||
msg: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
error: PropTypes.string,
|
||||
className: PropTypes.string
|
||||
className: PropTypes.string,
|
||||
isTest: PropTypes.bool.isRequired
|
||||
}
|
||||
|
||||
render () {
|
||||
const { payload, id, result, msg, status, error, date, className } = this.props;
|
||||
const { payload, id, result, msg, status, error, date, className, isTest } = this.props;
|
||||
|
||||
if (payload.sign) {
|
||||
const { sign } = payload;
|
||||
|
||||
return (
|
||||
<SignRequest
|
||||
className={ className }
|
||||
@@ -49,12 +51,14 @@ export default class RequestFinishedWeb3 extends Component {
|
||||
msg={ msg }
|
||||
status={ status }
|
||||
error={ error }
|
||||
isTest={ isTest }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (payload.transaction) {
|
||||
const { transaction } = payload;
|
||||
|
||||
return (
|
||||
<TransactionFinished
|
||||
className={ className }
|
||||
@@ -69,6 +73,7 @@ export default class RequestFinishedWeb3 extends Component {
|
||||
date={ date }
|
||||
status={ status }
|
||||
error={ error }
|
||||
isTest={ isTest }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ export default class RequestPendingWeb3 extends Component {
|
||||
PropTypes.shape({ transaction: PropTypes.object.isRequired }),
|
||||
PropTypes.shape({ sign: PropTypes.object.isRequired })
|
||||
]).isRequired,
|
||||
className: PropTypes.string
|
||||
className: PropTypes.string,
|
||||
isTest: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
onConfirm = data => {
|
||||
@@ -41,10 +42,11 @@ export default class RequestPendingWeb3 extends Component {
|
||||
};
|
||||
|
||||
render () {
|
||||
const { payload, id, className, isSending, date, onReject } = this.props;
|
||||
const { payload, id, className, isSending, date, onReject, isTest } = this.props;
|
||||
|
||||
if (payload.sign) {
|
||||
const { sign } = payload;
|
||||
|
||||
return (
|
||||
<SignRequest
|
||||
className={ className }
|
||||
@@ -55,12 +57,14 @@ export default class RequestPendingWeb3 extends Component {
|
||||
id={ id }
|
||||
address={ sign.address }
|
||||
hash={ sign.hash }
|
||||
isTest={ isTest }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (payload.transaction) {
|
||||
const { transaction } = payload;
|
||||
|
||||
return (
|
||||
<TransactionPending
|
||||
className={ className }
|
||||
@@ -75,6 +79,7 @@ export default class RequestPendingWeb3 extends Component {
|
||||
to={ transaction.to }
|
||||
value={ transaction.value }
|
||||
date={ date }
|
||||
isTest={ isTest }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,24 +39,15 @@ export default class SignRequest extends Component {
|
||||
onReject: PropTypes.func,
|
||||
status: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
chain: nullable(PropTypes.object),
|
||||
isTest: PropTypes.bool.isRequired,
|
||||
balance: nullable(PropTypes.object)
|
||||
};
|
||||
|
||||
state = {
|
||||
chain: null,
|
||||
balance: null
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
this.context.api.parity.netChain()
|
||||
.then((chain) => {
|
||||
this.setState({ chain });
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('could not fetch chain', err);
|
||||
});
|
||||
|
||||
this.context.api.eth.getBalance(this.props.address)
|
||||
.then((balance) => {
|
||||
this.setState({ balance });
|
||||
@@ -68,6 +59,7 @@ export default class SignRequest extends Component {
|
||||
|
||||
render () {
|
||||
const { className } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ `${styles.container} ${className || ''}` }>
|
||||
{ this.renderDetails() }
|
||||
@@ -77,15 +69,20 @@ export default class SignRequest extends Component {
|
||||
}
|
||||
|
||||
renderDetails () {
|
||||
const { address, hash } = this.props;
|
||||
const { balance, chain } = this.state;
|
||||
const { address, hash, isTest } = this.props;
|
||||
const { balance } = this.state;
|
||||
|
||||
if (!balance || !chain) return (<div />);
|
||||
if (!balance) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.signDetails }>
|
||||
<div className={ styles.address }>
|
||||
<Account address={ address } balance={ balance } chain={ chain } />
|
||||
<Account
|
||||
address={ address }
|
||||
balance={ balance }
|
||||
isTest={ isTest } />
|
||||
</div>
|
||||
<div className={ styles.info } title={ hash }>
|
||||
<p>Dapp is requesting to sign arbitrary transaction using this account.</p>
|
||||
@@ -100,15 +97,17 @@ export default class SignRequest extends Component {
|
||||
|
||||
if (isFinished) {
|
||||
if (status === 'confirmed') {
|
||||
const { hash } = this.props;
|
||||
const { chain } = this.state;
|
||||
const { hash, isTest } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ styles.actions }>
|
||||
<span className={ styles.isConfirmed }>Confirmed</span>
|
||||
<div>
|
||||
Transaction hash:
|
||||
<TxHashLink chain={ chain } txHash={ hash } className={ styles.txHash } />
|
||||
<TxHashLink
|
||||
isTest={ isTest }
|
||||
txHash={ hash }
|
||||
className={ styles.txHash } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -47,13 +47,12 @@ export default class TransactionFinished extends Component {
|
||||
txHash: PropTypes.string, // undefined if transacation is rejected
|
||||
className: PropTypes.string,
|
||||
data: PropTypes.string,
|
||||
chain: nullable(PropTypes.object),
|
||||
isTest: PropTypes.bool.isRequired,
|
||||
fromBalance: nullable(PropTypes.object),
|
||||
toBalance: nullable(PropTypes.object)
|
||||
};
|
||||
|
||||
state = {
|
||||
chain: null,
|
||||
fromBalance: null,
|
||||
toBalance: null
|
||||
};
|
||||
@@ -64,14 +63,6 @@ export default class TransactionFinished extends Component {
|
||||
const totalValue = tUtil.getTotalValue(fee, value);
|
||||
this.setState({ totalValue });
|
||||
|
||||
this.context.api.parity.netChain()
|
||||
.then((chain) => {
|
||||
this.setState({ chain });
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('could not fetch chain', err);
|
||||
});
|
||||
|
||||
this.fetchBalance(from, 'fromBalance');
|
||||
if (to) {
|
||||
this.fetchBalance(to, 'toBalance');
|
||||
@@ -79,8 +70,9 @@ export default class TransactionFinished extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { chain, fromBalance, toBalance } = this.state;
|
||||
if (!chain || !fromBalance || !toBalance) {
|
||||
const { fromBalance, toBalance } = this.state;
|
||||
|
||||
if (!fromBalance || !toBalance) {
|
||||
return (
|
||||
<div className={ `${styles.container} ${className}` }>
|
||||
<CircularProgress size={ 60 } />
|
||||
@@ -130,16 +122,19 @@ export default class TransactionFinished extends Component {
|
||||
}
|
||||
|
||||
renderTxHash () {
|
||||
const { txHash } = this.props;
|
||||
const { chain } = this.state;
|
||||
if (!txHash || !chain) {
|
||||
const { txHash, isTest } = this.props;
|
||||
|
||||
if (!txHash) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
Transaction hash:
|
||||
<TxHashLink chain={ chain } txHash={ txHash } className={ styles.txHash } />
|
||||
<TxHashLink
|
||||
isTest={ isTest }
|
||||
txHash={ txHash }
|
||||
className={ styles.txHash } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export default class TransactionMainDetails extends Component {
|
||||
fromBalance: PropTypes.object, // eth BigNumber, not required since it might take time to fetch
|
||||
value: PropTypes.object.isRequired, // wei hex
|
||||
totalValue: PropTypes.object.isRequired, // wei BigNumber
|
||||
chain: PropTypes.string.isRequired,
|
||||
isTest: PropTypes.bool.isRequired,
|
||||
to: PropTypes.string, // undefined if it's a contract
|
||||
toBalance: PropTypes.object, // eth BigNumber - undefined if it's a contract or until it's fetched
|
||||
className: PropTypes.string,
|
||||
@@ -39,11 +39,13 @@ export default class TransactionMainDetails extends Component {
|
||||
|
||||
componentWillMount () {
|
||||
const { value, totalValue } = this.props;
|
||||
|
||||
this.updateDisplayValues(value, totalValue);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
const { value, totalValue } = nextProps;
|
||||
|
||||
this.updateDisplayValues(value, totalValue);
|
||||
}
|
||||
|
||||
@@ -59,6 +61,7 @@ export default class TransactionMainDetails extends Component {
|
||||
|
||||
render () {
|
||||
const { className, children } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ className }>
|
||||
{ this.renderTransfer() }
|
||||
@@ -69,7 +72,8 @@ export default class TransactionMainDetails extends Component {
|
||||
}
|
||||
|
||||
renderTransfer () {
|
||||
const { from, fromBalance, to, toBalance, chain } = this.props;
|
||||
const { from, fromBalance, to, toBalance, isTest } = this.props;
|
||||
|
||||
if (!to) {
|
||||
return;
|
||||
}
|
||||
@@ -78,7 +82,10 @@ export default class TransactionMainDetails extends Component {
|
||||
<div className={ styles.transaction }>
|
||||
<div className={ styles.from }>
|
||||
<div className={ styles.account }>
|
||||
<Account address={ from } balance={ fromBalance } chain={ chain } />
|
||||
<Account
|
||||
address={ from }
|
||||
balance={ fromBalance }
|
||||
isTest={ isTest } />
|
||||
</div>
|
||||
</div>
|
||||
<div className={ styles.tx }>
|
||||
@@ -88,7 +95,10 @@ export default class TransactionMainDetails extends Component {
|
||||
</div>
|
||||
<div className={ styles.to }>
|
||||
<div className={ styles.account }>
|
||||
<Account address={ to } balance={ toBalance } chain={ chain } />
|
||||
<Account
|
||||
address={ to }
|
||||
balance={ toBalance }
|
||||
isTest={ isTest } />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,15 +106,20 @@ export default class TransactionMainDetails extends Component {
|
||||
}
|
||||
|
||||
renderContract () {
|
||||
const { from, fromBalance, to, chain } = this.props;
|
||||
const { from, fromBalance, to, isTest } = this.props;
|
||||
|
||||
if (to) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.transaction }>
|
||||
<div className={ styles.from }>
|
||||
<div className={ styles.account }>
|
||||
<Account address={ from } balance={ fromBalance } chain={ chain } />
|
||||
<Account
|
||||
address={ from }
|
||||
balance={ fromBalance }
|
||||
isTest={ isTest } />
|
||||
</div>
|
||||
</div>
|
||||
<div className={ styles.tx }>
|
||||
@@ -126,6 +141,7 @@ export default class TransactionMainDetails extends Component {
|
||||
renderValue () {
|
||||
const { id } = this.props;
|
||||
const { valueDisplay, valueDisplayWei } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
@@ -147,6 +163,7 @@ export default class TransactionMainDetails extends Component {
|
||||
renderTotalValue () {
|
||||
const { id } = this.props;
|
||||
const { totalValueDisplay, totalValueDisplayWei, feeEth } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
@@ -164,5 +181,4 @@ export default class TransactionMainDetails extends Component {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import CircularProgress from 'material-ui/CircularProgress';
|
||||
import TransactionMainDetails from '../TransactionMainDetails';
|
||||
import TransactionPendingForm from '../TransactionPendingForm';
|
||||
import TransactionSecondaryDetails from '../TransactionSecondaryDetails';
|
||||
@@ -43,7 +42,8 @@ export default class TransactionPending extends Component {
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
onReject: PropTypes.func.isRequired,
|
||||
isSending: PropTypes.bool.isRequired,
|
||||
className: PropTypes.string
|
||||
className: PropTypes.string,
|
||||
isTest: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@@ -51,7 +51,6 @@ export default class TransactionPending extends Component {
|
||||
};
|
||||
|
||||
state = {
|
||||
chain: null,
|
||||
fromBalance: null,
|
||||
toBalance: null
|
||||
};
|
||||
@@ -64,28 +63,12 @@ export default class TransactionPending extends Component {
|
||||
const gasToDisplay = tUtil.getGasDisplay(gas);
|
||||
this.setState({ gasPriceEthmDisplay, totalValue, gasToDisplay });
|
||||
|
||||
this.context.api.parity.netChain()
|
||||
.then((chain) => {
|
||||
this.setState({ chain });
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('could not fetch chain', err);
|
||||
});
|
||||
|
||||
const { from, to } = this.props;
|
||||
this.fetchBalance(from, 'fromBalance');
|
||||
if (to) this.fetchBalance(to, 'toBalance');
|
||||
}
|
||||
|
||||
render () {
|
||||
if (!this.state.chain) {
|
||||
return (
|
||||
<div className={ `${styles.container} ${className}` }>
|
||||
<CircularProgress size={ 60 } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const { totalValue, gasPriceEthmDisplay, gasToDisplay } = this.state;
|
||||
const { className, id, date, data, from } = this.props;
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ class TransactionPendingFormConfirm extends Component {
|
||||
data-effect='solid'
|
||||
>
|
||||
<RaisedButton
|
||||
onClick={ this.onConfirm }
|
||||
onTouchTap={ this.onConfirm }
|
||||
className={ styles.confirmButton }
|
||||
fullWidth
|
||||
primary
|
||||
|
||||
@@ -37,7 +37,7 @@ export default class TransactionPendingFormReject extends Component {
|
||||
<strong>This cannot be undone</strong>
|
||||
</div>
|
||||
<RaisedButton
|
||||
onClick={ onReject }
|
||||
onTouchTap={ onReject }
|
||||
className={ styles.rejectButton }
|
||||
fullWidth
|
||||
label={ 'Reject Transaction' }
|
||||
|
||||
@@ -59,10 +59,13 @@ export default class TransactionSecondaryDetails extends Component {
|
||||
}
|
||||
|
||||
renderGasPrice () {
|
||||
if (!this.props.gasPriceEthmDisplay && !this.props.gasToDisplay) return null;
|
||||
if (!this.props.gasPriceEthmDisplay && !this.props.gasToDisplay) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { id } = this.props;
|
||||
const { gasPriceEthmDisplay, gasToDisplay } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
data-tip
|
||||
@@ -83,11 +86,14 @@ export default class TransactionSecondaryDetails extends Component {
|
||||
}
|
||||
|
||||
renderData () {
|
||||
if (!this.props.data) return null;
|
||||
if (!this.props.data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { data, id } = this.props;
|
||||
let dataToDisplay = this.noData() ? 'no data' : tUtil.getShortData(data);
|
||||
const noDataClass = this.noData() ? styles.noData : '';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ `${styles.data} ${noDataClass}` }
|
||||
|
||||
@@ -22,17 +22,17 @@ export default class TxHashLink extends Component {
|
||||
|
||||
static propTypes = {
|
||||
txHash: PropTypes.string.isRequired,
|
||||
chain: PropTypes.string.isRequired,
|
||||
isTest: PropTypes.bool.isRequired,
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string
|
||||
}
|
||||
|
||||
render () {
|
||||
const { children, txHash, className, chain } = this.props;
|
||||
const { children, txHash, className, isTest } = this.props;
|
||||
|
||||
return (
|
||||
<a
|
||||
href={ txLink(txHash, chain === 'morden' || chain === 'testnet') }
|
||||
href={ txLink(txHash, isTest) }
|
||||
target='_blank'
|
||||
className={ className }>
|
||||
{ children || txHash }
|
||||
|
||||
@@ -35,7 +35,8 @@ class Embedded extends Component {
|
||||
actions: PropTypes.shape({
|
||||
startConfirmRequest: PropTypes.func.isRequired,
|
||||
startRejectRequest: PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
isTest: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
@@ -70,7 +71,7 @@ class Embedded extends Component {
|
||||
}
|
||||
|
||||
renderPending = (data) => {
|
||||
const { actions } = this.props;
|
||||
const { actions, isTest } = this.props;
|
||||
const { payload, id, isSending, date } = data;
|
||||
|
||||
return (
|
||||
@@ -83,6 +84,7 @@ class Embedded extends Component {
|
||||
id={ id }
|
||||
payload={ payload }
|
||||
date={ date }
|
||||
isTest={ isTest }
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -93,11 +95,13 @@ class Embedded extends Component {
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { isTest } = state.nodeStatus;
|
||||
const { actions, signer } = state;
|
||||
|
||||
return {
|
||||
actions,
|
||||
signer
|
||||
signer,
|
||||
isTest
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,8 @@ class RequestsPage extends Component {
|
||||
actions: PropTypes.shape({
|
||||
startConfirmRequest: PropTypes.func.isRequired,
|
||||
startRejectRequest: PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
isTest: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
@@ -96,7 +97,7 @@ class RequestsPage extends Component {
|
||||
}
|
||||
|
||||
renderPending = (data) => {
|
||||
const { actions } = this.props;
|
||||
const { actions, isTest } = this.props;
|
||||
const { payload, id, isSending, date } = data;
|
||||
|
||||
return (
|
||||
@@ -109,11 +110,13 @@ class RequestsPage extends Component {
|
||||
id={ id }
|
||||
payload={ payload }
|
||||
date={ date }
|
||||
isTest={ isTest }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderFinished = (data) => {
|
||||
const { isTest } = this.props;
|
||||
const { payload, id, result, msg, status, error, date } = data;
|
||||
|
||||
return (
|
||||
@@ -127,6 +130,7 @@ class RequestsPage extends Component {
|
||||
error={ error }
|
||||
payload={ payload }
|
||||
date={ date }
|
||||
isTest={ isTest }
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -143,7 +147,14 @@ class RequestsPage extends Component {
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return state;
|
||||
const { isTest } = state.nodeStatus;
|
||||
const { actions, signer } = state;
|
||||
|
||||
return {
|
||||
actions,
|
||||
signer,
|
||||
isTest
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
|
||||
@@ -57,7 +57,7 @@ export default class CallsToolbar extends Component {
|
||||
<div className={ styles.callActions } { ...this._test('button-container') }>
|
||||
<IconButton
|
||||
className={ styles.callAction }
|
||||
onClick={ this.setCall }
|
||||
onTouchTap={ this.setCall }
|
||||
tooltip='Set'
|
||||
tooltipPosition='top-left'
|
||||
{ ...this._test('button-setCall') }
|
||||
@@ -66,7 +66,7 @@ export default class CallsToolbar extends Component {
|
||||
</IconButton>
|
||||
<IconButton
|
||||
className={ styles.callAction }
|
||||
onClick={ this.makeCall }
|
||||
onTouchTap={ this.makeCall }
|
||||
tooltip='Fire again'
|
||||
tooltipPosition='top-left'
|
||||
{ ...this._test('button-makeCall') }
|
||||
|
||||
@@ -45,7 +45,7 @@ export default class ScrollTopButton extends Component {
|
||||
return (
|
||||
<IconButton
|
||||
className={ `${styles.scrollButton} ${hiddenClass}` }
|
||||
onClick={ this._scrollToTop }>
|
||||
onTouchTap={ this._scrollToTop }>
|
||||
<ArrowUpwardIcon />
|
||||
</IconButton>
|
||||
);
|
||||
|
||||
@@ -37,6 +37,7 @@ module.exports = {
|
||||
entry: {
|
||||
// dapps
|
||||
'basiccoin': ['./dapps/basiccoin.js'],
|
||||
'dappreg': ['./dapps/dappreg.js'],
|
||||
'githubhint': ['./dapps/githubhint.js'],
|
||||
'registry': ['./dapps/registry.js'],
|
||||
'signaturereg': ['./dapps/signaturereg.js'],
|
||||
|
||||
Reference in New Issue
Block a user