mirror of
https://github.com/embarklabs/embark.git
synced 2025-01-11 14:24:24 +00:00
Merge pull request #1041 from embark-framework/feature/debug-button
feat: add debug button to transaction and contract log
This commit is contained in:
commit
13f7a3ff41
@ -7,14 +7,23 @@ import {
|
|||||||
Button
|
Button
|
||||||
} from "reactstrap";
|
} from "reactstrap";
|
||||||
import ReactJson from 'react-json-view';
|
import ReactJson from 'react-json-view';
|
||||||
|
import DebugButton from './DebugButton';
|
||||||
|
|
||||||
class ContractDebugger extends Component {
|
class ContractDebugger extends Component {
|
||||||
handleChange(e) {
|
constructor(props) {
|
||||||
this.setState({txHash: e.target.value});
|
super(props);
|
||||||
|
this.state = {txHash: ''};
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(_e) {
|
componentDidMount() {
|
||||||
this.props.startDebug(this.state.txHash);
|
if (this.props.debuggerTransactionHash) {
|
||||||
|
this.setState({txHash: this.props.debuggerTransactionHash});
|
||||||
|
this.props.startDebug(this.props.debuggerTransactionHash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(e) {
|
||||||
|
this.setState({txHash: e.target.value});
|
||||||
}
|
}
|
||||||
|
|
||||||
debugJumpBack(_e) {
|
debugJumpBack(_e) {
|
||||||
@ -46,8 +55,8 @@ class ContractDebugger extends Component {
|
|||||||
<div>
|
<div>
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<Input name="txHash" id="txHash" onChange={(e) => this.handleChange(e)}/>
|
<Input name="txHash" id="txHash" value={this.state.txHash} onChange={(e) => this.handleChange(e)}/>
|
||||||
<Button color="primary" onClick={(e) => this.debug(e)}>Debug Tx</Button>
|
<DebugButton forceDebuggable transaction={{hash: this.state.txHash}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
@ -74,7 +83,7 @@ class ContractDebugger extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ContractDebugger.propTypes = {
|
ContractDebugger.propTypes = {
|
||||||
contract: PropTypes.object.isRequired,
|
debuggerTransactionHash: PropTypes.string,
|
||||||
startDebug: PropTypes.func,
|
startDebug: PropTypes.func,
|
||||||
debugJumpBack: PropTypes.func,
|
debugJumpBack: PropTypes.func,
|
||||||
debugJumpForward: PropTypes.func,
|
debugJumpForward: PropTypes.func,
|
||||||
|
@ -7,7 +7,6 @@ import classnames from 'classnames';
|
|||||||
import ContractDetail from '../components/ContractDetail';
|
import ContractDetail from '../components/ContractDetail';
|
||||||
import ContractTransactionsContainer from '../containers/ContractTransactionsContainer';
|
import ContractTransactionsContainer from '../containers/ContractTransactionsContainer';
|
||||||
import ContractOverviewContainer from '../containers/ContractOverviewContainer';
|
import ContractOverviewContainer from '../containers/ContractOverviewContainer';
|
||||||
import ContractDebuggerContainer from '../containers/ContractDebuggerContainer';
|
|
||||||
|
|
||||||
class ContractLayout extends React.Component {
|
class ContractLayout extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -57,14 +56,6 @@ class ContractLayout extends React.Component {
|
|||||||
<FontAwesomeIcon className="mr-2" name="list-alt" />Transactions
|
<FontAwesomeIcon className="mr-2" name="list-alt" />Transactions
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</NavItem>
|
</NavItem>
|
||||||
<NavItem>
|
|
||||||
<NavLink
|
|
||||||
className={classnames({ active: this.state.activeTab === '4' })}
|
|
||||||
onClick={() => { this.toggle('4'); }}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon className="mr-2" name="bug" />Debugger
|
|
||||||
</NavLink>
|
|
||||||
</NavItem>
|
|
||||||
</Nav>
|
</Nav>
|
||||||
<TabContent activeTab={this.state.activeTab}>
|
<TabContent activeTab={this.state.activeTab}>
|
||||||
<TabPane tabId="1">
|
<TabPane tabId="1">
|
||||||
@ -76,9 +67,6 @@ class ContractLayout extends React.Component {
|
|||||||
<TabPane tabId="3">
|
<TabPane tabId="3">
|
||||||
<ContractTransactionsContainer contract={this.props.contract} />
|
<ContractTransactionsContainer contract={this.props.contract} />
|
||||||
</TabPane>
|
</TabPane>
|
||||||
<TabPane tabId="4">
|
|
||||||
<ContractDebuggerContainer contract={this.props.contract} />
|
|
||||||
</TabPane>
|
|
||||||
</TabContent>
|
</TabContent>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -2,6 +2,8 @@ import PropTypes from "prop-types";
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Row, Col, Table, FormGroup, Label, Input, Form} from 'reactstrap';
|
import {Row, Col, Table, FormGroup, Label, Input, Form} from 'reactstrap';
|
||||||
|
|
||||||
|
import DebugButton from './DebugButton'
|
||||||
|
|
||||||
const TX_STATES = {Success: '0x1', Fail: '0x0', Any: ''};
|
const TX_STATES = {Success: '0x1', Fail: '0x0', Any: ''};
|
||||||
const EVENT = 'event';
|
const EVENT = 'event';
|
||||||
const FUNCTION = 'function';
|
const FUNCTION = 'function';
|
||||||
@ -107,6 +109,7 @@ class ContractTransactions extends React.Component {
|
|||||||
<Table>
|
<Table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th></th>
|
||||||
<th>Call</th>
|
<th>Call</th>
|
||||||
<th>Events</th>
|
<th>Events</th>
|
||||||
<th>Gas Used</th>
|
<th>Gas Used</th>
|
||||||
@ -120,6 +123,7 @@ class ContractTransactions extends React.Component {
|
|||||||
this.dataToDisplay().map((log, index) => {
|
this.dataToDisplay().map((log, index) => {
|
||||||
return (
|
return (
|
||||||
<tr key={'log-' + index}>
|
<tr key={'log-' + index}>
|
||||||
|
<td><DebugButton forceDebuggable transaction={{hash: log.transactionHash}}/></td>
|
||||||
<td>{`${log.name}.${log.functionName}(${log.paramString})`}</td>
|
<td>{`${log.name}.${log.functionName}(${log.paramString})`}</td>
|
||||||
<td>{log.events.join(', ')}</td>
|
<td>{log.events.join(', ')}</td>
|
||||||
<td>{log.gasUsed}</td>
|
<td>{log.gasUsed}</td>
|
||||||
|
42
embark-ui/src/components/DebugButton.js
Normal file
42
embark-ui/src/components/DebugButton.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {Button} from "reactstrap";
|
||||||
|
import FontAwesome from 'react-fontawesome';
|
||||||
|
import {withRouter} from "react-router-dom";
|
||||||
|
|
||||||
|
class DebugButton extends React.Component {
|
||||||
|
onClick() {
|
||||||
|
this.props.history.push(`/embark/editor?debuggerTransactionHash=${this.props.transaction.hash}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
isDebuggable() {
|
||||||
|
return this.props.forceDebuggable ||
|
||||||
|
(this.props.contracts && this.props.contracts.find(contract => contract.address === this.props.transaction.to));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!this.isDebuggable()) {
|
||||||
|
return <React.Fragment />
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Button color="primary" onClick={() => this.onClick()}>
|
||||||
|
<FontAwesome className="mr-2" name="bug"/>
|
||||||
|
Debug
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugButton.defaultProps = {
|
||||||
|
forceDebuggable: false
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugButton.propTypes = {
|
||||||
|
forceDebuggable: PropTypes.bool,
|
||||||
|
history: PropTypes.object,
|
||||||
|
transaction: PropTypes.object,
|
||||||
|
contracts: PropTypes.arrayOf(PropTypes.object)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withRouter(DebugButton);
|
@ -123,13 +123,14 @@ class TextEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (this.props.currentFile.content !== prevProps.currentFile.content) {
|
const isNewContent = this.props.currentFile.content !== prevProps.currentFile.content;
|
||||||
|
if (isNewContent) {
|
||||||
editor.setValue(this.props.currentFile.content || '');
|
editor.setValue(this.props.currentFile.content || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateMarkers();
|
this.updateMarkers();
|
||||||
const expectedDecorationsLength = this.props.debuggerLine ? this.props.breakpoints.length + 1 : this.props.breakpoints.length;
|
const expectedDecorationsLength = this.props.debuggerLine ? this.props.breakpoints.length + 1 : this.props.breakpoints.length;
|
||||||
if (expectedDecorationsLength !== this.state.decorations.length || this.props.debuggerLine !== prevProps.debuggerLine) {
|
if (expectedDecorationsLength !== this.state.decorations.length || this.props.debuggerLine !== prevProps.debuggerLine || isNewContent) {
|
||||||
this.updateDecorations();
|
this.updateDecorations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,10 @@ class TextEditorToolbar extends Component {
|
|||||||
return tab === TextEditorToolbarTabs.Browser;
|
return tab === TextEditorToolbarTabs.Browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isDebuggerTab(tab) {
|
||||||
|
return tab === TextEditorToolbarTabs.Debugger;
|
||||||
|
}
|
||||||
|
|
||||||
renderTab(tab) {
|
renderTab(tab) {
|
||||||
return (
|
return (
|
||||||
<NavLink key={tab.label} className={classnames('btn', { active: this.isActiveTab(tab)})} onClick={() => this.props.openAsideTab(tab)}>
|
<NavLink key={tab.label} className={classnames('btn', { active: this.isActiveTab(tab)})} onClick={() => this.props.openAsideTab(tab)}>
|
||||||
@ -45,7 +49,8 @@ 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 && Object.values(TextEditorToolbarTabs).map(tab => !this.isBrowserTab(tab) && this.renderTab(tab))}
|
{this.props.isContract && Object.values(TextEditorToolbarTabs).map(tab => !this.isBrowserTab(tab) && !this.isDebuggerTab(tab) && this.renderTab(tab))}
|
||||||
|
{this.renderTab(TextEditorToolbarTabs.Debugger)}
|
||||||
{this.renderTab(TextEditorToolbarTabs.Browser)}
|
{this.renderTab(TextEditorToolbarTabs.Browser)}
|
||||||
</Nav>
|
</Nav>
|
||||||
</li>
|
</li>
|
||||||
|
@ -3,17 +3,23 @@ import {Link} from 'react-router-dom';
|
|||||||
import {Row, Col, Card, CardHeader, CardBody} from 'reactstrap';
|
import {Row, Col, Card, CardHeader, CardBody} from 'reactstrap';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import DebugButton from './DebugButton';
|
||||||
import Description from './Description';
|
import Description from './Description';
|
||||||
import CardTitleIdenticon from './CardTitleIdenticon';
|
import CardTitleIdenticon from './CardTitleIdenticon';
|
||||||
import {utils} from 'web3';
|
import {utils} from 'web3';
|
||||||
|
|
||||||
|
|
||||||
const Transaction = ({transaction}) => (
|
const Transaction = ({transaction, contracts}) => (
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitleIdenticon id={transaction.hash}>Transaction {transaction.hash}</CardTitleIdenticon>
|
<CardTitleIdenticon id={transaction.hash}>
|
||||||
|
Transaction {transaction.hash}
|
||||||
|
<div className="float-right">
|
||||||
|
<DebugButton contracts={contracts} transaction={transaction} />
|
||||||
|
</div>
|
||||||
|
</CardTitleIdenticon>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<dl className="row">
|
<dl className="row">
|
||||||
@ -33,6 +39,7 @@ const Transaction = ({transaction}) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
Transaction.propTypes = {
|
Transaction.propTypes = {
|
||||||
|
contracts: PropTypes.arrayOf(PropTypes.object),
|
||||||
transaction: PropTypes.object
|
transaction: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,10 +3,11 @@ import {Link} from "react-router-dom";
|
|||||||
import {Row, Col, Card, CardHeader, CardBody} from 'reactstrap';
|
import {Row, Col, Card, CardHeader, CardBody} from 'reactstrap';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import DebugButton from './DebugButton';
|
||||||
import CardTitleIdenticon from './CardTitleIdenticon';
|
import CardTitleIdenticon from './CardTitleIdenticon';
|
||||||
import Pagination from "./Pagination";
|
import Pagination from "./Pagination";
|
||||||
|
|
||||||
const Transactions = ({transactions, changePage, currentPage, numberOfPages}) => (
|
const Transactions = ({transactions, contracts, changePage, currentPage, numberOfPages}) => (
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<Card>
|
<Card>
|
||||||
@ -21,6 +22,11 @@ const Transactions = ({transactions, changePage, currentPage, numberOfPages}) =>
|
|||||||
{transaction.hash}
|
{transaction.hash}
|
||||||
</Link>
|
</Link>
|
||||||
</CardTitleIdenticon>
|
</CardTitleIdenticon>
|
||||||
|
<Row>
|
||||||
|
<Col>
|
||||||
|
<DebugButton transaction={transaction} contracts={contracts} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Col md={6}>
|
<Col md={6}>
|
||||||
<strong>Block number</strong>
|
<strong>Block number</strong>
|
||||||
@ -50,6 +56,7 @@ const Transactions = ({transactions, changePage, currentPage, numberOfPages}) =>
|
|||||||
|
|
||||||
Transactions.propTypes = {
|
Transactions.propTypes = {
|
||||||
transactions: PropTypes.arrayOf(PropTypes.object),
|
transactions: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
contracts: PropTypes.arrayOf(PropTypes.object),
|
||||||
changePage: PropTypes.func,
|
changePage: PropTypes.func,
|
||||||
currentPage: PropTypes.number,
|
currentPage: PropTypes.number,
|
||||||
numberOfPages: PropTypes.number
|
numberOfPages: PropTypes.number
|
||||||
|
@ -1,42 +1,43 @@
|
|||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {startDebug, debugJumpBack, debugJumpForward, debugStepOverForward, debugStepOverBackward, debugStepIntoForward, debugStepIntoBackward} from '../actions';
|
import {
|
||||||
|
startDebug,
|
||||||
|
debugJumpBack,
|
||||||
|
debugJumpForward,
|
||||||
|
debugStepOverForward,
|
||||||
|
debugStepOverBackward,
|
||||||
|
debugStepIntoForward,
|
||||||
|
debugStepIntoBackward
|
||||||
|
} from '../actions';
|
||||||
import ContractDebugger from '../components/ContractDebugger';
|
import ContractDebugger from '../components/ContractDebugger';
|
||||||
import DataWrapper from "../components/DataWrapper";
|
import {getDebuggerInfo} from "../reducers/selectors";
|
||||||
import {getContractLogsByContract, debuggerInfo} from "../reducers/selectors";
|
|
||||||
|
|
||||||
class ContractDebuggerContainer extends Component {
|
class ContractDebuggerContainer extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<DataWrapper shouldRender={this.props.contractLogs !== undefined } {...this.props} render={() => (
|
<ContractDebugger debuggerTransactionHash={this.props.debuggerTransactionHash}
|
||||||
<ContractDebugger contract={this.props.contract} startDebug={this.props.startDebug}
|
startDebug={this.props.startDebug}
|
||||||
debugJumpBack={this.props.debugJumpBack} debugJumpForward={this.props.debugJumpForward}
|
debugJumpBack={this.props.debugJumpBack}
|
||||||
debugStepOverForward={this.props.debugStepOverForward}
|
debugJumpForward={this.props.debugJumpForward}
|
||||||
debugStepOverBackward={this.props.debugStepOverBackward}
|
debugStepOverForward={this.props.debugStepOverForward}
|
||||||
debugStepIntoForward={this.props.debugStepIntoForward}
|
debugStepOverBackward={this.props.debugStepOverBackward}
|
||||||
debugStepIntoBackward={this.props.debugStepIntoBackward}
|
debugStepIntoForward={this.props.debugStepIntoForward}
|
||||||
debuggerInfo={this.props.debuggerInfo}
|
debugStepIntoBackward={this.props.debugStepIntoBackward}
|
||||||
/>
|
debuggerInfo={this.props.debuggerInfo}/>
|
||||||
)} />
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps(state, props) {
|
function mapStateToProps(state, props) {
|
||||||
return {
|
return {
|
||||||
contractLogs: getContractLogsByContract(state, props.contract.className),
|
debuggerInfo: getDebuggerInfo(state)
|
||||||
debuggerInfo: debuggerInfo(state)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ContractDebuggerContainer.propTypes = {
|
ContractDebuggerContainer.propTypes = {
|
||||||
contractLogs: PropTypes.array,
|
debuggerTransactionHash: PropTypes.string,
|
||||||
fetchContractLogs: PropTypes.func,
|
|
||||||
listenToContractLogs: PropTypes.func,
|
|
||||||
match: PropTypes.object,
|
|
||||||
contract: PropTypes.object,
|
|
||||||
startDebug: PropTypes.func,
|
startDebug: PropTypes.func,
|
||||||
debugJumpBack: PropTypes.func,
|
debugJumpBack: PropTypes.func,
|
||||||
debugJumpForward: PropTypes.func,
|
debugJumpForward: PropTypes.func,
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
|
import {withRouter} from "react-router-dom";
|
||||||
import {Row, Col} from 'reactstrap';
|
import {Row, Col} from 'reactstrap';
|
||||||
import TextEditorAsideContainer from './TextEditorAsideContainer';
|
import TextEditorAsideContainer from './TextEditorAsideContainer';
|
||||||
import TextEditorContainer from './TextEditorContainer';
|
import TextEditorContainer from './TextEditorContainer';
|
||||||
import FileExplorerContainer from './FileExplorerContainer';
|
import FileExplorerContainer from './FileExplorerContainer';
|
||||||
import TextEditorToolbarContainer from './TextEditorToolbarContainer';
|
import TextEditorToolbarContainer from './TextEditorToolbarContainer';
|
||||||
import {fetchEditorTabs as fetchEditorTabsAction} from '../actions';
|
import {
|
||||||
import {getCurrentFile} from '../reducers/selectors';
|
fetchEditorTabs as fetchEditorTabsAction,
|
||||||
|
contracts as contractsAction,
|
||||||
|
file as fileAction,
|
||||||
|
transaction as transactionAction
|
||||||
|
} from '../actions';
|
||||||
|
import {getCurrentFile, getContracts, getTransaction} from '../reducers/selectors';
|
||||||
|
import {getDebuggerTransactionHash} from '../utils/utils';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Resizable from 're-resizable';
|
import Resizable from 're-resizable';
|
||||||
import {OPERATIONS} from '../constants';
|
import {OPERATIONS} from '../constants';
|
||||||
@ -24,16 +31,21 @@ class EditorContainer extends React.Component {
|
|||||||
this.windowWidth = window.innerWidth;
|
this.windowWidth = window.innerWidth;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
currentAsideTab: {}, showHiddenFiles: false, currentFile: this.props.currentFile,
|
currentAsideTab: {},
|
||||||
|
showHiddenFiles: false,
|
||||||
|
currentFile: this.props.currentFile,
|
||||||
editorHeight: this.DEFAULT_HEIGHT,
|
editorHeight: this.DEFAULT_HEIGHT,
|
||||||
editorWidth: ((this.windowWidth < this.SMALL_SIZE) ? this.DEFAULT_EDITOR_WIDTH_SMALL : this.DEFAULT_EDITOR_WIDTH) + '%',
|
editorWidth: ((this.windowWidth < this.SMALL_SIZE) ? this.DEFAULT_EDITOR_WIDTH_SMALL : this.DEFAULT_EDITOR_WIDTH) + '%',
|
||||||
asideHeight: '100%', asideWidth: '25%',
|
asideHeight: '100%',
|
||||||
|
asideWidth: '25%',
|
||||||
isSmallSize: (this.windowWidth < this.SMALL_SIZE)
|
isSmallSize: (this.windowWidth < this.SMALL_SIZE)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchEditorTabs();
|
this.props.fetchEditorTabs();
|
||||||
|
this.props.fetchContracts();
|
||||||
|
this.props.fetchTransaction(this.props.debuggerTransactionHash);
|
||||||
window.addEventListener("resize", this.updateDimensions.bind(this));
|
window.addEventListener("resize", this.updateDimensions.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +68,14 @@ class EditorContainer extends React.Component {
|
|||||||
if (this.props.currentFile.path !== prevProps.currentFile.path) {
|
if (this.props.currentFile.path !== prevProps.currentFile.path) {
|
||||||
this.setState({currentFile: this.props.currentFile});
|
this.setState({currentFile: this.props.currentFile});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this.props.contracts && this.props.transaction !== prevProps.transaction) {
|
||||||
|
const debuggingContract = this.props.contracts.find(contract => contract.address === this.props.transaction.to)
|
||||||
|
if (debuggingContract) {
|
||||||
|
this.setState({currentAsideTab: 'debugger'})
|
||||||
|
this.props.fetchFile({path: debuggingContract.path});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isContract() {
|
isContract() {
|
||||||
@ -129,6 +149,7 @@ class EditorContainer extends React.Component {
|
|||||||
const aside = (
|
const aside = (
|
||||||
<div className="editor-aside">
|
<div className="editor-aside">
|
||||||
<TextEditorAsideContainer currentAsideTab={this.state.currentAsideTab}
|
<TextEditorAsideContainer currentAsideTab={this.state.currentAsideTab}
|
||||||
|
debuggerTransactionHash={this.props.debuggerTransactionHash}
|
||||||
currentFile={this.props.currentFile}/>
|
currentFile={this.props.currentFile}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -188,21 +209,36 @@ class EditorContainer extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps(state, _props) {
|
function mapStateToProps(state, props) {
|
||||||
const currentFile = getCurrentFile(state);
|
const currentFile = getCurrentFile(state);
|
||||||
|
const debuggerTransactionHash = getDebuggerTransactionHash(props.location);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentFile
|
currentFile,
|
||||||
|
debuggerTransactionHash,
|
||||||
|
transaction: getTransaction(state, debuggerTransactionHash),
|
||||||
|
contracts: getContracts(state)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorContainer.propTypes = {
|
EditorContainer.propTypes = {
|
||||||
|
debuggerTransactionHash: PropTypes.string,
|
||||||
|
contracts: PropTypes.array,
|
||||||
|
transaction: PropTypes.object,
|
||||||
|
fetchContracts: PropTypes.func,
|
||||||
|
fetchFile: PropTypes.func,
|
||||||
|
fetchTransaction: PropTypes.func,
|
||||||
currentFile: PropTypes.object,
|
currentFile: PropTypes.object,
|
||||||
fetchEditorTabs: PropTypes.func
|
fetchEditorTabs: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default withRouter(connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
{fetchEditorTabs: fetchEditorTabsAction.request}
|
{
|
||||||
)(EditorContainer);
|
fetchEditorTabs: fetchEditorTabsAction.request,
|
||||||
|
fetchTransaction: transactionAction.request,
|
||||||
|
fetchFile: fileAction.request,
|
||||||
|
fetchContracts: contractsAction.request
|
||||||
|
},
|
||||||
|
)(EditorContainer));
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
|
|||||||
import {Card, CardBody} from 'reactstrap';
|
import {Card, CardBody} from 'reactstrap';
|
||||||
|
|
||||||
import Preview from '../components/Preview';
|
import Preview from '../components/Preview';
|
||||||
import {contracts as contractsAction} from '../actions';
|
|
||||||
import {getContractsByPath} from "../reducers/selectors";
|
import {getContractsByPath} from "../reducers/selectors";
|
||||||
import ContractDetail from '../components/ContractDetail';
|
import ContractDetail from '../components/ContractDetail';
|
||||||
import ContractTransactionsContainer from './ContractTransactionsContainer';
|
import ContractTransactionsContainer from './ContractTransactionsContainer';
|
||||||
@ -13,19 +12,8 @@ import ContractDebuggerContainer from '../containers/ContractDebuggerContainer';
|
|||||||
import { TextEditorToolbarTabs } from '../components/TextEditorToolbar';
|
import { TextEditorToolbarTabs } from '../components/TextEditorToolbar';
|
||||||
|
|
||||||
class TextEditorAsideContainer extends Component {
|
class TextEditorAsideContainer extends Component {
|
||||||
componentDidMount() {
|
|
||||||
this.props.fetchContracts();
|
|
||||||
}
|
|
||||||
|
|
||||||
renderContent(contract, index) {
|
renderContent(contract, index) {
|
||||||
switch (this.props.currentAsideTab.label) {
|
switch (this.props.currentAsideTab) {
|
||||||
case TextEditorToolbarTabs.Debugger.label:
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<h2>{contract.className} - Debugger</h2>
|
|
||||||
<ContractDebuggerContainer key={index} contract={contract}/>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
case TextEditorToolbarTabs.Details.label:
|
case TextEditorToolbarTabs.Details.label:
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
@ -56,15 +44,21 @@ class TextEditorAsideContainer extends Component {
|
|||||||
if (this.props.currentAsideTab.label === TextEditorToolbarTabs.Browser.label) {
|
if (this.props.currentAsideTab.label === TextEditorToolbarTabs.Browser.label) {
|
||||||
return <Preview/>;
|
return <Preview/>;
|
||||||
}
|
}
|
||||||
return this.props.contracts.map((contract, index) => {
|
if (this.props.currentAsideTab.label === TextEditorToolbarTabs.Debugger.label) {
|
||||||
return (
|
return (
|
||||||
<Card key={'contract-' + index} className="editor-aside-card rounded-0 border-top-0">
|
<React.Fragment>
|
||||||
<CardBody>
|
<h2>Debugger</h2>
|
||||||
{this.renderContent(contract, index)}
|
<ContractDebuggerContainer debuggerTransactionHash={this.props.debuggerTransactionHash}/>
|
||||||
</CardBody>
|
</React.Fragment>
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
return this.props.contracts.map((contract, index) => (
|
||||||
|
<Card key={'contract-' + index} className="editor-aside-card rounded-0 border-top-0">
|
||||||
|
<CardBody>
|
||||||
|
{this.renderContent(contract, index)}
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,15 +70,12 @@ function mapStateToProps(state, props) {
|
|||||||
|
|
||||||
TextEditorAsideContainer.propTypes = {
|
TextEditorAsideContainer.propTypes = {
|
||||||
currentFile: PropTypes.object,
|
currentFile: PropTypes.object,
|
||||||
currentAsideTab: PropTypes.object,
|
debuggerTransactionHash: PropTypes.string,
|
||||||
contract: PropTypes.array,
|
currentAsideTab: PropTypes.string,
|
||||||
fetchContracts: PropTypes.func,
|
|
||||||
contracts: PropTypes.array
|
contracts: PropTypes.array
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
{
|
{}
|
||||||
fetchContracts: contractsAction.request
|
|
||||||
}
|
|
||||||
)(TextEditorAsideContainer);
|
)(TextEditorAsideContainer);
|
||||||
|
@ -3,20 +3,21 @@ import {connect} from 'react-redux';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {withRouter} from 'react-router-dom';
|
import {withRouter} from 'react-router-dom';
|
||||||
|
|
||||||
import {transaction as transactionAction} from '../actions';
|
import {transaction as transactionAction, contracts as contractsAction} from '../actions';
|
||||||
import Transaction from '../components/Transaction';
|
import Transaction from '../components/Transaction';
|
||||||
import DataWrapper from "../components/DataWrapper";
|
import DataWrapper from "../components/DataWrapper";
|
||||||
import {getTransaction} from "../reducers/selectors";
|
import {getTransaction, getContracts} from "../reducers/selectors";
|
||||||
|
|
||||||
class TransactionContainer extends Component {
|
class TransactionContainer extends Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.props.fetchContracts();
|
||||||
this.props.fetchTransaction(this.props.match.params.hash);
|
this.props.fetchTransaction(this.props.match.params.hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<DataWrapper shouldRender={this.props.transaction !== undefined } {...this.props} render={({transaction}) => (
|
<DataWrapper shouldRender={this.props.transaction !== undefined } {...this.props} render={({transaction}) => (
|
||||||
<Transaction transaction={transaction} />
|
<Transaction contracts={this.props.contracts} transaction={transaction} />
|
||||||
)} />
|
)} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -25,6 +26,7 @@ class TransactionContainer extends Component {
|
|||||||
function mapStateToProps(state, props) {
|
function mapStateToProps(state, props) {
|
||||||
return {
|
return {
|
||||||
transaction: getTransaction(state, props.match.params.hash),
|
transaction: getTransaction(state, props.match.params.hash),
|
||||||
|
contracts: getContracts(state),
|
||||||
error: state.errorMessage,
|
error: state.errorMessage,
|
||||||
loading: state.loading
|
loading: state.loading
|
||||||
};
|
};
|
||||||
@ -33,7 +35,8 @@ function mapStateToProps(state, props) {
|
|||||||
TransactionContainer.propTypes = {
|
TransactionContainer.propTypes = {
|
||||||
match: PropTypes.object,
|
match: PropTypes.object,
|
||||||
transaction: PropTypes.object,
|
transaction: PropTypes.object,
|
||||||
transactions: PropTypes.arrayOf(PropTypes.object),
|
contracts: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
fetchContracts: PropTypes.func,
|
||||||
fetchTransaction: PropTypes.func,
|
fetchTransaction: PropTypes.func,
|
||||||
error: PropTypes.string
|
error: PropTypes.string
|
||||||
};
|
};
|
||||||
@ -41,6 +44,7 @@ TransactionContainer.propTypes = {
|
|||||||
export default withRouter(connect(
|
export default withRouter(connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
{
|
{
|
||||||
|
fetchContracts: contractsAction.request,
|
||||||
fetchTransaction: transactionAction.request
|
fetchTransaction: transactionAction.request
|
||||||
}
|
}
|
||||||
)(TransactionContainer));
|
)(TransactionContainer));
|
||||||
|
@ -2,10 +2,10 @@ import React, {Component} from 'react';
|
|||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import {transactions as transactionsAction, initBlockHeader, stopBlockHeader} from '../actions';
|
import {transactions as transactionsAction, initBlockHeader, stopBlockHeader, contracts as contractsAction} from '../actions';
|
||||||
import Transactions from '../components/Transactions';
|
import Transactions from '../components/Transactions';
|
||||||
import DataWrapper from "../components/DataWrapper";
|
import DataWrapper from "../components/DataWrapper";
|
||||||
import {getTransactions} from "../reducers/selectors";
|
import {getTransactions, getContracts} from "../reducers/selectors";
|
||||||
|
|
||||||
const MAX_TXS = 10; // TODO use same constant as API
|
const MAX_TXS = 10; // TODO use same constant as API
|
||||||
|
|
||||||
@ -20,6 +20,7 @@ class TransactionsContainer extends Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchTransactions();
|
this.props.fetchTransactions();
|
||||||
|
this.props.fetchContracts();
|
||||||
this.props.initBlockHeader();
|
this.props.initBlockHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +60,9 @@ class TransactionsContainer extends Component {
|
|||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<DataWrapper shouldRender={this.currentTxs.length > 0} {...this.props} render={() => (
|
<DataWrapper shouldRender={this.currentTxs.length > 0} {...this.props} render={() => (
|
||||||
<Transactions transactions={this.currentTxs} numberOfPages={this.getNumberOfPages()}
|
<Transactions transactions={this.currentTxs}
|
||||||
|
contracts={this.props.contracts}
|
||||||
|
numberOfPages={this.getNumberOfPages()}
|
||||||
changePage={(newPage) => this.changePage(newPage)}
|
changePage={(newPage) => this.changePage(newPage)}
|
||||||
currentPage={this.state.currentPage || this.getNumberOfPages()} />
|
currentPage={this.state.currentPage || this.getNumberOfPages()} />
|
||||||
)} />
|
)} />
|
||||||
@ -69,12 +72,19 @@ class TransactionsContainer extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
return {transactions: getTransactions(state), error: state.errorMessage, loading: state.loading};
|
return {
|
||||||
|
transactions: getTransactions(state),
|
||||||
|
contracts: getContracts(state),
|
||||||
|
error: state.errorMessage,
|
||||||
|
loading: state.loading
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionsContainer.propTypes = {
|
TransactionsContainer.propTypes = {
|
||||||
transactions: PropTypes.arrayOf(PropTypes.object),
|
transactions: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
contracts: PropTypes.arrayOf(PropTypes.object),
|
||||||
fetchTransactions: PropTypes.func,
|
fetchTransactions: PropTypes.func,
|
||||||
|
fetchContracts: PropTypes.func,
|
||||||
initBlockHeader: PropTypes.func,
|
initBlockHeader: PropTypes.func,
|
||||||
stopBlockHeader: PropTypes.func,
|
stopBlockHeader: PropTypes.func,
|
||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
@ -85,6 +95,7 @@ export default connect(
|
|||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
{
|
{
|
||||||
fetchTransactions: transactionsAction.request,
|
fetchTransactions: transactionsAction.request,
|
||||||
|
fetchContracts: contractsAction.request,
|
||||||
initBlockHeader,
|
initBlockHeader,
|
||||||
stopBlockHeader
|
stopBlockHeader
|
||||||
},
|
},
|
||||||
|
@ -225,7 +225,7 @@ export function getWeb3Deployments(state) {
|
|||||||
return state.web3.deployments;
|
return state.web3.deployments;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function debuggerInfo(state) {
|
export function getDebuggerInfo(state) {
|
||||||
return state.debuggerInfo;
|
return state.debuggerInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,10 @@ export function getQueryToken(location) {
|
|||||||
return qs.parse(location.search, {ignoreQueryPrefix: true}).token;
|
return qs.parse(location.search, {ignoreQueryPrefix: true}).token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDebuggerTransactionHash(location) {
|
||||||
|
return qs.parse(location.search, {ignoreQueryPrefix: true}).debuggerTransactionHash;
|
||||||
|
}
|
||||||
|
|
||||||
export function stripQueryToken(location) {
|
export function stripQueryToken(location) {
|
||||||
const _location = Object.assign({}, location);
|
const _location = Object.assign({}, location);
|
||||||
_location.search = _location.search.replace(
|
_location.search = _location.search.replace(
|
||||||
|
@ -607,12 +607,8 @@ class BlockchainConnector {
|
|||||||
return this.web3.eth.net.getId();
|
return this.web3.eth.net.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: fix me, why is this gasPrice??
|
|
||||||
getTransaction(hash, cb) {
|
getTransaction(hash, cb) {
|
||||||
const self = this;
|
return this.web3.eth.getTransaction(hash, cb);
|
||||||
this.onReady(() => {
|
|
||||||
self.web3.eth.getGasPrice(cb);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ContractObject(params) {
|
ContractObject(params) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user