diff --git a/embark-ui/package-lock.json b/embark-ui/package-lock.json index b57f63d0d..8c3da60b9 100644 --- a/embark-ui/package-lock.json +++ b/embark-ui/package-lock.json @@ -2039,11 +2039,47 @@ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.3.0.tgz", "integrity": "sha512-MAAAIOdi2s4Gl6rZ76PNcUa9IOYB+5ICdT41o5uMRf09aEu/F9RK+qhe8RjXNPwcTjGV7KU7h2P/fljThFVqyQ==" }, + "component-clone": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/component-clone/-/component-clone-0.2.2.tgz", + "integrity": "sha1-x/WXmCKID62M+wliuikYbQYe4E8=", + "requires": { + "component-type": "*" + } + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" }, + "component-raf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/component-raf/-/component-raf-1.2.0.tgz", + "integrity": "sha1-srxy1D8bAU/eeks8RHx2S8c8y6o=" + }, + "component-tween": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/component-tween/-/component-tween-1.2.0.tgz", + "integrity": "sha1-zDnOXbqwW1KCX0HRlHY4oLAbK4o=", + "requires": { + "component-clone": "0.2.2", + "component-emitter": "1.2.0", + "component-type": "1.1.0", + "ease-component": "1.0.0" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.0.tgz", + "integrity": "sha1-zNETqGOI0GSC0D3j/H35hSa6jv4=" + } + } + }, + "component-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.1.0.tgz", + "integrity": "sha1-lbZmqtU+XI0fK+E1xFtdSZGXwMU=" + }, "compressible": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz", @@ -2835,6 +2871,11 @@ "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" }, + "ease-component": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ease-component/-/ease-component-1.0.0.tgz", + "integrity": "sha1-s3VybbC1sEWVt3RAOW/sfapdd8k=" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -9033,6 +9074,14 @@ } } }, + "react-scroll-to-component": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/react-scroll-to-component/-/react-scroll-to-component-1.0.2.tgz", + "integrity": "sha1-8mDck2xipT53J4bXgy/giE4ZU1Q=", + "requires": { + "scroll-to": "0.0.2" + } + }, "react-text-mask": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/react-text-mask/-/react-text-mask-5.4.3.tgz", @@ -9554,6 +9603,15 @@ "ajv": "^5.0.0" } }, + "scroll-to": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/scroll-to/-/scroll-to-0.0.2.tgz", + "integrity": "sha1-k205ipEzZgokkhRcLACB38sHKPM=", + "requires": { + "component-raf": "1.2.0", + "component-tween": "1.2.0" + } + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", diff --git a/embark-ui/package.json b/embark-ui/package.json index 6fc98abab..99671d5fa 100644 --- a/embark-ui/package.json +++ b/embark-ui/package.json @@ -15,6 +15,7 @@ "react-redux": "^5.0.7", "react-router-dom": "^4.3.1", "react-scripts": "1.1.4", + "react-scroll-to-component": "^1.0.2", "redux": "^4.0.0", "redux-saga": "^0.16.0", "tabler-react": "^1.18.0" diff --git a/embark-ui/public/monaco-editor-worker-loader-proxy.js b/embark-ui/public/monaco-editor-worker-loader-proxy.js deleted file mode 100644 index 0585b5c06..000000000 --- a/embark-ui/public/monaco-editor-worker-loader-proxy.js +++ /dev/null @@ -1,5 +0,0 @@ -self.MonacoEnvironment = { - baseUrl: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.13.1/min/' -}; - -importScripts('https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.13.1/min/vs/base/worker/workerMain.js'); // eslint-disable-line diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index 50b6670b8..834b5d97b 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -144,13 +144,13 @@ export function listenToContractLogs() { } // Fiddle -export const FETCH_COMPILE_CODE = 'FETCH_COMPILE_CODE'; -export const RECEIVE_COMPILE_CODE = 'RECEIVE_COMPILE_CODE'; -export const RECEIVE_COMPILE_CODE_ERROR = 'RECEIVE_COMPILE_CODE_ERROR'; +export const COMPILE_CODE_REQUEST = 'COMPILE_CODE_REQUEST'; +export const COMPILE_CODE_SUCCESS = 'COMPILE_CODE_SUCCESS'; +export const COMPILE_CODE_FAILURE = 'COMPILE_CODE_FAILURE'; export function fetchCodeCompilation(codeToCompile){ return { - type: FETCH_COMPILE_CODE, + type: COMPILE_CODE_REQUEST, codeToCompile }; } @@ -158,14 +158,14 @@ export function fetchCodeCompilation(codeToCompile){ export function receiveCodeCompilation(compilationResult){ return { - type: RECEIVE_COMPILE_CODE, + type: COMPILE_CODE_SUCCESS, compilationResult }; } export function receiveCodeCompilationError(){ return { - type: RECEIVE_COMPILE_CODE_ERROR + type: COMPILE_CODE_FAILURE }; } diff --git a/embark-ui/src/components/Fiddle.js b/embark-ui/src/components/Fiddle.js index 6d6183049..a380fe935 100644 --- a/embark-ui/src/components/Fiddle.js +++ b/embark-ui/src/components/Fiddle.js @@ -5,28 +5,49 @@ import 'brace/theme/tomorrow_night_blue'; import 'ace-mode-solidity/build/remix-ide/mode-solidity'; import PropTypes from 'prop-types'; -const Fiddle = ({onCodeChange, value}) => { +class Fiddle extends React.Component { + constructor(props) { + super(props); - return ( - -

Fiddle

-

Play around with contract code and deploy against your running node.

- -
- ); -}; + this.ace = null; + } + + render() { + const {onCodeChange, value, errors, warnings} = this.props; + const annotations = errors.map((error) => { return error.annotation; }).concat(warnings.map(warning => { return warning.annotation; })); + return ( + + + { this.ace = ace; }} + setOptions={{ + useWorker: false + }} + editorProps={{ + $blockScrolling: Infinity, + enableLiveAutocompletion:true, + highlightSelectedWord: true + }} + /> + + ); + } +} Fiddle.propTypes = { onCodeChange: PropTypes.func, - value: PropTypes.string + value: PropTypes.string, + errors: PropTypes.array, + warnings: PropTypes.array }; export default Fiddle; diff --git a/embark-ui/src/components/FiddleResults.js b/embark-ui/src/components/FiddleResults.js index 1f69fc009..b79a55d1e 100644 --- a/embark-ui/src/components/FiddleResults.js +++ b/embark-ui/src/components/FiddleResults.js @@ -1,41 +1,35 @@ +/* eslint {jsx-a11y/anchor-has-content:"off"} */ import React, {Component} from 'react'; import {Card, List, Badge} from 'tabler-react'; import PropTypes from 'prop-types'; -class FiddleResults extends Component{ +class FiddleResults extends Component { - constructor(props){ - super(props); - this.state = { - errors: props.compilationResult.errors - }; + static _removeClass(elems, className) { + for (let elem of elems) { + elem.className = elem.className.replace(className, '').replace(' ', ' '); + } } - static _removeClass(elems, className){ - for(let elem of elems) { - elem.className = elem.className.replace(className, '').replace(' ', ' '); + static _toggleClass(elems, className) { + for (let elem of elems) { + if (elem.className.indexOf(className) > -1) { + FiddleResults._removeClass([elem], className); } - } - - static _toggleClass(elems, className){ - for(let elem of elems) { - if(elem.className.indexOf(className) > -1){ - FiddleResults._removeClass([elem], className); - } - else{ - elem.className = (elem.className.length > 0 ? elem.className + ' ' : '') + className; - } + else { + elem.className = (elem.className.length > 0 ? elem.className + ' ' : '') + className; } + } } - toggleCollapse(e) { + _toggleCollapse(e) { const collapsedClassName = 'card-collapsed'; const className = e.currentTarget.parentElement.className.replace('card-options', '').replace(' ', ''); const elems = document.getElementsByClassName(className + '-card'); FiddleResults._toggleClass(elems, collapsedClassName); } - - toggleFullscreen(e) { + + _toggleFullscreen(e) { const collapsedClassName = 'card-collapsed'; const fullscreenClassName = 'card-fullscreen'; const className = e.currentTarget.parentElement.className.replace('card-options', '').replace(' ', ''); @@ -44,91 +38,58 @@ class FiddleResults extends Component{ FiddleResults._removeClass(elems, collapsedClassName); } - render(){ - const warningObjs = this.props.compilationResult.errors.filter(error => { - return error.severity === 'warning'; - }); - const errorObjs = this.props.compilationResult.errors.filter(error => { - return error.severity === 'error'; - }); - const warnings = warningObjs.map((warning, index) => { - return ( - - - Lines {warning.sourceLocation.start}-{warning.sourceLocation.end} - - {warning.formattedMessage} - - ); - }); - const errors = errorObjs.map((error, index) => { - return ( - - - Lines {error.sourceLocation.start}-{error.sourceLocation.end} - - {error.formattedMessage} - - ); - }); - const errorsCard = + className={errorType + "s-card"} + key={errorType + "s-card"}> - Errors {errors.length} - - - + {errorType + "s"} {errors.length} + + + - {errors} - - - ; - const warningsCard = - - Warnings {warnings.length} - - - - - - - - {warnings} + {errors.map(error => { return error.node; })} ; + } + + render() { + const {warnings, errors} = this.props; let renderings = []; - if(!this.state.errors){ - return 'Compilation successful (add green tick mark)'; - } - if(errors.length) renderings.push(errorsCard); - if(warnings.length) renderings.push(warningsCard); - + if (errors.length) renderings.push( + + {errors.length} error{errors.length > 1 ? "s" : ""} + + ); + if(warnings.length) renderings.push( + + {warnings.length} warning{warnings.length > 1 ? "s" : ""} + + ); + + return ( +
+ {renderings} + {!(hasResult || isFetching) ? " " : ""} +
+ ); + } +} + +FiddleResultsSummary.propTypes = { + errors: PropTypes.array, + warnings: PropTypes.array, + isFetching: PropTypes.bool, + hasResult: PropTypes.bool +}; + +export default FiddleResultsSummary; diff --git a/embark-ui/src/containers/FiddleContainer.js b/embark-ui/src/containers/FiddleContainer.js index cb385c9c8..fd9e61675 100644 --- a/embark-ui/src/containers/FiddleContainer.js +++ b/embark-ui/src/containers/FiddleContainer.js @@ -6,43 +6,129 @@ import PropTypes from 'prop-types'; import {fetchCodeCompilation} from '../actions'; import Fiddle from '../components/Fiddle'; import FiddleResults from '../components/FiddleResults'; +import FiddleReultsSummary from '../components/FiddleResultsSummary'; +import {Badge} from 'tabler-react'; +import scrollToComponent from 'react-scroll-to-component'; class FiddleContainer extends Component { - constructor(props){ + constructor(props) { super(props); - this.state = { + this.state = { value: '' }; this.compileTimeout = null; + this.ace = null; + this.editor = null; } - componentDidMount(){ - if(this.state.value){ + componentDidMount() { + if (this.state.value) { this.props.fetchCodeCompilation(this.state.value); } } - onCodeChange(newValue) { + _onCodeChange(newValue) { this.setState({value: newValue}); - if(this.compileTimeout) clearTimeout(this.compileTimeout); + if (this.compileTimeout) clearTimeout(this.compileTimeout); this.compileTimeout = setTimeout(() => { this.props.fetchCodeCompilation(newValue); }, 1000); - + + } + + _getFormattedErrors(errors, errorType){ + return errors.reduce( + (errors, error, index) => { + if (error.severity === errorType) { + const errorRowCol = this._getRowCol(error.formattedMessage); + const annotation = Object.assign({}, { + row: errorRowCol.row - 1, // must be 0 based + column: errorRowCol.col - 1, // must be 0 based + text: error.formattedMessage, // text to show in tooltip + type: error.severity // "error"|"warning"|"info" + }); + errors.push({ + solcError: error, + node: + { this._onErrorClick(e, annotation); }} + key={index} + //ref={(item) => { this.refCallback(item, annotation); }} + > + + Line {errorRowCol.row} + + {error.formattedMessage} + , + annotation: annotation + }); + } + return errors; + }, []); + } + + _getRowCol(errorMessage){ + const errorSplit = errorMessage.split(':'); + if(errorSplit.length >= 3){ + return {row: errorSplit[1], col: errorSplit[2]}; + } + return {row: 0, col: 0}; + } + + _onErrorClick(e, annotation){ + e.preventDefault(); + this.editor.gotoLine(annotation.row + 1); + scrollToComponent(this.ace); } render() { const {fiddles} = this.props; - - let renderings = [ this.onCodeChange(n)} />]; - if(fiddles.compilationResult) { - renderings.push(); + let renderings = []; + let warnings = []; + let errors = []; + if (fiddles.compilationResult) { + warnings = this._getFormattedErrors(fiddles.compilationResult.errors, "warning"); + errors = this._getFormattedErrors(fiddles.compilationResult.errors, "error"); + } - else renderings.push('Nothing to compile'); - + renderings.push( + + + this._onCodeChange(n)} + errors={errors} + warnings={warnings} + ref={(fiddle) => { + if(fiddle) { + this.editor = fiddle.ace.editor; + this.ace = fiddle.ace; + } + }} + /> + + ); + if (fiddles.compilationResult) { + renderings.push( + ); + } + return ( - + +

Fiddle

+

Play around with contract code and deploy against your running node.

{renderings}
); diff --git a/embark-ui/src/general.css b/embark-ui/src/general.css index 97a265f08..819083634 100644 --- a/embark-ui/src/general.css +++ b/embark-ui/src/general.css @@ -25,5 +25,43 @@ white-space: pre-line; } .card.card-fullscreen{ - z-index:4; + z-index:6; } +.card.warnings-card, .card.errors-card{ + text-transform: capitalize; +} +.card.warnings-card .list-group-item, .card.errors-card .list-group-item{ + white-space: pre-line; +} +.card.warnings-card .card-options a, .card.errors-card .card-options a{ + cursor:pointer; +} +.compilation-summary { + float:right; + margin-bottom:3px; + line-height:30px; + visibility: hidden; +} +.compilation-summary.visible{ + visibility: visible; +} +.compilation-summary .badge-link:not(:last-child){ + margin-right:5px; +} +.ace_editor { + margin-bottom:24px; +} +.loader, .loader:before, .loader:after{ + width:1.2rem; + height:1.2rem; +} +.loader:before, .loader:after{ + margin:-0.6rem 0 0 -0.6rem; +} +.loader, .loader-text{ + display:inline-block; + vertical-align: middle; +} +.loader { + margin-right:5px; +} \ No newline at end of file diff --git a/embark-ui/src/reducers/fiddleReducer.js b/embark-ui/src/reducers/fiddleReducer.js index 4ce66f5e5..5d53d1308 100644 --- a/embark-ui/src/reducers/fiddleReducer.js +++ b/embark-ui/src/reducers/fiddleReducer.js @@ -1,11 +1,13 @@ -import {RECEIVE_COMPILE_CODE, RECEIVE_COMPILE_CODE_ERROR} from "../actions"; +import {COMPILE_CODE_REQUEST, COMPILE_CODE_FAILURE, COMPILE_CODE_SUCCESS} from "../actions"; export default function processes(state = {}, action) { switch (action.type) { - case RECEIVE_COMPILE_CODE: - return Object.assign({}, state, {compilationResult: action.compilationResult}); - case RECEIVE_COMPILE_CODE_ERROR: - return Object.assign({}, state, {error: true}); + case COMPILE_CODE_REQUEST: + return {...state, isFetching: true, compilationResult: action.compilationResult}; + case COMPILE_CODE_SUCCESS: + return {...state, isFetching: false, compilationResult: action.compilationResult}; + case COMPILE_CODE_FAILURE: + return {...state, isFetching: false, error: true}; default: return state; } diff --git a/embark-ui/src/sagas/index.js b/embark-ui/src/sagas/index.js index 85e09cc9c..5243cf852 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -170,7 +170,7 @@ export function *fetchCodeCompilation(action) { } export function *watchFetchCodeCompilation() { - yield takeEvery(actions.FETCH_COMPILE_CODE, fetchCodeCompilation); + yield takeEvery(actions.COMPILE_CODE_REQUEST, fetchCodeCompilation); } export default function *root() { diff --git a/lib/modules/solidity/index.js b/lib/modules/solidity/index.js index 386229cde..5784507d9 100644 --- a/lib/modules/solidity/index.js +++ b/lib/modules/solidity/index.js @@ -25,10 +25,7 @@ class Solidity { 'post', '/embark-api/contract/compile', (req, res) => { - console.log('=====> POST contract/compile, req = ' + JSON.stringify(req.body)); this.events.request("contract:compile", req.body.code, (errors, compilationResult) => { - console.log('=====> POST contract/compile, errors = ' + JSON.stringify(errors)); - console.log('=====> POST contract/compile, compilationResult = ' + JSON.stringify(compilationResult)); res.send({errors:errors, compilationResult: compilationResult}); }); }