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 FIDDLE_DEPLOY = createRequestTypes('FIDDLE_DEPLOY');
export const fiddleDeploy = { export const fiddleDeploy = {
request: (compiledCode) => action(FIDDLE_DEPLOY[REQUEST], {compiledCode}), 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}) failure: (error) => action(FIDDLE_DEPLOY[FAILURE], {error})
}; };

View File

@ -129,5 +129,5 @@ export function postFiddle(payload) {
} }
export function postFiddleDeploy(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 <Table
responsive responsive
className="card-table table-vcenter text-nowrap" className="card-table table-vcenter text-nowrap"
headerItems={[ >
{content: "Address"}, <Table.Header>
{content: "Balance"}, <Table.Row>
{content: "TX count"}, <Table.ColHeader>Address</Table.ColHeader>
{content: "Index"} <Table.ColHeader>Balance</Table.ColHeader>
]} <Table.ColHeader>TX count</Table.ColHeader>
bodyItems={ <Table.ColHeader>Index</Table.ColHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{
accounts.map((account) => { accounts.map((account) => {
return ([ return (
{content: <Link to={`/embark/explorer/accounts/${account.address}`}>{account.address}</Link>}, <Table.Row key={account.address}>
{content: account.balance}, <Table.Col><Link to={`/embark/explorer/accounts/${account.address}`}>{account.address}</Link></Table.Col>
{content: account.transactionCount}, <Table.Col>{account.balance}</Table.Col>
{content: account.index} <Table.Col>{account.transactionCount}</Table.Col>
]); <Table.Col>{account.index}</Table.Col>
</Table.Row>
);
}) })
} }
/> </Table.Body>
</Table>
</Card> </Card>
</Grid.Col> </Grid.Col>
</Grid.Row> </Grid.Row>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,9 @@
/* eslint {jsx-a11y/anchor-has-content:"off"} */ /* eslint {jsx-a11y/anchor-has-content:"off"} */
import React, {Component} from 'react'; 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 PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import {NavLink} from 'react-router-dom';
class FiddleResults extends Component { class FiddleResults extends Component {
@ -56,7 +57,7 @@ class FiddleResults extends Component {
} }
render() { render() {
const {warnings, errors, fatal, isLoading} = this.props; const {warnings, errors, fatal, isLoading, deployedContracts} = this.props;
let renderings = []; let renderings = [];
if(fatal){ if(fatal){
@ -72,12 +73,35 @@ class FiddleResults extends Component {
<Card.Title color="danger"><Icon name="slash"/> Failed to compile</Card.Title> <Card.Title color="danger"><Icon name="slash"/> Failed to compile</Card.Title>
</Card.Header> </Card.Header>
<Card.Body> <Card.Body>
<Dimmer active={isLoading ? "active" : ""} loader>
{fatal} {fatal}
</Dimmer>
</Card.Body> </Card.Body>
</Card> </Card>
</React.Fragment> </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{ else{
if (errors.length) renderings.push( if (errors.length) renderings.push(
<React.Fragment key="errors"> <React.Fragment key="errors">
@ -105,7 +129,8 @@ FiddleResults.propTypes = {
errors: PropTypes.array, errors: PropTypes.array,
warnings: PropTypes.array, warnings: PropTypes.array,
fatal: PropTypes.string, fatal: PropTypes.string,
isLoading: PropTypes.bool isLoading: PropTypes.bool,
deployedContracts: PropTypes.array
}; };
export default FiddleResults; export default FiddleResults;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,4 @@
import _ from 'lodash'; import _ from 'lodash';
import {REQUEST, FIDDLE, FIDDLE_DEPLOY} from '../actions/index.js';
export function getAccounts(state) { export function getAccounts(state) {
return state.entities.accounts; 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) { export function getEnsRecords(state) {
return state.entities.ensRecords; return state.entities.ensRecords;
} }

View File

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