diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index 34bb9c4e..4ee35715 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -288,10 +288,8 @@ export const file = { export const SAVE_FILE = createRequestTypes('SAVE_FILE'); export const saveFile = { - request: ({name, path, content}) => { - return action(SAVE_FILE[REQUEST], {name, path, content}); - }, - success: () => action(SAVE_FILE[SUCCESS]), + request: ({name, path, content}) => action(SAVE_FILE[REQUEST], {name, path, content}), + success: (_, {name, path, content}) => action(SAVE_FILE[SUCCESS], {name, path, content}), failure: (error) => action(SAVE_FILE[FAILURE], {error}) }; diff --git a/embark-ui/src/components/Account.js b/embark-ui/src/components/Account.js index 3cfed110..5b22bdfe 100644 --- a/embark-ui/src/components/Account.js +++ b/embark-ui/src/components/Account.js @@ -10,7 +10,7 @@ const Account = ({account}) => ( - Account {account.address} + {account.address}
diff --git a/embark-ui/src/components/Accounts.js b/embark-ui/src/components/Accounts.js index 35472d41..eb0116cf 100644 --- a/embark-ui/src/components/Accounts.js +++ b/embark-ui/src/components/Accounts.js @@ -12,15 +12,15 @@ const Accounts = ({accounts}) => ( {accounts.map(account => ( - - Account {account.address} - + Account  + {account.address} + Balance -
{account.balance} Wei
+
{account.balance} Ether
Tx Count diff --git a/embark-ui/src/components/Blocks.js b/embark-ui/src/components/Blocks.js index 355906c7..3ae9bb9e 100644 --- a/embark-ui/src/components/Blocks.js +++ b/embark-ui/src/components/Blocks.js @@ -12,7 +12,11 @@ const Blocks = ({blocks}) => ( {blocks.map(block => ( - Block {block.number} + Block  + + {block.number} + + diff --git a/embark-ui/src/components/CardTitleIdenticon.js b/embark-ui/src/components/CardTitleIdenticon.js index d3969217..e34d8886 100644 --- a/embark-ui/src/components/CardTitleIdenticon.js +++ b/embark-ui/src/components/CardTitleIdenticon.js @@ -6,4 +6,4 @@ const CardTitleIdenticon = ({id, children}) => ( {children} ) -export default CardTitleIdenticon \ No newline at end of file +export default CardTitleIdenticon diff --git a/embark-ui/src/components/ContractDetail.js b/embark-ui/src/components/ContractDetail.js new file mode 100644 index 00000000..5797afa7 --- /dev/null +++ b/embark-ui/src/components/ContractDetail.js @@ -0,0 +1,36 @@ +import PropTypes from "prop-types"; +import React from 'react'; +import ReactJson from "react-json-view"; +import {Row, Col, Table} from "reactstrap"; +import {formatContractForDisplay} from '../utils/presentation'; +import CopyButton from './CopyButton'; + +const ContractDetail = ({contract}) => { + const contractDisplay = formatContractForDisplay(contract); + return ( + + + ABI +
+ + {contract.abiDefinition && } +
+
+ Bytecode +
+ + {contract.runtimeBytecode} +
+ +
+ ); +}; + +ContractDetail.propTypes = { + contract: PropTypes.object +}; + +export default ContractDetail; + diff --git a/embark-ui/src/components/ContractFunctions.js b/embark-ui/src/components/ContractFunctions.js index 5af920c3..8953ce11 100644 --- a/embark-ui/src/components/ContractFunctions.js +++ b/embark-ui/src/components/ContractFunctions.js @@ -3,6 +3,7 @@ import React, {Component} from 'react'; import { Row, Col, + Form, FormGroup, Label, Input, @@ -12,6 +13,7 @@ import { CardHeader, CardTitle, CardFooter, + Collapse, ListGroup, ListGroupItem } from "reactstrap"; @@ -19,13 +21,17 @@ import { class ContractFunction extends Component { constructor(props) { super(props); - this.state = {inputs: {}}; + this.state = {inputs: {}, optionsCollapse: false, functionCollapse: false}; } static isPureCall(method) { return (method.mutability === 'view' || method.mutability === 'pure'); } + static isEvent(method) { + return !this.isPureCall(method) && (method.type === 'event'); + } + buttonTitle() { const {method} = this.props; if (method.name === 'constructor') { @@ -56,30 +62,65 @@ class ContractFunction extends Component { return this.inputsAsArray().length !== this.props.method.inputs.length; } + toggleOptions() { + this.setState({ + optionsCollapse: !this.state.optionsCollapse, + }); + } + + toggleFunction() { + this.setState({ + functionCollapse: !this.state.functionCollapse, + }); + } + render() { return ( - {this.props.method.name} + this.toggleFunction()}> + {ContractFunction.isPureCall(this.props.method) && + + } + {ContractFunction.isEvent(this.props.method) && + + } + {this.props.method.name}({this.props.method.inputs.map(input => input.name).join(', ')}) + - - {this.props.method.inputs.map(input => ( - - - this.handleChange(e, input.name)}/> - - ))} - {!ContractFunction.isPureCall(this.props.method) && - - - this.handleChange(e, 'gasPrice')}/> - - } - - + + +
+ {this.props.method.inputs.map(input => ( + + + this.handleChange(e, input.name)}/> + + ))} +
+ {!ContractFunction.isPureCall(this.props.method) && + + + this.toggleOptions()}>Advanced Options + +
+ + + this.handleChange(e, 'gasPrice')}/> + +
+
+
+ + } +
+ +
+
+
{this.props.contractFunctions && this.props.contractFunctions.length > 0 && {this.props.contractFunctions.map(contractFunction => ( diff --git a/embark-ui/src/components/ContractLayout.js b/embark-ui/src/components/ContractLayout.js index edc7da0b..acf8d114 100644 --- a/embark-ui/src/components/ContractLayout.js +++ b/embark-ui/src/components/ContractLayout.js @@ -3,9 +3,9 @@ import React from 'react'; import { TabContent, TabPane, Nav, NavItem, NavLink, Card, CardBody, CardTitle } from 'reactstrap'; import classnames from 'classnames'; -import ContractOverview from '../components/ContractOverview'; +import ContractDetail from '../components/ContractDetail'; import ContractLoggerContainer from '../containers/ContractLoggerContainer'; -import ContractFunctionsContainer from '../containers/ContractFunctionsContainer'; +import ContractOverviewContainer from '../containers/ContractOverviewContainer'; class ContractLayout extends React.Component { constructor(props) { @@ -44,7 +44,7 @@ class ContractLayout extends React.Component { className={classnames({ active: this.state.activeTab === '2' })} onClick={() => { this.toggle('2'); }} > - Functions + Detail @@ -58,10 +58,10 @@ class ContractLayout extends React.Component { - + - + diff --git a/embark-ui/src/components/ContractOverview.js b/embark-ui/src/components/ContractOverview.js index 69904113..837ced4c 100644 --- a/embark-ui/src/components/ContractOverview.js +++ b/embark-ui/src/components/ContractOverview.js @@ -1,54 +1,191 @@ import PropTypes from "prop-types"; -import React from 'react'; -import ReactJson from "react-json-view"; -import {Row, Col, Table} from "reactstrap"; +import React, {Component} from 'react'; +import { + Row, + Col, + Form, + FormGroup, + Label, + Input, + Button, + Card, + CardBody, + CardHeader, + CardTitle, + CardFooter, + Collapse, + ListGroup, + ListGroupItem +} from "reactstrap"; import {formatContractForDisplay} from '../utils/presentation'; -import CopyButton from './CopyButton'; -const Contract = ({contract}) => { +class ContractFunction extends Component { + constructor(props) { + super(props); + this.state = {inputs: {}, optionsCollapse: false, functionCollapse: false}; + } + + static isPureCall(method) { + return (method.mutability === 'view' || method.mutability === 'pure'); + } + + static isEvent(method) { + return !this.isPureCall(method) && (method.type === 'event'); + } + + buttonTitle() { + const {method} = this.props; + if (method.name === 'constructor') { + return 'Deploy'; + } + + return ContractFunction.isPureCall(method) ? 'Call' : 'Send'; + } + + inputsAsArray() { + return this.props.method.inputs + .map(input => this.state.inputs[input.name]) + .filter(value => value); + } + + handleChange(e, name) { + let newInputs = this.state.inputs; + newInputs[name] = e.target.value; + this.setState({inputs: newInputs}); + } + + handleCall(e) { + e.preventDefault(); + this.props.postContractFunction(this.props.contractProfile.name, this.props.method.name, this.inputsAsArray(), this.state.inputs.gasPrice * 1000000000); + } + + callDisabled() { + return this.inputsAsArray().length !== this.props.method.inputs.length; + } + + toggleOptions() { + this.setState({ + optionsCollapse: !this.state.optionsCollapse, + }); + } + + toggleFunction() { + this.setState({ + functionCollapse: !this.state.functionCollapse, + }); + } + + render() { + return ( + + + this.toggleFunction()}> + {ContractFunction.isPureCall(this.props.method) && + + } + {ContractFunction.isEvent(this.props.method) && + + } + {this.props.method.name}({this.props.method.inputs.map(input => input.name).join(', ')}) + + + + +
+ {this.props.method.inputs.map(input => ( + + + this.handleChange(e, input.name)}/> + + ))} +
+ {!ContractFunction.isPureCall(this.props.method) && + + + this.toggleOptions()}>Advanced Options + + + +
+ + + this.handleChange(e, 'gasPrice')}/> + +
+
+
+ +
+ + } +
+ +
+
+
+ {this.props.contractFunctions && this.props.contractFunctions.length > 0 && + + {this.props.contractFunctions.map(contractFunction => ( + + {contractFunction.inputs.length > 0 &&

Inputs: {contractFunction.inputs.join(', ')}

} + Result: {contractFunction.result} +
+ ))} +
+
} +
+ ); + } +} + +ContractFunction.propTypes = { + contractProfile: PropTypes.object, + method: PropTypes.object, + contractFunctions: PropTypes.arrayOf(PropTypes.object), + postContractFunction: PropTypes.func +}; + +const filterContractFunctions = (contractFunctions, contractName, method) => { + return contractFunctions.filter((contractFunction) => ( + contractFunction.contractName === contractName && contractFunction.method === method + )); +}; + +const ContractOverview = (props) => { + const {contractProfile, contract} = props; const contractDisplay = formatContractForDisplay(contract); + return ( - - - - - - - - - - - - - - - - - -
NameAddressState
{contract.className}{contractDisplay.address}{contractDisplay.state}
-

ABI

-
- - {contract.abiDefinition && } -
-

Bytecode

-
- - {contract.runtimeBytecode} -
- -
+
+ {(contractDisplay.state === 'Deployed') &&
Deployed at {contractDisplay.address}
} + {(contractDisplay.state !== 'Deployed') &&
{contractDisplay.address}
} +
+ {contractProfile.methods + .filter((method) => { + return props.onlyConstructor ? method.type === 'constructor' : method.type !== 'constructor'; + }) + .map(method => )} +
); }; -Contract.propTypes = { - contract: PropTypes.object +ContractOverview.propTypes = { + contract: PropTypes.object, + onlyConstructor: PropTypes.bool, + contractProfile: PropTypes.object, + contractFunctions: PropTypes.arrayOf(PropTypes.object), + postContractFunction: PropTypes.func }; -export default Contract; +ContractOverview.defaultProps = { + onlyConstructor: false +}; + +export default ContractOverview; diff --git a/embark-ui/src/components/Contracts.js b/embark-ui/src/components/Contracts.js index bee69040..1660b038 100644 --- a/embark-ui/src/components/Contracts.js +++ b/embark-ui/src/components/Contracts.js @@ -5,7 +5,7 @@ import ContractsList from './ContractsList'; const Contracts = ({contracts, title = "Contracts"}) => ( - + @@ -13,7 +13,7 @@ const Contracts = ({contracts, title = "Contracts"}) => ( Contracts -
+
diff --git a/embark-ui/src/components/ExplorerDashboardLayout.js b/embark-ui/src/components/ExplorerDashboardLayout.js index 97e9ad28..64a5e479 100644 --- a/embark-ui/src/components/ExplorerDashboardLayout.js +++ b/embark-ui/src/components/ExplorerDashboardLayout.js @@ -10,11 +10,6 @@ import TransactionsContainer from '../containers/TransactionsContainer'; const ExplorerDashboardLayout = () => ( - - -

Explorer

- -
diff --git a/embark-ui/src/components/FiddleLayout.css b/embark-ui/src/components/FiddleLayout.css deleted file mode 100644 index d51b2d3e..00000000 --- a/embark-ui/src/components/FiddleLayout.css +++ /dev/null @@ -1,4 +0,0 @@ -.fiddle--grid { - margin-left: -30px; - margin-right: -30px; -} \ No newline at end of file diff --git a/embark-ui/src/components/FiddleLayout.js b/embark-ui/src/components/FiddleLayout.js deleted file mode 100644 index 887db662..00000000 --- a/embark-ui/src/components/FiddleLayout.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import {Row, Col} from 'reactstrap'; -import TextEditorAsideContainer from '../containers/TextEditorAsideContainer'; -import TextEditorContainer from '../containers/TextEditorContainer'; -import FileExplorerContainer from '../containers/FileExplorerContainer'; - -import './FiddleLayout.css'; - -const DEFAULT_FILE = {name: 'newContract.sol', content: ''}; - -class FiddleLayout extends React.Component { - render() { - return ( - - - - - - - - - - - - ); - } -} - -export default FiddleLayout; diff --git a/embark-ui/src/components/FileExplorer.js b/embark-ui/src/components/FileExplorer.js index 313b4252..9eeab176 100644 --- a/embark-ui/src/components/FileExplorer.js +++ b/embark-ui/src/components/FileExplorer.js @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import {Treebeard, decorators} from 'react-treebeard'; -import {Input, Label, FormGroup} from 'reactstrap'; const style = { tree: { @@ -107,9 +106,7 @@ decorators.Header = Header; class FileExplorer extends React.Component { constructor(props) { super(props); - this.state = { - showHidden: false - }; + this.state = {cursor: null}; } onToggle(node, toggled) { @@ -122,10 +119,6 @@ class FileExplorer extends React.Component { this.setState({cursor: node}); } - onHiddenToggle(e) { - this.setState({showHidden: e.target.checked}); - } - nodeEquals(a, b) { return a && b && a.path && b.path && a.name && b.name && a.path === b.path && @@ -138,20 +131,21 @@ class FileExplorer extends React.Component { b.path.indexOf(a.path) > -1; } - filterHidden(nodes) { + data(nodes) { let filtered = []; if (!Array.isArray(nodes)) return filtered; + const cursor = this.state.cursor; + const showHidden = this.props.showHiddenFiles; // we need a foreach to build an array instead of a // filter to prevent mutating the original object (in props) nodes.forEach(node => { - const {showHidden, cursor} = this.state; if (!showHidden && node.isHidden) return; let updatedNode = {...node}; // if it's a folder, filter the children if (node.children) { - const children = this.filterHidden(node.children); + const children = this.data(node.children); if (children.length) { updatedNode.children = children; } @@ -178,14 +172,8 @@ class FileExplorer extends React.Component { render() { return (
- - - - + {HEADER_NAV_ITEMS.map((item) => ( @@ -220,7 +220,7 @@ class Layout extends React.Component { {searchResult.error} - + {children} diff --git a/embark-ui/src/components/Processes.js b/embark-ui/src/components/Processes.js index 9379cf01..5bcf2fdc 100644 --- a/embark-ui/src/components/Processes.js +++ b/embark-ui/src/components/Processes.js @@ -29,7 +29,7 @@ Process.propTypes = { }; const Processes = ({processes}) => ( - + {processes.map((process) => )} ); diff --git a/embark-ui/src/components/TextEditor.js b/embark-ui/src/components/TextEditor.js index ecf8aa1e..1b9efc7a 100644 --- a/embark-ui/src/components/TextEditor.js +++ b/embark-ui/src/components/TextEditor.js @@ -7,7 +7,7 @@ import './TextEditor.css'; const SUPPORTED_LANGUAGES = ['css', 'sol', 'html', 'json']; const DEFAULT_LANGUAGE = 'javascript'; const EDITOR_ID = 'react-monaco-editor-container'; -const GUTTER_GLYPH_MARGIN = 3; +const GUTTER_GLYPH_MARGIN = 2; let editor; @@ -62,19 +62,20 @@ class TextEditor extends React.Component { } updateMarkers() { - const {errors, warnings} = this.props.contractCompile; - const markers = [].concat(errors).concat(warnings).filter((e) => e).map((e) => { - const {row, col} = this.extractRowCol(e.formattedMessage); - return { - startLineNumber: row, - startColumn: col, - endLineNumber: row, - endColumn: col + 1, - message: e.formattedMessage, - severity: e.severity - }; - }); - monaco.editor.setModelMarkers(editor.getModel(), 'test', markers); + // TODO: Fetch Result of compilation in embark, via ws + // const {errors, warnings} = this.props.contractCompile; + // const markers = [].concat(errors).concat(warnings).filter((e) => e).map((e) => { + // const {row, col} = this.extractRowCol(e.formattedMessage); + // return { + // startLineNumber: row, + // startColumn: col, + // endLineNumber: row, + // endColumn: col + 1, + // message: e.formattedMessage, + // severity: e.severity + // }; + // }); + // monaco.editor.setModelMarkers(editor.getModel(), 'test', markers); } updateLanguage() { @@ -121,6 +122,7 @@ class TextEditor extends React.Component { this.updateDecorations(); } this.updateLanguage(); + this.handleResize(); } render() { @@ -135,7 +137,6 @@ class TextEditor extends React.Component { TextEditor.propTypes = { onFileContentChange: PropTypes.func, file: PropTypes.object, - contractCompile: PropTypes.object, toggleBreakpoint: PropTypes.func, breakpoints: PropTypes.array, debuggerLine: PropTypes.number diff --git a/embark-ui/src/components/TextEditorContractDeploy.js b/embark-ui/src/components/TextEditorContractDeploy.js deleted file mode 100644 index 5255449b..00000000 --- a/embark-ui/src/components/TextEditorContractDeploy.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {Card, CardHeader, CardTitle, CardBody} from 'reactstrap'; -import FontAwesomeIcon from 'react-fontawesome'; - -import ContractFunctions from '../components/ContractFunctions'; - -const TextEditorContractDeploy = (props) => { - const name = Object.keys(props.result)[0]; - const profile = { - name, - methods: props.result[name].abiDefinition - }; - return ( - - - - - Deploy Contract - - - - - - - ); -}; - -TextEditorContractDeploy.propTypes = { - result: PropTypes.object, - postContractDeploy: PropTypes.func, - contractDeploys: PropTypes.array -}; - -export default TextEditorContractDeploy; diff --git a/embark-ui/src/components/TextEditorContractErrors.js b/embark-ui/src/components/TextEditorContractErrors.js deleted file mode 100644 index 93946418..00000000 --- a/embark-ui/src/components/TextEditorContractErrors.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {Card, CardBody, CardHeader, CardTitle, ListGroup, ListGroupItem} from 'reactstrap'; -import FontAwesomeIcon from 'react-fontawesome'; - -const TextEditorContractErrors = (props) => ( - - - - - Failed to compile - - - - - {props.errors.map((error, index) => {error.formattedMessage})} - - - -); - -TextEditorContractErrors.propTypes = { - errors: PropTypes.array -}; - -export default TextEditorContractErrors; diff --git a/embark-ui/src/components/TextEditorContractToolbar.js b/embark-ui/src/components/TextEditorContractToolbar.js deleted file mode 100644 index 6a7ae8fc..00000000 --- a/embark-ui/src/components/TextEditorContractToolbar.js +++ /dev/null @@ -1,32 +0,0 @@ -import React, {Component} from 'react'; -import PropTypes from 'prop-types'; -import {Col, Badge} from 'reactstrap'; -import FontAwesomeIcon from 'react-fontawesome'; -import TextEditorToolbar from './TextEditorToolbar'; - -class TextEditorContractToolbar extends Component { - render(){ - return ( - - - - {this.props.compilingContract && - compiling} - {!this.props.compilingContract && this.props.contractCompile.result && - compiled} - - - ); - } -} - -TextEditorContractToolbar.propTypes = { - currentFile: PropTypes.object, - contractCompile: PropTypes.object, - compilingContract: PropTypes.bool, - deploy: PropTypes.func, - save: PropTypes.func, - remove: PropTypes.func -}; - -export default TextEditorContractToolbar; diff --git a/embark-ui/src/components/TextEditorContractWarnings.js b/embark-ui/src/components/TextEditorContractWarnings.js deleted file mode 100644 index adad2dfb..00000000 --- a/embark-ui/src/components/TextEditorContractWarnings.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {Card, CardHeader, CardBody, CardTitle, ListGroup, ListGroupItem} from 'reactstrap'; -import FontAwesomeIcon from 'react-fontawesome'; - -const TextEditorContractWarnings = (props) => ( - - - - - Warning during compilation - - - - - {props.warnings.map((warning, index) => {warning.formattedMessage})} - - - -); - -TextEditorContractWarnings.propTypes = { - warnings: PropTypes.array -}; - -export default TextEditorContractWarnings; diff --git a/embark-ui/src/components/TextEditorToolbar.js b/embark-ui/src/components/TextEditorToolbar.js index f4f6f18d..4eaf4305 100644 --- a/embark-ui/src/components/TextEditorToolbar.js +++ b/embark-ui/src/components/TextEditorToolbar.js @@ -1,21 +1,63 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {Col, Button} from 'reactstrap'; +import {Row, Label, Col, Button} from 'reactstrap'; +import FontAwesomeIcon from 'react-fontawesome'; +import { AppSwitch } from '@coreui/react' const TextEditorToolbar = (props) => ( - - {props.currentFile.name} - | - - | - - + + + + + + {props.currentFile.name} + | + + | + + + +
+ {props.isContract && + + + | + + | + + | + + } + +
+ +
); TextEditorToolbar.propTypes = { currentFile: PropTypes.object, + isContract: PropTypes.bool, save: PropTypes.func, - remove: PropTypes.func + remove: PropTypes.func, + toggleShowHiddenFiles: PropTypes.func, + openAsideTab: PropTypes.func }; export default TextEditorToolbar; diff --git a/embark-ui/src/components/Transaction.js b/embark-ui/src/components/Transaction.js index b7859586..4f8140fa 100644 --- a/embark-ui/src/components/Transaction.js +++ b/embark-ui/src/components/Transaction.js @@ -5,6 +5,8 @@ import PropTypes from 'prop-types'; import Description from './Description'; import CardTitleIdenticon from './CardTitleIdenticon'; +import {utils} from 'web3'; + const Transaction = ({transaction}) => ( @@ -18,7 +20,7 @@ const Transaction = ({transaction}) => ( {transaction.blockNumber}} /> - + diff --git a/embark-ui/src/components/Transactions.js b/embark-ui/src/components/Transactions.js index 030a23f0..afe78984 100644 --- a/embark-ui/src/components/Transactions.js +++ b/embark-ui/src/components/Transactions.js @@ -12,9 +12,11 @@ const Transactions = ({transactions}) => ( {transactions.map(transaction => ( - - Transaction {transaction.hash} - + Transaction  + + {transaction.hash} + + diff --git a/embark-ui/src/containers/ContractContainer.js b/embark-ui/src/containers/ContractContainer.js deleted file mode 100644 index 5c8f516f..00000000 --- a/embark-ui/src/containers/ContractContainer.js +++ /dev/null @@ -1,36 +0,0 @@ -import React, {Component} from 'react'; -import {connect} from 'react-redux'; -import PropTypes from 'prop-types'; -import {withRouter} from 'react-router-dom'; - -import Contract from '../components/Contract'; -import DataWrapper from "../components/DataWrapper"; -import {getContract} from "../reducers/selectors"; - -class ContractContainer extends Component { - render() { - return ( - ( - - )} /> - ); - } -} - -function mapStateToProps(state, props) { - return { - contract: getContract(state, props.match.params.contractName), - error: state.errorMessage, - loading: state.loading - }; -} - -ContractContainer.propTypes = { - match: PropTypes.object, - contract: PropTypes.object, - error: PropTypes.string -}; - -export default withRouter(connect( - mapStateToProps -)(ContractContainer)); diff --git a/embark-ui/src/containers/ContractFunctionsContainer.js b/embark-ui/src/containers/ContractOverviewContainer.js similarity index 84% rename from embark-ui/src/containers/ContractFunctionsContainer.js rename to embark-ui/src/containers/ContractOverviewContainer.js index 9f182d91..a32fec39 100644 --- a/embark-ui/src/containers/ContractFunctionsContainer.js +++ b/embark-ui/src/containers/ContractOverviewContainer.js @@ -3,12 +3,12 @@ import {connect} from 'react-redux'; import PropTypes from 'prop-types'; import {contractProfile as contractProfileAction, contractFunction as contractFunctionAction} from '../actions'; -import ContractFunctions from '../components/ContractFunctions'; +import ContractOverview from '../components/ContractOverview'; import DataWrapper from "../components/DataWrapper"; import GasStationContainer from "../containers/GasStationContainer"; import {getContractProfile, getContractFunctions} from "../reducers/selectors"; -class ContractFunctionsContainer extends Component { +class ContractOverviewContainer extends Component { componentDidMount() { this.props.fetchContractProfile(this.props.contract.className); } @@ -19,8 +19,9 @@ class ContractFunctionsContainer extends Component { {...this.props} render={({contractProfile, contractFunctions, postContractFunction}) => ( - @@ -39,7 +40,7 @@ function mapStateToProps(state, props) { }; } -ContractFunctionsContainer.propTypes = { +ContractOverviewContainer.propTypes = { contract: PropTypes.object, contractProfile: PropTypes.object, contractFunctions: PropTypes.arrayOf(PropTypes.object), @@ -54,4 +55,4 @@ export default connect( fetchContractProfile: contractProfileAction.request, postContractFunction: contractFunctionAction.post } -)(ContractFunctionsContainer); +)(ContractOverviewContainer); diff --git a/embark-ui/src/containers/EditorContainer.css b/embark-ui/src/containers/EditorContainer.css new file mode 100644 index 00000000..524a508c --- /dev/null +++ b/embark-ui/src/containers/EditorContainer.css @@ -0,0 +1,4 @@ +.editor--grid { + margin-left: -30px !important; + margin-right: -30px !important; +} \ No newline at end of file diff --git a/embark-ui/src/containers/EditorContainer.js b/embark-ui/src/containers/EditorContainer.js new file mode 100644 index 00000000..3a0b6486 --- /dev/null +++ b/embark-ui/src/containers/EditorContainer.js @@ -0,0 +1,103 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {connect} from 'react-redux'; +import {Row, Col} from 'reactstrap'; +import TextEditorAsideContainer from './TextEditorAsideContainer'; +import TextEditorContainer from './TextEditorContainer'; +import FileExplorerContainer from './FileExplorerContainer'; +import TextEditorToolbarContainer from './TextEditorToolbarContainer'; +import {currentFile as currentFileAction} from '../actions'; +import {getCurrentFile} from '../reducers/selectors'; + +import './EditorContainer.css'; + +const DEFAULT_FILE = {name: 'newContract.sol', content: ''}; + +class EditorContainer extends React.Component { + constructor(props) { + super(props) + this.state = {currentAsideTab: '', showHiddenFiles: false, currentFile: this.props.currentFile} + } + + componentDidMount() { + if(this.props.currentFile.content === '') { + this.props.fetchCurrentFile(); + } + } + + componentDidUpdate(prevProps) { + if(this.props.currentFile.path !== prevProps.currentFile.path) { + this.setState({currentFile: this.props.currentFile}); + } + } + + isContract() { + return this.state.currentFile.name.endsWith('.sol'); + } + + onFileContentChange(newContent) { + const newCurrentFile = this.state.currentFile; + newCurrentFile.content = newContent; + this.setState({currentFile: newCurrentFile}); + } + + toggleShowHiddenFiles() { + this.setState({showHiddenFiles: !this.state.showHiddenFiles}); + } + + openAsideTab(newTab) { + if (newTab === this.state.currentAsideTab) { + return this.setState({currentAsideTab: ''}) + } + this.setState({currentAsideTab: newTab}) + } + + textEditorMdSize() { + return this.state.currentAsideTab.length ? 5 : 10 + } + + textEditorXsSize() { + return this.state.currentAsideTab.length ? 2 : 8 + } + + render() { + return ( + + + this.toggleShowHiddenFiles()} + openAsideTab={(newTab) => this.openAsideTab(newTab)} + isContract={this.isContract()} + currentFile={this.props.currentFile} /> + + + + + + this.onFileContentChange(newContent)} /> + + {this.state.currentAsideTab && + + } + + ); + } +} + +function mapStateToProps(state, props) { + const currentFile = getCurrentFile(state) || DEFAULT_FILE; + + return { + currentFile + }; +} + +EditorContainer.propTypes = { + currentFile: PropTypes.object, + fetchCurrentFile: PropTypes.func +}; + +export default connect( + mapStateToProps, + {fetchCurrentFile: currentFileAction.request}, +)(EditorContainer); + diff --git a/embark-ui/src/containers/FileContractsContainer.js b/embark-ui/src/containers/FileContractsContainer.js deleted file mode 100644 index 5591aa5e..00000000 --- a/embark-ui/src/containers/FileContractsContainer.js +++ /dev/null @@ -1,41 +0,0 @@ -import React, {Component} from 'react'; -import {connect} from 'react-redux'; -import PropTypes from 'prop-types'; - -import {contracts as contractsAction} from '../actions'; -import ContractLayout from '../components/ContractLayout'; -import {getContractsByPath} from "../reducers/selectors"; - -class FileContractsContainer extends Component { - componentDidMount() { - this.props.fetchContracts(); - } - - render() { - return ( - this.props.contracts.map(contract => ) - ) - } -} - -function mapStateToProps(state, props) { - return { - contracts: getContractsByPath(state, props.currentFile.path), - error: state.errorMessage, - loading: state.loading - }; -} - -FileContractsContainer.propTypes = { - contracts: PropTypes.arrayOf(PropTypes.object), - fetchContractsByPath: PropTypes.func, - error: PropTypes.string, - loading: PropTypes.bool -}; - -export default connect( - mapStateToProps, - { - fetchContracts: contractsAction.request - } -)(FileContractsContainer); diff --git a/embark-ui/src/containers/FileExplorerContainer.js b/embark-ui/src/containers/FileExplorerContainer.js index ef36f318..4a7729a5 100644 --- a/embark-ui/src/containers/FileExplorerContainer.js +++ b/embark-ui/src/containers/FileExplorerContainer.js @@ -14,21 +14,22 @@ class FileExplorerContainer extends Component { render() { return ( - 0} {...this.props} render={({files, fetchFile}) => ( - + 0} {...this.props} render={({files, fetchFile, showHiddenFiles}) => ( + )} /> ); } } function mapStateToProps(state) { - return {files: getFiles(state), error: state.errorMessage, loading: state.loading}; + return {files: getFiles(state)}; } FileExplorerContainer.propTypes = { files: PropTypes.array, fetchFiles: PropTypes.func, - fetchFile: PropTypes.func + fetchFile: PropTypes.func, + showHiddenFiles: PropTypes.bool, }; export default connect( diff --git a/embark-ui/src/containers/TextEditorAsideContainer.js b/embark-ui/src/containers/TextEditorAsideContainer.js index c50177fd..2a9f7394 100644 --- a/embark-ui/src/containers/TextEditorAsideContainer.js +++ b/embark-ui/src/containers/TextEditorAsideContainer.js @@ -1,59 +1,79 @@ import React, {Component} from 'react'; import {connect} from 'react-redux'; import PropTypes from 'prop-types'; -import { - currentFile as currentFileAction, -} from '../actions'; -import {getCurrentFile} from '../reducers/selectors'; +import { Card, CardBody, CardTitle } from 'reactstrap'; + import Preview from '../components/Preview'; -import FileContractsContainer from './FileContractsContainer'; +import {contracts as contractsAction} from '../actions'; +import {getContractsByPath} from "../reducers/selectors"; +import ContractDetail from '../components/ContractDetail'; +import ContractLoggerContainer from '../containers/ContractLoggerContainer'; +import ContractOverviewContainer from '../containers/ContractOverviewContainer'; class TextEditorAsideContainer extends Component { - constructor(props) { - super(props); - this.state = {currentFile: this.props.currentFile}; - } - componentDidMount() { - this.props.fetchCurrentFile(); - } - - componentDidUpdate(prevProps) { - if(this.props.currentFile.path !== prevProps.currentFile.path) { - this.setState({currentFile: this.props.currentFile}); - } - } - - isContract() { - return this.state.currentFile.name.endsWith('.sol'); + this.props.fetchContracts(); } render() { - return this.isContract() ? : + switch(this.props.currentAsideTab) { + case 'browser': + return + case 'detail': + return this.props.contracts.map((contract, index) => { + return ( + + + {contract.className} - Details + + + + ) + }) + case 'logger': + return this.props.contracts.map((contract, index) => { + return ( + + + {contract.className} - Transactions + ) + + + ) + }) + case 'overview': + return this.props.contracts.map((contract, index) => { + return ( + + + {contract.className} - Overview + + + + ) + }) + default: + return ; + } } } function mapStateToProps(state, props) { - const currentFile = getCurrentFile(state) || props.defaultFile - return { - currentFile, - loading: state.loading, - error: state.errorMessage + contracts: getContractsByPath(state, props.currentFile.path) }; } TextEditorAsideContainer.propTypes = { currentFile: PropTypes.object, - fetchCurrentFile: PropTypes.func, - loading: PropTypes.bool, - error: PropTypes.string, - defaultFile: PropTypes.object + currentAsideTab: PropTypes.string, + contract: PropTypes.array, + fetchContracts: PropTypes.func }; export default connect( mapStateToProps, { - fetchCurrentFile: currentFileAction.request, + fetchContracts: contractsAction.request, }, )(TextEditorAsideContainer); diff --git a/embark-ui/src/containers/TextEditorContainer.js b/embark-ui/src/containers/TextEditorContainer.js index 2e76e84f..4f8489cf 100644 --- a/embark-ui/src/containers/TextEditorContainer.js +++ b/embark-ui/src/containers/TextEditorContainer.js @@ -1,157 +1,32 @@ -import React, {Component} from 'react'; +import React from 'react'; import {connect} from 'react-redux'; import PropTypes from 'prop-types'; import TextEditor from '../components/TextEditor'; -import TextEditorContractErrors from '../components/TextEditorContractErrors'; -import TextEditorContractWarnings from '../components/TextEditorContractWarnings'; -import TextEditorContractToolbar from '../components/TextEditorContractToolbar'; -import TextEditorContractDeploy from '../components/TextEditorContractDeploy'; -import TextEditorToolbar from '../components/TextEditorToolbar'; import { - currentFile as currentFileAction, - saveCurrentFile as saveCurrentFileAction, - saveFile as saveFileAction, - removeFile as removeFileAction, - contractCompile as contractCompileAction, - contractDeploy as postContractDeploy, toggleBreakpoint, } from '../actions'; -import {getCurrentFile, getContractCompile, getContractDeploys, getBreakpointsByFilename} from '../reducers/selectors'; +import {getBreakpointsByFilename} from '../reducers/selectors'; -class TextEditorContainer extends Component { - constructor(props) { - super(props); - this.state = {currentFile: this.props.currentFile}; - } - - componentDidMount() { - if(this.props.currentFile.content === '') { - this.props.fetchCurrentFile(); - } - } - - componentDidUpdate(prevProps) { - if(this.props.currentFile.path !== prevProps.currentFile.path) { - this.setState({currentFile: this.props.currentFile}); - } - } - - isContract() { - return this.state.currentFile.name.endsWith('.sol'); - } - - onFileContentChange(newContent) { - const newCurrentFile = this.state.currentFile; - newCurrentFile.content = newContent; - this.setState({currentFile: newCurrentFile}); - if (!this.isContract()) return; - - this.compileTimeout = setTimeout(() => { - this.props.compileContract(newContent, this.state.currentFile.name); - }, 1000); - } - - save() { - this.props.saveFile(this.state.currentFile); - this.props.saveCurrentFile(this.state.currentFile); - } - - remove() { - this.props.removeFile(this.state.currentFile); - this.setState({currentFile: this.props.defaultFile}); - } - - renderContractFooter() { - if (!this.isContract()) return ; - let components = []; - - const {errors, warnings, result} = this.props.contractCompile; - if (errors && errors.length > 0) { - components.push(); - } - - if (warnings && warnings.length > 0) { - components.push(); - } - - if (result) { - components.push(); - } - return {components}; - } - - renderToolbar(){ - if (this.isContract()) { - return this.save()} - remove={() => this.remove()} />; - } - return this.save()} - remove={() => this.remove()} />; - } - - render() { - return ( - this.onFileContentChange(newContent)} /> - ); - } -} +const TextEditorContainer = (props) => ( + +) function mapStateToProps(state, props) { - const currentFile = getCurrentFile(state) || props.defaultFile; - const contractCompile = getContractCompile(state, currentFile) || {}; - const contractName = contractCompile.result && Object.keys(contractCompile.result)[0]; - const contractDeploys = getContractDeploys(state, contractName); - const breakpoints = getBreakpointsByFilename(state, currentFile.name); - return { - compilingContract: state.compilingContract, - loading: state.loading, - error: state.errorMessage, - currentFile, - contractCompile, - contractDeploys, - breakpoints, - }; + const breakpoints = getBreakpointsByFilename(state, props.currentFile.name); + return {breakpoints}; } TextEditorContainer.propTypes = { - defaultFile: PropTypes.object, currentFile: PropTypes.object, - contractCompile: PropTypes.object, - saveCurrentFile: PropTypes.func, - fetchCurrentFile: PropTypes.func, - saveFile: PropTypes.func, - removeFile: PropTypes.func, - postContractDeploy: PropTypes.func, - compileContract: PropTypes.func, - compilingContract: PropTypes.bool, - contractDeploys: PropTypes.array, - loading: PropTypes.bool, - error: PropTypes.string, + onFileContentChange: PropTypes.func, toggleBreakpoints: PropTypes.func, breakpoints: PropTypes.array, }; export default connect( mapStateToProps, - { - fetchCurrentFile: currentFileAction.request, - saveCurrentFile: saveCurrentFileAction.request, - saveFile: saveFileAction.request, - removeFile: removeFileAction.request, - postContractDeploy: postContractDeploy.post, - compileContract: contractCompileAction.post, - toggleBreakpoint, - }, + {toggleBreakpoint}, )(TextEditorContainer); diff --git a/embark-ui/src/containers/TextEditorToolbarContainer.js b/embark-ui/src/containers/TextEditorToolbarContainer.js new file mode 100644 index 00000000..74653f4c --- /dev/null +++ b/embark-ui/src/containers/TextEditorToolbarContainer.js @@ -0,0 +1,45 @@ +import React, {Component} from 'react'; +import {connect} from 'react-redux'; +import PropTypes from 'prop-types'; +import TextEditorToolbar from '../components/TextEditorToolbar'; + +import { + saveFile as saveFileAction, + removeFile as removeFileAction, +} from '../actions'; + +class TextEditorToolbarContainer extends Component { + save() { + this.props.saveFile(this.props.currentFile); + } + + remove() { + this.props.removeFile(this.props.currentFile); + } + + render() { + return this.save()} + remove={() => this.remove()} />; + } +} + +TextEditorToolbarContainer.propTypes = { + currentFile: PropTypes.object, + isContract: PropTypes.bool, + saveFile: PropTypes.func, + removeFile: PropTypes.func, + toggleShowHiddenFiles: PropTypes.func, + openAsideTab: PropTypes.func +}; + +export default connect( + null, + { + saveFile: saveFileAction.request, + removeFile: removeFileAction.request + }, +)(TextEditorToolbarContainer); diff --git a/embark-ui/src/dark-theme/_nav.scss b/embark-ui/src/dark-theme/_nav.scss index 6316157a..d2507f5c 100644 --- a/embark-ui/src/dark-theme/_nav.scss +++ b/embark-ui/src/dark-theme/_nav.scss @@ -1,6 +1,6 @@ .nav-tabs { .nav-link { - color: $gray-600; + color: $white; &:hover { cursor: pointer; } diff --git a/embark-ui/src/dark-theme/_variables.scss b/embark-ui/src/dark-theme/_variables.scss index 2107fb3a..34267446 100644 --- a/embark-ui/src/dark-theme/_variables.scss +++ b/embark-ui/src/dark-theme/_variables.scss @@ -33,7 +33,7 @@ $navbar-brand-minimized-width: 50px !default; $navbar-brand-minimized-bg: $navbar-brand-bg !default; $navbar-brand-minimized-border: $navbar-brand-border !default; -$navbar-color: $gray-300 !default; +$navbar-color: $white !default; $navbar-hover-color: $gray-200 !default; $navbar-active-color: $gray-200 !default; $navbar-disabled-color: $gray-300 !default; diff --git a/embark-ui/src/index.css b/embark-ui/src/index.css index b36d836d..81320aa2 100644 --- a/embark-ui/src/index.css +++ b/embark-ui/src/index.css @@ -15,7 +15,7 @@ } .text-wrap { - word-wrap: break-word; + word-wrap: break-word; } .relative { @@ -28,3 +28,11 @@ .react-json-view { border-radius: .25rem; } + +.collapsable:hover { + cursor: pointer; +} + +.contractFunction { + margin-bottom: 0px; +} diff --git a/embark-ui/src/routes.js b/embark-ui/src/routes.js index 827f2409..9ce0f0a4 100644 --- a/embark-ui/src/routes.js +++ b/embark-ui/src/routes.js @@ -4,11 +4,11 @@ import {Route, Switch} from 'react-router-dom'; import HomeContainer from './containers/HomeContainer'; import ContractsContainer from './containers/ContractsContainer'; import ContractLayoutContainer from './containers/ContractLayoutContainer'; +import EditorContainer from './containers/EditorContainer'; import DeploymentContainer from './containers/DeploymentContainer'; import NoMatch from './components/NoMatch'; import ExplorerDashboardLayout from './components/ExplorerDashboardLayout'; import ExplorerLayout from './components/ExplorerLayout'; -import FiddleLayout from './components/FiddleLayout'; import UtilsLayout from './components/UtilsLayout'; const routes = ( @@ -20,7 +20,7 @@ const routes = ( - + diff --git a/embark-ui/src/sagas/index.js b/embark-ui/src/sagas/index.js index 1988a0d0..fe9a7f7c 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -200,6 +200,10 @@ export function *watchPostFile() { yield takeEvery(actions.SAVE_FILE[actions.REQUEST], postFile); } +export function *watchPostFileSuccess() { + yield takeEvery(actions.SAVE_FILE[actions.SUCCESS], postCurrentFile); +} + export function *watchDeleteFile() { yield takeEvery(actions.REMOVE_FILE[actions.REQUEST], deleteFile); } @@ -217,10 +221,6 @@ export function *watchFetchCurrentFile() { yield takeEvery(actions.CURRENT_FILE[actions.REQUEST], fetchCurrentFile); } -export function *watchPostCurrentFile() { - yield takeEvery(actions.SAVE_CURRENT_FILE[actions.REQUEST], postCurrentFile); -} - export function *watchFetchEthGas() { yield takeEvery(actions.GAS_ORACLE[actions.REQUEST], fetchEthGas); } @@ -433,7 +433,7 @@ export default function *root() { fork(watchDeleteFileSuccess), fork(watchFetchFileSuccess), fork(watchFetchCurrentFile), - fork(watchPostCurrentFile), + fork(watchPostFileSuccess), fork(watchFetchCredentials), fork(watchFetchEthGas), fork(watchAuthenticate),