feat(cockpit): introduce transaction decoder component

This commit adds a new component to decode and analyze transactions.
It's similar to the transaction component that's already available,
with the difference that it takes advantage of the ReactJson tree
view for better analysis experience.
This commit is contained in:
Pascal Precht 2018-10-17 17:36:46 +02:00
parent fb29e5a7c8
commit 923bacf22f
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
4 changed files with 130 additions and 1 deletions

View File

@ -39,7 +39,8 @@ const sidebarNavItems = {items: [
{url: "/embark/utilities/converter", icon: "fa fa-plug", name: "Converter"},
{url: "/embark/utilities/communication", icon: "fa fa-phone", name: "Communication"},
{url: "/embark/utilities/ens", icon: "fa fa-circle", name: "ENS"},
{url: "/embark/utilities/sign-and-verify", icon: "fa fa-edit", name: "Sign & Verify"}
{url: "/embark/utilities/sign-and-verify", icon: "fa fa-edit", name: "Sign & Verify"},
{url: "/embark/utilities/transaction-decoder", icon: "fa fa-edit", name: "Transaction Decoder"}
]}
]};

View File

@ -0,0 +1,68 @@
import React from 'react';
import {withRouter} from 'react-router-dom';
import {
Card,
CardHeader,
CardBody,
Form,
FormGroup,
Input,
InputGroup,
InputGroupAddon,
Button,
Alert
} from 'reactstrap';
import ReactJson from 'react-json-view';
class TransactionDecoder extends React.Component {
constructor(props) {
super(props);
this.state = {
transactionHash: this.props.transactionHash || ''
};
}
handleTransactionHashChange(event) {
const transactionHash = event.target.value;
this.setState({transactionHash});
}
fetchTransaction(e) {
e.preventDefault();
if (this.state.transactionHash !== '') {
this.props.history.push({
search: `hash=${this.state.transactionHash}`
});
}
}
render() {
return (
<Card>
<CardHeader>
<strong>Transaction Decoder</strong>
</CardHeader>
<CardBody>
<Form onSubmit={e => this.fetchTransaction(e)}>
<FormGroup>
<InputGroup>
<Input type="text" id="transactionHash" placeholder="Enter transaction hash" value={this.state.transactionHash} onChange={e => this.handleTransactionHashChange(e)}/>
<InputGroupAddon addonType="append">
<Button color="primary" type="submit">Decode</Button>
</InputGroupAddon>
</InputGroup>
</FormGroup>
</Form>
{this.props.transactionHash && !this.props.transaction && <Alert color="danger">Couldn't find transaction for hash {this.props.transactionHash}</Alert>}
<div className="mt-3">
{this.props.transaction && <ReactJson src={this.props.transaction} theme="monokai" sortKeys={true} collapsed={1} />}
</div>
</CardBody>
</Card>
);
}
}
export default withRouter(TransactionDecoder);

View File

@ -5,6 +5,7 @@ import ConverterContainer from '../containers/ConverterContainer';
import CommunicationContainer from '../containers/CommunicationContainer';
import EnsContainer from '../containers/EnsContainer';
import SignAndVerifyContainer from '../containers/SignAndVerifyContainer';
import TransactionDecoderContainer from '../containers/TransactionDecoderContainer';
const UtilsLayout = () => (
<Switch>
@ -12,6 +13,7 @@ const UtilsLayout = () => (
<Route exact path="/embark/utilities/communication" component={CommunicationContainer} />
<Route exact path="/embark/utilities/ens" component={EnsContainer} />
<Route exact path="/embark/utilities/sign-and-verify" component={SignAndVerifyContainer} />
<Route exact path="/embark/utilities/transaction-decoder" component={TransactionDecoderContainer} />
</Switch>
);

View File

@ -0,0 +1,58 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import qs from 'qs';
import {withRouter} from 'react-router-dom';
import TransactionDecoder from '../components/TransactionDecoder';
import { Row, Col } from 'reactstrap';
import { transaction as transactionAction } from '../actions';
import {getTransaction} from "../reducers/selectors";
const getQueryParams = (props) => {
return qs.parse(props.location.search, {
ignoreQueryPrefix: true
});
}
class TransactionDecoderContainer extends Component {
componentDidMount() {
const { hash } = getQueryParams(this.props);
if (hash) {
this.props.fetchTransaction(hash);
}
}
componentDidUpdate(prevProps) {
const hash = getQueryParams(this.props).hash;
const prevHash = getQueryParams(prevProps).hash;
if (hash && hash !== prevHash) {
this.props.fetchTransaction(hash);
}
}
render() {
return (
<Row className="mt-3">
<Col>
<TransactionDecoder transaction={this.props.transaction}
transactionHash={getQueryParams(this.props).hash}/>
</Col>
</Row>
);
}
}
function mapStateToProps(state, props) {
return {
transaction: getTransaction(state, getQueryParams(props).hash),
error: state.errorMessage,
loading: state.loading
};
}
export default withRouter(connect(
mapStateToProps,
{
fetchTransaction: transactionAction.request
}
)(TransactionDecoderContainer));