Fix Tabler browser errors

Fixed browser errors caused by tabler (bodyItems and headerItems complaints) as well as staticContext issues caused by using withRoute(NavLink)

Also added a response to fiddler deployment.

Added loading states to fiddler results, that shows the errors/warnings as having a loading state when compiling/deploying
This commit is contained in:
emizzle 2018-08-24 12:19:08 +10:00 committed by Pascal Precht
parent 3870f6d316
commit 609d4eb762
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
18 changed files with 242 additions and 150 deletions

View File

@ -178,7 +178,9 @@ export const fiddle = {
export const FIDDLE_DEPLOY = createRequestTypes('FIDDLE_DEPLOY');
export const fiddleDeploy = {
request: (compiledCode) => action(FIDDLE_DEPLOY[REQUEST], {compiledCode}),
success: () => action(FIDDLE_DEPLOY[SUCCESS]),
success: (response) => {
return action(FIDDLE_DEPLOY[SUCCESS], {fiddleDeploys: [response.contractNames]});
},
failure: (error) => action(FIDDLE_DEPLOY[FAILURE], {error})
};

View File

@ -129,5 +129,5 @@ export function postFiddle(payload) {
}
export function postFiddleDeploy(payload) {
return post('/contract/deploy', {compiledContract: payload.compiledCode.compilationResult});
return post('/contract/deploy', {compiledContract: payload.compiledCode});
}

View File

@ -16,23 +16,30 @@ const Accounts = ({accounts}) => (
<Table
responsive
className="card-table table-vcenter text-nowrap"
headerItems={[
{content: "Address"},
{content: "Balance"},
{content: "TX count"},
{content: "Index"}
]}
bodyItems={
>
<Table.Header>
<Table.Row>
<Table.ColHeader>Address</Table.ColHeader>
<Table.ColHeader>Balance</Table.ColHeader>
<Table.ColHeader>TX count</Table.ColHeader>
<Table.ColHeader>Index</Table.ColHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{
accounts.map((account) => {
return ([
{content: <Link to={`/embark/explorer/accounts/${account.address}`}>{account.address}</Link>},
{content: account.balance},
{content: account.transactionCount},
{content: account.index}
]);
return (
<Table.Row key={account.address}>
<Table.Col><Link to={`/embark/explorer/accounts/${account.address}`}>{account.address}</Link></Table.Col>
<Table.Col>{account.balance}</Table.Col>
<Table.Col>{account.transactionCount}</Table.Col>
<Table.Col>{account.index}</Table.Col>
</Table.Row>
);
})
}
/>
</Table.Body>
</Table>
</Card>
</Grid.Col>
</Grid.Row>

View File

@ -15,19 +15,32 @@ const Blocks = ({blocks}) => (
<Card>
<Table
responsive
className="card-table table-vcenter text-nowrap"
headerItems={[{content: "Number"}, {content: "Mined On"}, {content: "Gas Used"}, {content: "TX Count"}]}
bodyItems={
cards
verticalAlign="center"
className="text-nowrap">
<Table.Header>
<Table.Row>
<Table.ColHeader>Number</Table.ColHeader>
<Table.ColHeader>Mined On</Table.ColHeader>
<Table.ColHeader>Gas Used</Table.ColHeader>
<Table.ColHeader>TX Count</Table.ColHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{
blocks.map((block) => {
return ([
{content: <Link to={`/embark/explorer/blocks/${block.number}`}>{block.number}</Link>},
{content: new Date(block.timestamp * 1000).toLocaleString()},
{content: block.gasUsed},
{content: block.transactions.length}
]);
return (
<Table.Row key={block.number}>
<Table.Col><Link to={`/embark/explorer/blocks/${block.number}`}>{block.number}</Link></Table.Col>
<Table.Col>{new Date(block.timestamp * 1000).toLocaleString()}</Table.Col>
<Table.Col>{block.gasUsed}</Table.Col>
<Table.Col>{block.transactions.length}</Table.Col>
</Table.Row>
);
})
}
/>
</Table.Body>
</Table>
</Card>
</Grid.Col>
</Grid.Row>

View File

@ -15,19 +15,22 @@ const Contract = ({contract}) => (
<Table
responsive
className="card-table table-vcenter text-nowrap"
headerItems={[
{content: "Name"},
{content: "Address"},
{content: "State"}
]}
bodyItems={[
[
{content: (contract.name || contract.className)},
{content: (contract.address || contract.deployedAddress)},
{content: contract.deploy.toString()}
]
]}
/>
>
<Table.Header>
<Table.Row>
<Table.ColHeader>Name</Table.ColHeader>
<Table.ColHeader>Address</Table.ColHeader>
<Table.ColHeader>State</Table.ColHeader>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Col>{(contract.name || contract.className)}</Table.Col>
<Table.Col>{(contract.address || contract.deployedAddress)}</Table.Col>
<Table.Col>{contract.deploy}</Table.Col>
</Table.Row>
</Table.Body>
</Table>
</Card>
</Grid.Col>
</Grid.Row>

View File

@ -24,7 +24,7 @@ const ContractLayout = ({match}) => (
className="d-flex align-items-center"
to={`/embark/contracts/${match.params.contractName}/overview`}
icon="corner-left-up"
RootComponent={withRouter(NavLink)}
RootComponent={NavLink}
>
Back to {match.params.contractName}
</List.GroupItem>
@ -32,7 +32,7 @@ const ContractLayout = ({match}) => (
className="d-flex align-items-center"
to={`/embark/contracts/${match.params.contractName}/deployment`}
icon="users"
RootComponent={withRouter(NavLink)}
RootComponent={NavLink}
>
Deployment / Utils
</List.GroupItem>
@ -40,7 +40,7 @@ const ContractLayout = ({match}) => (
className="d-flex align-items-center"
to={`/embark/contracts/${match.params.contractName}/functions`}
icon="book-open"
RootComponent={withRouter(NavLink)}
RootComponent={NavLink}
>
Functions
</List.GroupItem>
@ -48,7 +48,7 @@ const ContractLayout = ({match}) => (
className="d-flex align-items-center"
to={`/embark/contracts/${match.params.contractName}/source`}
icon="activity"
RootComponent={withRouter(NavLink)}
RootComponent={NavLink}
>
Source Code
</List.GroupItem>
@ -56,7 +56,7 @@ const ContractLayout = ({match}) => (
className="d-flex align-items-center"
to={`/embark/contracts/${match.params.contractName}/profiler`}
icon="server"
RootComponent={withRouter(NavLink)}
RootComponent={NavLink}
>
Profile
</List.GroupItem>
@ -64,7 +64,7 @@ const ContractLayout = ({match}) => (
className="d-flex align-items-center"
to={`/embark/contracts/${match.params.contractName}/logger`}
icon="chevrons-right"
RootComponent={withRouter(NavLink)}
RootComponent={NavLink}
>
Logger
</List.GroupItem>

View File

@ -11,26 +11,34 @@ const ContractLogger = ({contractName, contractLogs}) => (
<Grid.Col>
<Table
responsive
className="card-table table-vcenter text-nowrap"
headerItems={[
{content: "call"},
{content: "Transaction hash"},
{content: "Gas Used"},
{content: "Block number"},
{content: "Status"}
]}
bodyItems={
cards
verticalAlign="center"
className="text-nowrap">
<Table.Header>
<Table.Row>
<Table.ColHeader>call</Table.ColHeader>
<Table.ColHeader>Transaction hash</Table.ColHeader>
<Table.ColHeader>Gas Used</Table.ColHeader>
<Table.ColHeader>Block number</Table.ColHeader>
<Table.ColHeader>Status</Table.ColHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{
contractLogs.map((log) => {
return ([
{content: `${log.name}.${log.functionName}(${log.paramString})`},
{content: log.transactionHash},
{content: log.gasUsed},
{content: log.blockNumber},
{content: log.status}
]);
return (
<Table.Row key={log.name}>
<Table.Col>{`${log.name}.${log.functionName}(${log.paramString})`}</Table.Col>
<Table.Col>{log.transactionHash}</Table.Col>
<Table.Col>{log.gasUsed}</Table.Col>
<Table.Col>{log.blockNumber}</Table.Col>
<Table.Col>{log.status}</Table.Col>
</Table.Row>
);
})
}
/>
</Table.Body>
</Table>
</Grid.Col>
</Grid.Row>
</Page.Content>

View File

@ -14,28 +14,36 @@ const ContractProfile = ({contractProfile}) => (
<Card>
<Table
responsive
className="card-table table-vcenter text-nowrap"
headerItems={[
{content: "Function"},
{content: "Payable"},
{content: "Mutability"},
{content: "Inputs"},
{content: "Outputs"},
{content: "Gas Estimates"}
]}
bodyItems={
cards
verticalAlign="center"
className="text-nowrap">
<Table.Header>
<Table.Row>
<Table.ColHeader>Function</Table.ColHeader>
<Table.ColHeader>Payable</Table.ColHeader>
<Table.ColHeader>Mutability</Table.ColHeader>
<Table.ColHeader>Inputs</Table.ColHeader>
<Table.ColHeader>Outputs</Table.ColHeader>
<Table.ColHeader>Gas Estimates</Table.ColHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{
contractProfile.methods.map((method) => {
return ([
{content: method.name},
{content: (method.payable === true).toString()},
{content: method.mutability},
{content: `(${method.inputs.map((x) => x.type).join(',')})`},
{content: `(${method.outputs.map((x) => x.type).join(',')})`},
{content: method.gasEstimates}
]);
return (
<Table.Row key={method.name}>
<Table.Col>{method.name}</Table.Col>
<Table.Col>{(method.payable === true).toString()}</Table.Col>
<Table.Col>{method.mutability}</Table.Col>
<Table.Col>{`(${method.inputs.map((x) => x.type).join(',')})`}</Table.Col>
<Table.Col>{`(${method.outputs.map((x) => x.type).join(',')})`}</Table.Col>
<Table.Col>{method.gasEstimates}</Table.Col>
</Table.Row>
);
})
}
/>
</Table.Body>
</Table>
</Card>
</Grid.Col>
</Grid.Row>

View File

@ -15,22 +15,30 @@ const Contracts = ({contracts}) => (
<Card>
<Table
responsive
className="card-table table-vcenter text-nowrap"
headerItems={[
{content: "Name"},
{content: "Address"},
{content: "State"}
]}
bodyItems={
cards
verticalAlign="center"
className="text-nowrap">
<Table.Header>
<Table.Row>
<Table.ColHeader>Name</Table.ColHeader>
<Table.ColHeader>Address</Table.ColHeader>
<Table.ColHeader>State</Table.ColHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{
contracts.map((contract) => {
return ([
{content: <Link to={`/embark/contracts/${contract.className}/overview`}>{contract.className}</Link>},
{content: contract.address},
{content: contract.deploy.toString()}
]);
return (
<Table.Row key={contract.className}>
<Table.Col><Link to={`/embark/contracts/${contract.className}/overview`}>{contract.className}</Link></Table.Col>
<Table.Col>{contract.address || 'Interface or not set to deploy'}</Table.Col>
<Table.Col>{contract.deploy ? 'Deployed' : 'Not deployed'}</Table.Col>
</Table.Row>
);
})
}
/>
</Table.Body>
</Table>
</Card>
</Grid.Col>
</Grid.Row>

View File

@ -1,5 +1,5 @@
import React from 'react';
import {NavLink, Route, Switch, withRouter} from 'react-router-dom';
import {NavLink, Route, Switch} from 'react-router-dom';
import {
Page,
Grid,
@ -37,7 +37,7 @@ const ExplorerLayout = () => (
className={className}
to={groupItem.to}
icon={groupItem.icon}
RootComponent={withRouter(NavLink)}
RootComponent={NavLink}
>
{groupItem.value}
</List.GroupItem>

View File

@ -1,8 +1,9 @@
/* eslint {jsx-a11y/anchor-has-content:"off"} */
import React, {Component} from 'react';
import {Card, List, Badge, Icon, Dimmer} from 'tabler-react';
import {Card, List, Badge, Icon, Dimmer, Button} from 'tabler-react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {NavLink} from 'react-router-dom';
class FiddleResults extends Component {
@ -56,7 +57,7 @@ class FiddleResults extends Component {
}
render() {
const {warnings, errors, fatal, isLoading} = this.props;
const {warnings, errors, fatal, isLoading, deployedContracts} = this.props;
let renderings = [];
if(fatal){
@ -72,12 +73,35 @@ class FiddleResults extends Component {
<Card.Title color="danger"><Icon name="slash"/> Failed to compile</Card.Title>
</Card.Header>
<Card.Body>
<Dimmer active={isLoading ? "active" : ""} loader>
{fatal}
</Dimmer>
</Card.Body>
</Card>
</React.Fragment>
);
}
else if (deployedContracts){
renderings.push(
<Card
statusColor="success"
statusSide="true"
className="success-card"
key="success-card">
<Card.Header>
<Card.Title color="success"><Icon name="check"/> Contract(s) deployed!</Card.Title>
</Card.Header>
<Card.Body>
<Dimmer active={isLoading ? "active" : ""} loader>
<Button
to={`/embark/contracts/${deployedContracts[0]}/overview`}
RootComponent={NavLink}
>Play with my contract(s)</Button>
</Dimmer>
</Card.Body>
</Card>
);
}
else{
if (errors.length) renderings.push(
<React.Fragment key="errors">
@ -105,7 +129,8 @@ FiddleResults.propTypes = {
errors: PropTypes.array,
warnings: PropTypes.array,
fatal: PropTypes.string,
isLoading: PropTypes.bool
isLoading: PropTypes.bool,
deployedContracts: PropTypes.array
};
export default FiddleResults;

View File

@ -1,17 +1,17 @@
import React from 'react';
import {NavLink, withRouter} from "react-router-dom";
import {NavLink} from "react-router-dom";
import {Site, Nav, Button, Container} from "tabler-react";
import PropTypes from 'prop-types';
import logo from '../images/logo.png';
const navBarItems = [
{value: "Home", to: "/embark", icon: "home", LinkComponent: withRouter(NavLink)},
{value: "Contracts", to: "/embark/contracts", icon: "box", LinkComponent: withRouter(NavLink)},
{value: "Explorer", to: "/embark/explorer/accounts", icon: "activity", LinkComponent: withRouter(NavLink)},
{value: "Processes", to: "/embark/processes", icon: "cpu", LinkComponent: withRouter(NavLink)},
{value: "Fiddle", to: "/embark/fiddle", icon: "codepen", LinkComponent: withRouter(NavLink)},
{value: "Documentation", to: "/embark/documentation", icon: "file-text", LinkComponent: withRouter(NavLink)}
{value: "Home", to: "/embark", icon: "home", LinkComponent: NavLink},
{value: "Contracts", to: "/embark/contracts", icon: "box", LinkComponent: NavLink},
{value: "Explorer", to: "/embark/explorer/accounts", icon: "activity", LinkComponent: NavLink},
{value: "Processes", to: "/embark/processes", icon: "cpu", LinkComponent: NavLink},
{value: "Fiddle", to: "/embark/fiddle", icon: "codepen", LinkComponent: NavLink},
{value: "Documentation", to: "/embark/documentation", icon: "file-text", LinkComponent: NavLink}
];
const Layout = (props) => (

View File

@ -1,7 +1,7 @@
import PropTypes from "prop-types";
import React, {Component} from 'react';
import connect from "react-redux/es/connect/connect";
import {NavLink, Route, Switch, withRouter, Redirect} from 'react-router-dom';
import {NavLink, Route, Switch, Redirect} from 'react-router-dom';
import {
Page,
Grid,
@ -30,7 +30,7 @@ class ProcessesLayout extends Component {
to={`${routePrefix}/${process.name}`}
key={'process-' + process.name}
active={index === 0 && this.props.match.isExact === true}
RootComponent={withRouter(NavLink)}
RootComponent={NavLink}
>
{process.name}
</List.GroupItem>);

View File

@ -15,26 +15,34 @@ const Transactions = ({transactions}) => (
<Card>
<Table
responsive
className="card-table table-vcenter text-nowrap"
headerItems={[
{content: "Hash"},
{content: "Block Number"},
{content: "From"},
{content: "To"},
{content: "Type"}
]}
bodyItems={
transactions.map((transaction) => {
return ([
{content: <Link to={`/embark/explorer/transactions/${transaction.hash}`}>{transaction.hash}</Link>},
{content: transaction.blockNumber},
{content: transaction.from},
{content: transaction.to},
{content: transaction.to ? "Contract Call" : "Contract Creation"}
]);
cards
verticalAlign="center"
className="text-nowrap">
<Table.Header>
<Table.Row>
<Table.ColHeader>Hash</Table.ColHeader>
<Table.ColHeader>Block Number</Table.ColHeader>
<Table.ColHeader>From</Table.ColHeader>
<Table.ColHeader>To</Table.ColHeader>
<Table.ColHeader>Type</Table.ColHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{
transactions.reduce((transaction) => {
return (
<Table.Row key={transaction.hash}>
<Table.Col><Link to={`/embark/explorer/transactions/${transaction.hash}`}>{transaction.hash}</Link></Table.Col>
<Table.Col>{transaction.blockNumber}</Table.Col>
<Table.Col>{transaction.from}</Table.Col>
<Table.Col>{transaction.to}</Table.Col>
<Table.Col>{transaction.to ? "Contract Call" : "Contract Creation"}</Table.Col>
</Table.Row>
);
})
}
/>
</Table.Body>
</Table>
</Card>
</Grid.Col>
</Grid.Row>

View File

@ -8,7 +8,7 @@ import Fiddle from '../components/Fiddle';
import FiddleResults from '../components/FiddleResults';
import FiddleResultsSummary from '../components/FiddleResultsSummary';
import scrollToComponent from 'react-scroll-to-component';
import {getFiddle} from "../reducers/selectors";
import {getFiddle, getFiddleDeploy} from "../reducers/selectors";
import CompilerError from "../components/CompilerError";
class FiddleContainer extends Component {
@ -82,7 +82,7 @@ class FiddleContainer extends Component {
}
render() {
const {fiddle, loading, error} = this.props;
const {fiddle, loading, error, deployedContracts} = this.props;
const {loadingMessage} = this.state;
let renderings = [];
let warnings = [];
@ -124,6 +124,7 @@ class FiddleContainer extends Component {
warnings={warnings}
fatal={error}
isLoading={loading}
deployedContracts={deployedContracts}
/>);
}
@ -138,9 +139,11 @@ class FiddleContainer extends Component {
}
function mapStateToProps(state) {
const fiddle = getFiddle(state);
const deployedFiddle = getFiddleDeploy(state);
return {
fiddle: fiddle.data,
error: fiddle.error,
deployedContracts: deployedFiddle.data,
error: fiddle.error || deployedFiddle.error,
loading: state.loading
};
}

View File

@ -21,6 +21,7 @@ const entitiesDefaultState = {
messages: [],
messageChannels: [],
fiddles: [],
fiddleDeploys: [],
versions: [],
plugins: [],
ensRecords: []

View File

@ -1,5 +1,4 @@
import _ from 'lodash';
import {REQUEST, FIDDLE, FIDDLE_DEPLOY} from '../actions/index.js';
export function getAccounts(state) {
return state.entities.accounts;
@ -112,6 +111,13 @@ export function getFiddle(state) {
};
}
export function getFiddleDeploy(state) {
return {
data: _.last(state.entities.fiddleDeploys),
error: _.last(state.errorEntities.fiddleDeploys)
};
}
export function getEnsRecords(state) {
return state.entities.ensRecords;
}

View File

@ -171,7 +171,7 @@ class ContractsManager {
(req, res) => {
self.compiledContracts = Object.assign(self.compiledContracts, req.body.compiledContract);
self.build((err, _mgr) => {
const responseData = {errors: err, success: !err};
const responseData = {errors: err, contractNames: Object.keys(req.body.compiledContract)};
this.logger.trace(`POST response /embark-api/contract/deploy:\n ${JSON.stringify(responseData)}`);
res.send(responseData);
}, false);