Adding tab to contract view

This commit is contained in:
Anthony Laibe 2018-10-12 12:33:48 +01:00 committed by Pascal Precht
parent df3bce145d
commit 4b2715421d
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
11 changed files with 93 additions and 121 deletions

View File

@ -1,94 +1,75 @@
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import React from 'react'; import React from 'react';
import {NavLink, Route, Switch, withRouter} from 'react-router-dom'; import { TabContent, TabPane, Nav, NavItem, NavLink, Card, Button, CardTitle, CardText, Row, Col } from 'reactstrap';
import { import classnames from 'classnames';
Page,
Grid,
List
} from "tabler-react";
import ContractContainer from '../containers/ContractContainer'; import ContractOverview from '../components/ContractOverview';
import ContractLoggerContainer from '../containers/ContractLoggerContainer'; import ContractLoggerContainer from '../containers/ContractLoggerContainer';
import ContractFunctionsContainer from '../containers/ContractFunctionsContainer'; import ContractFunctionsContainer from '../containers/ContractFunctionsContainer';
import ContractDeploymentContainer from '../containers/ContractDeploymentContainer';
import ContractProfileContainer from '../containers/ContractProfileContainer';
import ContractSourceContainer from '../containers/ContractSourceContainer';
const ContractLayout = ({match, contractIsFiddle = false}) => ( class ContractLayout extends React.Component {
<Grid.Row> constructor(props) {
<Grid.Col md={3}> super(props);
<Page.Title className="my-5">&nbsp;</Page.Title>
<div> this.state = {
<List.Group transparent={true}> activeTab: '1'
<List.GroupItem };
className="d-flex align-items-center" }
to={`/embark/contracts/${match.params.contractName}/overview`}
icon="corner-left-up" toggle(tab) {
RootComponent={NavLink} if (this.state.activeTab !== tab) {
> this.setState({
Overview activeTab: tab
</List.GroupItem> });
{!contractIsFiddle && }
<List.GroupItem }
className="d-flex align-items-center" render() {
to={`/embark/contracts/${match.params.contractName}/deployment`} return (
icon="users" <React.Fragment>
RootComponent={NavLink} <Nav tabs>
<NavItem>
<NavLink
className={classnames({ active: this.state.activeTab === '1' })}
onClick={() => { this.toggle('1'); }}
> >
Deployment / Utils Overview
</List.GroupItem> </NavLink>
} </NavItem>
<List.GroupItem <NavItem>
className="d-flex align-items-center" <NavLink
to={`/embark/contracts/${match.params.contractName}/functions`} className={classnames({ active: this.state.activeTab === '2' })}
icon="book-open" onClick={() => { this.toggle('2'); }}
RootComponent={NavLink} >
> Functions
Functions </NavLink>
</List.GroupItem> </NavItem>
<List.GroupItem <NavItem>
className="d-flex align-items-center" <NavLink
to={`/embark/contracts/${match.params.contractName}/source`} className={classnames({ active: this.state.activeTab === '3' })}
icon="activity" onClick={() => { this.toggle('3'); }}
RootComponent={NavLink} >
> Logger
Source Code </NavLink>
</List.GroupItem> </NavItem>
<List.GroupItem </Nav>
className="d-flex align-items-center" <TabContent activeTab={this.state.activeTab}>
to={`/embark/contracts/${match.params.contractName}/profiler`} <TabPane tabId="1">
icon="server" <ContractOverview contract={this.props.contract} />
RootComponent={NavLink} </TabPane>
> <TabPane tabId="2">
Profile <ContractFunctionsContainer contract={this.props.contract} />
</List.GroupItem> </TabPane>
<List.GroupItem <TabPane tabId="3">
className="d-flex align-items-center" <ContractLoggerContainer contract={this.props.contract} />
to={`/embark/contracts/${match.params.contractName}/logger`} </TabPane>
icon="chevrons-right" </TabContent>
RootComponent={NavLink} </React.Fragment>
> )
Logger }
</List.GroupItem> }
</List.Group>
</div>
</Grid.Col>
<Grid.Col md={9}>
<Switch>
<Route exact path="/embark/contracts/:contractName/overview" component={ContractContainer} />
<Route exact path="/embark/contracts/:contractName/deployment" component={ContractDeploymentContainer} />
<Route exact path="/embark/contracts/:contractName/functions" component={ContractFunctionsContainer} />
<Route exact path="/embark/contracts/:contractName/source" component={ContractSourceContainer} />
<Route exact path="/embark/contracts/:contractName/profiler" component={ContractProfileContainer} />
<Route exact path="/embark/contracts/:contractName/logger" component={ContractLoggerContainer} />
</Switch>
</Grid.Col>
</Grid.Row>
);
ContractLayout.propTypes = { ContractLayout.propTypes = {
match: PropTypes.object, contract: PropTypes.object
contractIsFiddle: PropTypes.bool
}; };
export default withRouter(ContractLayout); export default ContractLayout;

View File

@ -8,12 +8,11 @@ import {
} from "tabler-react"; } from "tabler-react";
import JSONTree from 'react-json-tree'; import JSONTree from 'react-json-tree';
import {formatContractForDisplay} from '../utils/presentation'; import {formatContractForDisplay} from '../utils/presentation';
import {withRouter} from 'react-router-dom';
const Contract = ({contract, match}) => { const Contract = ({contract, match}) => {
const contractDisplay = formatContractForDisplay(contract); const contractDisplay = formatContractForDisplay(contract);
return ( return (
<Page.Content title={match.params.contractName + " Overview"}> <Page.Content title={contract.className + " Overview"}>
<Grid.Row> <Grid.Row>
<Grid.Col> <Grid.Col>
<Card> <Card>
@ -30,7 +29,7 @@ const Contract = ({contract, match}) => {
</Table.Header> </Table.Header>
<Table.Body> <Table.Body>
<Table.Row className={contractDisplay.stateColor}> <Table.Row className={contractDisplay.stateColor}>
<Table.Col>{(contract.name || contract.className)}</Table.Col> <Table.Col>{contract.className}</Table.Col>
<Table.Col>{contractDisplay.address}</Table.Col> <Table.Col>{contractDisplay.address}</Table.Col>
<Table.Col>{contractDisplay.state}</Table.Col> <Table.Col>{contractDisplay.state}</Table.Col>
</Table.Row> </Table.Row>
@ -61,8 +60,7 @@ const Contract = ({contract, match}) => {
Contract.propTypes = { Contract.propTypes = {
contract: PropTypes.object, contract: PropTypes.object,
match: PropTypes.object
}; };
export default withRouter(Contract); export default Contract;

View File

@ -1,7 +1,6 @@
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 {withRouter} from 'react-router-dom';
import {contractProfile as contractProfileAction, contractFunction as contractFunctionAction} from '../actions'; import {contractProfile as contractProfileAction, contractFunction as contractFunctionAction} from '../actions';
import ContractFunctions from '../components/ContractFunctions'; import ContractFunctions from '../components/ContractFunctions';
@ -11,7 +10,7 @@ import {getContractProfile, getContractFunctions} from "../reducers/selectors";
class ContractFunctionsContainer extends Component { class ContractFunctionsContainer extends Component {
componentDidMount() { componentDidMount() {
this.props.fetchContractProfile(this.props.match.params.contractName); this.props.fetchContractProfile(this.props.contract.className);
} }
render() { render() {
@ -33,15 +32,15 @@ class ContractFunctionsContainer extends Component {
function mapStateToProps(state, props) { function mapStateToProps(state, props) {
return { return {
contractProfile: getContractProfile(state, props.match.params.contractName), contractProfile: getContractProfile(state, props.contract.className),
contractFunctions: getContractFunctions(state, props.match.params.contractName), contractFunctions: getContractFunctions(state, props.contract.className),
error: state.errorMessage, error: state.errorMessage,
loading: state.loading loading: state.loading
}; };
} }
ContractFunctionsContainer.propTypes = { ContractFunctionsContainer.propTypes = {
match: PropTypes.object, contract: PropTypes.object,
contractProfile: PropTypes.object, contractProfile: PropTypes.object,
contractFunctions: PropTypes.arrayOf(PropTypes.object), contractFunctions: PropTypes.arrayOf(PropTypes.object),
postContractFunction: PropTypes.func, postContractFunction: PropTypes.func,
@ -49,10 +48,10 @@ ContractFunctionsContainer.propTypes = {
error: PropTypes.string error: PropTypes.string
}; };
export default withRouter(connect( export default connect(
mapStateToProps, mapStateToProps,
{ {
fetchContractProfile: contractProfileAction.request, fetchContractProfile: contractProfileAction.request,
postContractFunction: contractFunctionAction.post postContractFunction: contractFunctionAction.post
} }
)(ContractFunctionsContainer)); )(ContractFunctionsContainer);

View File

@ -14,7 +14,7 @@ class ContractLayoutContainer extends Component {
render() { render() {
if (this.props.contract){ if (this.props.contract){
return <ContractLayout contractIsFiddle={this.props.contract.isFiddle} />; return <ContractLayout contract={this.props.contract}/>;
} else { } else {
return <React.Fragment />; return <React.Fragment />;
} }

View File

@ -1,7 +1,6 @@
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 {withRouter} from 'react-router-dom';
import {contractLogs as contractLogsAction, listenToContractLogs} from '../actions'; import {contractLogs as contractLogsAction, listenToContractLogs} from '../actions';
import ContractLogger from '../components/ContractLogger'; import ContractLogger from '../components/ContractLogger';
@ -12,14 +11,14 @@ class ContractLoggerContainer extends Component {
componentDidMount() { componentDidMount() {
if (this.props.contractLogs.length === 0) { if (this.props.contractLogs.length === 0) {
this.props.listenToContractLogs(); this.props.listenToContractLogs();
this.props.fetchContractLogs(this.props.match.params.contractName); this.props.fetchContractLogs(this.props.contract.className);
} }
} }
render() { render() {
return ( return (
<DataWrapper shouldRender={this.props.contractLogs !== undefined } {...this.props} render={() => ( <DataWrapper shouldRender={this.props.contractLogs !== undefined } {...this.props} render={() => (
<ContractLogger contractLogs={this.props.contractLogs} contractName={this.props.match.params.contractName}/> <ContractLogger contractLogs={this.props.contractLogs} contractName={this.props.contract.className}/>
)} /> )} />
); );
} }
@ -27,7 +26,7 @@ class ContractLoggerContainer extends Component {
function mapStateToProps(state, props) { function mapStateToProps(state, props) {
return { return {
contractLogs: getContractLogsByContract(state, props.match.params.contractName) contractLogs: getContractLogsByContract(state, props.contract.className)
}; };
} }
@ -38,10 +37,10 @@ ContractLoggerContainer.propTypes = {
match: PropTypes.object match: PropTypes.object
}; };
export default withRouter(connect( export default connect(
mapStateToProps, mapStateToProps,
{ {
fetchContractLogs: contractLogsAction.request, fetchContractLogs: contractLogsAction.request,
listenToContractLogs: listenToContractLogs listenToContractLogs: listenToContractLogs
} }
)(ContractLoggerContainer)); )(ContractLoggerContainer);

View File

@ -2,13 +2,13 @@ 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 {contract as contractAction} from '../actions'; import {contracts as contractsAction} from '../actions';
import ContractLayout from '../components/ContractLayout'; import ContractLayout from '../components/ContractLayout';
import {getContractsByPath} from "../reducers/selectors"; import {getContractsByPath} from "../reducers/selectors";
class FileContractsContainer extends Component { class FileContractsContainer extends Component {
componentDidMount() { componentDidMount() {
this.props.fetchContract(this.props.currentFile); this.props.fetchContracts();
} }
render() { render() {
@ -28,7 +28,7 @@ function mapStateToProps(state, props) {
FileContractsContainer.propTypes = { FileContractsContainer.propTypes = {
contracts: PropTypes.arrayOf(PropTypes.object), contracts: PropTypes.arrayOf(PropTypes.object),
fetchFileContracts: PropTypes.func, fetchContractsByPath: PropTypes.func,
error: PropTypes.string, error: PropTypes.string,
loading: PropTypes.bool loading: PropTypes.bool
}; };
@ -36,6 +36,6 @@ FileContractsContainer.propTypes = {
export default connect( export default connect(
mapStateToProps, mapStateToProps,
{ {
fetchContract: contractAction.request fetchContracts: contractsAction.request
} }
)(FileContractsContainer); )(FileContractsContainer);

View File

@ -1,5 +1,3 @@
/* eslint multiline-ternary: "off" */
/* eslint operator-linebreak: "off" */
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';

View File

@ -1,5 +1,3 @@
/* eslint multiline-ternary: "off" */
/* eslint operator-linebreak: "off" */
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';

View File

@ -68,7 +68,7 @@ export function fetchContracts() {
} }
export function fetchContract(payload) { export function fetchContract(payload) {
return get('/contract', ...arguments); return get(`/contract/${payload.contractName}`, ...arguments);
} }
export function postContractFunction(payload) { export function postContractFunction(payload) {

View File

@ -84,16 +84,9 @@ class ContractsManager {
embark.registerAPICall( embark.registerAPICall(
'get', 'get',
'/embark-api/contract', '/embark-api/contract/:contractName',
(req, res) => { (req, res) => {
const result = []; self.events.request('contracts:contract', req.params.contractName, res.send.bind(res));
self.events.request('contracts:all', null, (contracts) => {
const contractByFilename = contracts.filter((contract) => contract.filename === req.query.filename);
contractByFilename.forEach((contract) => {
self.events.request('contracts:contract', contract.className, (contract) => result.push(contract));
});
});
res.send(result);
} }
); );
@ -168,7 +161,13 @@ class ContractsManager {
'get', 'get',
'/embark-api/contracts', '/embark-api/contracts',
(req, res) => { (req, res) => {
self.events.request('contracts:all', null, res.send.bind(res)); const result = [];
self.events.request('contracts:all', null, (contracts) => {
contracts.forEach((contract) => {
self.events.request('contracts:contract', contract.className, (contract) => result.push(contract));
});
});
res.send(result);
} }
); );