mirror of https://github.com/embarklabs/embark.git
Merge branch 'master' into feature/deployment-strategy
This commit is contained in:
commit
087a2e8c6b
|
@ -1,24 +0,0 @@
|
||||||
## Overview
|
|
||||||
**TL;DR**
|
|
||||||
<One to two sentence description of the issue you are encountering.>
|
|
||||||
|
|
||||||
### Extra Detail
|
|
||||||
|
|
||||||
#### Steps to reproduce
|
|
||||||
1.
|
|
||||||
2.
|
|
||||||
3.
|
|
||||||
#### Screenshots
|
|
||||||
<please upload images of the error to better showcase the problem.>
|
|
||||||
|
|
||||||
#### Logs
|
|
||||||
<please upload logs of the error to better showcase the problem. You can use the following options: --nodashboard --logfile log.txt --loglevel trace>
|
|
||||||
|
|
||||||
#### Context (Environment)
|
|
||||||
* OS:
|
|
||||||
* Embark Version:
|
|
||||||
* Node Version:
|
|
||||||
* NPM Version:
|
|
||||||
|
|
||||||
### Questions?
|
|
||||||
- Leave a comment on this issue! Make sure to use @ mentions if you want a specific person's attention!
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
---
|
||||||
|
name: 🐞 Bug Report
|
||||||
|
about: Something is broken? 🔨
|
||||||
|
---
|
||||||
|
|
||||||
|
### Bug Report
|
||||||
|
|
||||||
|
#### Summary
|
||||||
|
|
||||||
|
<!-- Provide a summary describing the problem you are experiencing. -->
|
||||||
|
|
||||||
|
#### Current behavior
|
||||||
|
|
||||||
|
<!--
|
||||||
|
What is the current (buggy) behavior? Feel free to add as much information as possible.
|
||||||
|
Also, a screenshot often says more than a thousand words. :)
|
||||||
|
-->
|
||||||
|
|
||||||
|
#### How to reproduce
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide steps to reproduce the bug.
|
||||||
|
Adding a failing Unit or Functional Test would help us a lot - you can submit one in a Pull Request separately, referencing this bug report.
|
||||||
|
-->
|
||||||
|
|
||||||
|
#### Expected behavior
|
||||||
|
|
||||||
|
<!-- What was the expected (correct) behavior? -->
|
||||||
|
|
||||||
|
#### If you encounter an error, please create a logfile using the following command and post the output here
|
||||||
|
|
||||||
|
```
|
||||||
|
$ embark run --nodashboard --logfile log.txt --loglevel trace
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Please provide additional information about your system
|
||||||
|
|
||||||
|
**OS**:
|
||||||
|
**Embark Version**:
|
||||||
|
**Node Version**:
|
||||||
|
**NPM Version**:
|
||||||
|
|
||||||
|
#### Sometimes issues are related to Embark's installation. Can you provide information on how Embark was installed?
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
name: 🎉 Feature Request
|
||||||
|
about: You have a neat idea that should be implemented? 🎩
|
||||||
|
---
|
||||||
|
|
||||||
|
### Feature Request
|
||||||
|
|
||||||
|
<!-- Fill in the relevant information below to help triage your issue. -->
|
||||||
|
|
||||||
|
#### Summary
|
||||||
|
|
||||||
|
<!-- Provide a summary of the feature you would like to see implemented. -->
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
name: 🤔 Proposal
|
||||||
|
about: Have a nice proposal?
|
||||||
|
---
|
||||||
|
|
||||||
|
### Proposal description
|
||||||
|
|
||||||
|
<!-- Describe the proposal you want here. -->
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
## Overview
|
|
||||||
**TL;DR**
|
|
||||||
<One to two sentence description of the issue you are encountering or trying to solve.>
|
|
||||||
|
|
||||||
### Questions
|
|
||||||
<If relevant, write a list of questions that you would like to discuss related to the changes that you have made.>
|
|
||||||
|
|
||||||
### Review
|
|
||||||
<use @mentions for quick questions, specific feedback, and progress updates.>
|
|
||||||
|
|
||||||
### Cool Spaceship Picture
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
name: ⚙ Bugfix
|
||||||
|
about: Fixed a bug? 🐞
|
||||||
|
---
|
||||||
|
|
||||||
|
### What bug have you fixed?
|
||||||
|
|
||||||
|
<!-- Fill in the relevant information below to help triage your issue. -->
|
||||||
|
|
||||||
|
#### How did you fix it (give a brief summary)?
|
||||||
|
|
||||||
|
<!-- Provide a summary of the improvement you are submitting. -->
|
||||||
|
|
||||||
|
### Questions
|
||||||
|
<If relevant, write a list of questions that you would like to discuss related to the changes that you have made.>
|
||||||
|
|
||||||
|
### Review
|
||||||
|
<use @mentions for quick questions, specific feedback, and progress updates.>
|
||||||
|
|
||||||
|
### Cool Spaceship Picture
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
name: ⚙ Feature
|
||||||
|
about: Implemented a new feature? 🎁
|
||||||
|
---
|
||||||
|
|
||||||
|
### What feature did you implement?
|
||||||
|
|
||||||
|
<!-- Fill in the relevant information below to help triage your issue. -->
|
||||||
|
|
||||||
|
#### Anything that needs special attention (breaking changes etc)?
|
||||||
|
|
||||||
|
<!-- Provide a summary of the improvement you are submitting. -->
|
||||||
|
|
||||||
|
### Questions
|
||||||
|
<If relevant, write a list of questions that you would like to discuss related to the changes that you have made.>
|
||||||
|
|
||||||
|
### Review
|
||||||
|
<use @mentions for quick questions, specific feedback, and progress updates.>
|
||||||
|
|
||||||
|
### Cool Spaceship Picture
|
|
@ -10121,6 +10121,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"re-resizable": {
|
||||||
|
"version": "4.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-4.9.3.tgz",
|
||||||
|
"integrity": "sha512-JKzmZdUAYWs85YErkmZNB7hjGR9qUOHFUZUtEplZlEZBFHRguiWck5J+HFTy/NjlMJtqQsYPQq57nQAO2BuRRg=="
|
||||||
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"version": "16.4.2",
|
"version": "16.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"qs": "^6.5.2",
|
"qs": "^6.5.2",
|
||||||
"raf": "3.4.0",
|
"raf": "3.4.0",
|
||||||
|
"re-resizable": "^4.9.3",
|
||||||
"react": "^16.4.2",
|
"react": "^16.4.2",
|
||||||
"react-blockies": "^1.4.0",
|
"react-blockies": "^1.4.0",
|
||||||
"react-bootstrap-typeahead": "^3.2.4",
|
"react-bootstrap-typeahead": "^3.2.4",
|
||||||
|
|
|
@ -42,7 +42,7 @@ const LayoutContract = ({contract, children, cardTitle}) => (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>
|
<CardTitle>
|
||||||
<span className={orderClassName(contract.address)}>{contract.index + 1}</span>
|
<span className={orderClassName(contract.address)}>{contract.deployIndex + 1}</span>
|
||||||
{cardTitle}
|
{cardTitle}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
@ -55,7 +55,7 @@ const LayoutContract = ({contract, children, cardTitle}) => (
|
||||||
LayoutContract.propTypes = {
|
LayoutContract.propTypes = {
|
||||||
contract: PropTypes.object,
|
contract: PropTypes.object,
|
||||||
children: PropTypes.array,
|
children: PropTypes.array,
|
||||||
cardTitle: PropTypes.string
|
cardTitle: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
const DeploymentResult = ({deployment}) => {
|
const DeploymentResult = ({deployment}) => {
|
||||||
|
@ -81,7 +81,7 @@ const DeploymentResult = ({deployment}) => {
|
||||||
|
|
||||||
DeploymentResult.propTypes = {
|
DeploymentResult.propTypes = {
|
||||||
deployment: PropTypes.object
|
deployment: PropTypes.object
|
||||||
}
|
};
|
||||||
|
|
||||||
const GasEstimateResult = ({gasEstimate}) => {
|
const GasEstimateResult = ({gasEstimate}) => {
|
||||||
if (gasEstimate.running) {
|
if (gasEstimate.running) {
|
||||||
|
@ -244,7 +244,10 @@ const ContractsHeader = ({deploymentPipeline, updateDeploymentPipeline}) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
ContractsHeader.propTypes = {
|
ContractsHeader.propTypes = {
|
||||||
deploymentPipeline: PropTypes.object,
|
deploymentPipeline: PropTypes.oneOfType([
|
||||||
|
PropTypes.object,
|
||||||
|
PropTypes.string
|
||||||
|
]),
|
||||||
updateDeploymentPipeline: PropTypes.func
|
updateDeploymentPipeline: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -262,13 +265,16 @@ const Contract = ({web3, contract, deploymentPipeline, web3Deploy, web3EstimateG
|
||||||
web3Deploy={web3Deploy}
|
web3Deploy={web3Deploy}
|
||||||
web3EstimateGas={web3EstimateGas}/>;
|
web3EstimateGas={web3EstimateGas}/>;
|
||||||
default:
|
default:
|
||||||
return <React.Fragment></React.Fragment>;
|
return <React.Fragment/>;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Contract.propTypes = {
|
Contract.propTypes = {
|
||||||
contract: PropTypes.object,
|
contract: PropTypes.object,
|
||||||
deploymentPipeline: PropTypes.object,
|
deploymentPipeline: PropTypes.oneOfType([
|
||||||
|
PropTypes.object,
|
||||||
|
PropTypes.string
|
||||||
|
]),
|
||||||
toggleContractOverview: PropTypes.func,
|
toggleContractOverview: PropTypes.func,
|
||||||
web3: PropTypes.object,
|
web3: PropTypes.object,
|
||||||
web3Deploy: PropTypes.func,
|
web3Deploy: PropTypes.func,
|
||||||
|
@ -300,12 +306,15 @@ class ContractsDeployment extends React.Component {
|
||||||
<Col>
|
<Col>
|
||||||
<ContractsHeader deploymentPipeline={this.props.deploymentPipeline}
|
<ContractsHeader deploymentPipeline={this.props.deploymentPipeline}
|
||||||
updateDeploymentPipeline={this.props.updateDeploymentPipeline}/>
|
updateDeploymentPipeline={this.props.updateDeploymentPipeline}/>
|
||||||
{this.props.contracts.sort((a, b) => a.index - b.index).map(contract => (
|
{this.props.contracts.filter(contract => contract.code || contract.deploy)
|
||||||
<Contract key={contract.index}
|
.sort((a, b) => a.index - b.index).map((contract, index) => {
|
||||||
|
contract.deployIndex = index;
|
||||||
|
return (<Contract key={contract.deployIndex}
|
||||||
contract={contract}
|
contract={contract}
|
||||||
toggleContractOverview={(contract) => this.toggleContractOverview(contract)}
|
toggleContractOverview={(contract) => this.toggleContractOverview(contract)}
|
||||||
{...this.props} />
|
{...this.props} />);
|
||||||
))}
|
}
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
{this.isContractOverviewOpen() &&
|
{this.isContractOverviewOpen() &&
|
||||||
<Col xs={6} md={3}>
|
<Col xs={6} md={3}>
|
||||||
|
@ -322,9 +331,13 @@ class ContractsDeployment extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ContractsDeployment.propTypes = {
|
ContractsDeployment.propTypes = {
|
||||||
contracts: PropTypes.array,
|
contracts: PropTypes.array,
|
||||||
deploymentPipeline: PropTypes.string,
|
deploymentPipeline: PropTypes.oneOfType([
|
||||||
|
PropTypes.object,
|
||||||
|
PropTypes.string
|
||||||
|
]),
|
||||||
updateDeploymentPipeline: PropTypes.func,
|
updateDeploymentPipeline: PropTypes.func,
|
||||||
web3Deployments: PropTypes.object,
|
web3Deployments: PropTypes.object,
|
||||||
web3GasEstimates: PropTypes.object,
|
web3GasEstimates: PropTypes.object,
|
||||||
|
|
|
@ -21,7 +21,8 @@ const style = (theme) => ({
|
||||||
top: 0,
|
top: 0,
|
||||||
bottom: '40px',
|
bottom: '40px',
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0
|
right: 0,
|
||||||
|
minWidth: '175px'
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
base: {
|
base: {
|
||||||
|
@ -214,7 +215,7 @@ class FileExplorer extends React.Component {
|
||||||
style={style(this.props.theme)}
|
style={style(this.props.theme)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Label className="hidden-toogle mb-0 pt-2 pr-2 pb-1 border-top text-right">
|
<Label className="hidden-toggle mb-0 pt-2 pr-2 pb-1 border-top text-right">
|
||||||
<span className="mr-2 align-top" style={{"fontSize": "12px"}}>Show hidden files</span>
|
<span className="mr-2 align-top" style={{"fontSize": "12px"}}>Show hidden files</span>
|
||||||
<AppSwitch color="success" variant="pill" size="sm" onChange={this.props.toggleShowHiddenFiles}/>
|
<AppSwitch color="success" variant="pill" size="sm" onChange={this.props.toggleShowHiddenFiles}/>
|
||||||
</Label>
|
</Label>
|
||||||
|
|
|
@ -47,8 +47,11 @@ class Login extends React.Component {
|
||||||
name="token"
|
name="token"
|
||||||
placeholder="Enter token"
|
placeholder="Enter token"
|
||||||
onChange={(e) => this.handleChange(e)}
|
onChange={(e) => this.handleChange(e)}
|
||||||
|
autoComplete="off"
|
||||||
value={this.state.token}/>
|
value={this.state.token}/>
|
||||||
<small className="form-text text-muted">Execute <code>embark run</code> in the command line to get your token.</small>
|
<small className="form-text text-muted">Execute <code>embark run</code> in the command line to get
|
||||||
|
your token.
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" className="btn btn-pill btn-dark">Enter Cockpit</button>
|
<button type="submit" className="btn btn-pill btn-dark">Enter Cockpit</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -46,6 +46,10 @@ class TextEditor extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener("resize", this.handleResize);
|
||||||
|
}
|
||||||
|
|
||||||
handleResize = () => editor.layout();
|
handleResize = () => editor.layout();
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,6 +138,10 @@ class TextEditor extends React.Component {
|
||||||
this.handleResize();
|
this.handleResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addEditorTabs(e, file) {
|
||||||
|
e.preventDefault(); this.props.addEditorTabs(file);
|
||||||
|
}
|
||||||
|
|
||||||
renderTabs() {
|
renderTabs() {
|
||||||
return (
|
return (
|
||||||
<ul className="list-inline m-0 p-0">
|
<ul className="list-inline m-0 p-0">
|
||||||
|
@ -144,7 +152,7 @@ class TextEditor extends React.Component {
|
||||||
})}>
|
})}>
|
||||||
<a
|
<a
|
||||||
href="#switch-tab"
|
href="#switch-tab"
|
||||||
onClick={() => this.props.addEditorTabs(file)}
|
onClick={(e) => this.addEditorTabs(e, file)}
|
||||||
className="p-2 text-muted"
|
className="p-2 text-muted"
|
||||||
>
|
>
|
||||||
{file.name}
|
{file.name}
|
||||||
|
|
|
@ -4,12 +4,12 @@ import {Button, Nav, NavLink} from 'reactstrap';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import FontAwesomeIcon from 'react-fontawesome';
|
import FontAwesomeIcon from 'react-fontawesome';
|
||||||
|
|
||||||
const TextEditorToolbarTabs = {
|
export const TextEditorToolbarTabs = {
|
||||||
Overview: 'overview',
|
Interact: { label: 'Interact', icon: 'bolt' },
|
||||||
Detail: 'detail',
|
Details: { label: 'Details', icon: 'info-circle' },
|
||||||
Transactions: 'transactions',
|
Debugger: { label: 'Debugger', icon: 'bug' },
|
||||||
Debugger: 'debugger',
|
Transactions: { label: 'Transactions', icon: 'list-alt' },
|
||||||
Browser: 'browser'
|
Browser: { label: 'Browser', icon: 'eye' }
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextEditorToolbar extends Component {
|
class TextEditorToolbar extends Component {
|
||||||
|
@ -18,6 +18,18 @@ class TextEditorToolbar extends Component {
|
||||||
return this.props.activeTab === tab;
|
return this.props.activeTab === tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isBrowserTab(tab) {
|
||||||
|
return tab === TextEditorToolbarTabs.Browser;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTab(tab) {
|
||||||
|
return (
|
||||||
|
<NavLink key={tab.label} className={classnames('btn', { active: this.isActiveTab(tab)})} onClick={() => this.props.openAsideTab(tab)}>
|
||||||
|
<FontAwesomeIcon className="mr-2" name={tab.icon} /> {tab.label}
|
||||||
|
</NavLink>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ol className="breadcrumb mb-0">
|
<ol className="breadcrumb mb-0">
|
||||||
|
@ -33,27 +45,9 @@ class TextEditorToolbar extends Component {
|
||||||
</li>
|
</li>
|
||||||
<li className="breadcrumb-menu">
|
<li className="breadcrumb-menu">
|
||||||
<Nav className="btn-group">
|
<Nav className="btn-group">
|
||||||
{this.props.isContract &&
|
{this.props.isContract && Object.values(TextEditorToolbarTabs).map(tab => !this.isBrowserTab(tab) && this.renderTab(tab))}
|
||||||
<React.Fragment>
|
{this.renderTab(TextEditorToolbarTabs.Browser)}
|
||||||
<NavLink className={classnames('btn', { active: this.isActiveTab(TextEditorToolbarTabs.Overview)})} onClick={() => this.props.openAsideTab(TextEditorToolbarTabs.Overview)}>
|
|
||||||
<FontAwesomeIcon className="mr-2" name="bolt" />Interact
|
|
||||||
</NavLink>
|
|
||||||
<NavLink className={classnames('btn', { active: this.isActiveTab(TextEditorToolbarTabs.Detail)})} href="#" onClick={() => this.props.openAsideTab(TextEditorToolbarTabs.Detail)}>
|
|
||||||
<FontAwesomeIcon className="mr-2" name="info-circle" />Details
|
|
||||||
</NavLink>
|
|
||||||
<NavLink className={classnames('btn', { active: this.isActiveTab(TextEditorToolbarTabs.Transactions)})} href="#" onClick={() => this.props.openAsideTab(TextEditorToolbarTabs.Transactions)}>
|
|
||||||
<FontAwesomeIcon className="mr-2" name="list-alt" />Transactions
|
|
||||||
</NavLink>
|
|
||||||
<NavLink className={classnames('btn', { active: this.isActiveTab(TextEditorToolbarTabs.Debugger)})} href="#" onClick={() => this.props.openAsideTab(TextEditorToolbarTabs.Debugger)}>
|
|
||||||
<FontAwesomeIcon className="mr-2" name="bug" />Debugger
|
|
||||||
</NavLink>
|
|
||||||
</React.Fragment>
|
|
||||||
}
|
|
||||||
<NavLink className={classnames('btn', { active: this.isActiveTab(TextEditorToolbarTabs.Browser)})} href="#" onClick={() => this.props.openAsideTab(TextEditorToolbarTabs.Browser)}>
|
|
||||||
<FontAwesomeIcon className="mr-2" name="eye" /> Preview
|
|
||||||
</NavLink>
|
|
||||||
</Nav>
|
</Nav>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
);
|
);
|
||||||
|
@ -66,7 +60,7 @@ TextEditorToolbar.propTypes = {
|
||||||
remove: PropTypes.func,
|
remove: PropTypes.func,
|
||||||
toggleShowHiddenFiles: PropTypes.func,
|
toggleShowHiddenFiles: PropTypes.func,
|
||||||
openAsideTab: PropTypes.func,
|
openAsideTab: PropTypes.func,
|
||||||
activeTab: PropTypes.string
|
activeTab: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TextEditorToolbar;
|
export default TextEditorToolbar;
|
||||||
|
|
|
@ -8,3 +8,7 @@ export const DEPLOYMENT_PIPELINES = {
|
||||||
embark: 'embark'
|
embark: 'embark'
|
||||||
};
|
};
|
||||||
export const DEFAULT_HOST = process.env.NODE_ENV === 'development' ? 'localhost:8000' : window.location.host;
|
export const DEFAULT_HOST = process.env.NODE_ENV === 'development' ? 'localhost:8000' : window.location.host;
|
||||||
|
export const OPERATIONS = {
|
||||||
|
MORE: 1,
|
||||||
|
LESS: -1
|
||||||
|
};
|
||||||
|
|
|
@ -46,7 +46,10 @@ function mapStateToProps(state) {
|
||||||
|
|
||||||
DeploymentContainer.propTypes = {
|
DeploymentContainer.propTypes = {
|
||||||
contracts: PropTypes.array,
|
contracts: PropTypes.array,
|
||||||
deploymentPipeline: PropTypes.object,
|
deploymentPipeline: PropTypes.oneOfType([
|
||||||
|
PropTypes.object,
|
||||||
|
PropTypes.string
|
||||||
|
]),
|
||||||
fetchContracts: PropTypes.func,
|
fetchContracts: PropTypes.func,
|
||||||
updateDeploymentPipeline: PropTypes.func,
|
updateDeploymentPipeline: PropTypes.func,
|
||||||
web3: PropTypes.object,
|
web3: PropTypes.object,
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
margin-top: -1.5rem !important;
|
margin-top: -1.5rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden-toogle {
|
.hidden-toggle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-editor__debuggerLine {
|
.text-editor__debuggerLine {
|
||||||
|
@ -34,8 +35,12 @@
|
||||||
.editor-aside {
|
.editor-aside {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.aside-opened .text-editor-container {
|
.resizer-handle {
|
||||||
max-height: 500px;
|
width: 15px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resize-handle-horizontal {
|
||||||
|
height: 15px !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,47 @@ import TextEditorToolbarContainer from './TextEditorToolbarContainer';
|
||||||
import {fetchEditorTabs as fetchEditorTabsAction} from '../actions';
|
import {fetchEditorTabs as fetchEditorTabsAction} from '../actions';
|
||||||
import {getCurrentFile} from '../reducers/selectors';
|
import {getCurrentFile} from '../reducers/selectors';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import Resizable from 're-resizable';
|
||||||
|
import {OPERATIONS} from '../constants';
|
||||||
|
|
||||||
import './EditorContainer.css';
|
import './EditorContainer.css';
|
||||||
|
|
||||||
class EditorContainer extends React.Component {
|
class EditorContainer extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {currentAsideTab: '', showHiddenFiles: false, currentFile: this.props.currentFile};
|
this.DEFAULT_EDITOR_WIDTH = 85;
|
||||||
|
this.DEFAULT_EDITOR_WIDTH_SMALL = 75;
|
||||||
|
this.DEFAULT_HEIGHT = 500;
|
||||||
|
this.SMALL_SIZE = 768;
|
||||||
|
this.windowWidth = window.innerWidth;
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
currentAsideTab: {}, showHiddenFiles: false, currentFile: this.props.currentFile,
|
||||||
|
editorHeight: this.DEFAULT_HEIGHT,
|
||||||
|
editorWidth: ((this.windowWidth < this.SMALL_SIZE) ? this.DEFAULT_EDITOR_WIDTH_SMALL : this.DEFAULT_EDITOR_WIDTH) + '%',
|
||||||
|
asideHeight: '100%', asideWidth: '25%',
|
||||||
|
isSmallSize: (this.windowWidth < this.SMALL_SIZE)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchEditorTabs();
|
this.props.fetchEditorTabs();
|
||||||
|
window.addEventListener("resize", this.updateDimensions.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener("resize", this.updateDimensions.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDimensions() {
|
||||||
|
this.windowWidth = window.innerWidth;
|
||||||
|
|
||||||
|
const isSmallSize = (this.windowWidth < this.SMALL_SIZE);
|
||||||
|
if (this.state.isSmallSize !== isSmallSize) {
|
||||||
|
this.setState({isSmallSize});
|
||||||
|
this.changeEditorWidth(isSmallSize ? OPERATIONS.MORE : OPERATIONS.LESS);
|
||||||
|
this.editor.handleResize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
|
@ -43,38 +73,116 @@ class EditorContainer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
openAsideTab(newTab) {
|
openAsideTab(newTab) {
|
||||||
if (newTab === this.state.currentAsideTab) {
|
if (!this.state.isSmallSize) {
|
||||||
return this.setState({currentAsideTab: ''});
|
this.changeEditorWidth((!this.state.currentAsideTab.label) ? OPERATIONS.LESS : OPERATIONS.MORE);
|
||||||
}
|
}
|
||||||
|
if (newTab.label === this.state.currentAsideTab.label) {
|
||||||
|
this.editor.handleResize();
|
||||||
|
return this.setState({currentAsideTab: {}});
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({currentAsideTab: newTab});
|
this.setState({currentAsideTab: newTab});
|
||||||
}
|
}
|
||||||
|
|
||||||
textEditorMdSize() {
|
changeEditorWidth(operation) {
|
||||||
return this.state.currentAsideTab.length ? 7 : 10;
|
this.setState({
|
||||||
|
editorWidth: (parseFloat(this.state.editorWidth) + (operation * parseFloat(this.state.asideWidth))) + '%'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTextEditor() {
|
||||||
|
const height = !!(this.state.isSmallSize && this.state.currentAsideTab.label) ? this.state.editorHeight : 'auto';
|
||||||
|
return (
|
||||||
|
<Resizable
|
||||||
|
size={{width: this.state.editorWidth, height: height}}
|
||||||
|
minWidth="20%" maxWidth="90%"
|
||||||
|
handleClasses={{left: 'resizer-handle', right: 'resizer-handle', bottom: 'resize-handle-horizontal'}}
|
||||||
|
onResizeStop={(e, direction, ref, d) => {
|
||||||
|
this.setState({
|
||||||
|
editorWidth: ref.style.width,
|
||||||
|
editorHeight: this.state.editorHeight + d.height
|
||||||
|
});
|
||||||
|
this.editor.handleResize();
|
||||||
|
}}
|
||||||
|
className="text-editor-container border-left"
|
||||||
|
enable={{
|
||||||
|
top: false,
|
||||||
|
right: false,
|
||||||
|
bottom: !!(this.state.isSmallSize && this.state.currentAsideTab.label),
|
||||||
|
left: true,
|
||||||
|
topRight: false,
|
||||||
|
bottomRight: false,
|
||||||
|
bottomLeft: false,
|
||||||
|
topLeft: false
|
||||||
|
}}>
|
||||||
|
<TextEditorContainer
|
||||||
|
ref={instance => {
|
||||||
|
this.editor = instance ? instance.getWrappedInstance().editor : null;
|
||||||
|
}}
|
||||||
|
currentFile={this.props.currentFile}
|
||||||
|
onFileContentChange={(newContent) => this.onFileContentChange(newContent)}/>
|
||||||
|
</Resizable>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAside() {
|
||||||
|
const aside = (
|
||||||
|
<div className="editor-aside">
|
||||||
|
<TextEditorAsideContainer currentAsideTab={this.state.currentAsideTab}
|
||||||
|
currentFile={this.props.currentFile}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.windowWidth < this.SMALL_SIZE) {
|
||||||
|
return (<Col sm={12} className="border-left-0 relative">
|
||||||
|
{aside}
|
||||||
|
</Col>);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Resizable defaultSize={{width: this.state.asideWidth, height: 'auto'}}
|
||||||
|
maxWidth='60%' minWidth='17%'
|
||||||
|
handleClasses={{left: 'resizer-handle', right: 'resizer-handle'}}
|
||||||
|
className="border-left-0 relative"
|
||||||
|
enable={{
|
||||||
|
top: false,
|
||||||
|
right: false,
|
||||||
|
bottom: false,
|
||||||
|
left: true,
|
||||||
|
topRight: false,
|
||||||
|
bottomRight: false,
|
||||||
|
bottomLeft: false,
|
||||||
|
topLeft: false
|
||||||
|
}}
|
||||||
|
onResize={(e, direction, ref, _d) => {
|
||||||
|
this.setState({
|
||||||
|
editorWidth: this.DEFAULT_EDITOR_WIDTH - parseFloat(ref.style.width) + '%'
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
{aside}
|
||||||
|
</Resizable>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Row noGutters className={classnames('h-100', 'editor--grid', {'aside-opened': this.state.currentAsideTab.length})}>
|
<Row noGutters
|
||||||
|
className={classnames('h-100', 'editor--grid', {'aside-opened': this.state.currentAsideTab.label})}>
|
||||||
<Col xs={12}>
|
<Col xs={12}>
|
||||||
<TextEditorToolbarContainer openAsideTab={(newTab) => this.openAsideTab(newTab)}
|
<TextEditorToolbarContainer openAsideTab={(newTab) => this.openAsideTab(newTab)}
|
||||||
isContract={this.isContract()}
|
isContract={this.isContract()}
|
||||||
currentFile={this.props.currentFile}
|
currentFile={this.props.currentFile}
|
||||||
activeTab={this.state.currentAsideTab}/>
|
activeTab={this.state.currentAsideTab}/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col sm={4} md={2} xl={2} lg={2} className="border-right">
|
|
||||||
<FileExplorerContainer showHiddenFiles={this.state.showHiddenFiles} toggleShowHiddenFiles={() => this.toggleShowHiddenFiles()} />
|
<Col className="border-right">
|
||||||
|
<FileExplorerContainer showHiddenFiles={this.state.showHiddenFiles}
|
||||||
|
toggleShowHiddenFiles={() => this.toggleShowHiddenFiles()}/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col sm={8} md={this.textEditorMdSize()} className="text-editor-container">
|
|
||||||
<TextEditorContainer currentFile={this.props.currentFile} onFileContentChange={(newContent) => this.onFileContentChange(newContent)} />
|
{this.renderTextEditor()}
|
||||||
</Col>
|
|
||||||
{this.state.currentAsideTab &&
|
{this.state.currentAsideTab.label && this.renderAside()}
|
||||||
<Col sm={12} md={3} className="border-left-0 relative">
|
|
||||||
<div className="editor-aside">
|
|
||||||
<TextEditorAsideContainer currentAsideTab={this.state.currentAsideTab}
|
|
||||||
currentFile={this.props.currentFile}/>
|
|
||||||
</div>
|
|
||||||
</Col>}
|
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -95,6 +203,6 @@ EditorContainer.propTypes = {
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
{fetchEditorTabs: fetchEditorTabsAction.request},
|
{fetchEditorTabs: fetchEditorTabsAction.request}
|
||||||
)(EditorContainer);
|
)(EditorContainer);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import ContractDetail from '../components/ContractDetail';
|
||||||
import ContractTransactionsContainer from './ContractTransactionsContainer';
|
import ContractTransactionsContainer from './ContractTransactionsContainer';
|
||||||
import ContractOverviewContainer from '../containers/ContractOverviewContainer';
|
import ContractOverviewContainer from '../containers/ContractOverviewContainer';
|
||||||
import ContractDebuggerContainer from '../containers/ContractDebuggerContainer';
|
import ContractDebuggerContainer from '../containers/ContractDebuggerContainer';
|
||||||
|
import { TextEditorToolbarTabs } from '../components/TextEditorToolbar';
|
||||||
|
|
||||||
class TextEditorAsideContainer extends Component {
|
class TextEditorAsideContainer extends Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -17,29 +18,29 @@ class TextEditorAsideContainer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderContent(contract, index) {
|
renderContent(contract, index) {
|
||||||
switch (this.props.currentAsideTab) {
|
switch (this.props.currentAsideTab.label) {
|
||||||
case 'debugger':
|
case TextEditorToolbarTabs.Debugger.label:
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<h2>{contract.className} - Debugger</h2>
|
<h2>{contract.className} - Debugger</h2>
|
||||||
<ContractDebuggerContainer key={index} contract={contract}/>
|
<ContractDebuggerContainer key={index} contract={contract}/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
case 'detail':
|
case TextEditorToolbarTabs.Details.label:
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<h2>{contract.className} - Details</h2>
|
<h2>{contract.className} - Details</h2>
|
||||||
<ContractDetail key={index} contract={contract}/>
|
<ContractDetail key={index} contract={contract}/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
case 'transactions':
|
case TextEditorToolbarTabs.Transactions.label:
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<h2>{contract.className} - Transactions</h2>
|
<h2>{contract.className} - Transactions</h2>
|
||||||
<ContractTransactionsContainer key={index} contract={contract}/>
|
<ContractTransactionsContainer key={index} contract={contract}/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
case 'overview':
|
case TextEditorToolbarTabs.Interact.label:
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<h2>{contract.className} - Interact</h2>
|
<h2>{contract.className} - Interact</h2>
|
||||||
|
@ -52,7 +53,7 @@ class TextEditorAsideContainer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.props.currentAsideTab === 'browser') {
|
if (this.props.currentAsideTab.label === TextEditorToolbarTabs.Browser.label) {
|
||||||
return <Preview/>;
|
return <Preview/>;
|
||||||
}
|
}
|
||||||
return this.props.contracts.map((contract, index) => {
|
return this.props.contracts.map((contract, index) => {
|
||||||
|
@ -75,7 +76,7 @@ function mapStateToProps(state, props) {
|
||||||
|
|
||||||
TextEditorAsideContainer.propTypes = {
|
TextEditorAsideContainer.propTypes = {
|
||||||
currentFile: PropTypes.object,
|
currentFile: PropTypes.object,
|
||||||
currentAsideTab: PropTypes.string,
|
currentAsideTab: PropTypes.object,
|
||||||
contract: PropTypes.array,
|
contract: PropTypes.array,
|
||||||
fetchContracts: PropTypes.func,
|
fetchContracts: PropTypes.func,
|
||||||
contracts: PropTypes.array
|
contracts: PropTypes.array
|
||||||
|
|
|
@ -27,7 +27,10 @@ class TextEditorContainer extends React.Component {
|
||||||
addEditorTabs={this.props.addEditorTabs}
|
addEditorTabs={this.props.addEditorTabs}
|
||||||
debuggerLine={this.props.debuggerLine}
|
debuggerLine={this.props.debuggerLine}
|
||||||
onFileContentChange={this.props.onFileContentChange}
|
onFileContentChange={this.props.onFileContentChange}
|
||||||
theme={this.props.theme} />
|
theme={this.props.theme}
|
||||||
|
ref={instance => {
|
||||||
|
if (instance) this.editor = instance;
|
||||||
|
}}/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +48,7 @@ TextEditorContainer.propTypes = {
|
||||||
onFileContentChange: PropTypes.func,
|
onFileContentChange: PropTypes.func,
|
||||||
toggleBreakpoints: PropTypes.func,
|
toggleBreakpoints: PropTypes.func,
|
||||||
breakpoints: PropTypes.array,
|
breakpoints: PropTypes.array,
|
||||||
toggleBreakpoint: PropTypes.object,
|
toggleBreakpoint: PropTypes.func,
|
||||||
fetchEditorTabs: PropTypes.func,
|
fetchEditorTabs: PropTypes.func,
|
||||||
removeEditorTabs: PropTypes.func,
|
removeEditorTabs: PropTypes.func,
|
||||||
addEditorTabs: PropTypes.func,
|
addEditorTabs: PropTypes.func,
|
||||||
|
@ -57,9 +60,11 @@ TextEditorContainer.propTypes = {
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
{
|
{
|
||||||
toggleBreakpoint,
|
toggleBreakpoint: toggleBreakpoint.request,
|
||||||
fetchEditorTabs: fetchEditorTabsAction.request,
|
fetchEditorTabs: fetchEditorTabsAction.request,
|
||||||
removeEditorTabs: removeEditorTabsAction.request,
|
removeEditorTabs: removeEditorTabsAction.request,
|
||||||
addEditorTabs: addEditorTabsAction.request
|
addEditorTabs: addEditorTabsAction.request
|
||||||
},
|
},
|
||||||
|
null,
|
||||||
|
{ withRef: true }
|
||||||
)(TextEditorContainer);
|
)(TextEditorContainer);
|
||||||
|
|
|
@ -34,7 +34,7 @@ TextEditorToolbarContainer.propTypes = {
|
||||||
removeFile: PropTypes.func,
|
removeFile: PropTypes.func,
|
||||||
toggleShowHiddenFiles: PropTypes.func,
|
toggleShowHiddenFiles: PropTypes.func,
|
||||||
openAsideTab: PropTypes.func,
|
openAsideTab: PropTypes.func,
|
||||||
activeTab: PropTypes.string
|
activeTab: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -153,6 +153,10 @@ export function getEnsRecords(state) {
|
||||||
return state.entities.ensRecords;
|
return state.entities.ensRecords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getEnsRecordForName(state, name) {
|
||||||
|
return state.entities.ensRecords.find((record) => record.name === name);
|
||||||
|
}
|
||||||
|
|
||||||
export function getEnsErrors(state) {
|
export function getEnsErrors(state) {
|
||||||
return state.errorEntities.ensRecords;
|
return state.errorEntities.ensRecords;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,28 @@
|
||||||
import {put, select} from "redux-saga/effects";
|
import {put, select} from "redux-saga/effects";
|
||||||
import {getAccounts, getBlocks, getTransactions, getContracts} from "../reducers/selectors";
|
import {getAccounts, getBlocks, getTransactions, getContracts, getEnsRecordForName} from "../reducers/selectors";
|
||||||
import {fetchAccounts, fetchBlocks, fetchTransactions, fetchContracts} from "./index";
|
import {fetchAccounts, fetchBlocks, fetchTransactions, fetchContracts, fetchEnsRecord} from "./index";
|
||||||
import {ELEMENTS_LIMIT} from '../constants';
|
import {ELEMENTS_LIMIT} from '../constants';
|
||||||
|
|
||||||
export function *searchExplorer(entity, payload) {
|
export function *searchExplorer(entity, payload) {
|
||||||
let result;
|
let result;
|
||||||
|
let searchValue = payload.searchValue;
|
||||||
|
let isENSName = false;
|
||||||
|
if (searchValue.endsWith('.eth')) {
|
||||||
|
isENSName = true;
|
||||||
|
yield fetchEnsRecord({name: payload.searchValue});
|
||||||
|
const ensRecord = yield select(getEnsRecordForName, searchValue);
|
||||||
|
|
||||||
|
if (!ensRecord) {
|
||||||
|
return yield put(entity.success({error: 'No ENS record for that name'}));
|
||||||
|
}
|
||||||
|
searchValue = ensRecord.address;
|
||||||
|
}
|
||||||
|
|
||||||
// Accounts
|
// Accounts
|
||||||
yield fetchAccounts({});
|
yield fetchAccounts({});
|
||||||
const accounts = yield select(getAccounts);
|
const accounts = yield select(getAccounts);
|
||||||
result = accounts.find(account => {
|
result = accounts.find(account => {
|
||||||
return account.address === payload.searchValue;
|
return account.address === searchValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -21,7 +33,7 @@ export function *searchExplorer(entity, payload) {
|
||||||
yield fetchContracts({});
|
yield fetchContracts({});
|
||||||
const contracts = yield select(getContracts);
|
const contracts = yield select(getContracts);
|
||||||
result = contracts.find(contract => {
|
result = contracts.find(contract => {
|
||||||
return contract.address === payload.searchValue;
|
return contract.address === searchValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -31,9 +43,9 @@ export function *searchExplorer(entity, payload) {
|
||||||
// Blocks
|
// Blocks
|
||||||
yield fetchBlocks({limit: ELEMENTS_LIMIT});
|
yield fetchBlocks({limit: ELEMENTS_LIMIT});
|
||||||
const blocks = yield select(getBlocks);
|
const blocks = yield select(getBlocks);
|
||||||
const intSearchValue = parseInt(payload.searchValue, 10);
|
const intSearchValue = parseInt(searchValue, 10);
|
||||||
result = blocks.find(block => {
|
result = blocks.find(block => {
|
||||||
return block.hash === payload.searchValue || block.number === intSearchValue;
|
return block.hash === searchValue || block.number === intSearchValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -44,12 +56,16 @@ export function *searchExplorer(entity, payload) {
|
||||||
yield fetchTransactions({blockLimit: ELEMENTS_LIMIT});
|
yield fetchTransactions({blockLimit: ELEMENTS_LIMIT});
|
||||||
const transactions = yield select(getTransactions);
|
const transactions = yield select(getTransactions);
|
||||||
result = transactions.find(transaction => {
|
result = transactions.find(transaction => {
|
||||||
return transaction.hash === payload.searchValue;
|
return transaction.hash === searchValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
return yield put(entity.success(result));
|
return yield put(entity.success(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isENSName) {
|
||||||
|
return yield put(entity.success({error: `ENS resolved to ${searchValue}, but Embark couldn't find what this address represents`}));
|
||||||
|
}
|
||||||
|
|
||||||
return yield put(entity.success({error: `No result found in transactions, accounts, contracts, or blocks. Please note: We limit the search to the last ${ELEMENTS_LIMIT} elements for performance`}));
|
return yield put(entity.success({error: `No result found in transactions, accounts, contracts, or blocks. Please note: We limit the search to the last ${ELEMENTS_LIMIT} elements for performance`}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,5 +60,6 @@
|
||||||
"deploymentStrategy": {
|
"deploymentStrategy": {
|
||||||
"implicit": "implicit",
|
"implicit": "implicit",
|
||||||
"explicit": "explicit"
|
"explicit": "explicit"
|
||||||
}
|
},
|
||||||
|
"embarkResourceOrigin": "http://embark"
|
||||||
}
|
}
|
|
@ -148,10 +148,8 @@ Config.prototype._updateBlockchainCors = function(){
|
||||||
corsParts.push(utils.buildUrlFromConfig(storageConfig.upload));
|
corsParts.push(utils.buildUrlFromConfig(storageConfig.upload));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// add whisper cors
|
// Add cors for the proxy and whisper
|
||||||
if(this.communicationConfig && this.communicationConfig.enabled && this.communicationConfig.provider === 'whisper'){
|
corsParts.push(constants.embarkResourceOrigin);
|
||||||
corsParts.push('http://embark');
|
|
||||||
}
|
|
||||||
|
|
||||||
let cors = corsParts.join(',');
|
let cors = corsParts.join(',');
|
||||||
if(blockchainConfig.rpcCorsDomain === 'auto'){
|
if(blockchainConfig.rpcCorsDomain === 'auto'){
|
||||||
|
@ -208,7 +206,8 @@ Config.prototype.loadBlockchainConfigFile = function() {
|
||||||
"default": {
|
"default": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rpcCorsDomain": "auto",
|
"rpcCorsDomain": "auto",
|
||||||
"wsOrigins": "auto"
|
"wsOrigins": "auto",
|
||||||
|
"proxy": true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const AccountParser = require('../../utils/accountParser');
|
const AccountParser = require('../../utils/accountParser');
|
||||||
const fundAccount = require('./fundAccount');
|
const fundAccount = require('./fundAccount');
|
||||||
|
const constants = require('../../constants');
|
||||||
|
|
||||||
class Provider {
|
class Provider {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
@ -21,10 +22,10 @@ class Provider {
|
||||||
} else if (this.type === 'ws') {
|
} else if (this.type === 'ws') {
|
||||||
// Note: don't pass to the provider things like {headers: {Origin: "embark"}}. Origin header is for browser to fill
|
// Note: don't pass to the provider things like {headers: {Origin: "embark"}}. Origin header is for browser to fill
|
||||||
// to protect user, it has no meaning if it is used server-side. See here for more details: https://github.com/ethereum/go-ethereum/issues/16608
|
// to protect user, it has no meaning if it is used server-side. See here for more details: https://github.com/ethereum/go-ethereum/issues/16608
|
||||||
// Moreover, Parity reject origins that are not urls so if you try to connect with Origin: "embark" it gives the followin error:
|
// Moreover, Parity reject origins that are not urls so if you try to connect with Origin: "embark" it gives the following error:
|
||||||
// << Blocked connection to WebSockets server from untrusted origin: Some("embark") >>
|
// << Blocked connection to WebSockets server from untrusted origin: Some("embark") >>
|
||||||
// The best choice is to use void origin, BUT Geth rejects void origin, so to keep both clients happy we can use http://embark
|
// The best choice is to use void origin, BUT Geth rejects void origin, so to keep both clients happy we can use http://embark
|
||||||
self.provider = new this.web3.providers.WebsocketProvider(self.web3Endpoint, {headers: {Origin: "http://embark"}});
|
self.provider = new this.web3.providers.WebsocketProvider(self.web3Endpoint, {headers: {Origin: constants.embarkResourceOrigin}});
|
||||||
|
|
||||||
self.provider.on('error', () => self.logger.error('Websocket Error'));
|
self.provider.on('error', () => self.logger.error('Websocket Error'));
|
||||||
self.provider.on('end', () => self.logger.error('Websocket connection ended'));
|
self.provider.on('end', () => self.logger.error('Websocket connection ended'));
|
||||||
|
|
|
@ -12,7 +12,7 @@ const Ipc = require('../../core/ipc');
|
||||||
const {defaultHost, dockerHostSwap} = require('../../utils/host');
|
const {defaultHost, dockerHostSwap} = require('../../utils/host');
|
||||||
const Logger = require('../../core/logger');
|
const Logger = require('../../core/logger');
|
||||||
|
|
||||||
// time between IPC connection attmpts (in ms)
|
// time between IPC connection attempts (in ms)
|
||||||
const IPC_CONNECT_INTERVAL = 2000;
|
const IPC_CONNECT_INTERVAL = 2000;
|
||||||
|
|
||||||
/*eslint complexity: ["error", 42]*/
|
/*eslint complexity: ["error", 42]*/
|
||||||
|
@ -60,7 +60,7 @@ var Blockchain = function(userConfig, clientClass) {
|
||||||
targetGasLimit: this.userConfig.targetGasLimit || false,
|
targetGasLimit: this.userConfig.targetGasLimit || false,
|
||||||
syncMode: this.userConfig.syncMode || this.userConfig.syncmode,
|
syncMode: this.userConfig.syncMode || this.userConfig.syncmode,
|
||||||
verbosity: this.userConfig.verbosity,
|
verbosity: this.userConfig.verbosity,
|
||||||
proxy: this.userConfig.proxy || true
|
proxy: this.userConfig.proxy
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.userConfig === {} || this.userConfig.default || JSON.stringify(this.userConfig) === '{"enabled":true}') {
|
if (this.userConfig === {} || this.userConfig.default || JSON.stringify(this.userConfig) === '{"enabled":true}') {
|
||||||
|
|
|
@ -2,6 +2,7 @@ const async = require('async');
|
||||||
const Web3 = require('web3');
|
const Web3 = require('web3');
|
||||||
const {buildUrl} = require('../../utils/utils.js');
|
const {buildUrl} = require('../../utils/utils.js');
|
||||||
const {readFileSync, dappPath} = require('../../core/fs');
|
const {readFileSync, dappPath} = require('../../core/fs');
|
||||||
|
const constants = require('../../constants');
|
||||||
|
|
||||||
class DevFunds {
|
class DevFunds {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
@ -11,7 +12,7 @@ class DevFunds {
|
||||||
this.password = this.blockchainConfig.account.password ? readFileSync(dappPath(this.blockchainConfig.account.password), 'utf8').replace('\n', '') : 'dev_password';
|
this.password = this.blockchainConfig.account.password ? readFileSync(dappPath(this.blockchainConfig.account.password), 'utf8').replace('\n', '') : 'dev_password';
|
||||||
this.networkId = null;
|
this.networkId = null;
|
||||||
this.balance = Web3.utils.toWei("1", "ether");
|
this.balance = Web3.utils.toWei("1", "ether");
|
||||||
this.provider = options.provider || new Web3.providers.WebsocketProvider(buildUrl('ws', this.blockchainConfig.wsHost, this.blockchainConfig.wsPort), {headers: {Origin: "http://embark"}});
|
this.provider = options.provider || new Web3.providers.WebsocketProvider(buildUrl('ws', this.blockchainConfig.wsHost, this.blockchainConfig.wsPort), {headers: {Origin: constants.embarkResourceOrigin}});
|
||||||
this.web3 = new Web3(this.provider);
|
this.web3 = new Web3(this.provider);
|
||||||
if (this.blockchainConfig.account.balance) {
|
if (this.blockchainConfig.account.balance) {
|
||||||
this.balance = this.blockchainConfig.account.balance;
|
this.balance = this.blockchainConfig.account.balance;
|
||||||
|
|
|
@ -270,7 +270,7 @@ class ContractsManager {
|
||||||
function getGasPriceForNetwork(callback) {
|
function getGasPriceForNetwork(callback) {
|
||||||
return callback(null, self.contractsConfig.gasPrice);
|
return callback(null, self.contractsConfig.gasPrice);
|
||||||
},
|
},
|
||||||
function prepareContractsFromCompilation(gasPrice, callback) {
|
function prepareContractsForCompilation(gasPrice, callback) {
|
||||||
let className, compiledContract, contractConfig, contract;
|
let className, compiledContract, contractConfig, contract;
|
||||||
for (className in self.compiledContracts) {
|
for (className in self.compiledContracts) {
|
||||||
compiledContract = self.compiledContracts[className];
|
compiledContract = self.compiledContracts[className];
|
||||||
|
|
|
@ -4,6 +4,7 @@ let Web3 = require('web3');
|
||||||
const {parallel} = require('async');
|
const {parallel} = require('async');
|
||||||
const {sendMessage, listenTo} = require('./js/communicationFunctions');
|
const {sendMessage, listenTo} = require('./js/communicationFunctions');
|
||||||
const messageEvents = require('./js/message_events');
|
const messageEvents = require('./js/message_events');
|
||||||
|
const constants = require('../../constants');
|
||||||
|
|
||||||
const {canonicalHost, defaultHost} = require('../../utils/host');
|
const {canonicalHost, defaultHost} = require('../../utils/host');
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ class Whisper {
|
||||||
// Moreover, Parity reject origins that are not urls so if you try to connect with Origin: "embark" it gives the followin error:
|
// Moreover, Parity reject origins that are not urls so if you try to connect with Origin: "embark" it gives the followin error:
|
||||||
// << Blocked connection to WebSockets server from untrusted origin: Some("embark") >>
|
// << Blocked connection to WebSockets server from untrusted origin: Some("embark") >>
|
||||||
// The best choice is to use void origin, BUT Geth rejects void origin, so to keep both clients happy we can use http://embark
|
// The best choice is to use void origin, BUT Geth rejects void origin, so to keep both clients happy we can use http://embark
|
||||||
this.web3.setProvider(new Web3.providers.WebsocketProvider(web3Endpoint, {headers: {Origin: "http://embark"}}));
|
this.web3.setProvider(new Web3.providers.WebsocketProvider(web3Endpoint, {headers: {Origin: constants.embarkResourceOrigin}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForWeb3Ready(cb) {
|
waitForWeb3Ready(cb) {
|
||||||
|
@ -133,7 +134,7 @@ class Whisper {
|
||||||
const code = `\nEmbarkJS.Messages.setProvider('whisper', ${JSON.stringify(config)});`;
|
const code = `\nEmbarkJS.Messages.setProvider('whisper', ${JSON.stringify(config)});`;
|
||||||
this.embark.addProviderInit('communication', code, shouldInit);
|
this.embark.addProviderInit('communication', code, shouldInit);
|
||||||
|
|
||||||
const consoleConfig = Object.assign({}, config, {providerOptions: {headers: {Origin: "http://embark"}}});
|
const consoleConfig = Object.assign({}, config, {providerOptions: {headers: {Origin: constants.embarkResourceOrigin}}});
|
||||||
const consoleCode = `\nEmbarkJS.Messages.setProvider('whisper', ${JSON.stringify(consoleConfig)});`;
|
const consoleCode = `\nEmbarkJS.Messages.setProvider('whisper', ${JSON.stringify(consoleConfig)});`;
|
||||||
this.embark.addConsoleProviderInit('communication', consoleCode, shouldInit);
|
this.embark.addConsoleProviderInit('communication', consoleCode, shouldInit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5163,9 +5163,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"embarkjs": {
|
"embarkjs": {
|
||||||
"version": "0.4.4",
|
"version": "0.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/embarkjs/-/embarkjs-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/embarkjs/-/embarkjs-0.4.5.tgz",
|
||||||
"integrity": "sha512-HIetHNqngbhUgdESZ8V1gQiRzoti7LMu/P5xcfemn+8b4KwasUyrybaBdvqmo+ock9rExXZFHIgaYA+85s9DkA==",
|
"integrity": "sha512-WAW9tlvCiSa6DEC6M+ZfFS9WemE91DunOUP4rn7urtFgOpT0m08dFKB0F+Qfcmonb7cozEPfNv5C78xSt1JUsA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime-corejs2": "7.0.0-rc.1",
|
"@babel/runtime-corejs2": "7.0.0-rc.1",
|
||||||
"async": "2.6.1",
|
"async": "2.6.1",
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
"decompress": "4.2.0",
|
"decompress": "4.2.0",
|
||||||
"deep-equal": "1.0.1",
|
"deep-equal": "1.0.1",
|
||||||
"ejs": "2.6.1",
|
"ejs": "2.6.1",
|
||||||
"embarkjs": "0.4.4",
|
"embarkjs": "0.4.5",
|
||||||
"eth-ens-namehash": "2.0.8",
|
"eth-ens-namehash": "2.0.8",
|
||||||
"eth-lib": "0.2.8",
|
"eth-lib": "0.2.8",
|
||||||
"ethereumjs-wallet": "0.6.0",
|
"ethereumjs-wallet": "0.6.0",
|
||||||
|
|
|
@ -41,12 +41,9 @@ describe('embark.Blockchain', function() {
|
||||||
targetGasLimit: false,
|
targetGasLimit: false,
|
||||||
syncMode: undefined,
|
syncMode: undefined,
|
||||||
verbosity: undefined,
|
verbosity: undefined,
|
||||||
proxy: true,
|
proxy: undefined,
|
||||||
silent: undefined
|
silent: undefined
|
||||||
};
|
};
|
||||||
// We check also proxy's ports because proxy is set to true
|
|
||||||
expectedConfig.wsPort += constants.blockchain.servicePortOnProxy;
|
|
||||||
expectedConfig.rpcPort += constants.blockchain.servicePortOnProxy;
|
|
||||||
|
|
||||||
assert.deepEqual(blockchain.config, expectedConfig);
|
assert.deepEqual(blockchain.config, expectedConfig);
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -25,6 +25,7 @@ describe('embark.Config', function () {
|
||||||
"isDev": false,
|
"isDev": false,
|
||||||
"mineWhenNeeded": true,
|
"mineWhenNeeded": true,
|
||||||
"nodiscover": true,
|
"nodiscover": true,
|
||||||
|
"proxy": true,
|
||||||
"rpcHost": "localhost",
|
"rpcHost": "localhost",
|
||||||
"rpcPort": 8545,
|
"rpcPort": 8545,
|
||||||
"rpcCorsDomain": "http://localhost:8000",
|
"rpcCorsDomain": "http://localhost:8000",
|
||||||
|
@ -48,6 +49,7 @@ describe('embark.Config', function () {
|
||||||
"gasPrice": "8000000",
|
"gasPrice": "8000000",
|
||||||
"mineWhenNeeded": true,
|
"mineWhenNeeded": true,
|
||||||
"nodiscover": true,
|
"nodiscover": true,
|
||||||
|
"proxy": true,
|
||||||
"rpcHost": "localhost",
|
"rpcHost": "localhost",
|
||||||
"rpcPort": 8545,
|
"rpcPort": 8545,
|
||||||
"rpcCorsDomain": "http://localhost:8000",
|
"rpcCorsDomain": "http://localhost:8000",
|
||||||
|
@ -81,6 +83,7 @@ describe('embark.Config', function () {
|
||||||
"gasPrice": "8000000",
|
"gasPrice": "8000000",
|
||||||
"mineWhenNeeded": true,
|
"mineWhenNeeded": true,
|
||||||
"nodiscover": true,
|
"nodiscover": true,
|
||||||
|
"proxy": true,
|
||||||
"rpcHost": "localhost",
|
"rpcHost": "localhost",
|
||||||
"rpcPort": 8545,
|
"rpcPort": 8545,
|
||||||
"rpcCorsDomain": "http://localhost:8000",
|
"rpcCorsDomain": "http://localhost:8000",
|
||||||
|
|
Loading…
Reference in New Issue