diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index 327c10d83..fd162838b 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -170,14 +170,14 @@ export const ensRecords = { export const FIDDLE = createRequestTypes('FIDDLE'); export const fiddle = { - request: (codeToCompile) => action(FIDDLE[REQUEST], {codeToCompile}), + post: (codeToCompile) => action(FIDDLE[REQUEST], {codeToCompile}), success: (fiddle) => action(FIDDLE[SUCCESS], {fiddles: [fiddle]}), failure: (error) => action(FIDDLE[FAILURE], {error}) }; export const FIDDLE_DEPLOY = createRequestTypes('FIDDLE_DEPLOY'); export const fiddleDeploy = { - request: (compiledCode) => action(FIDDLE_DEPLOY[REQUEST], {compiledCode}), + post: (compiledCode) => action(FIDDLE_DEPLOY[REQUEST], {compiledCode}), success: (response) => { return action(FIDDLE_DEPLOY[SUCCESS], {fiddleDeploys: [response.contractNames]}); }, diff --git a/embark-ui/src/components/Contract.js b/embark-ui/src/components/Contract.js index a5e22d16f..658e6dac0 100644 --- a/embark-ui/src/components/Contract.js +++ b/embark-ui/src/components/Contract.js @@ -6,40 +6,46 @@ import { Card, Table } from "tabler-react"; +import {formatContractForDisplay} from '../utils/presentation'; +import {withRouter} from 'react-router-dom'; -const Contract = ({contract}) => ( - - - - - - - - Name - Address - State - - - - - {(contract.name || contract.className)} - {(contract.address || contract.deployedAddress)} - {contract.deploy} - - -
-
-
-
-
-); - -Contract.propTypes = { - contract: PropTypes.object +const Contract = ({contract, match}) => { + const contractDisplay = formatContractForDisplay(contract); + return ( + + + + + + + + Name + Address + State + + + + + {(contract.name || contract.className)} + {contractDisplay.address} + {contractDisplay.state} + + +
+
+
+
+
+ ); }; -export default Contract; +Contract.propTypes = { + contract: PropTypes.object, + match: PropTypes.object +}; + +export default withRouter(Contract); diff --git a/embark-ui/src/components/ContractLayout.js b/embark-ui/src/components/ContractLayout.js index 930d609c0..13360ac9a 100644 --- a/embark-ui/src/components/ContractLayout.js +++ b/embark-ui/src/components/ContractLayout.js @@ -17,7 +17,7 @@ import ContractSourceContainer from '../containers/ContractSourceContainer'; const ContractLayout = ({match}) => ( - Contract +  
( icon="corner-left-up" RootComponent={NavLink} > - Back to {match.params.contractName} + Overview ( @@ -28,11 +29,12 @@ const Contracts = ({contracts}) => ( { contracts.map((contract) => { + const contractDisplay = formatContractForDisplay(contract); return ( - + {contract.className} - {contract.address || 'Interface or not set to deploy'} - {contract.deploy ? 'Deployed' : 'Not deployed'} + {contractDisplay.address} + {contractDisplay.state} ); }) diff --git a/embark-ui/src/components/FiddleResults.js b/embark-ui/src/components/FiddleResults.js index f3c581743..5bf2460da 100644 --- a/embark-ui/src/components/FiddleResults.js +++ b/embark-ui/src/components/FiddleResults.js @@ -57,29 +57,51 @@ class FiddleResults extends Component { } render() { - const {warnings, errors, fatal, isLoading, deployedContracts} = this.props; - + const {warnings, errors, fatalFiddle, fatalFiddleDeploy, isLoading, deployedContracts} = this.props; + const hasFatal = fatalFiddle || fatalFiddleDeploy; let renderings = []; - if(fatal){ - renderings.push( - - - - ); - } - else if(isLoading){ + if(isLoading){ renderings.push(
{loadingMessage}
); } - else { - if(hasResult && !errors.length){ - renderings.push( - - Compiled - this.props.onDeployClick(e)} /> - - ); - } - if(errors.length) renderings.push( + if(fatalFiddle) { + renderings.push( - {errors.length} error{errors.length > 1 ? "s" : ""} - - ); - if(warnings.length) renderings.push( - - {warnings.length} warning{warnings.length > 1 ? "s" : ""} + Compilation ); } + + if(fatalFiddleDeploy) { + renderings.push( + + Deployment + + ); + } + + if(errors.length) renderings.push( + + {errors.length} error{errors.length > 1 ? "s" : ""} + + ); + if(warnings.length) renderings.push( + + {warnings.length} warning{warnings.length > 1 ? "s" : ""} + + ); + if(hasResult && !errors.length){ + renderings.push( + + Compiled + this.props.onDeployClick(e)} /> + + ); + } + return (
{renderings} @@ -55,7 +63,8 @@ FiddleResultsSummary.propTypes = { isLoading: PropTypes.bool, loadingMessage: PropTypes.string, hasResult: PropTypes.bool, - fatal: PropTypes.string, + fatalFiddle: PropTypes.string, + fatalFiddleDeploy: PropTypes.string, onDeployClick: PropTypes.func }; diff --git a/embark-ui/src/containers/FiddleContainer.js b/embark-ui/src/containers/FiddleContainer.js index 6e9ed8e51..9dc410670 100644 --- a/embark-ui/src/containers/FiddleContainer.js +++ b/embark-ui/src/containers/FiddleContainer.js @@ -82,7 +82,7 @@ class FiddleContainer extends Component { } render() { - const {fiddle, loading, error, deployedContracts} = this.props; + const {fiddle, loading, fiddleError, fiddleDeployError, deployedContracts} = this.props; const {loadingMessage} = this.state; let renderings = []; let warnings = []; @@ -99,7 +99,8 @@ class FiddleContainer extends Component { isLoading={loading} loadingMessage={loadingMessage} hasResult={Boolean(fiddle)} - fatal={error} + fatalFiddle={fiddleError} + fatalFiddleDeploy={fiddleDeployError} onDeployClick={(e) => this._onDeployClick(e)} /> ); - if (fiddle || (this.state.value && error)) { + if (fiddle || (this.state.value && (fiddleError || fiddleDeployError))) { renderings.push( ); @@ -143,23 +145,26 @@ function mapStateToProps(state) { return { fiddle: fiddle.data, deployedContracts: deployedFiddle.data, - error: fiddle.error || deployedFiddle.error, + fiddleError: fiddle.error, + fiddleDeployError: deployedFiddle.error, loading: state.loading }; } FiddleContainer.propTypes = { fiddle: PropTypes.object, - error: PropTypes.string, + fiddleError: PropTypes.string, + fiddleDeployError: PropTypes.string, loading: PropTypes.bool, postFiddle: PropTypes.func, - postFiddleDeploy: PropTypes.func + postFiddleDeploy: PropTypes.func, + deployedContracts: PropTypes.object }; export default connect( mapStateToProps, { - postFiddle: fiddleAction.request, - postFiddleDeploy: fiddleDeployAction.request + postFiddle: fiddleAction.post, + postFiddleDeploy: fiddleDeployAction.post }, )(FiddleContainer); diff --git a/embark-ui/src/reducers/selectors.js b/embark-ui/src/reducers/selectors.js index 847f59ba9..9887a1810 100644 --- a/embark-ui/src/reducers/selectors.js +++ b/embark-ui/src/reducers/selectors.js @@ -107,14 +107,14 @@ export function getMessages(state) { export function getFiddle(state) { return { data: _.last(state.entities.fiddles), - error: _.last(state.errorEntities.fiddles) + error: state.errorEntities.fiddles }; } export function getFiddleDeploy(state) { return { data: _.last(state.entities.fiddleDeploys), - error: _.last(state.errorEntities.fiddleDeploys) + error: state.errorEntities.fiddleDeploys }; } diff --git a/embark-ui/src/utils/presentation.js b/embark-ui/src/utils/presentation.js new file mode 100644 index 000000000..43ff127e4 --- /dev/null +++ b/embark-ui/src/utils/presentation.js @@ -0,0 +1,19 @@ +export function formatContractForDisplay(contract) { + let address = (contract.address || contract.deployedAddress); + let state = 'Deployed'; + let stateColor = 'success'; + if (contract.deploy === false) { + address = 'Interface or set to not deploy'; + state = 'N/A'; + stateColor = 'info'; + } else if (contract.error) { + address = contract.error; + state = 'Error'; + stateColor = 'danger'; + } else if (!address) { + address = '...'; + state = 'Pending'; + stateColor = 'warning'; + } + return {address, state, stateColor}; +} diff --git a/lib/modules/contracts_manager/index.js b/lib/modules/contracts_manager/index.js index 916c45e93..c2fc69c5c 100644 --- a/lib/modules/contracts_manager/index.js +++ b/lib/modules/contracts_manager/index.js @@ -1,6 +1,7 @@ let toposort = require('toposort'); let async = require('async'); const cloneDeep = require('clone-deep'); +const _ = require('lodash'); let utils = require('../../utils/utils.js'); @@ -169,22 +170,44 @@ class ContractsManager { 'post', '/embark-api/contract/deploy', (req, res) => { + this.logger.trace(`POST request /embark-api/contract/deploy:\n ${JSON.stringify(req.body)}`); self.compiledContracts = Object.assign(self.compiledContracts, req.body.compiledContract); + const contractNames = Object.keys(req.body.compiledContract); self.build((err, _mgr) => { - const responseData = {errors: err, contractNames: Object.keys(req.body.compiledContract)}; + if(err){ + return res.send({error: err.message}); + } + // pick the compiled contracts that have been built + const builtContracts = _.pick(self.contracts, contractNames); + + // for each contract, deploy (in parallel) + async.eachOf(builtContracts, (contract, contractName, callback) => { + contract.args = []; /* TODO: override contract.args */ + contract.className = contractName; + self.events.request("deploy:contract", contract, (err) => { + callback(err); + }); + }, (err) => { + let responseData = {}; + if(err){ + responseData.error = err.message; + } + else responseData.result = contractNames; this.logger.trace(`POST response /embark-api/contract/deploy:\n ${JSON.stringify(responseData)}`); res.send(responseData); - }, false); + }); + }, false, false); } ); } - build(done, useContractFiles = true) { + build(done, useContractFiles = true, resetContracts = true) { let self = this; self.contracts = {}; let compilerOptions = {disableOptimizations: this.disableOptimizations}; + if(resetContracts) self.contracts = {}; async.waterfall([ function loadContractFiles(callback) { self.events.request("config:contractsFiles", (contractsFiles) => { @@ -210,6 +233,12 @@ class ContractsManager { }, function prepareContractsFromConfig(callback) { self.events.emit("status", __("Building...")); + + // if we are appending contracts (ie fiddle), we + // don't need to build a contract from config, so + // we can skip this entirely + if(!resetContracts) return callback(); + let className, contract; for (className in self.contractsConfig.contracts) { contract = self.contractsConfig.contracts[className]; diff --git a/lib/modules/solidity/index.js b/lib/modules/solidity/index.js index ced9c980f..ab30cc13c 100644 --- a/lib/modules/solidity/index.js +++ b/lib/modules/solidity/index.js @@ -1,5 +1,6 @@ let async = require('../../utils/async_extend.js'); let SolcW = require('./solcW.js'); +const fs = require('../../core/fs'); class Solidity { @@ -19,8 +20,12 @@ class Solidity { 'post', '/embark-api/contract/compile', (req, res) => { - const input = {'fiddler': {content: req.body.code.replace(/\r\n/g, '\n')}}; + const input = {'fiddle': {content: req.body.code.replace(/\r\n/g, '\n')}}; this.compile_solidity_code(input, {}, true, (errors, compilationResult) => { + // write code to filesystem so we can view the source after page refresh + const filePath = `.embark/fiddles/${Object.keys(compilationResult).join('_')}.sol`; + fs.writeFile(filePath, req.body.code, 'utf8'); // async, do not need to wait + const responseData = {errors: errors, compilationResult: compilationResult}; this.logger.trace(`POST response /embark-api/contract/compile:\n ${JSON.stringify(responseData)}`); res.send(responseData); @@ -122,7 +127,8 @@ class Solidity { let contract = json[contractFile][contractName]; const className = contractName; - const filename = contractFile; + let filename = contractFile; + if(filename === 'fiddle') filename = `.embark/fiddles/${className}.sol`; compiled_object[className] = {}; compiled_object[className].code = contract.evm.bytecode.object;