Added section to embark backend tab
This commit is contained in:
parent
05f0fef46d
commit
1528dd9022
Binary file not shown.
After Width: | Height: | Size: 714 B |
File diff suppressed because one or more lines are too long
|
@ -1,102 +0,0 @@
|
|||
h2 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.scenario p {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.scenario p.note {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.scenario p.error {
|
||||
color: #ff0000;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.code {
|
||||
background: #dedeff;
|
||||
padding: 0px 15px;
|
||||
border: 1px dashed #a0a0ff;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.code button {
|
||||
background: none;
|
||||
border: none;
|
||||
font-weight: bold;
|
||||
padding: 0 10px 3px 10px;
|
||||
font-size: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.code button:hover,
|
||||
.code select:hover,
|
||||
.code input:hover {
|
||||
background: #a0a0ff;
|
||||
}
|
||||
|
||||
.code select {
|
||||
background: none;
|
||||
border: 1px dashed #a0a0ff;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.code input {
|
||||
background: none;
|
||||
border: 1px dashed #a0a0ff;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.scenario {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
code .Highlight-boolean {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
code .Highlight-class {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
code .Highlight-comment {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
code .Highlight-constant {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
code .Highlight-function {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
code .Highlight-keyword {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
code .Highlight-number {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
code .Highlight-operator {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
code .Highlight-punctuation {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
code .Highlight-string {
|
||||
color: #df5000;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Contract UI</title>
|
||||
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
|
||||
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/languages/javascript.min.js"></script>
|
||||
<script src="./contracts-section.js"></script>
|
||||
</head>
|
||||
<body class="container-fluid">
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,22 +0,0 @@
|
|||
import 'bootstrap';
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import './contracts-section.css';
|
||||
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import IdentityFactory from 'Embark/contracts/IdentityFactory'; // Import all contracts
|
||||
|
||||
import ContractUI from './contracts/contract-ui';
|
||||
|
||||
|
||||
__embarkContext.execWhenReady(function(){
|
||||
|
||||
// Each contract should be available on window
|
||||
window["IdentityFactory"] = IdentityFactory;
|
||||
|
||||
ReactDOM.render(
|
||||
<ContractUI name="IdentityFactory" contract={IdentityFactory} sourceURL="https://raw.githubusercontent.com/status-im/contracts/contracts-ui-demo/contracts/identity/IdentityFactory.sol" />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
|
||||
});
|
|
@ -1,46 +0,0 @@
|
|||
import ContractContext from './contract-context';
|
||||
|
||||
class AccountList extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error: false,
|
||||
errorMessage: "",
|
||||
accounts: []
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
async handleClick(e, updateAccountsCallback){
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
updateAccountsCallback();
|
||||
} catch(err) {
|
||||
this.setState({
|
||||
error: true,
|
||||
errorMessage: e.name + ': ' + e.message
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render(){
|
||||
return <ContractContext.Consumer>
|
||||
{(context) => (
|
||||
<div>
|
||||
<h3>Get Accounts</h3>
|
||||
<div className="scenario">
|
||||
<div id="getAccounts" className="code">
|
||||
await web3.eth.getAccounts(); <button onClick={event => this.handleClick(event, context.updateAccounts)}>⏎</button>
|
||||
</div>
|
||||
<p className="note"><tt>accounts</tt> variable is available in the console</p>
|
||||
{this.state.error ? '<p className="error">' + this.state.errorMessage + '</p>' : ''}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ContractContext.Consumer>;
|
||||
}
|
||||
}
|
||||
|
||||
export default AccountList;
|
|
@ -1,88 +0,0 @@
|
|||
import Function from './function';
|
||||
|
||||
class FunctionForm extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
fields: {},
|
||||
error: false,
|
||||
message: null,
|
||||
receipt: null
|
||||
};
|
||||
|
||||
this.showResults = this.showResults.bind(this);
|
||||
}
|
||||
|
||||
_getFunctionParamFields(elem){
|
||||
if(this.props.abi.type == 'fallback') return '';
|
||||
|
||||
return '(' + this.props.abi.inputs
|
||||
.map((input, i) => <input type="text" data-var-type={input.type} data-type="inputParam" data-name={input.name} placeholder={input.name} title={input.type + ' ' + input.name} size={input.name.length} />)
|
||||
.join(', ') + ')';
|
||||
}
|
||||
|
||||
_getMethodType(elem){
|
||||
return (this.props.abi.constant == true || this.props.abi.stateMutability == 'view' || this.props.abi.stateMutability == 'pure') ? 'call' : 'send';
|
||||
}
|
||||
|
||||
render(){
|
||||
const functionName = this.props.abi.name;
|
||||
const isDuplicated = this.props.contract.options.jsonInterface.filter(x => x.name == functionName).length > 1;
|
||||
const contract = this.props.contract;
|
||||
const receipt = this.state.receipt;
|
||||
|
||||
return <div className="function">
|
||||
<h4>{this.props.abi.type == 'function' ? this.props.abi.name : (this.props.abi.type == 'fallback' ? '(fallback)' : this.props.abi.name)}</h4>
|
||||
<div className="scenario">
|
||||
<div className="code">
|
||||
<Function contract={this.props.contract} contractName={this.props.contractName} duplicated={isDuplicated} abi={this.props.abi} resultHandler={this.showResults} />
|
||||
</div>
|
||||
{ receipt != null ?
|
||||
<ul>
|
||||
<li>Status: {receipt.status}</li>
|
||||
<li>Transaction Hash: {receipt.transactionHash}</li>
|
||||
{
|
||||
receipt.events != null ?
|
||||
<li>Events:
|
||||
<ul>
|
||||
{
|
||||
Object.keys(receipt.events).map(function(ev, index) {
|
||||
if(!isNaN(ev)) return null;
|
||||
const eventAbi = contract.options.jsonInterface.filter(x => x.name == ev)[0];
|
||||
let props = [];
|
||||
for(let prop in receipt.events[ev].returnValues){
|
||||
if(isNaN(prop)){
|
||||
let input = eventAbi.inputs.filter(x => x.name == prop)[0];
|
||||
props.push(prop + ': '
|
||||
+ (input.type.indexOf('int') == -1 ? '"' : '')
|
||||
+ receipt.events[ev].returnValues[prop]
|
||||
+ (input.type.indexOf('int') == -1 ? '"' : ''));
|
||||
}
|
||||
}
|
||||
return <li key={index}>{ev}({props.join(', ')})</li>;
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
: ''
|
||||
}
|
||||
</ul>
|
||||
: ""
|
||||
}
|
||||
{this.state.error ? <p className="error">{this.state.message}</p> : '' }
|
||||
{!this.state.error && this.state.message != null ? <p className="note">{this.state.message}</p> : '' }
|
||||
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
showResults(_error, _message, _receipt){
|
||||
this.setState({
|
||||
error: _error,
|
||||
message: _message,
|
||||
receipt: _receipt
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default FunctionForm;
|
|
@ -1,105 +0,0 @@
|
|||
import ContractContext from './contract-context';
|
||||
|
||||
class InstanceSelector extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showInstances: false,
|
||||
showCustomAddressField: false,
|
||||
selectedInstance: props.selectedInstance,
|
||||
customInstance: "",
|
||||
error: false,
|
||||
errorMessage: ""
|
||||
};
|
||||
|
||||
this.handleShowInstances = this.handleShowInstances.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleTextChange = this.handleTextChange.bind(this);
|
||||
}
|
||||
|
||||
handleTextChange(e){
|
||||
this.setState({customInstance: e.target.value});
|
||||
}
|
||||
|
||||
handleShowInstances(e){
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
showInstances: !this.state.showInstances
|
||||
});
|
||||
}
|
||||
|
||||
handleClick(e){
|
||||
e.preventDefault();
|
||||
|
||||
let instance;
|
||||
if(this.state.selectedInstance == "custom"){
|
||||
instance = this.state.customInstance;
|
||||
} else {
|
||||
instance = this.state.selectedInstance;
|
||||
}
|
||||
|
||||
if(!/^0x[0-9a-f]{40}$/i.test(instance)){
|
||||
this.setState({error: true, errorMessage: 'Not a valid Ethereum address.'});
|
||||
console.log(this.state.errorMessage);
|
||||
return;
|
||||
} else {
|
||||
this.setState({error: false});
|
||||
}
|
||||
|
||||
this.props.instanceUpdate(instance);
|
||||
|
||||
this.setState({
|
||||
showInstances: false,
|
||||
showCustomAddressField: false,
|
||||
selectedInstance: instance,
|
||||
customInstance: this.state.selectedInstance == "custom" ? this.state.customInstance : ""
|
||||
})
|
||||
}
|
||||
|
||||
handleChange(e){
|
||||
this.setState({
|
||||
showCustomAddressField: e.target.value == "custom",
|
||||
selectedInstance: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
return <ContractContext.Consumer>
|
||||
{ (context) => (<div className="contractSelection">
|
||||
<h5>
|
||||
<b>Instance Selected:</b> <span><b>{this.props.selectedInstance != null ? this.props.selectedInstance : 'none'}</b></span>
|
||||
{!this.state.showInstances ? <a href="#" onClick={this.handleShowInstances}>Change</a> : <a href="#" onClick={this.handleShowInstances}>Cancel</a> }
|
||||
</h5>
|
||||
{this.state.showInstances ?
|
||||
<div className="form-group control-group error">
|
||||
<select className="form-control" id="contracts" value={this.state.selectedInstance} onChange={this.handleChange}>
|
||||
<option value="custom">Specific contract address</option>
|
||||
{
|
||||
context.instances.map(function (item, i) {
|
||||
return <option key={i} value={item}>{item}</option>;
|
||||
})
|
||||
}
|
||||
</select>
|
||||
{
|
||||
this.state.showCustomAddressField ?
|
||||
<input type="text" className="form-control" id="specificAddress" onChange={this.handleTextChange} placeholder="0x" />
|
||||
: ''
|
||||
}
|
||||
<button className="btn btn-default" onClick={this.handleClick}>Change</button>
|
||||
{
|
||||
this.state.error ?
|
||||
<p className="error">{this.state.errorMessage}</p>
|
||||
: ""
|
||||
}
|
||||
</div> : "" }
|
||||
</div>
|
||||
)}
|
||||
</ContractContext.Consumer>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default InstanceSelector;
|
|
@ -1,27 +0,0 @@
|
|||
class SourceArea extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
sourceCode: ""
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
fetch(this.props.sourceURL)
|
||||
.then(response => response.text())
|
||||
.then(text => {
|
||||
let colorCodedText = hljs.highlight('javascript', text, true).value;
|
||||
this.setState({sourceCode: colorCodedText});
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
return <React.Fragment>
|
||||
<h3 className="filename">{this.props.sourceURL.split('\\').pop().split('/').pop()}</h3>
|
||||
<small className="url">{this.props.sourceURL}</small>
|
||||
<pre dangerouslySetInnerHTML={{__html: this.state.sourceCode}}></pre>
|
||||
</React.Fragment>;
|
||||
}
|
||||
}
|
||||
|
||||
export default SourceArea;
|
|
@ -1,10 +0,0 @@
|
|||
class Tab extends React.Component {
|
||||
render(){
|
||||
return <div role="tabpanel" className={this.props.active || false ? 'tab-pane active' : 'tab-pane'} id={this.props.id}>
|
||||
<h2>{this.props.name}</h2>
|
||||
{ this.props.children }
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default Tab;
|
|
@ -0,0 +1,68 @@
|
|||
class AccountList extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error: false,
|
||||
errorMessage: "",
|
||||
accounts: []
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
async handleClick(e, updateAccountsCallback){
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
updateAccountsCallback();
|
||||
} catch(err) {
|
||||
this.setState({
|
||||
error: true,
|
||||
errorMessage: e.name + ': ' + e.message
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
render(){
|
||||
return <ContractContext.Consumer>
|
||||
{(context) => (
|
||||
|
||||
<div className="card function">
|
||||
<div className="card-header">
|
||||
<h3 className="card-title">Get Accounts</h3>
|
||||
</div>
|
||||
{
|
||||
this.state.error
|
||||
?
|
||||
<div className="card-alert alert alert-danger mb-0">
|
||||
{this.state.errorMessage}
|
||||
</div>
|
||||
:
|
||||
''
|
||||
}
|
||||
<div className="card-body row">
|
||||
<div className="col-md-11">
|
||||
<code>
|
||||
await web3.eth.getAccounts();
|
||||
<input type="text" id="accountsTxt" />
|
||||
</code>
|
||||
</div>
|
||||
<div className="col-md-1">
|
||||
<button className="btn btn-primary ml-auto" onClick={event => this.handleClick(event, context.updateAccounts)}>⏎</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-footer">
|
||||
<p><tt>accounts</tt> variable is available in the console</p>
|
||||
<ul>
|
||||
{
|
||||
context.accounts.map((account, i) => <li key={i}>{account}</li>)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ContractContext.Consumer>;
|
||||
}
|
||||
}
|
|
@ -5,5 +5,3 @@ const ContractContext = React.createContext({
|
|||
updateInstances: (_instance) => {}
|
||||
|
||||
});
|
||||
|
||||
export default ContractContext;
|
|
@ -1,11 +1,3 @@
|
|||
import Tab from './tab';
|
||||
import AccountList from './account-list';
|
||||
import SourceArea from './source-area';
|
||||
import InstanceSelector from './instance-selector';
|
||||
import FunctionArea from './function-area';
|
||||
import ContractContext from './contract-context';
|
||||
|
||||
|
||||
class ContractUI extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -13,13 +5,15 @@ class ContractUI extends React.Component {
|
|||
this.updateInstances = this.updateInstances.bind(this);
|
||||
this.updateAccounts = this.updateAccounts.bind(this);
|
||||
this.handleInstanceSelection = this.handleInstanceSelection.bind(this);
|
||||
|
||||
this.handleMenuClick = this.handleMenuClick.bind(this);
|
||||
|
||||
this.state = {
|
||||
accounts: [],
|
||||
instances: [],
|
||||
selectedInstance: null,
|
||||
updateAccounts: this.updateAccounts,
|
||||
updateInstances: this.updateInstances
|
||||
updateInstances: this.updateInstances,
|
||||
selectedTab: 'deploy'
|
||||
};
|
||||
|
||||
if(props.contract.options.address != null){
|
||||
|
@ -32,6 +26,14 @@ class ContractUI extends React.Component {
|
|||
this.updateAccounts();
|
||||
}
|
||||
|
||||
handleMenuClick(e){
|
||||
console.log(e.target);
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
selectedTab: e.target.getAttribute('data-target')
|
||||
});
|
||||
}
|
||||
|
||||
async updateAccounts(){
|
||||
let accounts = await web3.eth.getAccounts();
|
||||
window.accounts = accounts;
|
||||
|
@ -59,34 +61,67 @@ class ContractUI extends React.Component {
|
|||
render() {
|
||||
return (
|
||||
<ContractContext.Provider value={this.state}>
|
||||
<div>
|
||||
<h1><span>{this.props.name}</span> <small>contract</small></h1>
|
||||
<p>Open your browser's console: <code>Tools > Developer Tools</code></p>
|
||||
<p>Remix: <a href="https://remix.ethereum.org">http://remix.ethereum.org</a></p>
|
||||
<ul className="nav nav-tabs" role="tablist" id="myTabs">
|
||||
<li role="presentation" className="active"><a href="#deploy" role="tab" data-toggle="tab">Instance</a></li>
|
||||
<li role="presentation"><a href="#functions" role="tab" data-toggle="tab">Functions</a></li>
|
||||
<li role="presentation"><a href="#contract" role="tab" data-toggle="tab">Contract</a></li>
|
||||
</ul>
|
||||
<div className="tab-content">
|
||||
<Tab id="deploy" name="Deployment / Utils" active={true}>
|
||||
<div className="row">
|
||||
<div className="col-md-3">
|
||||
<h3 className="page-title mb-5">{this.props.name}</h3>
|
||||
<div>
|
||||
<div className="list-group list-group-transparent mb-0">
|
||||
<MenuItem click={this.handleMenuClick} target="deploy" text="Deployment / Utils" />
|
||||
<MenuItem click={this.handleMenuClick} target="functions" text="Functions" />
|
||||
<MenuItem click={this.handleMenuClick} target="contract" text="Source Code" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-9">
|
||||
<Tab id="deploy" selectedTab={this.state.selectedTab}>
|
||||
<h4 className="mb-5">Deployment Utils</h4>
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<ul>
|
||||
<li>Open your browser's console: <code>Tools > Developer Tools</code></li>
|
||||
<li>Remix: <a href="https://remix.ethereum.org" target="_blank">http://remix.ethereum.org</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<AccountList accountUpdate={this.updateAccounts} />
|
||||
<h3>Deploy</h3>
|
||||
<h5>Deploy</h5>
|
||||
<FunctionArea contractName={this.props.name} contract={this.props.contract} type="constructor" />
|
||||
</Tab>
|
||||
<Tab id="functions" name="Functions">
|
||||
|
||||
<Tab id="functions" selectedTab={this.state.selectedTab}>
|
||||
<h4 className="mb-5">Functions</h4>
|
||||
<InstanceSelector selectedInstance={this.state.selectedInstance} instanceUpdate={this.handleInstanceSelection} />
|
||||
<FunctionArea contractName={this.props.name} contract={this.props.contract} type="function" />
|
||||
<FunctionArea contractName={this.props.name} contract={this.props.contract} type="fallback" />
|
||||
</Tab>
|
||||
<Tab id="contract" name="Contract">
|
||||
<SourceArea sourceURL={this.props.sourceURL} />
|
||||
|
||||
<Tab id="contract" selectedTab={this.state.selectedTab}>
|
||||
<h4 className="mb-5">Source Code</h4>
|
||||
<SourceArea definition={this.props.definition} source={this.props.source} />
|
||||
</Tab>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</ContractContext.Provider>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ContractUI;
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
import FunctionForm from './function-form';
|
||||
|
||||
class FunctionArea extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -20,5 +18,3 @@ class FunctionArea extends React.Component {
|
|||
</React.Fragment>;
|
||||
}
|
||||
}
|
||||
|
||||
export default FunctionArea;
|
|
@ -0,0 +1,109 @@
|
|||
class FunctionForm extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
fields: {},
|
||||
error: false,
|
||||
message: null,
|
||||
receipt: null
|
||||
};
|
||||
|
||||
this.showResults = this.showResults.bind(this);
|
||||
}
|
||||
|
||||
_getFunctionParamFields(elem){
|
||||
if(this.props.abi.type == 'fallback') return '';
|
||||
|
||||
return '(' + this.props.abi.inputs
|
||||
.map((input, i) => <input type="text" data-var-type={input.type} data-type="inputParam" data-name={input.name} placeholder={input.name} title={input.type + ' ' + input.name} size={input.name.length} />)
|
||||
.join(', ') + ')';
|
||||
}
|
||||
|
||||
_getMethodType(elem){
|
||||
return (this.props.abi.constant == true || this.props.abi.stateMutability == 'view' || this.props.abi.stateMutability == 'pure') ? 'call' : 'send';
|
||||
}
|
||||
|
||||
render(){
|
||||
const functionName = this.props.abi.name;
|
||||
const isDuplicated = this.props.contract.options.jsonInterface.filter(x => x.name == functionName).length > 1;
|
||||
const contract = this.props.contract;
|
||||
const receipt = this.state.receipt;
|
||||
|
||||
return <div className="card function">
|
||||
{
|
||||
this.props.abi.type == "function" || this.props.abi.type == "fallback"
|
||||
?
|
||||
<div className="card-header">
|
||||
<h3 className="card-title">{this.props.abi.type == 'function' ? this.props.abi.name : (this.props.abi.type == 'fallback' ? '(fallback)' : this.props.abi.name)}</h3>
|
||||
</div>
|
||||
:
|
||||
""
|
||||
}
|
||||
{
|
||||
this.state.error
|
||||
?
|
||||
<div className="card-alert alert alert-danger mb-0">
|
||||
{this.state.message}
|
||||
</div>
|
||||
:
|
||||
''
|
||||
}
|
||||
<div className="card-body row">
|
||||
<Function contract={this.props.contract} contractName={this.props.contractName} duplicated={isDuplicated} abi={this.props.abi} resultHandler={this.showResults} />
|
||||
</div>
|
||||
{
|
||||
receipt != null || !this.state.error && this.state.message != null
|
||||
?
|
||||
<div className="card-footer">
|
||||
{ receipt != null ?
|
||||
<ul>
|
||||
<li>Status: {receipt.status}</li>
|
||||
<li>Transaction Hash: {receipt.transactionHash}</li>
|
||||
{
|
||||
receipt.events != null ?
|
||||
<li>Events:
|
||||
<ul>
|
||||
{
|
||||
Object.keys(receipt.events).map(function(ev, index) {
|
||||
if(!isNaN(ev)) return null;
|
||||
const eventAbi = contract.options.jsonInterface.filter(x => x.name == ev)[0];
|
||||
let props = [];
|
||||
for(let prop in receipt.events[ev].returnValues){
|
||||
if(isNaN(prop)){
|
||||
let input = eventAbi.inputs.filter(x => x.name == prop)[0];
|
||||
props.push(prop + ': '
|
||||
+ (input.type.indexOf('int') == -1 ? '"' : '')
|
||||
+ receipt.events[ev].returnValues[prop]
|
||||
+ (input.type.indexOf('int') == -1 ? '"' : ''));
|
||||
}
|
||||
}
|
||||
return <li key={index}>{ev}({props.join(', ')})</li>;
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
: ''
|
||||
}
|
||||
</ul>
|
||||
: ""
|
||||
}
|
||||
{
|
||||
!this.state.error && this.state.message != null
|
||||
?
|
||||
<React.Fragment>{this.state.message}</React.Fragment>
|
||||
: '' }
|
||||
|
||||
</div>
|
||||
: ''
|
||||
}
|
||||
</div>;
|
||||
}
|
||||
|
||||
showResults(_error, _message, _receipt){
|
||||
this.setState({
|
||||
error: _error,
|
||||
message: _message,
|
||||
receipt: _receipt
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
import ContractContext from './contract-context';
|
||||
|
||||
class Function extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
|
@ -72,6 +70,7 @@ class Function extends React.Component {
|
|||
[this._getMethodType()](executionParams)
|
||||
|
||||
if(this._getMethodType() == 'call'){
|
||||
console.log("A");
|
||||
this.props.resultHandler(false, _receipt, null);
|
||||
} else {
|
||||
this.props.resultHandler(false, null, _receipt);
|
||||
|
@ -163,7 +162,7 @@ class Function extends React.Component {
|
|||
return <React.Fragment>
|
||||
{
|
||||
this.props.abi.inputs
|
||||
.map((input, i) => <input key={i} type="text" data-var-type={input.type} data-type="inputParam" data-name={input.name} placeholder={input.name} title={input.type + ' ' + input.name} size={input.name.length} value={this.state.fields[input.name] || ''} size="6" onChange={this.handleParameterChange} />)
|
||||
.map((input, i) => <input key={i} type="text" data-var-type={input.type} data-type="inputParam" data-name={input.name} placeholder={input.name} title={input.type + ' ' + input.name} size={input.name.length + 2} value={this.state.fields[input.name] || ''} onChange={this.handleParameterChange} />)
|
||||
.reduce((accu, elem) => {
|
||||
return accu === null ? [elem] : [...accu, ', ', elem]
|
||||
}, null)
|
||||
|
@ -198,22 +197,28 @@ class Function extends React.Component {
|
|||
return <ContractContext.Consumer>
|
||||
{ (context) => (
|
||||
<React.Fragment>
|
||||
await {this._getFunctionLabel()}
|
||||
{ this.props.abi.type != 'fallback' ? '(' : '' }
|
||||
{ this.props.abi.type != 'fallback' ? this._getFunctionParamFields() : '' }
|
||||
{ this.props.abi.type != 'fallback' ? ')' : '' }
|
||||
{ this.props.abi.type != 'fallback' ? '.' + this._getMethodType() : '' }
|
||||
({ this._getMethodFields(context.accounts) })
|
||||
<button onClick={event => this.handleClick(event, context.updateInstances)} disabled={this.state.onRequest}>⏎</button>
|
||||
{ this.state.onRequest ?
|
||||
<img src="images/loading.gif" className="loading" alt="" />
|
||||
: ''
|
||||
}
|
||||
<div className="col-md-11">
|
||||
<code>
|
||||
await {this._getFunctionLabel()}
|
||||
{ this.props.abi.type != 'fallback' ? '(' : '' }
|
||||
{ this.props.abi.type != 'fallback' ? this._getFunctionParamFields() : '' }
|
||||
{ this.props.abi.type != 'fallback' ? ')' : '' }
|
||||
{ this.props.abi.type != 'fallback' ? '.' + this._getMethodType() : '' }
|
||||
({ this._getMethodFields(context.accounts) })
|
||||
</code>
|
||||
</div>
|
||||
<div className="col-md-1">
|
||||
<button className="btn btn-primary ml-auto" onClick={event => this.handleClick(event, context.updateInstances)} disabled={this.state.onRequest}>
|
||||
{ this.state.onRequest ?
|
||||
<img src="../assets/images/loading.gif" className="loading" alt="" />
|
||||
:
|
||||
<React.Fragment>⏎</React.Fragment>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</ContractContext.Consumer>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Function;
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
class InstanceSelector extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showInstances: false,
|
||||
showCustomAddressField: false,
|
||||
selectedInstance: props.selectedInstance,
|
||||
customInstance: "",
|
||||
error: false,
|
||||
errorMessage: ""
|
||||
};
|
||||
|
||||
this.handleShowInstances = this.handleShowInstances.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleTextChange = this.handleTextChange.bind(this);
|
||||
}
|
||||
|
||||
handleTextChange(e){
|
||||
this.setState({customInstance: e.target.value});
|
||||
}
|
||||
|
||||
handleShowInstances(e){
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
showInstances: !this.state.showInstances
|
||||
});
|
||||
}
|
||||
|
||||
handleClick(e){
|
||||
e.preventDefault();
|
||||
|
||||
let instance;
|
||||
if(this.state.selectedInstance == "custom"){
|
||||
instance = this.state.customInstance;
|
||||
} else {
|
||||
instance = this.state.selectedInstance;
|
||||
}
|
||||
|
||||
if(!/^0x[0-9a-f]{40}$/i.test(instance)){
|
||||
this.setState({error: true, errorMessage: 'Not a valid Ethereum address.'});
|
||||
console.log(this.state.errorMessage);
|
||||
return;
|
||||
} else {
|
||||
this.setState({error: false});
|
||||
}
|
||||
|
||||
this.props.instanceUpdate(instance);
|
||||
|
||||
this.setState({
|
||||
showInstances: false,
|
||||
showCustomAddressField: false,
|
||||
selectedInstance: instance,
|
||||
customInstance: this.state.selectedInstance == "custom" ? this.state.customInstance : ""
|
||||
})
|
||||
}
|
||||
|
||||
handleChange(e){
|
||||
this.setState({
|
||||
showCustomAddressField: e.target.value == "custom",
|
||||
selectedInstance: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
return <ContractContext.Consumer>
|
||||
{ (context) => (<div className="contractSelection">
|
||||
|
||||
|
||||
|
||||
<div className="card">
|
||||
<div className="card-header">
|
||||
<h3 className="card-title">
|
||||
Instance Selected: <b>{this.props.selectedInstance != null ? this.props.selectedInstance : 'none'}</b>
|
||||
</h3>
|
||||
<div className="card-options">
|
||||
{
|
||||
!this.state.showInstances
|
||||
?
|
||||
<a href="#" className="btn btn-primary btn-sm" onClick={this.handleShowInstances}>Change</a>
|
||||
:
|
||||
<a href="#" className="btn btn-secondary btn-sm" onClick={this.handleShowInstances}>Cancel</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
this.state.showInstances ?
|
||||
<React.Fragment>
|
||||
{
|
||||
this.state.error
|
||||
?
|
||||
<div className="card-alert alert alert-danger mb-0">
|
||||
{this.state.errorMessage}
|
||||
</div>
|
||||
:
|
||||
''
|
||||
}
|
||||
<div className="card-body">
|
||||
<div className="form-group control-group error">
|
||||
<select className="form-control" id="contracts" value={this.state.selectedInstance} onChange={this.handleChange}>
|
||||
<option value="custom">Specific contract address</option>
|
||||
{
|
||||
context.instances.map(function (item, i) {
|
||||
return <option key={i} value={item}>{item}</option>;
|
||||
})
|
||||
}
|
||||
</select>
|
||||
{
|
||||
this.state.showCustomAddressField ?
|
||||
<input type="text" className="form-control" id="specificAddress" onChange={this.handleTextChange} placeholder="0x" />
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-footer text-right">
|
||||
<button className="btn btn-primary" onClick={this.handleClick}>Change</button>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
:
|
||||
''
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ContractContext.Consumer>;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
class MenuItem extends React.Component {
|
||||
render(){
|
||||
return <a href="#" onClick={this.props.click} data-target={this.props.target} className="list-group-item list-group-item-action d-flex align-items-center">
|
||||
<span className="icon mr-3"><i className="fe fe-file"></i></span>{this.props.text}
|
||||
</a>;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
class SourceArea extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
sourceCode: ""
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
let colorCodedText = hljs.highlight('javascript', this.props.source, true).value;
|
||||
this.setState({sourceCode: colorCodedText});
|
||||
}
|
||||
|
||||
render(){
|
||||
return <div className="card">
|
||||
<div className="card-header">
|
||||
<h3 className="card-title">{this.props.definition.className}</h3>
|
||||
<div className="card-options">
|
||||
<small>{this.props.definition.filename}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<pre dangerouslySetInnerHTML={{__html: this.state.sourceCode}}></pre>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
class Tab extends React.Component {
|
||||
render(){
|
||||
return (
|
||||
this.props.selectedTab == this.props.id
|
||||
?
|
||||
<div id={this.props.id}>
|
||||
{ this.props.children }
|
||||
</div>
|
||||
:
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
code {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
code input, code select {
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.6;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid rgba(0, 40, 100, 0.12);
|
||||
border-radius: 3px;
|
||||
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.function button {
|
||||
margin-top: .6em;
|
||||
}
|
||||
|
||||
#accountsTxt {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.card-options a.btn-primary {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.card-options a.btn-primary:hover {
|
||||
background-color: #ccc;
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
<!doctype html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta http-equiv="Content-Language" content="en" />
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="theme-color" content="#4188c9">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="HandheldFriendly" content="True">
|
||||
<meta name="MobileOptimized" content="320">
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon"/>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="./favicon.ico" />
|
||||
<!-- Generated: 2018-04-04 13:48:30 +0200 -->
|
||||
<title>Embark</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,300i,400,400i,500,500i,600,600i,700,700i&subset=latin-ext">
|
||||
<!--
|
||||
<script src="./assets/js/require.min.js"></script>
|
||||
<script>
|
||||
requirejs.config({
|
||||
baseUrl: '.'
|
||||
});
|
||||
</script>
|
||||
-->
|
||||
<!-- Dashboard Core -->
|
||||
<link href="../assets/css/dashboard.css" rel="stylesheet" />
|
||||
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
|
||||
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
|
||||
<script src="../assets/js/jquery-3.3.1.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/languages/javascript.min.js"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Import this with a bundler -->
|
||||
<link rel="stylesheet" href="./contracts.css">
|
||||
<script src="../assets/js/web3-1.0.min.js" type="text/javascript"></script>
|
||||
<script src="./components/account-list.js" type="text/babel"></script>
|
||||
<script src="./components/contract-context.js" type="text/babel"></script>
|
||||
<script src="./components/contract-ui.js" type="text/babel"></script>
|
||||
<script src="./components/function-area.js" type="text/babel"></script>
|
||||
<script src="./components/function-form.js" type="text/babel"></script>
|
||||
<script src="./components/function.js" type="text/babel"></script>
|
||||
<script src="./components/instance-selector.js" type="text/babel"></script>
|
||||
<script src="./components/source-area.js" type="text/babel"></script>
|
||||
<script src="./components/tab.js" type="text/babel"></script>
|
||||
<script src="./components/menu-item.js" type="text/babel"></script>
|
||||
<script src="./view.js" type="text/babel"></script>
|
||||
|
||||
|
||||
<!--
|
||||
<script src="./assets/js/dashboard.js"></script>
|
||||
<link href="./assets/plugins/charts-c3/plugin.css" rel="stylesheet" />
|
||||
<script src="./assets/plugins/charts-c3/plugin.js"></script>
|
||||
<link href="./assets/plugins/maps-google/plugin.css" rel="stylesheet" />
|
||||
<script src="./assets/plugins/maps-google/plugin.js"></script>
|
||||
<script src="./assets/plugins/input-mask/plugin.js"></script>
|
||||
|
||||
-->
|
||||
|
||||
</head>
|
||||
<body class="">
|
||||
<div class="page">
|
||||
<div class="page-main">
|
||||
<div class="header">
|
||||
<div class="container">
|
||||
<div class="d-flex">
|
||||
<a class="navbar-brand" href="./index.html">
|
||||
<img src="../assets/images/logo.png" class="navbar-brand-img" alt="Embark">
|
||||
</a>
|
||||
<div class="ml-auto d-flex order-lg-2">
|
||||
<div class="dropdown d-none d-md-flex">
|
||||
<a class="nav-link icon" data-toggle="dropdown">
|
||||
<i class="fe fe-bell"></i>
|
||||
<span class="nav-unread"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
|
||||
<a href="#" class="dropdown-item d-flex">
|
||||
<span class="avatar mr-3 align-self-center" style="background-image: url(demo/faces/male/41.jpg)"></span>
|
||||
<div>
|
||||
<strong>Nathan</strong> pushed new commit: Fix page load performance issue.
|
||||
<div class="small text-muted">10 minutes ago</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" class="dropdown-item d-flex">
|
||||
<span class="avatar mr-3 align-self-center" style="background-image: url(demo/faces/female/1.jpg)"></span>
|
||||
<div>
|
||||
<strong>Alice</strong> started new task: Tabler UI design.
|
||||
<div class="small text-muted">1 hour ago</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" class="dropdown-item d-flex">
|
||||
<span class="avatar mr-3 align-self-center" style="background-image: url(demo/faces/female/18.jpg)"></span>
|
||||
<div>
|
||||
<strong>Rose</strong> deployed new version of NodeJS REST Api V3
|
||||
<div class="small text-muted">2 hours ago</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="#" class="dropdown-item text-center text-muted-dark">Mark all as read</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="nav-link pr-0" data-toggle="dropdown">
|
||||
<span class="avatar" style="background-image: url(./demo/faces/female/25.jpg)"></span>
|
||||
<span class="ml-2 d-none d-lg-block">
|
||||
<span class="text-default">Dade Murphy</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="dropdown-icon fe fe-user"></i> Profile
|
||||
</a>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="dropdown-icon fe fe-settings"></i> Settings
|
||||
</a>
|
||||
<a class="dropdown-item" href="#">
|
||||
<span class="float-right"><span class="badge badge-primary">6</span></span>
|
||||
<i class="dropdown-icon fe fe-mail"></i> Inbox
|
||||
</a>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="dropdown-icon fe fe-send"></i> Message
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="dropdown-icon fe fe-help-circle"></i> Need help?
|
||||
</a>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="dropdown-icon fe fe-log-out"></i> Sign out
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-nav d-none d-lg-flex">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item">
|
||||
<a href="./index.html" class="nav-link"><i class="fe fe-home"></i> Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="javascript:void(0)" class="nav-link active"><i class="fe fe-box"></i> Contracts</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="./docs/index.html" class="nav-link"><i class="fe fe-file-text"></i> Documentation</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-3 ml-auto">
|
||||
<form class="input-icon">
|
||||
<input type="search" class="form-control header-search" placeholder="Search…" tabindex="1">
|
||||
<div class="input-icon-addon">
|
||||
<i class="fe fe-search"></i>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-content">
|
||||
<div class="container">
|
||||
<div id="contracts-area"></div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="row align-items-center flex-row-reverse">
|
||||
<div class="col-auto ml-auto">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<ul class="list-inline list-inline-dots mb-0">
|
||||
<li class="list-inline-item"><a href="./docs/index.html">Documentation</a></li>
|
||||
<li class="list-inline-item"><a href="./faq.html">FAQ</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="https://github.com/tabler/tabler" class="btn btn-outline-primary btn-sm">Source code</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-auto mt-3 mt-lg-0 text-center">
|
||||
Copyright © 2018 <a href=".">Status Embark</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
const contractName = location.search.replace(/\?/, '');
|
||||
|
||||
let contractDefinition;
|
||||
let host;
|
||||
|
||||
fetch("/embark/console", {
|
||||
method: "POST",
|
||||
headers: { 'content-type' : 'application/x-www-form-urlencoded; charset=UTF-8' },
|
||||
body: "cmd=web3.currentProvider.host"
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(text => {
|
||||
host = text;
|
||||
return fetch("/embark/contract/" + contractName);
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(_contractDefinition => {
|
||||
contractDefinition = _contractDefinition;
|
||||
return fetch("/embark/files/contracts?filename=" + contractDefinition.originalFilename);
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(contractSource => {
|
||||
const web3 = new Web3(host);
|
||||
window.web3 = web3;
|
||||
|
||||
let contractObj = new web3.eth.Contract(contractDefinition.abiDefinition);
|
||||
contractObj.options.data = "0x" + contractDefinition.code;
|
||||
contractObj.options.address = contractDefinition.deployedAddress;
|
||||
|
||||
window[contractDefinition.className] = contractObj;
|
||||
|
||||
ReactDOM.render(
|
||||
<ContractUI name={contractDefinition.className} definition={contractDefinition} contract={contractObj} source={contractSource} />,
|
||||
document.getElementById('contracts-area')
|
||||
);
|
||||
});
|
Loading…
Reference in New Issue