Merge branch 'develop_51' into restyle-code-editor-top-bar

This commit is contained in:
André Medeiros 2018-10-24 14:14:59 -04:00 committed by GitHub
commit 5fd69b60fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 26497 additions and 441 deletions

View File

@ -12194,14 +12194,6 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
}, },
"typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"requires": {
"is-typedarray": "^1.0.0"
}
},
"ua-parser-js": { "ua-parser-js": {
"version": "0.7.18", "version": "0.7.18",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
@ -12932,8 +12924,19 @@
"integrity": "sha512-wAnENuZx75T5ZSrT2De2LOaUuPf2yRjq1VfcbD7+Zd79F3DZZLBJcPyCNVQ1U0fAXt0wfgCKl7sVw5pffqR9Bw==", "integrity": "sha512-wAnENuZx75T5ZSrT2De2LOaUuPf2yRjq1VfcbD7+Zd79F3DZZLBJcPyCNVQ1U0fAXt0wfgCKl7sVw5pffqR9Bw==",
"requires": { "requires": {
"underscore": "1.8.3", "underscore": "1.8.3",
"web3-core-helpers": "1.0.0-beta.36", "web3-core-helpers": "1.0.0-beta.36"
"websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" },
"dependencies": {
"websocket": {
"version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2",
"from": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2",
"requires": {
"debug": "^2.2.0",
"nan": "^2.3.3",
"typedarray-to-buffer": "^3.1.2",
"yaeti": "^0.0.6"
}
}
} }
}, },
"web3-shh": { "web3-shh": {
@ -13371,16 +13374,6 @@
"source-map": "~0.6.1" "source-map": "~0.6.1"
} }
}, },
"websocket": {
"version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2",
"from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible",
"requires": {
"debug": "^2.2.0",
"nan": "^2.3.3",
"typedarray-to-buffer": "^3.1.2",
"yaeti": "^0.0.6"
}
},
"websocket-driver": { "websocket-driver": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
@ -13611,11 +13604,6 @@
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
}, },
"yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc="
},
"yallist": { "yallist": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",

View File

@ -282,7 +282,7 @@ export const files = {
export const FILE = createRequestTypes('FILE'); export const FILE = createRequestTypes('FILE');
export const file = { export const file = {
request: (file) => action(FILE[REQUEST], file), request: (file) => action(FILE[REQUEST], file),
success: (file) => action(FILE[SUCCESS], file), success: (file) => action(FILE[SUCCESS], {file}),
failure: (error) => action(FILE[FAILURE], {error}) failure: (error) => action(FILE[FAILURE], {error})
}; };
@ -300,20 +300,6 @@ export const removeFile = {
failure: (error) => action(REMOVE_FILE[FAILURE], {error}) failure: (error) => action(REMOVE_FILE[FAILURE], {error})
}; };
export const CURRENT_FILE = createRequestTypes('CURRENT_FILE');
export const currentFile = {
request: () => action(CURRENT_FILE[REQUEST]),
success: (file) => action(CURRENT_FILE[SUCCESS], {currentFiles: [file]}),
failure: () => action(CURRENT_FILE[FAILURE])
};
export const SAVE_CURRENT_FILE = createRequestTypes('SAVE_CURRENT_FILE');
export const saveCurrentFile = {
request: (file) => action(SAVE_CURRENT_FILE[REQUEST], file),
success: (file) => action(SAVE_CURRENT_FILE[SUCCESS], {currentFiles: [file]}),
failure: () => action(SAVE_CURRENT_FILE[FAILURE])
};
export const GAS_ORACLE = createRequestTypes('GAS_ORACLE'); export const GAS_ORACLE = createRequestTypes('GAS_ORACLE');
export const gasOracle = { export const gasOracle = {
request: () => action(GAS_ORACLE[REQUEST]), request: () => action(GAS_ORACLE[REQUEST]),
@ -349,6 +335,88 @@ export const web3EstimateGas = {
failure: (error, payload) => action(WEB3_ESTIMAGE_GAS[FAILURE], {web3Error: error, contract: payload.contract}) failure: (error, payload) => action(WEB3_ESTIMAGE_GAS[FAILURE], {web3Error: error, contract: payload.contract})
}; };
export const START_DEBUG = createRequestTypes('START_DEBUG');
export const startDebug = {
request: (txHash) => action(START_DEBUG[REQUEST], {txHash}),
success: () => action(START_DEBUG[SUCCESS]),
failure: (error) => action(START_DEBUG[FAILURE], {error})
};
export const DEBUG_JUMP_BACK = createRequestTypes('DEBUG_JUMP_BACK');
export const debugJumpBack = {
request: () => action(DEBUG_JUMP_BACK[REQUEST], {}),
success: () => action(DEBUG_JUMP_BACK[SUCCESS]),
failure: (error) => action(DEBUG_JUMP_BACK[FAILURE], {error})
};
export const DEBUG_JUMP_FORWARD = createRequestTypes('DEBUG_JUMP_FORWARD');
export const debugJumpForward = {
request: () => action(DEBUG_JUMP_FORWARD[REQUEST], {}),
success: () => action(DEBUG_JUMP_FORWARD[SUCCESS]),
failure: (error) => action(DEBUG_JUMP_FORWARD[FAILURE], {error})
};
export const DEBUG_STEP_OVER_BACKWARD = createRequestTypes('DEBUG_STEP_OVER_BACKWARD');
export const debugStepOverBackward = {
request: () => action(DEBUG_STEP_OVER_BACKWARD[REQUEST], {}),
success: () => action(DEBUG_STEP_OVER_BACKWARD[SUCCESS]),
failure: (error) => action(DEBUG_STEP_OVER_BACKWARD[FAILURE], {error})
};
export const DEBUG_STEP_OVER_FORWARD = createRequestTypes('DEBUG_STEP_OVER_FORWARD');
export const debugStepOverForward = {
request: () => action(DEBUG_STEP_OVER_FORWARD[REQUEST], {}),
success: () => action(DEBUG_STEP_OVER_FORWARD[SUCCESS]),
failure: (error) => action(DEBUG_STEP_OVER_FORWARD[FAILURE], {error})
};
export const DEBUG_STEP_INTO_BACKWARD = createRequestTypes('DEBUG_STEP_INTO_BACKWARD');
export const debugStepIntoBackward = {
request: () => action(DEBUG_STEP_INTO_BACKWARD[REQUEST], {}),
success: () => action(DEBUG_STEP_INTO_BACKWARD[SUCCESS]),
failure: (error) => action(DEBUG_STEP_INTO_BACKWARD[FAILURE], {error})
};
export const DEBUG_STEP_INTO_FORWARD = createRequestTypes('DEBUG_STEP_INTO_FORWARD');
export const debugStepIntoForward = {
request: () => action(DEBUG_STEP_INTO_FORWARD[REQUEST], {}),
success: () => action(DEBUG_STEP_INTO_FORWARD[SUCCESS]),
failure: (error) => action(DEBUG_STEP_INTO_FORWARD[FAILURE], {error})
};
export const TOGGLE_BREAKPOINT = createRequestTypes('TOGGLE_BREAKPOINT');
export const toggleBreakpoint = {
request: (filename, lineNumber) => action(TOGGLE_BREAKPOINT[REQUEST], {filename, lineNumber}),
success: (data, payload) => action(TOGGLE_BREAKPOINT[SUCCESS], {payload}),
failure: (error) => action(TOGGLE_BREAKPOINT[FAILURE], {error})
};
export const DEBUGGER_INFO = createRequestTypes('DEBUGGER_INFO');
export const debuggerInfo = {
success: (data) => action(DEBUGGER_INFO[SUCCESS], {data})
};
export const FETCH_EDITOR_TABS = createRequestTypes('FETCH_EDITOR_TABS');
export const fetchEditorTabs = {
request: () => action(FETCH_EDITOR_TABS[REQUEST]),
success: (editorTabs) => action(FETCH_EDITOR_TABS[SUCCESS], {editorTabs}),
failure: () => action(FETCH_EDITOR_TABS[FAILURE])
};
export const ADD_EDITOR_TABS = createRequestTypes('ADD_EDITOR_TABS');
export const addEditorTabs = {
request: (file) => action(ADD_EDITOR_TABS[REQUEST], {file}),
success: () => action(ADD_EDITOR_TABS[SUCCESS]),
failure: () => action(ADD_EDITOR_TABS[FAILURE])
};
export const REMOVE_EDITOR_TABS = createRequestTypes('REMOVE_EDITOR_TABS');
export const removeEditorTabs = {
request: (file) => action(REMOVE_EDITOR_TABS[REQUEST], {file}),
success: () => action(REMOVE_EDITOR_TABS[SUCCESS]),
failure: () => action(REMOVE_EDITOR_TABS[FAILURE])
};
// Web Socket // Web Socket
export const WATCH_NEW_PROCESS_LOGS = 'WATCH_NEW_PROCESS_LOGS'; export const WATCH_NEW_PROCESS_LOGS = 'WATCH_NEW_PROCESS_LOGS';
export const STOP_NEW_PROCESS_LOGS = 'STOP_NEW_PROCESS_LOGS'; export const STOP_NEW_PROCESS_LOGS = 'STOP_NEW_PROCESS_LOGS';
@ -358,6 +426,7 @@ export const INIT_BLOCK_HEADER = 'INIT_BLOCK_HEADER';
export const STOP_BLOCK_HEADER = 'STOP_BLOCK_HEADER'; export const STOP_BLOCK_HEADER = 'STOP_BLOCK_HEADER';
export const WATCH_GAS_ORACLE = 'WATCH_GAS_ORACLE'; export const WATCH_GAS_ORACLE = 'WATCH_GAS_ORACLE';
export const STOP_GAS_ORACLE = 'STOP_GAS_ORACLE'; export const STOP_GAS_ORACLE = 'STOP_GAS_ORACLE';
export const STOP_DEBUGGER = 'STOP_DEBUGGER';
export function listenToProcessLogs(processName) { export function listenToProcessLogs(processName) {
return { return {
@ -409,6 +478,12 @@ export function stopGasOracle(){
}; };
} }
export function stopDebugger(){
return {
type: STOP_DEBUGGER
}
}
// Actions without Side Effect // Actions without Side Effect
export const UPDATE_BASE_ETHER = 'UPDATE_BASE_ETHER'; export const UPDATE_BASE_ETHER = 'UPDATE_BASE_ETHER';
export function updateBaseEther(value) { export function updateBaseEther(value) {
@ -418,14 +493,6 @@ export function updateBaseEther(value) {
}; };
} }
export const TOGGLE_BREAKPOINT = 'TOGGLE_BREAKPOINT';
export function toggleBreakpoint(filename, lineNumber) {
return {
type: TOGGLE_BREAKPOINT,
payload: {filename, lineNumber}
};
}
export const UPDATE_DEPLOYMENT_PIPELINE = 'UPDATE_DEPLOYMENT_PIPELINE'; export const UPDATE_DEPLOYMENT_PIPELINE = 'UPDATE_DEPLOYMENT_PIPELINE';
export function updateDeploymentPipeline(value) { export function updateDeploymentPipeline(value) {
return { return {

View File

@ -8,32 +8,34 @@ import CardTitleIdenticon from './CardTitleIdenticon';
const Accounts = ({accounts}) => ( const Accounts = ({accounts}) => (
<Row> <Row>
<Col> <Col>
<h1>Accounts</h1> <Card>
{accounts.map(account => ( <CardHeader>
<Card key={account.address}> <h2>Accounts</h2>
<CardHeader> </CardHeader>
<CardBody>
{accounts.map(account => (
<div className="explorer-row border-top" key={account.address}>
<CardTitleIdenticon id={account.address}>Account&nbsp; <CardTitleIdenticon id={account.address}>Account&nbsp;
<Link to={`/embark/explorer/accounts/${account.address}`}>{account.address}</Link> <Link to={`/embark/explorer/accounts/${account.address}`}>{account.address}</Link>
</CardTitleIdenticon> </CardTitleIdenticon>
</CardHeader> <Row>
<CardBody> <Col>
<Row> <strong>Balance</strong>
<Col> <div>{account.balance} Ether</div>
<strong>Balance</strong> </Col>
<div>{account.balance} Ether</div> <Col>
</Col> <strong>Tx Count</strong>
<Col> <div>{account.transactionCount}</div>
<strong>Tx Count</strong> </Col>
<div>{account.transactionCount}</div> <Col>
</Col> <strong>Index</strong>
<Col> <div>{account.index}</div>
<strong>Index</strong> </Col>
<div>{account.index}</div> </Row>
</Col> </div>
</Row> ))}
</CardBody> </CardBody>
</Card> </Card>
))}
</Col> </Col>
</Row> </Row>
); );

View File

@ -13,7 +13,7 @@ const Block = ({block}) => (
<CardTitleIdenticon id={block.hash}>Block {block.number}</CardTitleIdenticon> <CardTitleIdenticon id={block.hash}>Block {block.number}</CardTitleIdenticon>
</CardHeader> </CardHeader>
<CardBody> <CardBody>
<dl class="row"> <dl className="row">
<Description label="Hash" value={block.hash} /> <Description label="Hash" value={block.hash} />
<Description label="Timestamp" value={block.timestamp} /> <Description label="Timestamp" value={block.timestamp} />
<Description label="Difficulty" value={block.difficulty} /> <Description label="Difficulty" value={block.difficulty} />

View File

@ -4,48 +4,50 @@ import {Row, Col, Card, CardHeader, CardBody} from 'reactstrap';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import CardTitleIdenticon from './CardTitleIdenticon'; import CardTitleIdenticon from './CardTitleIdenticon';
import LoadMore from "./LoadMore";
const Blocks = ({blocks}) => ( const Blocks = ({blocks, showLoadMore, loadMore}) => (
<Row> <Row>
<Col> <Col>
<h1>Blocks</h1> <Card>
{blocks.map(block => ( <CardHeader>
<Card key={block.number}> <h2>Blocks</h2>
<CardHeader> </CardHeader>
<CardTitleIdenticon id={block.hash}>Block&nbsp; <CardBody>
<Link to={`/embark/explorer/blocks/${block.number}`}> {blocks.map(block => (
{block.number} <div className="explorer-row border-top" key={block.number}>
</Link> <CardTitleIdenticon id={block.hash}>Block&nbsp;
</CardTitleIdenticon> <Link to={`/embark/explorer/blocks/${block.number}`}>
</CardHeader> {block.number}
<CardBody> </Link>
<Row> </CardTitleIdenticon>
<Col> <Row>
<strong>Number</strong> <Col>
<div>{block.number}</div> <strong>Mined On</strong>
</Col> <div>{new Date(block.timestamp * 1000).toLocaleString()}</div>
<Col> </Col>
<strong>Mined On</strong> <Col>
<div>{new Date(block.timestamp * 1000).toLocaleString()}</div> <strong>Gas Used</strong>
</Col> <div>{block.gasUsed}</div>
<Col> </Col>
<strong>Gas Used</strong> <Col>
<div>{block.gasUsed}</div> <strong>TX Count</strong>
</Col> <div>{block.transactions.length}</div>
<Col> </Col>
<strong>TX Count</strong> </Row>
<div>{block.transactions.length}</div> </div>
</Col> ))}
</Row> {showLoadMore && <LoadMore loadMore={() => loadMore()}/>}
</CardBody> </CardBody>
</Card> </Card>
))}
</Col> </Col>
</Row> </Row>
); );
Blocks.propTypes = { Blocks.propTypes = {
blocks: PropTypes.arrayOf(PropTypes.object) blocks: PropTypes.arrayOf(PropTypes.object),
showLoadMore: PropTypes.bool,
loadMore: PropTypes.func
}; };
export default Blocks; export default Blocks;

View File

@ -1,9 +1,20 @@
import PropTypes from "prop-types";
import React from 'react'; import React from 'react';
import {CardTitle} from 'reactstrap'; import {CardTitle} from 'reactstrap';
import Blockies from 'react-blockies'; import Blockies from 'react-blockies';
const CardTitleIdenticon = ({id, children}) => ( const CardTitleIdenticon = ({id, children}) => (
<CardTitle><Blockies seed={id} className="rounded"/><span className="ml-2 align-top">{children}</span></CardTitle> <CardTitle>
) <Blockies seed={id} className="rounded"/><span className="ml-2 align-top text-truncate">{children}</span>
</CardTitle>
);
export default CardTitleIdenticon CardTitleIdenticon.propTypes = {
id: PropTypes.string,
children: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array
])
};
export default CardTitleIdenticon;

View File

@ -0,0 +1,95 @@
import PropTypes from "prop-types";
import React, {Component} from 'react';
import {
Row,
Col,
FormGroup,
Label,
Input,
Button,
Card,
CardBody,
CardHeader,
CardTitle,
CardFooter,
ListGroup,
ListGroupItem
} from "reactstrap";
import ReactJson from 'react-json-view';
class ContractDebugger extends Component {
constructor(props) {
super(props);
}
handleChange(e) {
this.setState({txHash: e.target.value});
}
debug(e) {
this.props.startDebug(this.state.txHash);
}
debugJumpBack(e) {
this.props.debugJumpBack()
}
debugJumpForward(e) {
this.props.debugJumpForward()
}
debugStepOverForward(e) {
this.props.debugStepOverForward()
}
debugStepOverBackward(e) {
this.props.debugStepOverBackward()
}
debugStepIntoForward(e) {
this.props.debugStepIntoForward()
}
debugStepIntoBackward(e) {
this.props.debugStepIntoBackward()
}
render() {
return (
<div>
<Row>
<Col>
<Input name="txHash" id="txHash" onChange={(e) => this.handleChange(e)}/>
<Button color="primary" onClick={(e) => this.debug(e)}>Debug Tx</Button>
</Col>
</Row>
<Row>
<Col>
<Button color="light" className="btn-square debugButton jumpBack" alt="jump to previous breakpoint" onClick={(e) => this.debugJumpBack(e)}></Button>
<Button color="light" className="btn-square debugButton jumpForward" alt="jump to revious breakpoint" onClick={(e) => this.debugJumpForward(e)}></Button>
<Button color="light" className="btn-square debugButton stepOverBack" alt="step back" onClick={(e) => this.debugStepOverBackward(e)}></Button>
<Button color="light" className="btn-square debugButton stepOverForward" alt="step over" onClick={(e) => this.debugStepOverForward(e)}></Button>
<Button color="light" className="btn-square debugButton stepIntoForward" alt="step into" onClick={(e) => this.debugStepIntoForward(e)}></Button>
<Button color="light" className="btn-square debugButton stepIntoBack" alt="step out" onClick={(e) => this.debugStepIntoBackward(e)}></Button>
</Col>
</Row>
<Row>
<Col>
<br /><strong>Scopes</strong>
<div>
<ReactJson src={{locals: this.props.debuggerInfo.locals, contract: this.props.debuggerInfo.globals}} theme="monokai" sortKeys={true} name={false} collapse={1} />
</div>
</Col>
</Row>
</div>
);
}
}
ContractDebugger.propTypes = {
contract: PropTypes.object.isRequired,
};
export default ContractDebugger;

View File

@ -1,12 +1,10 @@
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import React from 'react'; import React from 'react';
import ReactJson from "react-json-view"; import ReactJson from "react-json-view";
import {Row, Col, Table} from "reactstrap"; import {Row, Col} from "reactstrap";
import {formatContractForDisplay} from '../utils/presentation';
import CopyButton from './CopyButton'; import CopyButton from './CopyButton';
const ContractDetail = ({contract}) => { const ContractDetail = ({contract}) => {
const contractDisplay = formatContractForDisplay(contract);
return ( return (
<Row> <Row>
<Col> <Col>

View File

@ -1,183 +0,0 @@
import PropTypes from "prop-types";
import React, {Component} from 'react';
import {
Row,
Col,
Form,
FormGroup,
Label,
Input,
Button,
Card,
CardBody,
CardHeader,
CardTitle,
CardFooter,
Collapse,
ListGroup,
ListGroupItem
} from "reactstrap";
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 (
<Col xs={12}>
<Card>
<CardHeader>
<CardTitle className="collapsable contractFunction" onClick={() => this.toggleFunction()}>
{ContractFunction.isPureCall(this.props.method) &&
<button class="btn btn-brand btn-sm" style={{ "color": "#fff", "background-color": "#ff4500", "border-color": "#ff4500", "float": "right" }}>call</button>
}
{ContractFunction.isEvent(this.props.method) &&
<button class="btn btn-brand btn-sm" style={{ "color": "#fff", "background-color": "#aad450", "border-color": "#aad450", "float": "right" }}>event</button>
}
{this.props.method.name}({this.props.method.inputs.map(input => input.name).join(', ')})
</CardTitle>
</CardHeader>
<Collapse isOpen={this.state.functionCollapse}>
<CardBody>
<Form action="" method="post" inline>
{this.props.method.inputs.map(input => (
<FormGroup key={input.name} className="pr-1">
<Label for={input.name} className="pr-1">{input.name}: </Label>
<Input name={input.name} id={input.name} placeholder={input.type} onChange={(e) => this.handleChange(e, input.name)}/>
</FormGroup>
))}
</Form>
{!ContractFunction.isPureCall(this.props.method) &&
<Col xs={12} style={{"margin-bottom": "5px", "margin-top": "5px"}}>
<Row>
<strong className="collapsable" onClick={() => this.toggleOptions()}><i className={this.state.optionsCollapse ? 'fa fa-caret-down' : 'fa fa-caret-right'}/>Advanced Options</strong>
<Collapse isOpen={this.state.optionsCollapse}>
<Form action="" method="post" inline>
<FormGroup key="gasPrice" className="pr-1">
<Label for="gasPrice" className="pr-1">Gas Price (in GWei)(optional)</Label>
<Input name="gasPrice" id="gasPrice" onChange={(e) => this.handleChange(e, 'gasPrice')}/>
</FormGroup>
</Form>
</Collapse>
</Row>
</Col>
}
<div align="right">
<Button color="primary" disabled={this.callDisabled()} onClick={(e) => this.handleCall(e)} >
{this.buttonTitle()}
</Button>
</div>
</CardBody>
</Collapse>
{this.props.contractFunctions && this.props.contractFunctions.length > 0 && <CardFooter>
<ListGroup>
{this.props.contractFunctions.map(contractFunction => (
<ListGroupItem key={contractFunction.result}>
{contractFunction.inputs.length > 0 && <p>Inputs: {contractFunction.inputs.join(', ')}</p>}
<strong>Result: {contractFunction.result}</strong>
</ListGroupItem>
))}
</ListGroup>
</CardFooter>}
</Card>
</Col>
);
}
}
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 ContractFunctions = (props) => {
const {contractProfile} = props;
return (
<Row>
{contractProfile.methods
.filter((method) => {
return props.onlyConstructor ? method.type === 'constructor' : method.type !== 'constructor';
})
.map(method => <ContractFunction key={method.name}
method={method}
contractFunctions={filterContractFunctions(props.contractFunctions, contractProfile.name, method.name)}
contractProfile={contractProfile}
postContractFunction={props.postContractFunction}/>)}
</Row>
);
};
ContractFunctions.propTypes = {
onlyConstructor: PropTypes.bool,
contractProfile: PropTypes.object,
contractFunctions: PropTypes.arrayOf(PropTypes.object),
postContractFunction: PropTypes.func
};
ContractFunctions.defaultProps = {
onlyConstructor: false
};
export default ContractFunctions;

View File

@ -6,6 +6,7 @@ import classnames from 'classnames';
import ContractDetail from '../components/ContractDetail'; import ContractDetail from '../components/ContractDetail';
import ContractLoggerContainer from '../containers/ContractLoggerContainer'; import ContractLoggerContainer from '../containers/ContractLoggerContainer';
import ContractOverviewContainer from '../containers/ContractOverviewContainer'; import ContractOverviewContainer from '../containers/ContractOverviewContainer';
import ContractDebuggerContainer from '../containers/ContractDebuggerContainer';
class ContractLayout extends React.Component { class ContractLayout extends React.Component {
constructor(props) { constructor(props) {
@ -55,6 +56,14 @@ class ContractLayout extends React.Component {
Logger Logger
</NavLink> </NavLink>
</NavItem> </NavItem>
<NavItem>
<NavLink
className={classnames({ active: this.state.activeTab === '4' })}
onClick={() => { this.toggle('4'); }}
>
Debugger
</NavLink>
</NavItem>
</Nav> </Nav>
<TabContent activeTab={this.state.activeTab}> <TabContent activeTab={this.state.activeTab}>
<TabPane tabId="1"> <TabPane tabId="1">
@ -66,6 +75,9 @@ class ContractLayout extends React.Component {
<TabPane tabId="3"> <TabPane tabId="3">
<ContractLoggerContainer contract={this.props.contract} /> <ContractLoggerContainer contract={this.props.contract} />
</TabPane> </TabPane>
<TabPane tabId="4">
<ContractDebuggerContainer contract={this.props.contract} />
</TabPane>
</TabContent> </TabContent>
</CardBody> </CardBody>
</Card> </Card>

View File

@ -79,12 +79,12 @@ class ContractFunction extends Component {
return ( return (
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="collapsable contractFunction" onClick={() => this.toggleFunction()}> <CardTitle className="collapsable" onClick={() => this.toggleFunction()}>
{ContractFunction.isPureCall(this.props.method) && {ContractFunction.isPureCall(this.props.method) &&
<button class="btn btn-brand btn-sm" style={{ "color": "#fff", "background-color": "#ff4500", "border-color": "#ff4500", "float": "right" }}>call</button> <button className="btn btn-warning btn-sm float-right">call</button>
} }
{ContractFunction.isEvent(this.props.method) && {ContractFunction.isEvent(this.props.method) &&
<button class="btn btn-brand btn-sm" style={{ "color": "#fff", "background-color": "#aad450", "border-color": "#aad450", "float": "right" }}>event</button> <button className="btn btn-info btn-sm float-right">event</button>
} }
{this.props.method.name}({this.props.method.inputs.map(input => input.name).join(', ')}) {this.props.method.name}({this.props.method.inputs.map(input => input.name).join(', ')})
</CardTitle> </CardTitle>

View File

@ -0,0 +1,14 @@
.explorer-row {
border-top-width: 0 !important; /*Bootstrap uses important, so we need to override it*/
}
.explorer-row + .explorer-row {
margin-top: 5px;
padding-top: 20px;
border-top-width: 1px !important;
}
.explorer-row .text-truncate {
width: 90%;
display: inline-block;
}

View File

@ -8,9 +8,11 @@ import AccountsContainer from '../containers/AccountsContainer';
import BlocksContainer from '../containers/BlocksContainer'; import BlocksContainer from '../containers/BlocksContainer';
import TransactionsContainer from '../containers/TransactionsContainer'; import TransactionsContainer from '../containers/TransactionsContainer';
import './Explorer.css';
const ExplorerDashboardLayout = () => ( const ExplorerDashboardLayout = () => (
<React.Fragment> <React.Fragment>
<Row> <Row className="mt-4">
<Col> <Col>
<AccountsContainer /> <AccountsContainer />
</Col> </Col>

View File

@ -1,6 +1,8 @@
import React from 'react'; import React from 'react';
import * as monaco from 'monaco-editor'; import * as monaco from 'monaco-editor';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import FontAwesomeIcon from 'react-fontawesome';
import classNames from 'classnames';
import './TextEditor.css'; import './TextEditor.css';
@ -40,7 +42,7 @@ class TextEditor extends React.Component {
editor.onMouseDown((e) => { editor.onMouseDown((e) => {
if (e.target.type === GUTTER_GLYPH_MARGIN){ if (e.target.type === GUTTER_GLYPH_MARGIN){
this.props.toggleBreakpoint(this.props.file.name, e.target.position.lineNumber); this.props.toggleBreakpoint(this.props.currentFile.name, e.target.position.lineNumber);
} }
}); });
} }
@ -49,7 +51,10 @@ class TextEditor extends React.Component {
getLanguage() { getLanguage() {
const extension = this.props.file.name.split('.').pop(); if (!this.props.currentFile.name) {
return DEFAULT_LANGUAGE;
}
const extension = this.props.currentFile.name.split('.').pop();
return SUPPORTED_LANGUAGES[SUPPORTED_LANGUAGES.indexOf(extension)] || DEFAULT_LANGUAGE; return SUPPORTED_LANGUAGES[SUPPORTED_LANGUAGES.indexOf(extension)] || DEFAULT_LANGUAGE;
} }
@ -97,8 +102,9 @@ class TextEditor extends React.Component {
} }
)); ));
//TODO remove me when debuggerLine comes from the debugger API let debuggerLine = this.props.debuggerLine;
let debuggerLine = this.props.debuggerLine || 11; console.dir("debuggerLine")
console.dir(debuggerLine)
newDecorations.push({ newDecorations.push({
range: new monaco.Range(debuggerLine,1,debuggerLine,1), range: new monaco.Range(debuggerLine,1,debuggerLine,1),
options: { options: {
@ -111,23 +117,36 @@ class TextEditor extends React.Component {
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (this.props.file.content !== prevProps.file.content) { if (this.props.currentFile.content && this.props.currentFile.content !== prevProps.currentFile.content) {
editor.setValue(this.props.file.content); editor.setValue(this.props.currentFile.content);
} }
this.updateMarkers(); this.updateMarkers();
// TODO replace with const expectedDecorationsLength = this.props.debuggerLine ? this.props.breakpoints.length + 1 : this.props.breakpoints.length const expectedDecorationsLength = this.props.debuggerLine ? this.props.breakpoints.length + 1 : this.props.breakpoints.length
const expectedDecorationsLength = this.props.breakpoints.length + 1; if (expectedDecorationsLength !== this.state.decorations.length || this.props.debuggerLine !== prevProps.debuggerLine) {
if (expectedDecorationsLength !== this.state.decorations.length) {
this.updateDecorations(); this.updateDecorations();
} }
this.updateLanguage(); this.updateLanguage();
this.handleResize(); this.handleResize();
} }
renderTabs() {
return (
<ul className="list-inline m-0 p-2">
{this.props.editorTabs.map(file => (
<li key={file.name} className={classNames("list-inline-item", "border-right", "p-2", { 'bg-dark': file.name === this.props.currentFile.name })}>
<a className="text-white no-underline" href='#switch-tab' onClick={() => this.props.addEditorTabs(file)}>{file.name}</a>
<FontAwesomeIcon onClick={() => this.props.removeEditorTabs(file)} className="mx-1" name="close" />
</li>
))}
</ul>
)
}
render() { render() {
return ( return (
<div className="h-100 d-flex flex-column"> <div className="h-100 d-flex flex-column">
{this.renderTabs()}
<div style={{height: '100%'}} id={EDITOR_ID} /> <div style={{height: '100%'}} id={EDITOR_ID} />
</div> </div>
) )
@ -136,10 +155,13 @@ class TextEditor extends React.Component {
TextEditor.propTypes = { TextEditor.propTypes = {
onFileContentChange: PropTypes.func, onFileContentChange: PropTypes.func,
file: PropTypes.object, currentFile: PropTypes.object,
toggleBreakpoint: PropTypes.func, toggleBreakpoint: PropTypes.func,
breakpoints: PropTypes.array, breakpoints: PropTypes.array,
debuggerLine: PropTypes.number debuggerLine: PropTypes.number,
editorTabs: PropTypes.array,
removeEditorTabs: PropTypes.func,
addEditorTabs: PropTypes.func
}; };
export default TextEditor; export default TextEditor;

View File

@ -30,6 +30,9 @@ const TextEditorToolbar = (props) => (
<FontAwesomeIcon className="mr-2" name="file-text-o" /> Details <FontAwesomeIcon className="mr-2" name="file-text-o" /> Details
</NavLink> </NavLink>
<NavLink className="btn" href="#" onClick={() => props.openAsideTab('logger')}>Logger</NavLink> <NavLink className="btn" href="#" onClick={() => props.openAsideTab('logger')}>Logger</NavLink>
<NavLink className="btn" href="#" onClick={() => props.openAsideTab('debugger')}>
<FontAwesomeIcon className="mr-2" name="bug" /> Debugger
</NavLink>
</React.Fragment> </React.Fragment>
} }
<NavLink className="btn" href="#" onClick={() => props.openAsideTab('browser')}> <NavLink className="btn" href="#" onClick={() => props.openAsideTab('browser')}>
@ -42,7 +45,6 @@ const TextEditorToolbar = (props) => (
); );
TextEditorToolbar.propTypes = { TextEditorToolbar.propTypes = {
currentFile: PropTypes.object,
isContract: PropTypes.bool, isContract: PropTypes.bool,
save: PropTypes.func, save: PropTypes.func,
remove: PropTypes.func, remove: PropTypes.func,

View File

@ -4,48 +4,54 @@ import {Row, Col, Card, CardHeader, CardBody} from 'reactstrap';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import CardTitleIdenticon from './CardTitleIdenticon'; import CardTitleIdenticon from './CardTitleIdenticon';
import LoadMore from "./LoadMore";
const Transactions = ({transactions}) => ( const Transactions = ({transactions, showLoadMore, loadMore}) => (
<Row> <Row>
<Col> <Col>
<h1>Transactions</h1> <Card>
{transactions.map(transaction => ( <CardHeader>
<Card key={transaction.hash}> <h2>Transactions</h2>
<CardHeader> </CardHeader>
<CardTitleIdenticon id={transaction.hash}>Transaction&nbsp; <CardBody>
<Link to={`/embark/explorer/transactions/${transaction.hash}`}> {transactions.map(transaction => (
{transaction.hash} <div className="explorer-row border-top" key={transaction.hash}>
</Link> <CardTitleIdenticon id={transaction.hash}>Transaction&nbsp;
</CardTitleIdenticon> <Link to={`/embark/explorer/transactions/${transaction.hash}`}>
</CardHeader> {transaction.hash}
<CardBody> </Link>
<Row> </CardTitleIdenticon>
<Col> <Row>
<strong>Block number</strong> <Col md={6}>
<div>{transaction.blockNumber}</div> <strong>Block number</strong>
</Col> <div>{transaction.blockNumber}</div>
<Col> </Col>
<strong>From</strong> <Col md={6}>
<div>{transaction.from}</div> <strong>From</strong>
</Col> <div>{transaction.from}</div>
<Col> </Col>
<strong>To</strong> <Col md={6}>
<div>{transaction.to}</div> <strong>To</strong>
</Col> <div>{transaction.to}</div>
<Col> </Col>
<strong>Type</strong> <Col md={6}>
<div>{transaction.to ? "Contract Call" : "Contract Creation"}</div> <strong>Type</strong>
</Col> <div>{transaction.to ? "Contract Call" : "Contract Creation"}</div>
</Row> </Col>
</CardBody> </Row>
</Card> </div>
))} ))}
{showLoadMore && <LoadMore loadMore={() => loadMore()}/>}
</CardBody>
</Card>
</Col> </Col>
</Row> </Row>
); );
Transactions.propTypes = { Transactions.propTypes = {
transactions: PropTypes.arrayOf(PropTypes.object) transactions: PropTypes.arrayOf(PropTypes.object),
showLoadMore: PropTypes.bool,
loadMore: PropTypes.func
}; };
export default Transactions; export default Transactions;

View File

@ -5,7 +5,6 @@ import PropTypes from 'prop-types';
import {blocks as blocksAction, initBlockHeader, stopBlockHeader} from '../actions'; import {blocks as blocksAction, initBlockHeader, stopBlockHeader} from '../actions';
import Blocks from '../components/Blocks'; import Blocks from '../components/Blocks';
import DataWrapper from "../components/DataWrapper"; import DataWrapper from "../components/DataWrapper";
import LoadMore from "../components/LoadMore";
import {getBlocks} from "../reducers/selectors"; import {getBlocks} from "../reducers/selectors";
class BlocksContainer extends Component { class BlocksContainer extends Component {
@ -34,9 +33,8 @@ class BlocksContainer extends Component {
return ( return (
<React.Fragment> <React.Fragment>
<DataWrapper shouldRender={this.props.blocks.length > 0} {...this.props} render={({blocks}) => ( <DataWrapper shouldRender={this.props.blocks.length > 0} {...this.props} render={({blocks}) => (
<Blocks blocks={blocks} /> <Blocks blocks={blocks} showLoadMore={(this.loadMoreFrom() >= 0)} loadMore={() => this.loadMore()} />
)} /> )} />
{(this.loadMoreFrom() >= 0) ? <LoadMore loadMore={() => this.loadMore()} /> : <React.Fragment />}
</React.Fragment> </React.Fragment>
); );
} }

View File

@ -0,0 +1,54 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import {contractLogs as contractLogsAction, listenToContractLogs, startDebug, debugJumpBack, debugJumpForward, debugStepOverForward, debugStepOverBackward, debugStepIntoForward, debugStepIntoBackward} from '../actions';
import ContractDebugger from '../components/ContractDebugger';
import DataWrapper from "../components/DataWrapper";
import {getContractLogsByContract, debuggerInfo} from "../reducers/selectors";
class ContractDebuggerContainer extends Component {
componentDidMount() {
// if (this.props.contractLogs.length === 0) {
// this.props.listenToContractLogs();
// this.props.fetchContractLogs(this.props.contract.className);
// }
}
render() {
return (
<DataWrapper shouldRender={this.props.contractLogs !== undefined } {...this.props} render={() => (
<ContractDebugger contract={this.props.contract} startDebug={this.props.startDebug} debugJumpBack={this.props.debugJumpBack} debugJumpForward={this.props.debugJumpForward} debugStepOverForward={this.props.debugStepOverForward} debugStepOverBackward={this.props.debugStepOverBackward} debugStepIntoForward={this.props.debugStepIntoForward} debugStepIntoBackward={this.props.debugStepIntoBackward} debuggerInfo={this.props.debuggerInfo}
/>
)} />
);
}
}
function mapStateToProps(state, props) {
return {
contractLogs: getContractLogsByContract(state, props.contract.className),
debuggerInfo: debuggerInfo(state)
};
}
ContractDebuggerContainer.propTypes = {
contractLogs: PropTypes.array,
fetchContractLogs: PropTypes.func,
listenToContractLogs: PropTypes.func,
match: PropTypes.object
};
export default connect(
mapStateToProps,
{
startDebug: startDebug.request,
debugJumpBack: debugJumpBack.request,
debugJumpForward: debugJumpForward.request,
debugStepOverForward: debugStepOverForward.request,
debugStepOverBackward: debugStepOverBackward.request,
debugStepIntoForward: debugStepIntoForward.request,
debugStepIntoBackward: debugStepIntoBackward.request
}
)(ContractDebuggerContainer);

View File

@ -1,4 +1,5 @@
.editor--grid { .editor--grid {
margin-left: -30px !important; margin-left: -30px !important;
margin-right: -30px !important; margin-right: -30px !important;
background-color: #1C1C1C;
} }

View File

@ -6,13 +6,11 @@ import TextEditorAsideContainer from './TextEditorAsideContainer';
import TextEditorContainer from './TextEditorContainer'; import TextEditorContainer from './TextEditorContainer';
import FileExplorerContainer from './FileExplorerContainer'; import FileExplorerContainer from './FileExplorerContainer';
import TextEditorToolbarContainer from './TextEditorToolbarContainer'; import TextEditorToolbarContainer from './TextEditorToolbarContainer';
import {currentFile as currentFileAction} from '../actions'; import {fetchEditorTabs as fetchEditorTabsAction} from '../actions';
import {getCurrentFile} from '../reducers/selectors'; import {getCurrentFile} from '../reducers/selectors';
import './EditorContainer.css'; import './EditorContainer.css';
const DEFAULT_FILE = {name: 'newContract.sol', content: ''};
class EditorContainer extends React.Component { class EditorContainer extends React.Component {
constructor(props) { constructor(props) {
super(props) super(props)
@ -20,9 +18,7 @@ class EditorContainer extends React.Component {
} }
componentDidMount() { componentDidMount() {
if(this.props.currentFile.content === '') { this.props.fetchEditorTabs();
this.props.fetchCurrentFile();
}
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
@ -32,7 +28,7 @@ class EditorContainer extends React.Component {
} }
isContract() { isContract() {
return this.state.currentFile.name.endsWith('.sol'); return this.state.currentFile.name && this.state.currentFile.name.endsWith('.sol');
} }
onFileContentChange(newContent) { onFileContentChange(newContent) {
@ -83,7 +79,7 @@ class EditorContainer extends React.Component {
} }
function mapStateToProps(state, props) { function mapStateToProps(state, props) {
const currentFile = getCurrentFile(state) || DEFAULT_FILE; const currentFile = getCurrentFile(state);
return { return {
currentFile currentFile
@ -92,11 +88,11 @@ function mapStateToProps(state, props) {
EditorContainer.propTypes = { EditorContainer.propTypes = {
currentFile: PropTypes.object, currentFile: PropTypes.object,
fetchCurrentFile: PropTypes.func fetchEditorTabs: PropTypes.func
}; };
export default connect( export default connect(
mapStateToProps, mapStateToProps,
{fetchCurrentFile: currentFileAction.request}, {fetchEditorTabs: fetchEditorTabsAction.request},
)(EditorContainer); )(EditorContainer);

View File

@ -9,6 +9,7 @@ import {getContractsByPath} from "../reducers/selectors";
import ContractDetail from '../components/ContractDetail'; import ContractDetail from '../components/ContractDetail';
import ContractLoggerContainer from '../containers/ContractLoggerContainer'; import ContractLoggerContainer from '../containers/ContractLoggerContainer';
import ContractOverviewContainer from '../containers/ContractOverviewContainer'; import ContractOverviewContainer from '../containers/ContractOverviewContainer';
import ContractDebuggerContainer from '../containers/ContractDebuggerContainer';
class TextEditorAsideContainer extends Component { class TextEditorAsideContainer extends Component {
componentDidMount() { componentDidMount() {
@ -19,6 +20,17 @@ class TextEditorAsideContainer extends Component {
switch(this.props.currentAsideTab) { switch(this.props.currentAsideTab) {
case 'browser': case 'browser':
return <Preview /> return <Preview />
case 'debugger':
return this.props.contracts.map((contract, index) => {
return (
<Card>
<CardBody>
<CardTitle style={{"font-size": "2em"}}>{contract.className} - Details</CardTitle>
<ContractDebuggerContainer key={index} contract={contract} />
</CardBody>
</Card>
)
})
case 'detail': case 'detail':
return this.props.contracts.map((contract, index) => { return this.props.contracts.map((contract, index) => {
return ( return (

View File

@ -3,20 +3,39 @@ import {connect} from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import TextEditor from '../components/TextEditor'; import TextEditor from '../components/TextEditor';
import { import {
addEditorTabs as addEditorTabsAction,
fetchEditorTabs as fetchEditorTabsAction,
removeEditorTabs as removeEditorTabsAction,
toggleBreakpoint, toggleBreakpoint,
} from '../actions'; } from '../actions';
import {getBreakpointsByFilename} from '../reducers/selectors';
const TextEditorContainer = (props) => ( import {getCurrentFile, getContractCompile, getContractDeploys, getBreakpointsByFilename, getDebuggerLine, getEditorTabs} from '../reducers/selectors';
<TextEditor file={props.currentFile}
breakpoints={props.breakpoints} class TextEditorContainer extends React.Component {
toggleBreakpoint={props.toggleBreakpoint} componentDidMount() {
onFileContentChange={props.onFileContentChange} /> this.props.fetchEditorTabs();
) }
render() {
return (
<TextEditor file={this.props.currentFile}
currentFile={this.props.currentFile}
breakpoints={this.props.breakpoints}
toggleBreakpoint={this.props.toggleBreakpoint}
editorTabs={this.props.editorTabs}
removeEditorTabs={this.props.removeEditorTabs}
addEditorTabs={this.props.addEditorTabs}
debuggerLine={this.props.debuggerLine}
onFileContentChange={this.props.onFileContentChange} />
)
}
}
function mapStateToProps(state, props) { function mapStateToProps(state, props) {
const breakpoints = getBreakpointsByFilename(state, props.currentFile.name); const breakpoints = getBreakpointsByFilename(state, props.currentFile.name);
return {breakpoints}; const editorTabs = getEditorTabs(state);
const debuggerLine = getDebuggerLine(state);
return {breakpoints, editorTabs, debuggerLine};
} }
TextEditorContainer.propTypes = { TextEditorContainer.propTypes = {
@ -24,9 +43,18 @@ TextEditorContainer.propTypes = {
onFileContentChange: PropTypes.func, onFileContentChange: PropTypes.func,
toggleBreakpoints: PropTypes.func, toggleBreakpoints: PropTypes.func,
breakpoints: PropTypes.array, breakpoints: PropTypes.array,
toggleBreakpoint: PropTypes.object,
fetchEditorTabs: PropTypes.func,
removeEditorTabs: PropTypes.func,
addEditorTabs: PropTypes.func
}; };
export default connect( export default connect(
mapStateToProps, mapStateToProps,
{toggleBreakpoint}, {
toggleBreakpoint,
fetchEditorTabs: fetchEditorTabsAction.request,
removeEditorTabs: removeEditorTabsAction.request,
addEditorTabs: addEditorTabsAction.request
},
)(TextEditorContainer); )(TextEditorContainer);

View File

@ -3,7 +3,6 @@ import {connect} from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {transactions as transactionsAction, initBlockHeader, stopBlockHeader} from '../actions'; import {transactions as transactionsAction, initBlockHeader, stopBlockHeader} from '../actions';
import LoadMore from "../components/LoadMore";
import Transactions from '../components/Transactions'; import Transactions from '../components/Transactions';
import DataWrapper from "../components/DataWrapper"; import DataWrapper from "../components/DataWrapper";
import {getTransactions} from "../reducers/selectors"; import {getTransactions} from "../reducers/selectors";
@ -34,9 +33,9 @@ class TransactionsContainer extends Component {
return ( return (
<React.Fragment> <React.Fragment>
<DataWrapper shouldRender={this.props.transactions.length > 0} {...this.props} render={({transactions}) => ( <DataWrapper shouldRender={this.props.transactions.length > 0} {...this.props} render={({transactions}) => (
<Transactions transactions={transactions} /> <Transactions transactions={transactions}
showLoadMore={(this.loadMoreFrom() >= 0)} loadMore={() => this.loadMore()} />
)} /> )} />
{(this.loadMoreFrom() > 0) ? <LoadMore loadMore={() => this.loadMore()} /> : <React.Fragment />}
</React.Fragment> </React.Fragment>
); );
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -0,0 +1,360 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="224" height="216" id="svg2" version="1.1" inkscape:version="0.92.2pre0 (973e216, 2017-07-25)" sodipodi:docname="largeIcons.svg">
<metadata id="metadata606">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
</cc:Work>
</rdf:RDF>
</metadata>
<defs id="defs604"/>
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1946" inkscape:window-height="1546" id="namedview602" showgrid="true" inkscape:zoom="4.3703705" inkscape:cx="92.781028" inkscape:cy="118.13064" inkscape:window-x="1047" inkscape:window-y="228" inkscape:window-maximized="0" inkscape:current-layer="svg2" inkscape:snap-grids="true" showguides="true" inkscape:guide-bbox="true">
<inkscape:grid type="xygrid" id="grid3583" empspacing="5" visible="true" enabled="true" snapvisiblegridlinesonly="true" spacingx="28" spacingy="24" originx="0" originy="0"/>
</sodipodi:namedview>
<g id="g4">
<g transform="translate(-322,-72)" id="g8">
<circle transform="translate(326,74)" cx="15" cy="17" r="3" id="circle10" sodipodi:cx="15" sodipodi:cy="17" sodipodi:rx="3" sodipodi:ry="3" style="fill:#009802"/>
<path d="m 329,77 h 18 v 18 h -18 z" id="path12" inkscape:connector-curvature="0" style="fill:none"/>
<path d="m 327.25,75.25 h 20 v 20 h -20 z" id="path14" inkscape:connector-curvature="0" style="fill:none"/>
<path d="m 325.12,73.125 h 20 v 20 h -20 z" id="path16" inkscape:connector-curvature="0" style="fill:none"/>
</g>
</g>
<g transform="translate(26,0)" id="g18">
<path transform="translate(-32,0)" d="M 57,12 53.5,8 H 39 v 8 h 14.5" id="path22" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(-2.003,24)" id="g24">
<path transform="translate(-224,-120)" d="m 240.77,127 h -1.534 v 4.233 h -4.233 v 1.534 h 4.233 V 137 h 1.534 v -4.233 h 4.233 v -1.534 H 240.77 V 127 z" id="path28" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(26,24)" id="g30">
<path transform="translate(-96,-145)" d="m 103,148 h 18 v 18 h -18 z" id="path34" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-96,-145)" d="m 115.42,154.7 -6.705,-6.705 -1.0575,1.0575 1.785,1.785 -3.8625,3.8625 c -0.4425,0.4425 -0.4425,1.155 0,1.59 l 4.125,4.125 c 0.2175,0.2175 0.51,0.33 0.795,0.33 0.285,0 0.5775,-0.1125 0.795,-0.33 l 4.125,-4.125 c 0.4425,-0.435 0.4425,-1.1475 0,-1.59 z m -8.5125,0.795 3.5925,-3.5925 3.5925,3.5925 h -7.185 z m 10.342,1.125 c 0,0 -1.5,1.6275 -1.5,2.625 0,0.825 0.675,1.5 1.5,1.5 0.825,0 1.5,-0.675 1.5,-1.5 0,-0.9975 -1.5,-2.625 -1.5,-2.625 z" id="path36" inkscape:connector-curvature="0"/>
<path transform="translate(-96,-145)" d="m 103,163 h 18 v 3 h -18 z" id="path38" inkscape:connector-curvature="0" style="fill-opacity:0.36000001"/>
</g>
<g transform="translate(0,48)" id="g40">
<path transform="translate(7,3)" d="M 0,0 H 18 V 18 H 0 z" id="path44" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(7,3)" d="m 13,5 h 1.4936 C 15.32558,5 16,5.67154 16,6.5064 v 7.9871 c 0,0.83198 -0.67154,1.5064 -1.5064,1.5064 H 6.5065 c -0.83198,0 -1.5064,-0.67154 -1.5064,-1.5064 v -1.4936 h 6.4936 c 0.8349,0 1.5064,-0.67446 1.5064,-1.5064 V 4.9999 z" id="path46" inkscape:connector-curvature="0" style="fill-opacity:0.36000001"/>
<path transform="translate(7,3)" d="M 3.5,2 C 2.669,2 2,2.669 2,3.5 v 8 C 2,12.331 2.669,13 3.5,13 h 8 c 0.831,0 1.5,-0.669 1.5,-1.5 v -8 C 13,2.669 12.331,2 11.5,2 h -8 z m 0,1.5 h 8 v 8 h -8 v -8 z" id="path48" inkscape:connector-curvature="0" style="fill:#212121"/>
</g>
<g transform="translate(26,48)" id="g50">
<path transform="translate(-96,-24)" d="m 107,33 h 8 v 6 h -8 z" stroke-miterlimit="4.2" id="path54" inkscape:connector-curvature="0" style="stroke:#000000;stroke-width:2;stroke-miterlimit:4.19999981"/>
<path transform="translate(-96,-24)" d="m 115,36 4,-4 v 8" id="path56" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(54,0)" id="g58">
<g id="g62" style="stroke:#000000">
<path transform="matrix(0.36,0,0,0.36,-2.5,7.46)" d="m 53,14 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" id="path64" inkscape:connector-curvature="0" style="fill-rule:evenodd;stroke-width:2.77800012"/>
<path transform="translate(-128,-120)" d="m 143.48,129.5 2.5403,-2 h -1.5242 v -2 h -2 l -0.0161,2 h -1.5403 z" id="path66" inkscape:connector-curvature="0"/>
<path transform="translate(-128,-120)" d="m 146.5,132.5 2,2.5 v -1.4998 l 2,-1e-4 v -2.0002 l -2,1e-4 V 130 z" id="path68" inkscape:connector-curvature="0"/>
<path transform="translate(-128,-120)" d="m 143.5,135.5 -2.5,2 h 1.5 v 2 h 2 v -2 h 1.5 z" id="path70" inkscape:connector-curvature="0"/>
<path transform="translate(-128,-120)" d="m 140.5,132.5 -2,-2.5 v 1.4999 h -2 v 2.0002 l 2,-3e-4 V 135 z" id="path72" inkscape:connector-curvature="0"/>
</g>
</g>
<g transform="translate(56,24)" id="g74">
<g id="g78" style="fill-rule:evenodd">
<path transform="matrix(0.9018,0,0,0.9018,4.308,4.525)" d="M 0,0 H 18 V 18 H 0 z" id="path80" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="matrix(0.9018,0,0,0.9018,4.308,4.525)" d="M 4.174,8.343 2.76,9.757 7.003,13.999 15.488,5.514 14.074,4.1 7.003,11.171 z" id="path82" inkscape:connector-curvature="0"/>
</g>
</g>
<g transform="translate(57,47)" id="g84">
<path transform="translate(-68,-143)" d="M 76.94,152 76,152.94 79.0533,156 76,159.06 l 0.94,0.94 4,-4 z" id="path88" inkscape:connector-curvature="0"/>
<path transform="translate(-68,-143)" d="M 80.94,152 80,152.94 83.0533,156 80,159.06 l 0.94,0.94 4,-4 z" id="path90" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(-2,72)" id="g92">
<path transform="translate(-64,0)" d="m 80.44,16.94 c -2.48,0 -4.5,-2.02 -4.5,-4.5 0,-0.88 0.26,-1.7 0.69,-2.39 l 6.2,6.2 c -0.69,0.44 -1.51,0.69 -2.39,0.69 m 4.5,-4.5 c 0,0.88 -0.26,1.7 -0.69,2.39 l -6.2,-6.2 c 0.69,-0.44 1.51,-0.69 2.39,-0.69 2.48,0 4.5,2.02 4.5,4.5 M 80.5,6 C 76.91,6 74,8.91 74,12.5 74,16.09 76.91,19 80.5,19 84.09,19 87,16.09 87,12.5 87,8.91 84.09,6 80.5,6" id="path96" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(28,72)" id="g98">
<g id="g102" style="fill-rule:evenodd">
<path transform="matrix(0.87153,0,0,0.87153,4.071,4.568)" d="M 0,0 H 18 V 18 H 0 z" id="path104" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="matrix(0.87153,0,0,0.87153,4.071,4.568)" d="M 12,3.5 A 1.505,1.505 0 0 0 10.494,2 H 4.506 C 3.676,2 3,2.674 3,3.506 v 7.988 C 3,12.326 3.671,12.997 4.5,13 V 3.5 H 12 z M 6,6.506 C 6,5.674 6.676,5 7.506,5 h 5.988 C 14.326,5 15,5.672 15,6.506 v 7.988 C 15,15.326 14.324,16 13.494,16 H 7.506 A 1.505,1.505 0 0 1 6,14.494 V 6.506 z M 7.5,6.5 h 6 v 8 h -6 v -8 z" id="path106" inkscape:connector-curvature="0"/>
</g>
</g>
<g transform="translate(54,72)" id="g108">
<path transform="translate(0,-24)" d="M 25,36 21.36,32 H 19.57 L 14,40 h 7.36 L 25,36 z" id="path112" inkscape:connector-curvature="0"/>
<path transform="translate(0,-24)" d="m 7,32 v 8 H 9.05 L 14,32 H 7 z" id="path114" inkscape:connector-curvature="0"/>
<path transform="translate(0,-24)" d="M 9.67,44.55 8.08,43.23 18.84,27.45 20.43,28.77 9.67,44.55 z" id="path116" inkscape:connector-curvature="0"/>
<path transform="translate(0,-24)" d="M 0,24 H 24 V 48 H 0 z" id="path118" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(0,-24)" d="M 0,24 H 24 V 48 H 0 z m 0,0 H 24 V 48 H 0 z m 0,0 H 24 V 48 H 0 z m 0,0 H 24 V 48 H 0 z" id="path120" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(0,-24)" d="M 0,24 H 24 V 48 H 0 z" id="path122" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(0,-24)" d="M 0,24 H 24 V 48 H 0 z" id="path124" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(0,-24)" d="M 0,24 H 24 V 48 H 0 z" id="path126" inkscape:connector-curvature="0" style="fill:none"/>
</g>
<g transform="translate(82,0)" id="g128">
<path transform="translate(-128,0)" d="M 149,8.33 147.67,7 144,10.67 140.33,7 139,8.33 142.67,12 139,15.67 140.33,17 144,13.33 147.67,17 149,15.67 145.33,12 149,8.33 z" id="path132" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(82,24)" id="g134">
<path transform="translate(-32,-24)" d="M 53,37 H 43 v -5 h 10 v 5 z M 41,42 H 55 V 30 H 41 v 12 z" id="path138" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(82,48)" id="g140">
<path transform="translate(-224,-48)" d="m 238,64 h 7 v -8 h -7 z m 9,2 H 233 V 54 h 14 z" id="path144" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(82,72)" id="g146">
<path transform="translate(-256,-48)" d="m 274,64 h -7 v -8 h 7 v 8 z m -9,2 h 14 V 54 h -14 v 12 z" id="path150" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(-2,96)" id="g152">
<path transform="translate(-160,0)" d="m 169,16.089 v 2.9105 h 2.9105 L 180.1944,10.7156 177.2838,7.8051 169,16.089 z m 13.769,-7.9387 c 0.30785,-0.30785 0.30785,-0.79294 0,-1.1008 l -1.8191,-1.8191 c -0.30785,-0.30784 -0.79295,-0.30784 -1.1008,0 l -1.5206,1.5299 2.9105,2.9105 1.5299,-1.5206 z" id="path156" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(26,96)" id="g158">
<path transform="translate(-288,-120)" d="m 310.77,127.04 -1.816,-1.8164 c -0.30331,-0.30338 -0.79716,-0.30338 -1.1005,0 l -2.4304,2.4309 -1.4894,-1.4935 -1.1005,1.1007 1.1044,1.1046 -6.9373,6.9348 v 3.695 h 3.6942 l 6.9373,-6.9387 1.1005,1.1046 1.1005,-1.1007 -1.4932,-1.4935 2.4304,-2.4309 c 0.3072,-0.30338 0.3072,-0.79345 0,-1.0968 z m -10.721,10.4 -1.4932,-1.4935 6.2724,-6.2736 1.4932,1.4935 -6.2723,6.2736 z" id="path162" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(54,96)" id="g164">
<path transform="translate(-32,-48)" d="m 44,59 2,3 v 4 h 4 v -4 l 2,-3 z" id="path168" inkscape:connector-curvature="0" style="opacity:0.5;fill:#424242"/>
<path transform="translate(-32,-48)" d="m 46.5,65.23 c 0.32,0.13 0.84,0.24 1.47,0.24 0.59,0 1.14,-0.1 1.53,-0.26 v -3.93 l 4,-4.57 v -0.19 h -11 v 0.22 l 4,4.57 v 3.93 z M 47.97,67 C 46.81,66.91 45.82,66.71 45,66.01 V 61.89 L 41,57.32 V 55 h 14 v 2.35 l -4,4.57 v 4.13 c -0.92,0.67 -2.1,0.94 -3.03,0.95" id="path170" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(82.001,96)" id="g172">
<path transform="matrix(0.75,0,0,0.75,-74.421,-143.43)" d="m 108.56,195.24 h 24 v 24 h -24 z" id="path176" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="matrix(0.75,0,0,0.75,-74.421,-143.43)" d="m 108.56,215.24 h 24 v 4 h -24 z" id="path178" inkscape:connector-curvature="0" style="fill-opacity:0.36000001"/>
<path transform="matrix(0.75,0,0,0.75,-74.421,-143.43)" d="m 119.56,198.24 -5.5,14 h 2.25 l 1.12,-3 h 6.25 l 1.12,3 h 2.25 l -5.49,-14 h -2 z m -1.38,9 2.38,-6.33 2.38,6.33 h -4.76 z" id="path180" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(106,1)" id="g182">
<path transform="matrix(0,-1,1,0,-112,-260)" d="m -278.5,126.5 h 14 v 12 h -14 z" id="path186" inkscape:connector-curvature="0" style="fill:none;stroke:#000000"/>
<path transform="matrix(0,1,1,0,-112,-260)" d="m 272,132.5 -5,-3.25 v 6.5" id="path188" inkscape:connector-curvature="0"/>
<path transform="matrix(0,-1,1,0,-112,-260)" d="m -275,126 h 1 v 13 h -1 z" id="path190" inkscape:connector-curvature="0"/>
</g>
<path style="fill:none;stroke:#000000" inkscape:connector-curvature="0" id="path196" d="m 119.5,30.5 h 14 v 12 h -14 z"/>
<path inkscape:connector-curvature="0" id="path198" d="m 126,36.5 5,-3.25 v 6.5"/>
<path inkscape:connector-curvature="0" id="path200" d="m 123,30 h 1 v 13 h -1 z"/>
<g transform="translate(111,48)" id="g202">
<path transform="matrix(-1,0,0,1,-192,-120)" d="m -214.5,126.5 h 14 v 12 h -14 z" id="path206" inkscape:connector-curvature="0" style="fill:none;stroke:#000000"/>
<path transform="translate(-192,-120)" d="m 208,132.5 -5,-3.25 v 6.5" id="path208" inkscape:connector-curvature="0"/>
<path transform="matrix(-1,0,0,1,-192,-120)" d="m -211,126 h 1 v 13 h -1 z" id="path210" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(106,73)" id="g212">
<path transform="matrix(0,1,1,0,-88,283)" d="m -278.5,102.5 h 14 v 12 h -14 z" id="path216" inkscape:connector-curvature="0" style="fill:none;stroke:#000000"/>
<path transform="matrix(0,-1,1,0,-88,283)" d="m 272,108.5 -5,-3.25 v 6.5" id="path218" inkscape:connector-curvature="0"/>
<path transform="matrix(0,1,1,0,-88,283)" d="m -275,102 h 1 v 13 h -1 z" id="path220" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(110,96)" id="g222">
<path transform="translate(-224,0)" d="m 237,11 h -4 V 7 h 4 v 4 z" id="path226" inkscape:connector-curvature="0"/>
<path transform="translate(-224,0)" d="m 247,9 h -9 V 7 h 9 v 2 z" id="path228" inkscape:connector-curvature="0"/>
<path transform="translate(-224,0)" d="m 247,11 h -9 v -1 h 9 v 1 z" id="path230" inkscape:connector-curvature="0"/>
<path transform="translate(-224,0)" d="m 247,15 h -9 v -2 h 9 v 2 z" id="path232" inkscape:connector-curvature="0"/>
<path transform="translate(-224,0)" d="m 237,17 h -4 v -4 h 4 v 4 z" id="path234" inkscape:connector-curvature="0"/>
<path transform="translate(-224,0)" d="m 247,17 h -9 v -1 h 9 v 1 z" id="path236" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(-2,120)" id="g238">
<path transform="translate(0,-144)" d="m 23,157 h -2 v 2 h 2 z" id="path242" inkscape:connector-curvature="0"/>
<path transform="translate(0,-144)" d="m 23,161 h -2 v 2 c 1,0 2,-1 2,-2 z" id="path244" inkscape:connector-curvature="0"/>
<path transform="translate(0,-144)" d="m 23,153 h -2 v 2 h 2 z" id="path246" inkscape:connector-curvature="0"/>
<path transform="translate(0,-144)" d="m 21,149 v 2 h 2 c 0,-1 -1,-2 -2,-2 z" id="path248" inkscape:connector-curvature="0"/>
<path transform="translate(0,-144)" d="m 11,163 h 4 v -6 H 9 v 4 c 0,1.1 0.9,2 2,2 z" id="path250" inkscape:connector-curvature="0"/>
<path transform="translate(0,-144)" d="M 11,153 H 9 v 2 h 2 z" id="path252" inkscape:connector-curvature="0"/>
<path transform="translate(0,-144)" d="m 19,149 h -2 v 2 h 2 z" id="path254" inkscape:connector-curvature="0"/>
<path transform="translate(0,-144)" d="m 19,161 h -2 v 2 h 2 z" id="path256" inkscape:connector-curvature="0"/>
<path transform="translate(0,-144)" d="m 11,149 c -1,0 -2,1 -2,2 h 2 z" id="path258" inkscape:connector-curvature="0"/>
<path transform="translate(0,-144)" d="m 15,149 h -2 v 2 h 2 z" id="path260" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(26,120)" id="g262">
<path transform="translate(-290,-46)" d="m 317,69 v -5 l -5,5 h 5 z" id="path266" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(54,120)" id="g268">
<g id="g272" style="fill-rule:evenodd">
<path transform="matrix(1.4142,0,0,1.4142,-278.88,-36.772)" d="m 209.92,31.305 a 1.0607,1.0607 0 1 1 -2.1213,0 1.0607,1.0607 0 1 1 2.1213,0 z" id="path274" inkscape:connector-curvature="0"/>
<path transform="matrix(1.4142,0,0,1.4142,-278.88,-31.772)" d="m 209.92,31.305 a 1.0607,1.0607 0 1 1 -2.1213,0 1.0607,1.0607 0 1 1 2.1213,0 z" id="path276" inkscape:connector-curvature="0"/>
<path transform="matrix(1.4142,0,0,1.4142,-278.88,-26.772)" d="m 209.92,31.305 a 1.0607,1.0607 0 1 1 -2.1213,0 1.0607,1.0607 0 1 1 2.1213,0 z" id="path278" inkscape:connector-curvature="0"/>
</g>
</g>
<g transform="translate(84,120)" id="g280">
<path transform="translate(-162,-144)" d="m 166,147 h 18 v 18 h -18 z" id="path284" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-162,-144)" d="m 181.52,154.53 c -0.51,-2.58 -2.7862,-4.5262 -5.5162,-4.5262 -2.1675,0 -4.0462,1.23 -4.9875,3.0262 -2.2538,0.24375 -4.0125,2.1525 -4.0125,4.4738 0,2.4862 2.0138,4.5 4.5,4.5 h 9.75 c 2.07,0 3.75,-1.68 3.75,-3.75 0,-1.98 -1.5412,-3.585 -3.4838,-3.7238 z m -0.26625,5.9738 h -9.75 c -1.6575,0 -3,-1.3425 -3,-3 0,-1.6575 1.3425,-3 3,-3 h 0.5325 c 0.49125,-1.7288 2.0775,-3 3.9675,-3 2.28,0 4.125,1.845 4.125,4.125 v 0.375 h 1.125 c 1.2412,0 2.25,1.0088 2.25,2.25 0,1.2412 -1.0088,2.25 -2.25,2.25 z" id="path286" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(112,120)" id="g288">
<path transform="translate(-226,-72)" d="m 235,76 c -0.55,0 -0.99,0.45 -0.99,1 L 234,91 c 0,0.55 0.44,1 1,1 h 10 c 0.55,0 1,-0.45 1,-1 V 81 l -5,-5 h -6 z m 6,5 v -4 l 4,4 h -4 z" id="path292" inkscape:connector-curvature="0"/>
<path transform="translate(-226,-72)" d="m 231,75 h 18 v 18 h -18 z" id="path294" inkscape:connector-curvature="0" style="fill:none"/>
</g>
<g transform="translate(140,0)" id="g296">
<path transform="translate(-162,-24)" d="m 169,29 h 18 v 18 h -18 z" id="path300" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-162,-24)" d="m 167.25,27.25 h 20 v 20 h -20 z" id="path302" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-162,-24)" d="m 165.12,25.125 h 20 v 20 h -20 z" id="path304" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-162,-24)" d="m 171,28 c -0.55,0 -1,0.45 -1,1 v 14 c 0,0.55 0.44,1 1,1 h 5.0938 c -0.0656,-0.32311 -0.0937,-0.65753 -0.0937,-1 0,-2.7614 2.2386,-5 5,-5 0.34247,0 0.67689,0.02816 1,0.09375 v -5.0938 l -5,-5 h -6 z m 6,1 4,4 h -4 v -4 z" id="path306" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(140,24)" id="g308">
<path transform="translate(-66,-120)" d="m 71,124 h 18 v 18 H 71 z" id="path312" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-66,-120)" d="m 82,129 -2,-2 h -5 c -0.55,0 -1,0.45 -1,1 v 10 c 0,0.55 0.45,1 1,1 h 12 c 0.55,0 1,-0.45 1,-1 v -8 c 0,-0.55 -0.45,-1 -1,-1 h -5 z" id="path314" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(140,48)" id="g316">
<path transform="translate(-258,-144)" d="m 278,150 h -10.5 c -0.8325,0 -1.5,0.675 -1.5,1.5 v 9 c 0,0.825 0.6675,1.5 1.5,1.5 H 278 c 0.825,0 1.5,-0.675 1.5,-1.5 v -9 c 0,-0.825 -0.6675,-1.5 -1.5,-1.5 z m 0,10.5 H 267.5 V 153 H 278 v 7.5 z" id="path320" inkscape:connector-curvature="0" style="fill:#010101"/>
<path transform="translate(-258,-144)" d="m 262.97,147.07 h 18 v 18 h -18 z" id="path322" inkscape:connector-curvature="0" style="fill:none"/>
</g>
<g transform="translate(140,72)" id="g324">
<path transform="translate(6,3.9)" d="M 9,1 H 3.9954 C 3.45567,1 3,1.45078 3,2.0068 v 11.986 c 0,0.5569 0.44565,1.0068 0.9954,1.0068 h 8.0092 C 12.54433,14.9996 13,14.54882 13,13.9928 V 4.9996 l -4,-4 z m 3,4 H 9 V 2 l 3,3 z M 6,7 11,9.5 6,12 V 7 z" id="path328" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(140,96)" id="g330">
<g id="g334" style="stroke:#000000">
<path transform="matrix(0.72907,0,0,0.72907,5.617,4.598)" d="M 7.854,6.963 6.877,7.279 6.857,8.617 6.889,8.705 7.398,9.699 6.188,10.578 5.398,9.787 5.326,9.73 4.047,9.336 3.443,10.166 4.213,11.26 4.291,11.313 5.287,11.817 4.824,13.241 3.72,13.065 3.628,13.061 2.362,13.493 v 1.027 l 1.266,0.434 0.092,-0.004 1.104,-0.178 0.463,1.424 -0.996,0.506 -0.078,0.051 -0.77,1.094 0.604,0.83 1.279,-0.393 0.072,-0.059 0.789,-0.791 1.211,0.879 -0.51,0.996 -0.031,0.086 0.02,1.338 0.977,0.316 0.803,-1.068 0.025,-0.09 0.172,-1.104 h 1.498 l 0.172,1.104 0.025,0.09 0.803,1.068 0.977,-0.316 0.02,-1.338 -0.031,-0.086 -0.51,-0.996 1.211,-0.879 0.789,0.791 0.072,0.059 1.279,0.393 0.604,-0.83 -0.771,-1.094 -0.076,-0.051 -0.996,-0.506 0.461,-1.424 1.105,0.178 0.092,0.004 1.266,-0.434 v -1.027 l -1.266,-0.432 -0.092,0.004 -1.105,0.176 -0.461,-1.424 0.996,-0.504 0.076,-0.053 0.771,-1.094 L 15.159,9.336 13.88,9.731 13.808,9.788 13.019,10.579 11.808,9.7 12.318,8.706 12.349,8.618 12.329,7.28 11.352,6.964 10.549,8.034 10.524,8.122 10.352,9.227 H 8.854 L 8.682,8.121 8.656,8.03 7.854,6.963 m 1.748,3.398 a 3.621,3.645 0 0 1 3.621,3.645 3.621,3.645 0 0 1 -3.621,3.646 3.621,3.645 0 0 1 -3.619,-3.646 3.621,3.645 0 0 1 3.619,-3.645 z" id="path336" inkscape:connector-curvature="0"/>
<path transform="matrix(0.72907,0,0,0.72907,5.227,3.617)" d="M 14.885,1.563 14.178,1.957 14.365,3.24 14.396,3.279 15.14,4.04 14.553,5.03 13.529,4.736 13.479,4.729 12.262,5.172 12.25,5.98 13.455,6.459 13.506,6.453 14.537,6.189 15.1,7.191 14.332,7.932 14.301,7.971 14.08,9.248 14.771,9.662 15.787,8.859 15.807,8.811 16.1,7.787 17.242,7.803 17.502,8.834 17.52,8.883 18.514,9.715 19.219,9.32 19.03,8.04 19,7.998 18.258,7.234 18.844,6.25 19.869,6.541 19.92,6.551 21.14,6.105 21.15,5.297 19.943,4.818 19.893,4.824 18.861,5.088 18.301,4.086 19.07,3.346 19.1,3.307 19.322,2.029 18.627,1.615 17.609,2.418 17.59,2.467 17.303,3.49 16.16,3.475 15.896,2.443 15.879,2.395 14.885,1.563 z m 1.814,2.138 a 1.938,1.938 0 0 1 1.938,1.938 1.938,1.938 0 0 1 -1.938,1.937 1.938,1.938 0 0 1 -1.937,-1.937 1.938,1.938 0 0 1 1.937,-1.938 z" id="path338" inkscape:connector-curvature="0" style="stroke-width:0.89899999"/>
</g>
</g>
<g transform="translate(138,120)" id="g340">
<g id="g344" style="fill:none">
<path transform="translate(8,4)" d="M 0,0 H 16 V 16 H 0 V 0 z" id="path346" inkscape:connector-curvature="0" style="opacity:0.5"/>
<path transform="translate(8,4)" d="M 6,14 H 3.5 C 2.5,14 2,13.5 2,12.5 v -9 C 2,2.5 2.5,2 3.5,2 h 9 C 14,2 14,3.4678 14,3.5 V 6 H 13 V 3 H 3 v 10 h 3 v 1 z m 9,-5 -3,2 3,3 -1,1 -3,-3 -2,3 -2,-8 8,2 z" id="path348" inkscape:connector-curvature="0" style="fill:#000000"/>
</g>
</g>
<g transform="translate(0,144)" id="g350">
<path transform="translate(-98,-120)" d="m 110.5,127.5 h -1 l 2,-2 2,2 h -1 c 0,0 -0.0345,4.6379 -0.0345,4.0345 l 4.0345,-0.034 v -1 l 2,2 -2,2 v -1 l -4.0345,-0.034 0.0345,4.0346 h 1 l -2,2 -2,-2 h 1 l 0.0345,-4.0346 -4.0345,0.034 v 1 l -2,-2 2,-2 v 1 l 4.0345,0.034 z" id="path354" inkscape:connector-curvature="0" style="stroke:#000000"/>
</g>
<g transform="translate(26,144)" id="g356">
<path transform="translate(-320,0)" d="m 333.6,15.2 h 1.6 V 8.8 h -1.6 v 6.4 z M 336,4 c -4.42,0 -8,3.58 -8,8 0,4.42 3.58,8 8,8 4.42,0 8,-3.58 8,-8 0,-4.42 -3.58,-8 -8,-8 z m 0,14.4 c -3.528,0 -6.4,-2.872 -6.4,-6.4 0,-3.528 2.872,-6.4 6.4,-6.4 3.528,0 6.4,2.872 6.4,6.4 0,3.528 -2.872,6.4 -6.4,6.4 z m 0.8,-3.2 h 1.6 V 8.8 h -1.6 v 6.4 z" id="path360" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(54,144)" id="g362">
<path transform="translate(-32,-72)" d="m 47,88 h -3 v -8 h 3 v 8 z" id="path366" inkscape:connector-curvature="0"/>
<path transform="translate(-32,-72)" d="m 53,88 h -3 v -8 h 3 v 8 z" id="path368" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(82,144)" id="g370">
<path transform="translate(-256,0)" d="m 275,15 h -2 V 9 h 2 z m -4,0 h -2 V 9 h 2 z m 4,-10 h -6 l -4,4 v 6 l 4,4 h 6 l 4,-4.12 V 9 z" id="path374" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(110,144)" id="g376">
<g font-weight="400" id="g380" style="font-weight:400;font-family:Sans">
<path transform="translate(-289,-96)" d="m 300,101 v 4.0001 1.0001 l 3.3434,0.53115 -0.0156,8.0468 -1.3278,0.42183 c 0.006,0.59278 0.43931,1.0114 1,1 h 8 c 0.57896,0.002 0.98177,-0.42708 1,-1 v -14 c -0.0102,-0.53477 -0.48177,-0.99739 -1,-1 h -10 c -0.53297,0.008 -0.99716,0.45677 -1,1 z m 1,0 h 10 v 14 h -8 l 0.71845,-0.42179 0.0937,-8.4218 -2.8122,-0.1561 v -0.99993 z" overflow="visible" style="text-indent:0;line-height:normal;text-transform:none;block-progression:tb;overflow:visible" id="path382" inkscape:connector-curvature="0"/>
<path transform="translate(-289,-96)" d="m 297,106 v 9 c 0.006,0.59278 0.43931,1.0114 1,1 h 5 c 0.57896,0.002 0.98177,-0.42708 1,-1 v -9 c -0.0102,-0.53477 -0.48177,-0.99739 -1,-1 h -5 c -0.53297,0.008 -0.99716,0.45677 -1,1 z m 1,1.0002 h 5 v 7 h -5 z" overflow="visible" style="text-indent:0;line-height:normal;text-transform:none;block-progression:tb;overflow:visible" id="path384" inkscape:connector-curvature="0"/>
</g>
</g>
<g transform="translate(138,144)" id="g386">
<path transform="translate(-320,-48)" d="m 328,60 c 0,4.42 3.58,8 8,8 4.42,0 8,-3.58 8,-8 0,-4.42 -3.58,-8 -8,-8 -4.42,0 -8,3.58 -8,8 z m 8,6.4 c -3.528,0 -6.4,-2.872 -6.4,-6.4 0,-3.528 2.872,-6.4 6.4,-6.4 3.528,0 6.4,2.872 6.4,6.4 0,3.528 -2.872,6.4 -6.4,6.4 z M 334.5067,63.4286 339.0781,60 334.5067,56.5714 v 6.8571 z" id="path390" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(-2,168)" id="g392">
<path transform="translate(-96,-48)" d="m 108,60 10,-5 v 10" id="path396" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(26,168)" id="g398">
<path transform="translate(-64,-48)" d="M 86,60 76,55 v 10" id="path402" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(54,168)" id="g404">
<path transform="translate(-256,-24)" d="m 268.01,35.99 c 0.61,0.28 1.07,0.9 1.07,1.58 0.11,0.85 -0.05,1.72 0.12,2.57 0.27,0.54 1,0.28 1.43,0.55 0.49,0.24 0.48,1.01 -0.06,1.18 -0.56,0.22 -1.18,0.08 -1.74,-0.05 -0.71,-0.2 -1.41,-0.72 -1.5,-1.5 -0.18,-0.89 0.01,-1.8 -0.16,-2.68 -0.22,-0.64 -0.94,-0.9 -1.57,-0.93 -0.58,-0.1 -0.83,-0.94 -0.35,-1.3 0.51,-0.35 1.26,-0.14 1.69,-0.66 0.44,-0.48 0.29,-1.18 0.32,-1.78 0,-0.81 -0.02,-1.77 0.65,-2.34 0.66,-0.54 1.58,-0.71 2.41,-0.63 0.63,0 0.98,0.87 0.4,1.22 -0.44,0.37 -1.2,0.06 -1.51,0.65 -0.14,0.56 -0.05,1.15 -0.07,1.73 -0.01,0.75 -0.05,1.64 -0.72,2.13 -0.12,0.1 -0.26,0.19 -0.4,0.26" id="path408" inkscape:connector-curvature="0"/>
<path transform="translate(-256,-24)" d="m 276.98,35.99 c -0.67,-0.3 -1.08,-1.02 -1.08,-1.75 -0.07,-0.76 0.03,-1.52 -0.06,-2.28 -0.24,-0.58 -0.98,-0.4 -1.46,-0.59 -0.59,-0.24 -0.48,-1.18 0.14,-1.31 0.73,-0.15 1.52,-0.01 2.18,0.32 0.56,0.28 0.95,0.86 0.99,1.48 0.13,0.83 -0.03,1.68 0.13,2.5 0.2,0.68 0.94,0.83 1.54,0.9 0.56,0.07 0.86,0.8 0.46,1.21 -0.44,0.46 -1.2,0.2 -1.65,0.66 -0.51,0.46 -0.4,1.21 -0.4,1.83 -0.03,0.78 0.06,1.69 -0.52,2.3 -0.74,0.65 -1.8,0.86 -2.75,0.68 -0.52,-0.16 -0.69,-1.01 -0.15,-1.25 0.44,-0.23 1.02,-0.08 1.41,-0.45 0.26,-0.45 0.09,-0.98 0.14,-1.47 0.01,-0.76 -0.07,-1.63 0.43,-2.26 0.18,-0.21 0.42,-0.37 0.66,-0.51" id="path410" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(82,168)" id="g412">
<g id="g416">
<path d="M 0,0 H 24 V 24 H 0 z" id="path418" inkscape:connector-curvature="0" style="fill:none"/>
<path d="m 16,6 c -3.31,0 -6,2.69 -6,6 0,3.31 2.69,6 6,6 3.31,0 6,-2.69 6,-6 h -2 c 0,2.2091 -1.7909,4 -4,4 -2.2091,0 -4,-1.7909 -4,-4 0,-2.2091 1.7909,-4 4,-4 1.2756,0 2.3926,0.60127 3.125,1.5312 h 2.3438 C 20.52659,7.4496 18.4308,6 16,6 z" id="path420" inkscape:connector-curvature="0"/>
<path d="M 21.091,6.88 V 9.9718 H 17.9992 z" id="path422" inkscape:connector-curvature="0" style="stroke:#000000;stroke-width:1.06799996"/>
</g>
</g>
<g transform="translate(110,168)" id="g424">
<path transform="translate(8,4)" d="M 2.5858,13.891 C 0.9959,12.4291 0,10.3315 0,8.0002 c 0,-4.42 3.58,-8 8,-8 4.42,0 8,3.58 8,8 0,4.42 -3.58,8 -8,8 v -1.6 c 3.528,0 6.4,-2.872 6.4,-6.4 0,-3.528 -2.872,-6.4 -6.4,-6.4 -3.528,0 -6.4,2.872 -6.4,6.4 0,1.9357 0.86461,3.674 2.2278,4.8487 l 1.6925,-1.4201 0.015145,4.463 -4.3925,-0.7899 1.443,-1.2108 z M 6.5066,11.4287 11.078,8.0001 6.5066,4.5715 v 6.8571 z" id="path428" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(138,168)" id="g430">
<path transform="translate(0,-72)" d="M 23,84 15,79 V 89" id="path434" inkscape:connector-curvature="0"/>
<path transform="translate(0,-72)" d="M 13,89 H 10 V 79 h 3 v 10 z" id="path436" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(166,0)" id="g438">
<path transform="translate(-160,-120)" d="m 169.2,130.15 c 0.0551,-0.1128 0.15339,-0.22 0.2313,-0.3064 0.54584,-0.6074 1.3889,-1.1974 3.0053,-1.5702 v -2.1715 c -1.2931,0.2523 -2.3146,0.6686 -3.304,1.5597 -0.33248,0.3832 -0.50543,0.6247 -0.514,1.1665 -0.007,0.443 0.17732,0.8863 0.58141,1.3219 z m 6.6309,3.1292 c -1.6164,-0.024 -3.1091,-0.2558 -4.6228,-0.764 -2.6938,-0.9037 -3.0286,-2.1697 -3.1703,-2.5931 -0.0958,1.6897 0.028,2.9573 0.0346,3.0648 0.092,1.5004 1.2918,2.6742 2.1575,3.1151 1.7796,0.9067 3.6614,1.3756 5.601,1.4151 v 2.4842 l 3.251,-4.6483 -3.251,-4.6486 v 2.5748 z m -0.32327,-5.2959 c 1.6164,0.01 3.4529,0.3384 5.2454,1.1131 0.73528,0.3177 1.3275,0.7904 1.8082,1.3048 0.33152,-0.1523 0.80672,-0.7308 0.74126,-1.2923 -0.16163,-1.3879 -1.6264,-2.1912 -1.8801,-2.3045 -1.7704,-0.7908 -3.9751,-1.0356 -5.9147,-1.0589 v -1.7442 l -2.0132,2.8787 2.0132,2.8783 v -1.775 z m 8.4236,1.8658 c -0.0824,0.6478 -0.82676,2.0349 -3.8978,2.9138 v 4.5247 c 1.1314,-0.3677 2.465,-1.2956 3.1787,-2.1988 0.2911,-0.3677 0.46906,-0.875 0.57736,-1.242 0.33216,-1.1229 0.18604,-3.3136 0.14175,-3.9977 z" id="path442" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(166,24)" id="g444">
<path transform="translate(8,4)" d="m 10.624,2.47 c 1.9155,0.90417 3.2862,2.7533 3.4971,4.9467 h 0.87866 C 14.70102,3.8234 11.68426,1 7.99976,1 L 7.61315,1.0175 9.84495,3.24 10.62403,2.47 z M 6.9629,2.02083 c -0.34561,-0.34417 -0.90209,-0.34417 -1.2418,0 l -3.7255,3.71 c -0.34561,0.34417 -0.34561,0.89833 0,1.2367 l 7.041,7.0117 c 0.34561,0.34417 0.90209,0.34417 1.2418,0 l 3.7255,-3.71 c 0.34561,-0.34417 0.34561,-0.89833 0,-1.2367 l -7.041,-7.0117 z m 2.6946,11.34 -7.041,-7.0117 3.7255,-3.71 7.041,7.0117 -3.7255,3.71 z M 5.3755,13.53 C 3.46,12.63167 2.0893,10.7767 1.8784,8.5833 H 0.99974 C 1.29848,12.1766 4.31524,15 7.99974,15 L 8.38635,14.9825 6.15455,12.76 5.37547,13.53 z" id="path448" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(166,48)" id="g450">
<path transform="translate(-288,-72)" d="m 293.96,74.013 h 20 v 20 h -20 z" id="path454" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-288,-72)" d="m 297,77 h 18 v 18 h -18 z" id="path456" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-288,-72)" d="m 295.25,75.25 h 20 v 20 h -20 z" id="path458" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-288,-72)" d="m 293.12,73.125 h 20 v 20 h -20 z" id="path460" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-288,-72)" d="m 288,72 h 24 v 24 h -24 z" id="path462" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(-288,-72)" d="m 309.35,84.686 c 0.0288,-0.224 0.0504,-0.448 0.0504,-0.686 0,-0.238 -0.0216,-0.462 -0.0504,-0.686 l 1.5184,-1.155 c 0.13673,-0.105 0.17272,-0.294 0.0863,-0.448 l -1.4393,-2.422 c -0.0863,-0.154 -0.28065,-0.21 -0.43897,-0.154 l -1.7919,0.7 c -0.37422,-0.28 -0.77722,-0.511 -1.2162,-0.686 l -0.27341,-1.855 C 305.77334,77.126 305.62223,77 305.44232,77 h -2.8785 c -0.17992,0 -0.33104,0.126 -0.35263,0.294 l -0.27346,1.855 c -0.43898,0.175 -0.84198,0.413 -1.2162,0.686 l -1.7919,-0.7 c -0.16551,-0.063 -0.35262,0 -0.43898,0.154 l -1.4393,2.422 c -0.0935,0.154 -0.0504,0.343 0.0863,0.448 l 1.5184,1.155 c -0.0287,0.224 -0.0504,0.455 -0.0504,0.686 0,0.231 0.0216,0.462 0.0504,0.686 l -1.5184,1.155 c -0.13673,0.105 -0.17271,0.294 -0.0863,0.448 l 1.4393,2.422 c 0.0863,0.154 0.28067,0.21 0.43898,0.154 l 1.7919,-0.7 c 0.37421,0.28 0.77721,0.511 1.2162,0.686 l 0.27346,1.855 c 0.0216,0.168 0.17271,0.294 0.35263,0.294 h 2.8785 c 0.17991,0 0.33103,-0.126 0.35263,-0.294 l 0.27345,-1.855 c 0.43898,-0.175 0.84198,-0.413 1.2162,-0.686 l 1.7919,0.7 c 0.16552,0.063 0.35263,0 0.43898,-0.154 l 1.4393,-2.422 c 0.0863,-0.154 0.0504,-0.343 -0.0863,-0.448 l -1.5184,-1.155 z m -5.3469,1.764 c -1.3889,0 -2.5187,-1.099 -2.5187,-2.45 0,-1.351 1.1298,-2.45 2.5187,-2.45 1.3889,0 2.5187,1.099 2.5187,2.45 0,1.351 -1.1298,2.45 -2.5187,2.45 z" id="path464" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(162,73)" id="g466">
<path transform="matrix(0,-1,1,0,-136,251)" d="m 232.5,150.5 h 14 v 12 h -14 z" id="path470" inkscape:connector-curvature="0" style="fill:none;stroke:#000000"/>
<path transform="matrix(0,-1,1,0,-136,251)" d="m 244,156.5 -5,-3.25 v 6.5" id="path472" inkscape:connector-curvature="0"/>
<path transform="matrix(0,-1,1,0,-136,251)" d="m 236,150 h 1 v 13 h -1 z" id="path474" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(166,96)" id="g476">
<path transform="translate(-160,-72)" d="m 168.5,78.5 h 14 v 12 h -14 z" id="path480" inkscape:connector-curvature="0" style="fill:none;stroke:#000000"/>
<path transform="translate(-160,-72)" d="m 180,84.5 -5,-3.25 v 6.5" id="path482" inkscape:connector-curvature="0"/>
<path transform="translate(-160,-72)" d="m 172,78 h 1 v 13 h -1 z" id="path484" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(166,120)" id="g486">
<path transform="matrix(-1,0,0,1,-192,-96)" d="m -214.5,102.5 h 14 v 12 h -14 z" id="path490" inkscape:connector-curvature="0" style="fill:none;stroke:#000000"/>
<path transform="translate(-192,-96)" d="m 203,108.5 5,-3.25 v 6.5" id="path492" inkscape:connector-curvature="0"/>
<path transform="matrix(-1,0,0,1,-192,-96)" d="m -211,102 h 1 v 13 h -1 z" id="path494" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(162,145)" id="g496">
<path transform="matrix(0,1,1,0,-88,219)" d="m -214.5,102.5 h 14 v 12 h -14 z" id="path500" inkscape:connector-curvature="0" style="fill:none;stroke:#000000"/>
<path transform="matrix(0,-1,1,0,-88,219)" d="m 203,108.5 5,-3.25 v 6.5" id="path502" inkscape:connector-curvature="0"/>
<path transform="matrix(0,1,1,0,-88,219)" d="m -211,102 h 1 v 13 h -1 z" id="path504" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(166,168)" id="g506">
<path transform="translate(-288,0)" d="m 298,12 c 0,3.31 2.69,6 6,6 3.31,0 6,-2.69 6,-6 0,-3.31 -2.69,-6 -6,-6 -3.31,0 -6,2.69 -6,6" id="path510" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(-2,192)" id="g512">
<path transform="translate(-64,-72)" d="m 78.5,89 c 0,1.1 0.9,2 2,2 1.1,0 2,-0.9 2,-2 0,-1.1 -0.9,-2 -2,-2 -1.1,0 -2,0.9 -2,2" id="path516" inkscape:connector-curvature="0"/>
<path transform="translate(-64,-72)" d="m 79,78 v 4 h -3 l 4.5,4 4.5,-4 h -3 v -4 h -3 z" id="path518" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(26,192)" id="g520">
<path transform="translate(-96,-72)" d="m 110.5,89 c 0,1.1 0.9,2 2,2 1.1,0 2,-0.9 2,-2 0,-1.1 -0.9,-2 -2,-2 -1.1,0 -2,0.9 -2,2" id="path524" inkscape:connector-curvature="0"/>
<path transform="translate(-96,-72)" d="m 112.5,78 -4.5,4 h 3 v 4 h 3 v -4 h 3 l -4.5,-4 z" id="path526" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(54,192)" id="g528">
<path transform="translate(-128,-72)" d="m 142,86.5 c 0,1.1 0.9,2 2,2 1.1,0 2,-0.9 2,-2 0,-1.1 -0.9,-2 -2,-2 -1.1,0 -2,0.9 -2,2" id="path532" inkscape:connector-curvature="0"/>
<path transform="translate(-128,-72)" d="m 137.25,87.03 c 2.55,-8.43 11.4,-8.73 13.94,0" id="path534" inkscape:connector-curvature="0" style="fill:none;stroke:#000000;stroke-width:2.5"/>
<path transform="translate(-128,-72)" d="m 151.68,89 -4.54,-2.76 6.68,-2.1" id="path536" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(82,192)" id="g538">
<path transform="translate(-288,-24)" d="m 295,36 c 0,4.97 4.03,9 9,9 4.97,0 9,-4.03 9,-9 0,-4.97 -4.03,-9 -9,-9 -4.97,0 -9,4.03 -9,9" id="path542" inkscape:connector-curvature="0" style="fill:url(#sprite60_a)"/>
<path transform="translate(-288,-24)" d="m 298,36 c 0,3.31 2.69,6 6,6 3.31,0 6,-2.69 6,-6 0,-3.31 -2.69,-6 -6,-6 -3.31,0 -6,2.69 -6,6" id="path544" inkscape:connector-curvature="0"/>
<defs id="defs546">
<radialGradient id="sprite60_b" cx="0" cy="0" r="1" gradientTransform="matrix(18,0,0,-18,680,341)" gradientUnits="userSpaceOnUse">
<stop offset="0" id="stop549"/>
<stop stop-opacity="0" offset="1" id="stop551"/>
</radialGradient>
<radialGradient id="sprite60_a" cx="0" cy="0" r="1" gradientTransform="matrix(9,0,0,9,304,36)" gradientUnits="userSpaceOnUse" xlink:href="#sprite60_b"/>
</defs>
</g>
<g transform="translate(110,192)" id="g554">
<g id="g558">
<path transform="translate(7,3)" d="M 0,0 H 18 V 18 H 0 z" id="path560" inkscape:connector-curvature="0" style="fill:none"/>
<path transform="translate(7,3)" d="M 15.25,8 H 16 V 6.125 5 H 5 V 6.125 8 h 0.75 c 0,-0.82843 0.67157,-1.5 1.5,-1.5 h 2.5 v 7.25 c 0,0.82843 -0.67157,1.5 -1.5,1.5 V 16 h 1.875 0.75 1.875 v -0.75 c -0.82843,0 -1.5,-0.67157 -1.5,-1.5 V 6.5 h 2.5 c 0.82843,0 1.5,0.67157 1.5,1.5 z" id="path562" inkscape:connector-curvature="0" style="fill-opacity:0.36000001"/>
<path transform="translate(7,3)" d="M 12.25,5 H 13 V 3.125 2 H 2 V 3.125 5 h 0.75 c 0,-0.82843 0.67157,-1.5 1.5,-1.5 h 2.5 v 7.25 c 0,0.82843 -0.67157,1.5 -1.5,1.5 V 13 h 1.875 0.75 1.875 v -0.75 c -0.82843,0 -1.5,-0.67157 -1.5,-1.5 V 3.5 h 2.5 c 0.82843,0 1.5,0.67157 1.5,1.5 z" id="path564" inkscape:connector-curvature="0"/>
</g>
</g>
<g transform="translate(138,192)" id="g566">
<path transform="translate(-128,-24)" d="m 139.5,33 h 9 L 147,43 h -6" id="path570" inkscape:connector-curvature="0"/>
<path transform="translate(-128,-24)" d="m 147.5,30 h -2 v -1 h -3 v 1 h -2 c -0.55,0 -1,0.48 -1,1 v 1 h 1 7 1 v -1 c 0,-0.52 -0.45,-1 -1,-1" id="path572" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(168,192)" id="g574">
<path transform="translate(0,-48)" d="M 10,57 H 8 v 9 h 11 v -2 h -9 z" id="path578" inkscape:connector-curvature="0"/>
<path transform="translate(0,-48)" d="m 13,56 h 7 v 5 h -7 z m -2,-2 v 9 h 11 v -9 z" id="path580" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(194,0)" id="g582">
<path transform="translate(-96,0)" d="m 112,6.6909 c -3.6364,0 -6.7418,2.2618 -8,5.4545 1.2582,3.1927 4.3636,5.4545 8,5.4545 3.6364,0 6.7418,-2.2618 8,-5.4545 -1.2582,-3.1927 -4.3636,-5.4545 -8,-5.4545 z m 0,9.0909 c -2.0073,0 -3.6364,-1.6291 -3.6364,-3.6364 0,-2.0073 1.6291,-3.6364 3.6364,-3.6364 2.0073,0 3.6364,1.6291 3.6364,3.6364 0,2.0073 -1.6291,3.6364 -3.6364,3.6364 z m 0,-5.8182 c -1.2073,0 -2.1818,0.97455 -2.1818,2.1818 0,1.2073 0.97455,2.1818 2.1818,2.1818 1.2073,0 2.1818,-0.97455 2.1818,-2.1818 0,-1.2073 -0.97455,-2.1818 -2.1818,-2.1818 z" id="path586" inkscape:connector-curvature="0"/>
</g>
<g transform="translate(194,24)" id="g588">
<path transform="translate(-128,-48)" d="m 153,57 h -11 v -2 h 11 v 2 z" id="path592" inkscape:connector-curvature="0" style="opacity:0.2"/>
<path transform="translate(-128,-48)" d="m 142,57 h -6 v -2 h 6 v 2 z" id="path594" inkscape:connector-curvature="0"/>
<path transform="translate(-128,-48)" d="m 145,60 h -6 v -2 h 6 v 2 z" id="path596" inkscape:connector-curvature="0"/>
<path transform="translate(-128,-48)" d="m 150,63 h -6 v -2 h 6 v 2 z" id="path598" inkscape:connector-curvature="0"/>
<path transform="translate(-128,-48)" d="m 152,66 h -6 v -2 h 6 v 2 z" id="path600" inkscape:connector-curvature="0"/>
</g>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="12.355932" y="231.55931" id="text4355"><tspan sodipodi:role="line" id="tspan4357" x="12.355932" y="231.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">a</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="40.355934" y="231.55931" id="text4355-3"><tspan sodipodi:role="line" id="tspan4357-6" x="40.355934" y="231.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">b</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="68.355934" y="231.55931" id="text4355-7"><tspan sodipodi:role="line" id="tspan4357-5" x="68.355934" y="231.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">c</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="96.355934" y="231.55931" id="text4355-35"><tspan sodipodi:role="line" id="tspan4357-62" x="96.355934" y="231.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">d</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="124.35593" y="231.55931" id="text4355-9"><tspan sodipodi:role="line" id="tspan4357-1" x="124.35593" y="231.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">e</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="152.35593" y="231.55931" id="text4355-2"><tspan sodipodi:role="line" id="tspan4357-7" x="152.35593" y="231.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">f</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="180.35593" y="231.55931" id="text4355-0"><tspan sodipodi:role="line" id="tspan4357-9" x="180.35593" y="231.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">g</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="208.35593" y="231.55931" id="text4355-36"><tspan sodipodi:role="line" id="tspan4357-0" x="208.35593" y="231.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">h</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="-15.644068" y="207.55931" id="text4355-6"><tspan sodipodi:role="line" id="tspan4357-2" x="-15.644068" y="207.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">1</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="-15.644068" y="183.55931" id="text4355-61"><tspan sodipodi:role="line" id="tspan4357-8" x="-15.644068" y="183.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">2</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="-15.644068" y="159.55931" id="text4355-79"><tspan sodipodi:role="line" id="tspan4357-20" x="-15.644068" y="159.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">3</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="-15.644068" y="135.55931" id="text4355-23"><tspan sodipodi:role="line" id="tspan4357-75" x="-15.644068" y="135.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">4</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="-15.644068" y="111.55931" id="text4355-92"><tspan sodipodi:role="line" id="tspan4357-28" x="-15.644068" y="111.55931" style="font-size:12px;line-height:1.25;font-family:sans-serif">5</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="-15.644068" y="87.559311" id="text4355-97"><tspan sodipodi:role="line" id="tspan4357-3" x="-15.644068" y="87.559311" style="font-size:12px;line-height:1.25;font-family:sans-serif">6</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="-15.644068" y="63.559311" id="text4355-612"><tspan sodipodi:role="line" id="tspan4357-93" x="-15.644068" y="63.559311" style="font-size:12px;line-height:1.25;font-family:sans-serif">7</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="-15.644068" y="39.559311" id="text4355-1"><tspan sodipodi:role="line" id="tspan4357-94" x="-15.644068" y="39.559311" style="font-size:12px;line-height:1.25;font-family:sans-serif">8</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none" x="-15.644068" y="15.559311" id="text4355-78"><tspan sodipodi:role="line" id="tspan4357-4" x="-15.644068" y="15.559311" style="font-size:12px;line-height:1.25;font-family:sans-serif">9</tspan></text>
<g id="Page-1-6" style="fill:none;stroke:none" transform="translate(200,50)">
<g id="undo">
<rect height="20" width="20" y="0" x="0" id="bounds" style="fill:#ffffff;fill-opacity:0"/>
<path id="shape" d="M 4.3431457,9.3431458 C 5.790861,7.8954305 7.790861,7 10,7 c 3.555275,0 6.568879,2.3191676 7.610506,5.527197 L 16.155367,13 15.658589,13 C 14.834916,10.669615 12.612438,9 10,9 8.3431458,9 6.8431457,9.6715729 5.7573593,10.757359 L 8,13 2,13 2,7 l 2.3431457,2.3431458 0,0 z" inkscape:connector-curvature="0" style="fill:#000000"/>
</g>
</g>
<path style="fill:#000000" sodipodi:nodetypes="ccccccccccccc" inkscape:connector-curvature="0" d="m 215,82 -3,0 0,-4 -4,0 0,4 -3,0 5,6 z m -10,7 0,1 10,0 0,-1 z" id="path4295"/>
<path style="fill:none" inkscape:connector-curvature="0" d="m 196,72 h 24 v 24 h -24 z" id="path4297"/>
<path style="fill:#000000" d="m 210,102 -5,6 3,0 0,4 4,0 0,-4 3,0 z m -5,11 0,1 10,0 0,-1 z" id="path4295-3" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
<rect style="fill:#000000;" id="square-icon" width="8" height="8" x="206" y="176"/>
<g style="fill:#000000" id="g4456" transform="matrix(0.78548728,0,0,0.78548728,200.6822,123.63151)">
<path id="path4442" d="M 15.5,14 H 14.71 L 14.43,13.73 C 15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3 5.91,3 3,5.91 3,9.5 3,13.09 5.91,16 9.5,16 c 1.61,0 3.09,-0.59 4.23,-1.57 L 14,14.71 v 0.79 l 5,4.99 1.49,-1.49 z m -6,0 C 7.01,14 5,11.99 5,9.5 5,7.01 7.01,5 9.5,5 11.99,5 14,7.01 14,9.5 14,11.99 11.99,14 9.5,14 Z" inkscape:connector-curvature="0"/>
<path id="path4444" d="M 0,0 H 24 V 24 H 0 Z" inkscape:connector-curvature="0" style="fill:none"/>
</g>
<path inkscape:connector-curvature="0" id="path524-5" d="m 211.71941,203.4233 c 0,1.1 0.9,2 2,2 1.1,0 2,-0.9 2,-2 0,-1.1 -0.9,-2 -2,-2 -1.1,0 -2,0.9 -2,2"/>
<g transform="translate(190.16772,189.5042)" id="g520-3">
<path d="m 20.83228,13.9958 -4,-4.5 v 3 h -4 v 3 h 4 v 3 z" id="path526-7" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -36,3 +36,44 @@
.contractFunction { .contractFunction {
margin-bottom: 0px; margin-bottom: 0px;
} }
.debugButton {
width: 28px;
height: 24px;
}
.jumpBack {
background-position: 0px 48px;
background-image: url(images/icons.png);
}
.jumpForward {
background-position: -28px 48px;
background-image: url(images/icons.png);
}
.stepOverBack {
transform: scaleX(-1);
background-position: -56px 24px;
background-image: url(images/icons.png);
}
.stepOverForward {
background-position: -56px 24px;
background-image: url(images/icons.png);
}
.stepIntoForward {
background-position: 0px 24px;
background-image: url(images/icons.png);
}
.stepIntoBack {
background-position: -28px 24px;
background-image: url(images/icons.png);
}
.no-underline {
text-decoration: none;
}

View File

@ -1,8 +1,8 @@
import {combineReducers} from 'redux'; import {combineReducers} from 'redux';
import {REQUEST, SUCCESS, FAILURE, CONTRACT_COMPILE, FILES, LOGOUT, AUTHENTICATE, import {REQUEST, SUCCESS, FAILURE, CONTRACT_COMPILE, FILES, LOGOUT, AUTHENTICATE,
FETCH_CREDENTIALS, UPDATE_BASE_ETHER, CHANGE_THEME, FETCH_THEME, EXPLORER_SEARCH, FETCH_CREDENTIALS, UPDATE_BASE_ETHER, CHANGE_THEME, FETCH_THEME, EXPLORER_SEARCH, DEBUGGER_INFO,
SIGN_MESSAGE, VERIFY_MESSAGE, TOGGLE_BREAKPOINT, SIGN_MESSAGE, VERIFY_MESSAGE, TOGGLE_BREAKPOINT,
UPDATE_DEPLOYMENT_PIPELINE, WEB3_CONNECT, WEB3_DEPLOY, WEB3_ESTIMAGE_GAS} from "../actions"; UPDATE_DEPLOYMENT_PIPELINE, WEB3_CONNECT, WEB3_DEPLOY, WEB3_ESTIMAGE_GAS, FETCH_EDITOR_TABS} from "../actions";
import {EMBARK_PROCESS_NAME, DARK_THEME, DEPLOYMENT_PIPELINES, DEFAULT_HOST} from '../constants'; import {EMBARK_PROCESS_NAME, DARK_THEME, DEPLOYMENT_PIPELINES, DEFAULT_HOST} from '../constants';
const BN_FACTOR = 10000; const BN_FACTOR = 10000;
@ -31,7 +31,6 @@ const entitiesDefaultState = {
ensRecords: [], ensRecords: [],
files: [], files: [],
gasOracleStats: [], gasOracleStats: [],
currentFiles: []
}; };
const sorter = { const sorter = {
@ -80,7 +79,7 @@ const sorter = {
if (a.name < b.name) return -1; if (a.name < b.name) return -1;
if (a.name > b.name) return 1; if (a.name > b.name) return 1;
return 0; return 0;
} },
}; };
const filtrer = { const filtrer = {
@ -313,7 +312,7 @@ function messageVerification(state = DEFAULT_MESSAGE_VERIFICATION_STATE, action)
} }
function breakpoints(state = {}, action) { function breakpoints(state = {}, action) {
if (action.type === TOGGLE_BREAKPOINT) { if (action.type === TOGGLE_BREAKPOINT[SUCCESS]) {
const {filename, lineNumber} = action.payload; const {filename, lineNumber} = action.payload;
let lineNumbers = state[filename] || []; let lineNumbers = state[filename] || [];
if (lineNumbers.includes(lineNumber)){ if (lineNumbers.includes(lineNumber)){
@ -347,6 +346,20 @@ function web3(state = {deployments: {}, gasEstimates: {}}, action) {
return state return state
} }
function debuggerInfo(state={}, action) {
if (action.type === DEBUGGER_INFO[SUCCESS]) {
return action.data;
}
return state;
}
function editorTabs(state = [], action) {
if (action.type === FETCH_EDITOR_TABS[SUCCESS] && action.editorTabs) {
return action.editorTabs;
}
return state;
}
const rootReducer = combineReducers({ const rootReducer = combineReducers({
entities, entities,
loading, loading,
@ -355,13 +368,15 @@ const rootReducer = combineReducers({
errorEntities, errorEntities,
credentials, credentials,
baseEther, baseEther,
theme,
searchResult, searchResult,
messageSignature, messageSignature,
messageVerification, messageVerification,
breakpoints, breakpoints,
deploymentPipeline, deploymentPipeline,
web3 web3,
debuggerInfo,
theme,
editorTabs
}); });
export default rootReducer; export default rootReducer;

View File

@ -170,7 +170,7 @@ export function getFiles(state) {
} }
export function getCurrentFile(state) { export function getCurrentFile(state) {
return last(state.entities.currentFiles); return state.editorTabs.find(file => file.active) || {};
} }
export function getBaseEther(state) { export function getBaseEther(state) {
@ -224,3 +224,16 @@ export function getWeb3GasEstimates(state) {
export function getWeb3Deployments(state) { export function getWeb3Deployments(state) {
return state.web3.deployments; return state.web3.deployments;
} }
export function debuggerInfo(state) {
return state.debuggerInfo;
}
export function getDebuggerLine(state) {
if (!state.debuggerInfo.sources) return 10;
return state.debuggerInfo.sources.lineColumnPos[0].start.line + 1;
}
export function getEditorTabs(state) {
return state.editorTabs
}

View File

@ -69,11 +69,16 @@ export const fetchFile = doRequest.bind(null, actions.file, api.fetchFile);
export const postFile = doRequest.bind(null, actions.saveFile, api.postFile); export const postFile = doRequest.bind(null, actions.saveFile, api.postFile);
export const deleteFile = doRequest.bind(null, actions.removeFile, api.deleteFile); export const deleteFile = doRequest.bind(null, actions.removeFile, api.deleteFile);
export const fetchEthGas = doRequest.bind(null, actions.gasOracle, api.getEthGasAPI); export const fetchEthGas = doRequest.bind(null, actions.gasOracle, api.getEthGasAPI);
export const startDebug = doRequest.bind(null, actions.startDebug, api.startDebug);
export const debugJumpBack = doRequest.bind(null, actions.debugJumpBack, api.debugJumpBack);
export const debugJumpForward = doRequest.bind(null, actions.debugJumpForward, api.debugJumpForward);
export const debugStepOverForward = doRequest.bind(null, actions.debugStepOverForward, api.debugStepOverForward);
export const debugStepOverBackward = doRequest.bind(null, actions.debugStepOverBackward, api.debugStepOverBackward);
export const debugStepIntoForward = doRequest.bind(null, actions.debugStepIntoForward, api.debugStepIntoForward);
export const debugStepIntoBackward = doRequest.bind(null, actions.debugStepIntoBackward, api.debugStepIntoBackward);
export const toggleBreakpoint = doRequest.bind(null, actions.toggleBreakpoint, api.toggleBreakpoint);
export const authenticate = doRequest.bind(null, actions.authenticate, api.authenticate); export const authenticate = doRequest.bind(null, actions.authenticate, api.authenticate);
export const fetchCurrentFile = doRequest.bind(null, actions.currentFile, storage.fetchCurrentFile);
export const postCurrentFile = doRequest.bind(null, actions.saveCurrentFile, storage.postCurrentFile);
export const deleteCurrentFile = doRequest.bind(null, null, storage.deleteCurrentFile);
export const fetchCredentials = doRequest.bind(null, actions.fetchCredentials, storage.fetchCredentials); export const fetchCredentials = doRequest.bind(null, actions.fetchCredentials, storage.fetchCredentials);
export const saveCredentials = doRequest.bind(null, actions.saveCredentials, storage.saveCredentials); export const saveCredentials = doRequest.bind(null, actions.saveCredentials, storage.saveCredentials);
export const logout = doRequest.bind(null, actions.logout, storage.logout); export const logout = doRequest.bind(null, actions.logout, storage.logout);
@ -81,6 +86,9 @@ export const changeTheme = doRequest.bind(null, actions.changeTheme, storage.cha
export const fetchTheme = doRequest.bind(null, actions.fetchTheme, storage.fetchTheme); export const fetchTheme = doRequest.bind(null, actions.fetchTheme, storage.fetchTheme);
export const signMessage = doRequest.bind(null, actions.signMessage, api.signMessage); export const signMessage = doRequest.bind(null, actions.signMessage, api.signMessage);
export const verifyMessage = doRequest.bind(null, actions.verifyMessage, api.verifyMessage); export const verifyMessage = doRequest.bind(null, actions.verifyMessage, api.verifyMessage);
export const fetchEditorTabs = doRequest.bind(null, actions.fetchEditorTabs, storage.fetchEditorTabs);
export const addEditorTabs = doRequest.bind(null, actions.addEditorTabs, storage.addEditorTabs);
export const removeEditorTabs = doRequest.bind(null, actions.removeEditorTabs, storage.removeEditorTabs);
export const explorerSearch = searchExplorer.bind(null, actions.explorerSearch); export const explorerSearch = searchExplorer.bind(null, actions.explorerSearch);
@ -200,31 +208,55 @@ export function *watchPostFile() {
yield takeEvery(actions.SAVE_FILE[actions.REQUEST], postFile); yield takeEvery(actions.SAVE_FILE[actions.REQUEST], postFile);
} }
export function *watchPostFileSuccess() {
yield takeEvery(actions.SAVE_FILE[actions.SUCCESS], postCurrentFile);
}
export function *watchDeleteFile() { export function *watchDeleteFile() {
yield takeEvery(actions.REMOVE_FILE[actions.REQUEST], deleteFile); yield takeEvery(actions.REMOVE_FILE[actions.REQUEST], deleteFile);
} }
export function *watchDeleteFileSuccess() { export function *watchDeleteFileSuccess() {
yield takeEvery(actions.REMOVE_FILE[actions.SUCCESS], fetchFiles); yield takeEvery(actions.REMOVE_FILE[actions.SUCCESS], fetchFiles);
yield takeEvery(actions.REMOVE_FILE[actions.SUCCESS], deleteCurrentFile); yield takeEvery(actions.REMOVE_FILE[actions.SUCCESS], removeEditorTabs);
} }
export function *watchFetchFileSuccess() { export function *watchFetchFileSuccess() {
yield takeEvery(actions.FILE[actions.SUCCESS], postCurrentFile); yield takeEvery(actions.FILE[actions.SUCCESS], addEditorTabs);
}
export function *watchFetchCurrentFile() {
yield takeEvery(actions.CURRENT_FILE[actions.REQUEST], fetchCurrentFile);
} }
export function *watchFetchEthGas() { export function *watchFetchEthGas() {
yield takeEvery(actions.GAS_ORACLE[actions.REQUEST], fetchEthGas); yield takeEvery(actions.GAS_ORACLE[actions.REQUEST], fetchEthGas);
} }
export function *watchStartDebug() {
yield takeEvery(actions.START_DEBUG[actions.REQUEST], startDebug);
}
export function *watchDebugJumpBack() {
yield takeEvery(actions.DEBUG_JUMP_BACK[actions.REQUEST], debugJumpBack);
}
export function *watchDebugJumpForward() {
yield takeEvery(actions.DEBUG_JUMP_FORWARD[actions.REQUEST], debugJumpForward);
}
export function *watchDebugStepOverForward() {
yield takeEvery(actions.DEBUG_STEP_OVER_FORWARD[actions.REQUEST], debugStepOverForward);
}
export function *watchDebugStepOverBackward() {
yield takeEvery(actions.DEBUG_STEP_OVER_BACKWARD[actions.REQUEST], debugStepOverBackward);
}
export function *watchDebugStepIntoForward() {
yield takeEvery(actions.DEBUG_STEP_INTO_FORWARD[actions.REQUEST], debugStepIntoForward);
}
export function *watchDebugStepIntoBackward() {
yield takeEvery(actions.DEBUG_STEP_INTO_BACKWARD[actions.REQUEST], debugStepIntoBackward);
}
export function *watchToggleBreakpoint() {
yield takeEvery(actions.TOGGLE_BREAKPOINT[actions.REQUEST], toggleBreakpoint);
}
export function *watchAuthenticate() { export function *watchAuthenticate() {
yield takeEvery(actions.AUTHENTICATE[actions.REQUEST], authenticate); yield takeEvery(actions.AUTHENTICATE[actions.REQUEST], authenticate);
} }
@ -273,6 +305,26 @@ export function *watchUpdateDeploymentPipeline() {
yield takeEvery(actions.UPDATE_DEPLOYMENT_PIPELINE, web3Connect); yield takeEvery(actions.UPDATE_DEPLOYMENT_PIPELINE, web3Connect);
} }
export function *watchFetchEditorTabs() {
yield takeEvery(actions.FETCH_EDITOR_TABS[actions.REQUEST], fetchEditorTabs);
}
export function *watchAddEditorTabs() {
yield takeEvery(actions.ADD_EDITOR_TABS[actions.REQUEST], addEditorTabs);
}
export function *watchRemoveEditorTabs() {
yield takeEvery(actions.REMOVE_EDITOR_TABS[actions.REQUEST], removeEditorTabs);
}
export function *watchAddEditorTabsSuccess() {
yield takeEvery(actions.ADD_EDITOR_TABS[actions.SUCCESS], fetchEditorTabs);
}
export function *watchRemoveEditorTabsSuccess() {
yield takeEvery(actions.REMOVE_EDITOR_TABS[actions.SUCCESS], fetchEditorTabs);
}
function createChannel(socket) { function createChannel(socket) {
return eventChannel(emit => { return eventChannel(emit => {
socket.onmessage = ((message) => { socket.onmessage = ((message) => {
@ -385,6 +437,28 @@ export function *watchListenGasOracle() {
yield takeEvery(actions.WATCH_GAS_ORACLE, listenGasOracle); yield takeEvery(actions.WATCH_GAS_ORACLE, listenGasOracle);
} }
export function *listenDebugger() {
const credentials = yield select(getCredentials);
const socket = api.listenToDebugger(credentials);
const channel = yield call(createChannel, socket);
while (true) {
const { cancel, debuggerInfo } = yield race({
debuggerInfo: take(channel),
cancel: take(actions.STOP_DEBUGGER)
});
if (cancel) {
channel.close();
return;
}
yield put(actions.debuggerInfo.success(debuggerInfo));
}
}
export function *watchListenDebugger() {
yield takeEvery(actions.START_DEBUG[actions.SUCCESS], listenDebugger);
}
export function *listenToMessages(action) { export function *listenToMessages(action) {
const credentials = yield select(getCredentials); const credentials = yield select(getCredentials);
const socket = api.listenToChannel(credentials, action.messageChannels[0]); const socket = api.listenToChannel(credentials, action.messageChannels[0]);
@ -432,10 +506,16 @@ export default function *root() {
fork(watchDeleteFile), fork(watchDeleteFile),
fork(watchDeleteFileSuccess), fork(watchDeleteFileSuccess),
fork(watchFetchFileSuccess), fork(watchFetchFileSuccess),
fork(watchFetchCurrentFile),
fork(watchPostFileSuccess),
fork(watchFetchCredentials), fork(watchFetchCredentials),
fork(watchFetchEthGas), fork(watchFetchEthGas),
fork(watchStartDebug),
fork(watchDebugJumpBack),
fork(watchDebugJumpForward),
fork(watchDebugStepOverForward),
fork(watchDebugStepOverBackward),
fork(watchDebugStepIntoForward),
fork(watchDebugStepIntoBackward),
fork(watchToggleBreakpoint),
fork(watchAuthenticate), fork(watchAuthenticate),
fork(watchAuthenticateSuccess), fork(watchAuthenticateSuccess),
fork(watchLogout), fork(watchLogout),
@ -447,6 +527,12 @@ export default function *root() {
fork(watchVerifyMessage), fork(watchVerifyMessage),
fork(watchWeb3EstimateGas), fork(watchWeb3EstimateGas),
fork(watchWeb3Deploy), fork(watchWeb3Deploy),
fork(watchUpdateDeploymentPipeline) fork(watchUpdateDeploymentPipeline),
fork(watchListenDebugger),
fork(watchFetchEditorTabs),
fork(watchAddEditorTabs),
fork(watchRemoveEditorTabs),
fork(watchAddEditorTabsSuccess),
fork(watchRemoveEditorTabsSuccess),
]); ]);
} }

View File

@ -185,6 +185,42 @@ export function verifyMessage(payload) {
return post('/messages/verify', ...arguments); return post('/messages/verify', ...arguments);
} }
export function startDebug(payload) {
return post('/debugger/start', {params: payload, credentials: payload.credentials});
}
export function debugJumpBack(payload) {
return post('/debugger/jumpBack', {params: payload, credentials: payload.credentials});
}
export function debugJumpForward(payload) {
return post('/debugger/jumpForward', {params: payload, credentials: payload.credentials});
}
export function debugStepOverForward(payload) {
return post('/debugger/stepOverForward', {params: payload, credentials: payload.credentials});
}
export function debugStepOverBackward(payload) {
return post('/debugger/stepOverBackward', {params: payload, credentials: payload.credentials});
}
export function debugStepIntoForward(payload) {
return post('/debugger/stepIntoForward', {params: payload, credentials: payload.credentials});
}
export function debugStepIntoBackward(payload) {
return post('/debugger/stepIntoBackward', {params: payload, credentials: payload.credentials});
}
export function toggleBreakpoint(payload) {
return post('/debugger/breakpoint', {params: payload, credentials: payload.credentials});
}
export function listenToDebugger(credentials) {
return new WebSocket(`ws://${credentials.host}/embark-api/debugger`, [credentials.token]);
}
export function listenToChannel(credentials, channel) { export function listenToChannel(credentials, channel) {
return new WebSocket(`ws://${credentials.host}/embark-api/communication/listenTo/${channel}`, [credentials.token]); return new WebSocket(`ws://${credentials.host}/embark-api/communication/listenTo/${channel}`, [credentials.token]);
} }

View File

@ -1,20 +1,34 @@
export function postCurrentFile(file) { export function addEditorTabs({file}) {
return new Promise(resolve => { return new Promise(resolve => {
localStorage.setItem('currentFile', JSON.stringify(file)); const editorTabs = findOrCreateEditorTabs();
resolve({response: {data: file}}); editorTabs.forEach(f => f.active = false);
const alreadyAddedFile = editorTabs.find(f => f.name === file.name)
if (alreadyAddedFile) {
alreadyAddedFile.active = true
} else {
file.active = true
editorTabs.push(file);
}
localStorage.setItem('editorTabs', JSON.stringify(editorTabs));
resolve({response: {data: editorTabs}});
}); });
} }
export function fetchCurrentFile() { export function fetchEditorTabs() {
return new Promise(resolve => { return new Promise(resolve => {
resolve({response: {data: JSON.parse(localStorage.getItem('currentFile'))}}); resolve({response: {data: JSON.parse(localStorage.getItem('editorTabs'))}});
}); });
} }
export function deleteCurrentFile() { export function removeEditorTabs({file}) {
return new Promise(resolve => { return new Promise(resolve => {
localStorage.removeItem('currentFile'); const editorTabs = findOrCreateEditorTabs();
resolve({}); const filtered = editorTabs.filter(value => value.name !== file.name);
if (file.active && filtered.length) {
filtered[0].active = true;
}
localStorage.setItem('editorTabs', JSON.stringify(filtered));
resolve({response: {data: filtered}});
}); });
} }
@ -50,3 +64,8 @@ export function changeTheme({theme}) {
export function fetchTheme() { export function fetchTheme() {
return new Promise(resolve => resolve({response: {data: localStorage.getItem('theme')}})); return new Promise(resolve => resolve({response: {data: localStorage.getItem('theme')}}));
} }
function findOrCreateEditorTabs() {
return JSON.parse(localStorage.getItem('editorTabs')) || [];
}

View File

@ -217,6 +217,7 @@ class Engine {
this.registerModule('console_listener', {ipc: self.ipc}); this.registerModule('console_listener', {ipc: self.ipc});
this.registerModule('deployment', {plugins: this.plugins, onlyCompile: options.onlyCompile}); this.registerModule('deployment', {plugins: this.plugins, onlyCompile: options.onlyCompile});
this.registerModule('transactionTracker'); this.registerModule('transactionTracker');
this.registerModule('debugger');
this.events.on('file-event', function ({fileType, path}) { this.events.on('file-event', function ({fileType, path}) {
clearTimeout(self.fileTimeout); clearTimeout(self.fileTimeout);

View File

@ -33,6 +33,10 @@ class BlockchainConnector {
cb(self); cb(self);
}); });
self.events.setCommandHandler("blockchain:getTransaction", (txHash, cb) => {
self.getTransactionByHash(txHash, cb);
});
embark.registerActionForEvent("contracts:deploy:afterAll", this.subscribeToContractEvents.bind(this)); embark.registerActionForEvent("contracts:deploy:afterAll", this.subscribeToContractEvents.bind(this));
if (!this.web3) { if (!this.web3) {
@ -580,7 +584,7 @@ class BlockchainConnector {
this.web3.eth.getBlock(blockNumber, true, cb); this.web3.eth.getBlock(blockNumber, true, cb);
} }
getTransaction(hash, cb) { getTransactionByHash(hash, cb) {
this.web3.eth.getTransaction(hash, cb); this.web3.eth.getTransaction(hash, cb);
} }
@ -595,6 +599,14 @@ class BlockchainConnector {
return this.web3.eth.net.getId(); return this.web3.eth.net.getId();
} }
//TODO: fix me, why is this gasPrice??
getTransaction(hash, cb) {
const self = this;
this.onReady(() => {
self.web3.eth.getGasPrice(cb);
});
}
ContractObject(params) { ContractObject(params) {
return new this.web3.eth.Contract(params.abi, params.address); return new this.web3.eth.Contract(params.abi, params.address);
} }

View File

@ -47,7 +47,7 @@ class Console {
} }
processEmbarkCmd (cmd) { processEmbarkCmd (cmd) {
if (cmd === 'help' || cmd === __('help')) { if (cmd === 'help' || cmd === __('help') || cmd === '01189998819991197253') {
let helpText = [ let helpText = [
__('Welcome to Embark') + ' ' + this.version, __('Welcome to Embark') + ' ' + this.version,
'', '',

View File

@ -101,6 +101,7 @@ class ConsoleListener {
this.events.emit('contracts:log', this.logs[this.logs.length - 1]); this.events.emit('contracts:log', this.logs[this.logs.length - 1]);
this.logger.info(`Blockchain>`.underline + ` ${name}.${functionName}(${paramString})`.bold + ` | ${transactionHash} | gas:${gasUsed} | blk:${blockNumber} | status:${status}`); this.logger.info(`Blockchain>`.underline + ` ${name}.${functionName}(${paramString})`.bold + ` | ${transactionHash} | gas:${gasUsed} | blk:${blockNumber} | status:${status}`);
this.events.emit('blockchain:tx', { name: name, functionName: functionName, paramString: paramString, transactionHash: transactionHash, gasUsed: gasUsed, blockNumber: blockNumber, status: status });
}); });
} }

View File

@ -36,6 +36,10 @@ class ContractsManager {
cb(self.getContract(contractName)); cb(self.getContract(contractName));
}); });
self.events.setCommandHandler("contracts:contract:byTxHash", (txHash, cb) => {
self.getContractByTxHash(txHash, cb)
});
self.events.setCommandHandler("contracts:build", (configOnly, cb) => { self.events.setCommandHandler("contracts:build", (configOnly, cb) => {
self.deployOnlyOnConfig = configOnly; // temporary, should refactor self.deployOnlyOnConfig = configOnly; // temporary, should refactor
self.build((err) => { self.build((err) => {
@ -490,6 +494,19 @@ class ContractsManager {
return this.contracts[className]; return this.contracts[className];
} }
getContractByTxHash(txHash, cb) {
this.events.request("blockchain:getTransaction", txHash, (err, tx) => {
if (err) return cb(err);
for (let contractName in this.contracts) {
let contract = this.contracts[contractName];
if (tx.to === contract.deployedAddress) {
return cb(null, contract);
}
}
cb("no known contract found for txHash: " + txHash);
});
}
sortContracts(contractList) { sortContracts(contractList) {
let converted_dependencies = [], i; let converted_dependencies = [], i;

View File

@ -0,0 +1,78 @@
var RemixDebug = require('remix-debug-debugtest');
var CmdLine = RemixDebug.CmdLine;
const async = require('async');
class DebuggerManager {
constructor(nodeUrl) {
this.nodeUrl = nodeUrl
this.outputJson = {}
this.inputJson = {}
}
setInputJson(inputJson) {
this.inputJson = inputJson
}
setOutputJson(outputJson) {
this.outputJson = outputJson
}
createDebuggerSession(txHash, filename, cb) {
return this.debug(txHash, filename, cb)
}
debug(txHash, filename, cb) {
console.dir("debugging tx " + txHash)
var cmd_line = new CmdLine()
this.cmd_line = cmd_line
cmd_line.connect("http", this.nodeUrl)
cmd_line.loadCompilationData(this.inputJson, this.outputJson)
cmd_line.initDebugger(() => {
this.isDebugging = true
cmd_line.startDebug(txHash, filename, () => {
if (cb) {
cmd_line.triggerSourceUpdate()
cb()
}
})
})
return cmd_line
}
getLastLine(txHash, filename, outputCb) {
const self = this;
let cmd_line = new CmdLine()
async.waterfall([
function initDebugger(next) {
cmd_line = new CmdLine()
cmd_line.connect("http", self.nodeUrl)
cmd_line.loadCompilationData(self.inputJson, self.outputJson)
cmd_line.initDebugger(() => {
// self.isDebugging = true
next()
})
},
function startDebug(next) {
cmd_line.startDebug(txHash, filename, () => {
cmd_line.events.on("source", () => {
outputCb(cmd_line.getSource())
})
let total_size = cmd_line.getTraceLength()
cmd_line.jumpTo(total_size - 1)
cmd_line.unload()
next()
})
}
], () => {
})
}
}
module.exports = DebuggerManager;

View File

@ -0,0 +1,212 @@
var RemixDebug = require('remix-debug-debugtest');
var CmdLine = RemixDebug.CmdLine;
var DebuggerManager = require('./debugger_manager.js');
class TransactionDebugger {
constructor(embark, _options) {
const self = this
this.embark = embark
this.debugger_manager = new DebuggerManager("http://localhost:8545")
embark.events.on('contracts:compile:solc', this.debugger_manager.setInputJson.bind(this.debugger_manager))
embark.events.on('contracts:compiled:solc', this.debugger_manager.setOutputJson.bind(this.debugger_manager))
this.tx_tracker = {}
this.last_tx = ""
this.isDebugging = false
this.listenToEvents()
this.listenToCommands()
this.listentoAPI()
}
listenToEvents() {
const self = this
this.embark.events.on('blockchain:tx', (tx) => {
this.embark.events.request("contracts:contract", tx.name, (contract) => {
self.tx_tracker[tx.transactionHash] = {tx: tx, contract: contract}
self.last_tx = tx.transactionHash
if (tx.status !== '0x0') return
self.embark.logger.info("Transaction failed");
self.debugger_manager.getLastLine(tx.transactionHash, contract.filename, (lines) => {
lines.forEach((line) => {
self.embark.logger.error(line)
})
})
})
})
}
listentoAPI() {
this.debuggerData = {}
this.apiDebugger = false
this.embark.registerAPICall('post', '/embark-api/debugger/start', (req, res) => {
let txHash = req.body.params.txHash
this.embark.events.request("contracts:contract:byTxHash", txHash, (err, contract) => {
if (err) {
this.embark.logger.error(err);
return res.send({error: err})
}
let filename = contract.filename
this.debuggerData = {}
this.apiDebugger = this.debugger_manager.createDebuggerSession(txHash, filename, () => {
})
res.send({ok :true})
})
});
this.embark.registerAPICall('post', '/embark-api/debugger/JumpBack', (req, res) => {
this.apiDebugger.stepJumpNextBreakpoint()
res.send({ok :true})
})
this.embark.registerAPICall('post', '/embark-api/debugger/JumpForward', (req, res) => {
this.apiDebugger.stepJumpPreviousBreakpoint()
res.send({ok :true})
})
this.embark.registerAPICall('post', '/embark-api/debugger/StepOverForward', (req, res) => {
this.apiDebugger.stepOverForward(true)
res.send({ok :true})
})
this.embark.registerAPICall('post', '/embark-api/debugger/StepOverBackward', (req, res) => {
this.apiDebugger.stepOverBack(true)
res.send({ok :true})
})
this.embark.registerAPICall('post', '/embark-api/debugger/StepIntoForward', (req, res) => {
this.apiDebugger.stepIntoForward(true)
res.send({ok :true})
})
this.embark.registerAPICall('post', '/embark-api/debugger/StepIntoBackward', (req, res) => {
this.apiDebugger.stepIntoBack(true)
res.send({ok :true})
});
this.embark.registerAPICall('post', '/embark-api/debugger/breakpoint', (req, res) => {
console.dir("new breakpoint")
res.send({ok :true})
});
this.embark.registerAPICall('ws', '/embark-api/debugger', (ws, _req) => {
if (!this.apiDebugger) return
this.apiDebugger.events.on("source", (lineColumnPos, rawLocation) => {
this.debuggerData.sources = {lineColumnPos, rawLocation}
ws.send(JSON.stringify(this.debuggerData), () => {})
})
this.apiDebugger.events.on("locals", (data) => {
this.debuggerData.locals = this.simplifyDebuggerVars(data)
ws.send(JSON.stringify(this.debuggerData), () => {})
})
this.apiDebugger.events.on("globals", (data) => {
this.debuggerData.globals = this.simplifyDebuggerVars(data)
ws.send(JSON.stringify(this.debuggerData), () => {})
})
});
}
simplifyDebuggerVars(data) {
let new_data = {};
for (let key in data) {
let field = data[key];
new_data[`${key} (${field.type})`] = field.value
}
return new_data
}
listenToCommands() {
const self = this
this.cmdDebugger = false
this.embark.registerConsoleCommand((cmd, _options) => {
let cmdName = cmd.split(" ")[0]
let txHash = cmd.split(" ")[1]
return {
match: () => cmdName === 'debug',
process: (cb) => {
if (txHash) {
this.embark.events.request("contracts:contract:byTxHash", txHash, (err, contract) => {
if (err) {
this.embark.logger.error(err);
return;
}
let filename = contract.filename
self.cmdDebugger = self.debugger_manager.createDebuggerSession(txHash, filename, () => {
self.cmdDebugger.getSource().forEach((line) => {
console.dir(line)
})
})
});
return
}
let filename = self.tx_tracker[self.last_tx].contract.filename
self.cmdDebugger = self.debugger_manager.createDebuggerSession(self.last_tx, filename, () => {
self.cmdDebugger.getSource().forEach((line) => {
console.dir(line)
})
})
}
};
})
this.embark.registerConsoleCommand((cmd, _options) => {
return {
match: () => (cmd === 'next' || cmd === 'n'),
process: (cb) => {
if (!self.cmdDebugger.currentStep()) {
console.dir("end of execution reached")
return self.cmdDebugger.unload()
}
self.cmdDebugger.stepOverForward(true)
self.cmdDebugger.getSource().forEach((line) => {
console.dir(line)
})
}
};
})
this.embark.registerConsoleCommand((cmd, _options) => {
return {
match: () => (cmd === 'previous' || cmd === 'p'),
process: (cb) => {
if (!self.cmdDebugger.currentStep()) {
console.dir("end of execution reached")
return self.cmdDebugger.unload()
}
self.cmdDebugger.stepOverBack(true)
self.cmdDebugger.getSource().forEach((line) => {
console.dir(line)
})
}
};
})
this.embark.registerConsoleCommand((cmd, _options) => {
return {
match: () => (cmd === 'var local' || cmd === 'v l' || cmd === 'vl'),
process: (cb) => {
self.cmdDebugger.displayLocals()
}
};
})
this.embark.registerConsoleCommand((cmd, _options) => {
return {
match: () => (cmd === 'var global' || cmd === 'v g' || cmd === 'vg'),
process: (cb) => {
self.cmdDebugger.displayGlobals()
}
};
})
}
}
module.exports = TransactionDebugger

View File

@ -88,7 +88,7 @@ class Solidity {
}, },
outputSelection: { outputSelection: {
'*': { '*': {
'': ['ast'], '': ['ast', 'legacyAST'], // legacyAST is needed by the debugger, for now
'*': [ '*': [
'abi', 'abi',
'devdoc', 'devdoc',

23439
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -115,6 +115,7 @@
"swarm-api": "0.1.2", "swarm-api": "0.1.2",
"tar": "3.2.1", "tar": "3.2.1",
"toposort": "1.0.7", "toposort": "1.0.7",
"remix-debug-debugtest": "latest",
"underscore": "1.9.1", "underscore": "1.9.1",
"url-loader": "1.1.1", "url-loader": "1.1.1",
"uuid": "3.3.2", "uuid": "3.3.2",

BIN
test_apps/.DS_Store vendored Normal file

Binary file not shown.

5
test_apps/embark_demo/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.embark/
node_modules/
dist/
config/production/password
config/livenet/password

View File

@ -0,0 +1,87 @@
import EmbarkJS from 'Embark/EmbarkJS';
import SimpleStorage from 'Embark/contracts/SimpleStorage';
import React from 'react';
import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap';
class Blockchain extends React.Component {
constructor(props) {
super(props);
this.state = {
valueSet: 10,
valueGet: "",
logs: []
}
}
handleChange(e) {
this.setState({ valueSet: e.target.value });
}
checkEnter(e, func) {
if (e.key !== 'Enter') {
return;
}
e.preventDefault();
func.apply(this, [e]);
}
setValue(e) {
e.preventDefault();
var value = parseInt(this.state.valueSet, 10);
SimpleStorage.methods.set(value).send();
this._addToLog("SimpleStorage.methods.set(value).send()");
}
getValue(e) {
e.preventDefault();
SimpleStorage.methods.get().call().then(_value => this.setState({ valueGet: _value }));
this._addToLog("SimpleStorage.methods.get(console.log)");
}
_addToLog(txt) {
this.state.logs.push(txt);
this.setState({ logs: this.state.logs });
}
render() {
return (<React.Fragment>
<h3> 1. Set the value in the blockchain</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.setValue)}>
<FormGroup>
<FormControl
type="text"
defaultValue={this.state.valueSet}
onChange={(e) => this.handleChange(e)}/>
<Button bsStyle="primary" onClick={(e) => this.setValue(e)}>Set Value</Button>
<HelpBlock>Once you set the value, the transaction will need to be mined and then the value will be updated
on the blockchain.</HelpBlock>
</FormGroup>
</Form>
<h3> 2. Get the current value</h3>
<Form inline>
<FormGroup>
<HelpBlock>current value is <span className="value">{this.state.valueGet}</span></HelpBlock>
<Button bsStyle="primary" onClick={(e) => this.getValue(e)}>Get Value</Button>
<HelpBlock>Click the button to get the current value. The initial value is 100.</HelpBlock>
</FormGroup>
</Form>
<h3> 3. Contract Calls </h3>
<p>Javascript calls being made: </p>
<div className="logs">
{
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
}
</div>
</React.Fragment>
);
}
}
export default Blockchain;

View File

@ -0,0 +1,180 @@
/*global web3*/
import EmbarkJS from 'Embark/EmbarkJS';
import React from 'react';
import { Alert, Form, FormGroup, FormControl, Button } from 'react-bootstrap';
window.EmbarkJS = EmbarkJS;
class ENS extends React.Component {
constructor(props) {
super(props);
this.state = {
valueResolve: 'eth',
responseResolve: null,
isResolveError: false,
valueLookup: '',
responseLookup: null,
isLookupError: false,
valueRegister: '',
addressRegister: '',
responseRegister: null,
isRegisterError: false,
embarkLogs: []
};
}
componentDidMount() {
EmbarkJS.onReady(() => {
if (!web3.eth.defaultAccount) {
this.setState({
globalError: 'There is currently no default account. If Metamask is active, please sign in or deactivate it.'
});
}
this.setState({
addressRegister: web3.eth.defaultAccount,
valueLookup: web3.eth.defaultAccount
})
});
}
handleChange(stateName, e) {
this.setState({ [stateName]: e.target.value });
}
checkEnter(e, func) {
if (e.key !== 'Enter') {
return;
}
e.preventDefault();
func.apply(this, [e]);
}
registerSubDomain(e) {
e.preventDefault();
const self = this;
const embarkLogs = this.state.embarkLogs;
embarkLogs.push(`EmbarkJS.Names.registerSubDomain('${this.state.valueRegister}', '${this.state.addressRegister}', console.log)`);
this.setState({
embarkLogs: embarkLogs
});
EmbarkJS.Names.registerSubDomain(this.state.valueRegister, this.state.addressRegister, (err, transaction) => {
const message = err ? err : `Successfully registered "${this.state.valueRegister}" with ${transaction.gasUsed} gas`;
self.setState({
responseRegister: message,
isRegisterError: !!err
});
});
}
resolveName(e) {
e.preventDefault();
const embarkLogs = this.state.embarkLogs;
embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueResolve}', console.log)`);
this.setState({
embarkLogs: embarkLogs
});
EmbarkJS.Names.resolve(this.state.valueResolve, (err, result) => {
if (err) {
return this.setState({
responseResolve: err.message || err,
isResolveError: true
});
}
this.setState({
responseResolve: result,
isResolveError: false
});
});
}
lookupAddress(e) {
e.preventDefault();
const embarkLogs = this.state.embarkLogs;
embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueLookup}', console.log)`);
this.setState({
embarkLogs: embarkLogs
});
EmbarkJS.Names.lookup(this.state.valueLookup, (err, result) => {
if (err) {
return this.setState({
responseLookup: err.message || err,
isLookupError: true
});
}
this.setState({
responseLookup: result,
isLookupError: false
});
});
}
render() {
return (<React.Fragment>
{this.state.globalError && <Alert bsStyle="danger">{this.state.globalError}</Alert>}
<h3>Resolve a name</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.resolveName)}>
<FormGroup>
{this.state.responseResolve &&
<Alert className="alert-result" bsStyle={this.state.isResolveError ? 'danger' : 'success'}>
Resolved address: <span className="value">{this.state.responseResolve}</span>
</Alert>}
<FormControl
type="text"
defaultValue={this.state.valueResolve}
onChange={(e) => this.handleChange('valueResolve', e)}/>
<Button bsStyle="primary" onClick={(e) => this.resolveName(e)}>Resolve name</Button>
</FormGroup>
</Form>
<h3>Lookup an address</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.lookupAddress)}>
<FormGroup>
{this.state.responseLookup &&
<Alert className="alert-result" bsStyle={this.state.isLookupError ? 'danger' : 'success'}>
Looked up domain: <span className="value">{this.state.responseLookup}</span>
</Alert>}
<FormControl
type="text"
defaultValue={this.state.valueLookup}
onChange={(e) => this.handleChange('valueLookup', e)}/>
<Button bsStyle="primary" onClick={(e) => this.lookupAddress(e)}>Lookup address</Button>
</FormGroup>
</Form>
<h3>Register subdomain</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.registerSubDomain)}>
<FormGroup>
{this.state.responseRegister &&
<Alert className="alert-result" bsStyle={this.state.isRegisterError ? 'danger' : 'success'}>
<span className="value">{this.state.responseRegister}</span>
</Alert>}
<FormControl
type="text"
defaultValue={this.state.valueRegister}
onChange={(e) => this.handleChange('valueRegister', e)}/>
<FormControl
type="text"
defaultValue={this.state.addressRegister}
onChange={(e) => this.handleChange('addressRegister', e)}/>
<Button bsStyle="primary" onClick={(e) => this.registerSubDomain(e)}>Register subdomain</Button>
</FormGroup>
</Form>
<h3>Embark Calls </h3>
<p>Javascript calls being made: </p>
<div className="logs">
{
this.state.embarkLogs.map((item, i) => <p key={i}>{item}</p>)
}
</div>
</React.Fragment>
);
}
}
export default ENS;

View File

@ -0,0 +1,272 @@
import EmbarkJS from 'Embark/EmbarkJS';
import React from 'react';
import {Alert, Form, FormGroup, FormControl, HelpBlock, Button} from 'react-bootstrap';
class Storage extends React.Component {
constructor(props) {
super(props);
this.state = {
textToSave: 'hello world!',
generatedHash: '',
loadText: '',
storedText: '',
fileToUpload: null,
fileHash: '',
imageToDownload: '',
url: '',
logs: [],
storageError: '',
valueRegister: '',
valueResolver: '',
};
}
handleChange(e, name) {
this.state[name] = e.target.value;
this.setState(this.state);
}
checkEnter(e, func) {
if (e.key !== 'Enter') {
return;
}
e.preventDefault();
func.apply(this, [e]);
}
handleFileUpload(e) {
this.setState({fileToUpload: [e.target]});
}
addToLog(txt) {
this.state.logs.push(txt);
this.setState({logs: this.state.logs});
}
setText(e) {
e.preventDefault();
EmbarkJS.Storage.saveText(this.state.textToSave)
.then((hash) => {
this.setState({
generatedHash: hash,
loadText: hash,
storageError: ''
});
this.addToLog("EmbarkJS.Storage.saveText('" + this.state.textToSave + "').then(function(hash) { })");
})
.catch((err) => {
if (err) {
this.setState({storageError: err.message});
console.log("Storage saveText Error => " + err.message);
}
});
}
loadHash(e) {
e.preventDefault();
EmbarkJS.Storage.get(this.state.loadText)
.then((content) => {
this.setState({storedText: content, storageError: ''});
this.addToLog("EmbarkJS.Storage.get('" + this.state.loadText + "').then(function(content) { })");
})
.catch((err) => {
if (err) {
this.setState({storageError: err.message});
console.log("Storage get Error => " + err.message);
}
});
}
uploadFile(e) {
e.preventDefault();
EmbarkJS.Storage.uploadFile(this.state.fileToUpload)
.then((hash) => {
this.setState({
fileHash: hash,
imageToDownload: hash,
storageError: ''
});
this.addToLog("EmbarkJS.Storage.uploadFile(this.state.fileToUpload).then(function(hash) { })");
})
.catch((err) => {
if (err) {
this.setState({storageError: err.message});
console.log("Storage uploadFile Error => " + err.message);
}
});
}
loadFile(e) {
let _url = EmbarkJS.Storage.getUrl(this.state.imageToDownload);
this.setState({url: _url});
this.addToLog("EmbarkJS.Storage.getUrl('" + this.state.imageToDownload + "')");
}
ipnsRegister(e) {
e.preventDefault();
this.setState({ registering: true, responseRegister: false });
this.addToLog("EmbarkJS.Storage.register(this.state.ipfsHash).then(function(hash) { })");
EmbarkJS.Storage.register(this.state.valueRegister, (err, name) => {
let responseRegister;
let isRegisterError = false;
if (err) {
isRegisterError = true;
responseRegister = "Name Register Error: " + (err.message || err)
} else {
responseRegister = name;
}
this.setState({
registering: false,
responseRegister,
isRegisterError
});
});
}
ipnsResolve(e) {
e.preventDefault();
this.setState({ resolving: true, responseResolver: false });
this.addToLog("EmbarkJS.Storage.resolve(this.state.ipnsName, function(err, path) { })");
EmbarkJS.Storage.resolve(this.state.valueResolver, (err, path) => {
let responseResolver;
let isResolverError = false;
if (err) {
isResolverError = true;
responseResolver = "Name Resolve Error: " + (err.message || err)
} else {
responseResolver = path;
}
this.setState({
resolving: false,
responseResolver,
isResolverError
});
});
}
isIpfs(){
return EmbarkJS.Storage.currentProviderName === 'ipfs';
}
render() {
return <React.Fragment>
{
!this.props.enabled ?
<React.Fragment>
<Alert bsStyle="warning">The node you are using does not support IPFS. Please ensure <a
href="https://github.com/ipfs/js-ipfs-api#cors" target="_blank">CORS</a> is setup for the IPFS
node.</Alert>
</React.Fragment> : ''
}
{
this.state.storageError !== '' ?
<Alert bsStyle="danger">{this.state.storageError}</Alert>
: ''
}
<h3>Save text to storage</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.setText)}>
<FormGroup>
<FormControl
type="text"
defaultValue={this.state.textToSave}
onChange={e => this.handleChange(e, 'textToSave')}/>
<Button bsStyle="primary" onClick={(e) => this.setText(e)}>Save Text</Button>
<HelpBlock>generated Hash: <span className="textHash">{this.state.generatedHash}</span></HelpBlock>
</FormGroup>
</Form>
<h3>Load text from storage given an hash</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.loadHash)}>
<FormGroup>
<FormControl
type="text"
value={this.state.loadText}
onChange={e => this.handleChange(e, 'loadText')}/>
<Button bsStyle="primary" onClick={(e) => this.loadHash(e)}>Load</Button>
<HelpBlock>result: <span className="textHash">{this.state.storedText}</span></HelpBlock>
</FormGroup>
</Form>
<h3>Upload file to storage</h3>
<Form inline>
<FormGroup>
<FormControl
type="file"
onChange={(e) => this.handleFileUpload(e)}/>
<Button bsStyle="primary" onClick={(e) => this.uploadFile(e)}>Upload</Button>
<HelpBlock>generated hash: <span className="fileHash">{this.state.fileHash}</span></HelpBlock>
</FormGroup>
</Form>
<h3>Get file or image from storage</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.loadFile)}>
<FormGroup>
<FormControl
type="text"
value={this.state.imageToDownload}
onChange={e => this.handleChange(e, 'imageToDownload')}/>
<Button bsStyle="primary" onClick={(e) => this.loadFile(e)}>Download</Button>
<HelpBlock>file available at: <span><a href={this.state.url}
target="_blank">{this.state.url}</a></span></HelpBlock>
<HelpBlock><img src={this.state.url}/></HelpBlock>
</FormGroup>
</Form>
{!this.isIpfs() && <Alert bsStyle="warning">The 2 functions below are only available with IPFS</Alert>}
<h3>Register to IPNS</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.ipnsRegister)}>
<FormGroup>
<FormControl
type="text"
value={this.state.valueRegister}
onChange={e => this.handleChange(e, 'valueRegister')}/>
<Button bsStyle="primary" onClick={(e) => this.ipnsRegister(e)}>
{this.state.registering ? 'Registering...' : 'Register' }
</Button>
<HelpBlock>It will take around 1 minute</HelpBlock>
{this.state.responseRegister &&
<Alert className="alert-result" bsStyle={this.state.isRegisterError ? 'danger' : 'success'}>
<span className="value">{this.state.responseRegister}</span>
</Alert>}
</FormGroup>
</Form>
<h3>Resolve name</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.ipnsResolve)}>
<FormGroup>
<FormControl
type="text"
value={this.state.valueResolver}
onChange={e => this.handleChange(e, 'valueResolver')}/>
<Button bsStyle="primary" onClick={(e) => this.ipnsResolve(e)}>
{this.state.resolving ? 'Resolving...' : 'Resolve' }
</Button>
<HelpBlock>It will take around 1 minute</HelpBlock>
{this.state.responseResolver &&
<Alert className="alert-result" bsStyle={this.state.isResolverError ? 'danger' : 'success'}>
<span className="value">{this.state.responseResolver}</span>
</Alert>}
</FormGroup>
</Form>
<p>Javascript calls being made: </p>
<div className="logs">
<p>EmbarkJS.Storage.setProvider('ipfs',{'{'}server: 'localhost', port: '5001'{'}'})</p>
{
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
}
</div>
</React.Fragment>;
}
}
export default Storage;

View File

@ -0,0 +1,126 @@
import EmbarkJS from 'Embark/EmbarkJS';
import React from 'react';
import {Alert, Form, FormGroup, FormControl, Button} from 'react-bootstrap';
class Whisper extends React.Component {
constructor (props) {
super(props);
this.state = {
listenTo: '',
channel: '',
message: '',
subscribedChannels: [],
messageList: [],
logs: []
};
}
handleChange (e, name) {
this.state[name] = e.target.value;
this.setState(this.state);
}
checkEnter(e, func) {
if (e.key !== 'Enter') {
return;
}
e.preventDefault();
func.apply(this, [e]);
}
sendMessage (e) {
e.preventDefault();
EmbarkJS.Messages.sendMessage({topic: this.state.channel, data: this.state.message});
this.addToLog("EmbarkJS.Messages.sendMessage({topic: '" + this.state.channel + "', data: '" + this.state.message + "'})");
}
listenToChannel (e) {
e.preventDefault();
const subscribedChannels = this.state.subscribedChannels;
subscribedChannels.push(<span>Subscribed to <b>{this.state.listenTo}</b>. Now try sending a message</span>);
this.setState({
subscribedChannels
});
EmbarkJS.Messages.listenTo({topic: [this.state.listenTo]}, (error, message) => {
const messageList = this.state.messageList;
if (error) {
messageList.push(<span className="alert-danger">Error: {error}</span>);
} else {
messageList.push(<span>Channel: <b>{message.topic}</b> | Message: <b>{message.data}</b></span>);
}
this.setState({
messageList
});
});
this.addToLog("EmbarkJS.Messages.listenTo({topic: ['" + this.state.listenTo + "']}).then(function(message) {})");
}
addToLog (txt) {
this.state.logs.push(txt);
this.setState({logs: this.state.logs});
}
render () {
return (
<React.Fragment>
{
!this.props.enabled ?
<React.Fragment>
<Alert bsStyle="warning">The node you are using does not support Whisper</Alert>
<Alert bsStyle="warning">The node uses an unsupported version of Whisper</Alert>
</React.Fragment> : ''
}
<h3>Listen To channel</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.listenToChannel)}>
<FormGroup>
<FormControl
type="text"
defaultValue={this.state.listenTo}
placeholder="channel"
onChange={e => this.handleChange(e, 'listenTo')}/>
<Button bsStyle="primary" onClick={(e) => this.listenToChannel(e)}>Start Listening</Button>
<div id="subscribeList">
{this.state.subscribedChannels.map((item, i) => <p key={i}>{item}</p>)}
</div>
<p>messages received:</p>
<div id="messagesList">
{this.state.messageList.map((item, i) => <p key={i}>{item}</p>)}
</div>
</FormGroup>
</Form>
<h3>Send Message</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.sendMessage)}>
<FormGroup>
<FormControl
type="text"
defaultValue={this.state.channel}
placeholder="channel"
onChange={e => this.handleChange(e, 'channel')}/>
<FormControl
type="text"
defaultValue={this.state.message}
placeholder="message"
onChange={e => this.handleChange(e, 'message')}/>
<Button bsStyle="primary" onClick={(e) => this.sendMessage(e)}>Send Message</Button>
</FormGroup>
</Form>
<p>Javascript calls being made: </p>
<div className="logs">
<p>EmbarkJS.Messages.setProvider('whisper')</p>
{
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
}
</div>
</React.Fragment>
);
}
}
export default Whisper;

View File

@ -0,0 +1,57 @@
div {
margin: 15px;
}
.logs {
background-color: black;
font-size: 14px;
color: white;
font-weight: bold;
padding: 10px;
border-radius: 8px;
}
.tab-content {
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
border-bottom: 1px solid #ddd;
padding: 10px;
margin: 0px;
}
.nav-tabs {
margin-bottom: 0;
}
.status-offline {
vertical-align: middle;
margin-left: 5px;
margin-top: 4px;
width: 12px;
height: 12px;
background: red;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
.status-online {
vertical-align: middle;
margin-left: 5px;
margin-top: 4px;
width: 12px;
height: 12px;
background: mediumseagreen;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
input.form-control {
margin-right: 5px;
}
.alert-result {
margin-left: 0;
}

View File

@ -0,0 +1,94 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {Tabs, Tab} from 'react-bootstrap';
import EmbarkJS from 'Embark/EmbarkJS';
import Blockchain from './components/blockchain';
import Whisper from './components/whisper';
import Storage from './components/storage';
import ENS from './components/ens';
import './dapp.css';
class App extends React.Component {
constructor(props) {
super(props);
this.handleSelect = this.handleSelect.bind(this);
this.state = {
error: null,
activeKey: 1,
whisperEnabled: false,
storageEnabled: false,
blockchainEnabled: false,
ensEnabled: false
};
}
componentDidMount() {
EmbarkJS.onReady((err) => {
this.setState({blockchainEnabled: true});
if (err) {
// If err is not null then it means something went wrong connecting to ethereum
// you can use this to ask the user to enable metamask for e.g
return this.setState({error: err.message || err});
}
EmbarkJS.Messages.Providers.whisper.getWhisperVersion((err, _version) => {
if (err) {
return console.log(err);
}
this.setState({whisperEnabled: true});
});
EmbarkJS.Storage.isAvailable().then((result) => {
this.setState({storageEnabled: result});
}).catch(() => {
this.setState({storageEnabled: false});
});
});
}
_renderStatus(title, available) {
let className = available ? 'pull-right status-online' : 'pull-right status-offline';
return <React.Fragment>
{title}
<span className={className}></span>
</React.Fragment>;
}
handleSelect(key) {
this.setState({ activeKey: key });
}
render() {
const ensEnabled = EmbarkJS.Names.currentNameSystems && EmbarkJS.Names.isAvailable();
if (this.state.error) {
return (<div>
<div>Something went wrong connecting to ethereum. Please make sure you have a node running or are using metamask to connect to the ethereum network:</div>
<div>{this.state.error}</div>
</div>);
}
return (<div>
<h3>Embark - Usage Example</h3>
<Tabs onSelect={this.handleSelect} activeKey={this.state.activeKey} id="uncontrolled-tab-example">
<Tab eventKey={1} title={this._renderStatus('Blockchain', this.state.blockchainEnabled)}>
<Blockchain/>
</Tab>
<Tab eventKey={2} title={this._renderStatus('Decentralized Storage', this.state.storageEnabled)}>
<Storage enabled={this.state.storageEnabled}/>
</Tab>
<Tab eventKey={3} title={this._renderStatus('P2P communication (Whisper)', this.state.whisperEnabled)}>
<Whisper enabled={this.state.whisperEnabled}/>
</Tab>
<Tab eventKey={4} title={this._renderStatus('Naming (ENS)', ensEnabled)}>
<ENS enabled={ensEnabled}/>
</Tab>
</Tabs>
</div>);
}
}
ReactDOM.render(<App></App>, document.getElementById('app'));

View File

@ -0,0 +1,12 @@
<html>
<head>
<title>Embark - SimpleStorage Demo</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body class="container">
<div id="app">
</div>
<script src="js/dapp.js"></script>
</body>
</html>

View File

@ -0,0 +1,22 @@
{
"0x4c88925b6fabc1d138606800ff7f4fb5d90b1977624f38f99576056449a6a500": {
"contracts": {
"0x0aea975ceeaff5c320a0559708c5c6f94999421a0be61587cdece9b4542cc110": {
"name": "SimpleStorage",
"address": "0x74A18cBcd27e4652cD3FE852C5362432056E6480"
},
"0x3043b04ad856d169c8f0b0509c0bc63192dc7edd92d6933c58708298a0e381be": {
"name": "ENSRegistry",
"address": "0x88D7fD23Fc1c96FF89BeAd9aEb24Ccca96432c63"
},
"0x60daddeb23aae81f0807e071c25012fc78e521a3e829d2b1fcda1b8bc40d3815": {
"name": "Resolver",
"address": "0xcF1FF793d4510E1E2838642BC4B118AB14C5B1ac"
},
"0x842276d67a5bf54ee66032015bbeb8f58ca3ce6cabf05cf7ec19b0b282c6dbc0": {
"name": "FIFSRegistrar",
"address": "0x8fcDa55C6F48A9c591eA5227837dA30B9560Ed33"
}
}
}
}

View File

@ -0,0 +1,99 @@
module.exports = {
// applies to all environments
default: {
enabled: true,
rpcHost: "localhost", // HTTP-RPC server listening interface (default: "localhost")
rpcPort: 8545, // HTTP-RPC server listening port (default: 8545)
rpcCorsDomain: "auto", // Comma separated list of domains from which to accept cross origin requests (browser enforced)
// When set to "auto", Embark will automatically set the cors to the address of the webserver
wsRPC: true, // Enable the WS-RPC server
wsOrigins: "auto", // Origins from which to accept websockets requests
// When set to "auto", Embark will automatically set the cors to the address of the webserver
wsHost: "localhost", // WS-RPC server listening interface (default: "localhost")
wsPort: 8546 // WS-RPC server listening port (default: 8546)
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run` and `embark blockchain`
development: {
networkType: "custom", // Can be: testnet, rinkeby, livenet or custom, in which case, it will use the specified networkId
networkId: "1337", // Network id used when networkType is custom
isDev: true, // Uses and ephemeral proof-of-authority network with a pre-funded developer account, mining enabled
datadir: ".embark/development/datadir", // Data directory for the databases and keystore
mineWhenNeeded: true, // Uses our custom script (if isDev is false) to mine only when needed
nodiscover: true, // Disables the peer discovery mechanism (manual peer addition)
maxpeers: 0, // Maximum number of network peers (network disabled if set to 0) (default: 25)
proxy: true, // Proxy is used to present meaningful information about transactions
targetGasLimit: 8000000, // Target gas limit sets the artificial target gas floor for the blocks to mine
simulatorMnemonic: "example exile argue silk regular smile grass bomb merge arm assist farm", // Mnemonic used by the simulator to generate a wallet
simulatorBlocktime: 0, // Specify blockTime in seconds for automatic mining. Default is 0 and no auto-mining.
account: {
// numAccounts: 3, // When specified, creates accounts for use in the dapp. This option only works in the development environment, and can be used as a quick start option that bypasses the need for MetaMask in development. These accounts are unlocked and funded with the below settings.
// password: "config/development/password", // Password for the created accounts (as specified in the `numAccounts` setting). If `mineWhenNeeded` is enabled (and isDev is not), this password is used to create a development account controlled by the node.
// balance: "5 ether" // Balance to be given to the created accounts (as specified in the `numAccounts` setting)
}
},
// merges with the settings in default
// used with "embark run privatenet" and/or "embark blockchain privatenet"
privatenet: {
networkType: "custom",
networkId: "1337",
isDev: false,
datadir: ".embark/privatenet/datadir",
// -- mineWhenNeeded --
// This options is only valid when isDev is false.
// Enabling this option uses our custom script to mine only when needed.
// Embark creates a development account for you (using `geth account new`) and funds the account. This account can be used for
// development (and even imported in to MetaMask). To enable correct usage, a password for this account must be specified
// in the `account > password` setting below.
// NOTE: once `mineWhenNeeded` is enabled, you must run an `embark reset` on your dApp before running
// `embark blockchain` or `embark run` for the first time.
mineWhenNeeded: true,
// -- genesisBlock --
// This option is only valid when mineWhenNeeded is true (which is only valid if isDev is false).
// When enabled, geth uses POW to mine transactions as it would normally, instead of using POA as it does in --dev mode.
// On the first `embark blockchain or embark run` after this option is enabled, geth will create a new chain with a
// genesis block, which can be configured using the `genesisBlock` configuration option below.
genesisBlock: "config/privatenet/genesis.json", // Genesis block to initiate on first creation of a development node
nodiscover: true,
maxpeers: 0,
proxy: true,
account: {
// "address": "", // When specified, uses that address instead of the default one for the network
password: "config/privatenet/password" // Password to unlock the account
},
targetGasLimit: 8000000,
wsHost: "localhost",
wsPort: 8546,
simulatorMnemonic: "example exile argue silk regular smile grass bomb merge arm assist farm",
simulatorBlocktime: 0
},
// merges with the settings in default
// used with "embark run testnet" and/or "embark blockchain testnet"
testnet: {
networkType: "testnet",
syncMode: "light",
account: {
password: "config/testnet/password"
}
},
// merges with the settings in default
// used with "embark run livenet" and/or "embark blockchain livenet"
livenet: {
networkType: "livenet",
syncMode: "light",
rpcCorsDomain: "http://localhost:8000",
wsOrigins: "http://localhost:8000",
account: {
password: "config/livenet/password"
}
},
// you can name an environment with specific settings and then specify with
// "embark run custom_name" or "embark blockchain custom_name"
//custom_name: {
//}
};

View File

@ -0,0 +1,46 @@
module.exports = {
// default applies to all environments
default: {
enabled: true,
provider: "whisper", // Communication provider. Currently, Embark only supports whisper
available_providers: ["whisper"], // Array of available providers
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run`
development: {
connection: {
host: "localhost", // Host of the blockchain node
port: 8546, // Port of the blockchain node
type: "ws" // Type of connection (ws or rpc)
}
},
// merges with the settings in default
// used with "embark run privatenet"
privatenet: {
},
// merges with the settings in default
// used with "embark run testnet"
testnet: {
},
// merges with the settings in default
// used with "embark run livenet"
livenet: {
},
// you can name an environment with specific settings and then specify with
// "embark run custom_name"
//custom_name: {
//}
// Use this section when you need a specific symmetric or private keys in whisper
/*
,keys: {
symmetricKey: "your_symmetric_key",// Symmetric key for message decryption
privateKey: "your_private_key" // Private Key to be used as a signing key and for message decryption
}
*/
};

View File

@ -0,0 +1,72 @@
module.exports = {
// default applies to all environments
default: {
// Blockchain node to deploy the contracts
deployment: {
host: "localhost", // Host of the blockchain node
port: 8545, // Port of the blockchain node
type: "rpc" // Type of connection (ws or rpc),
// Accounts to use instead of the default account to populate your wallet
/*,accounts: [
{
privateKey: "your_private_key",
balance: "5 ether" // You can set the balance of the account in the dev environment
// Balances are in Wei, but you can specify the unit with its name
},
{
privateKeyFile: "path/to/file", // Either a keystore or a list of keys, separated by , or ;
password: "passwordForTheKeystore" // Needed to decrypt the keystore file
},
{
mnemonic: "12 word mnemonic",
addressIndex: "0", // Optionnal. The index to start getting the address
numAddresses: "1", // Optionnal. The number of addresses to get
hdpath: "m/44'/60'/0'/0/" // Optionnal. HD derivation path
}
]*/
},
// order of connections the dapp should connect to
dappConnection: [
"$WEB3", // uses pre existing web3 object if available (e.g in Mist)
"ws://localhost:8546",
"http://localhost:8545"
],
gas: "auto",
contracts: {
SimpleStorage: {
fromIndex: 0,
args: [100]
}
}
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run`
development: {
dappConnection: [
"ws://localhost:8546",
"http://localhost:8545",
"$WEB3" // uses pre existing web3 object if available (e.g in Mist)
]
},
// merges with the settings in default
// used with "embark run privatenet"
privatenet: {
},
// merges with the settings in default
// used with "embark run testnet"
testnet: {
},
// merges with the settings in default
// used with "embark run livenet"
livenet: {
},
// you can name an environment with specific settings and then specify with
// "embark run custom_name" or "embark blockchain custom_name"
//custom_name: {
//}
};

View File

@ -0,0 +1,39 @@
module.exports = {
// default applies to all environments
default: {
enabled: true,
available_providers: ["ens"],
provider: "ens"
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run`
development: {
register: {
rootDomain: "eth",
subdomains: {
'embark': '0x1a2f3b98e434c02363f3dac3174af93c1d690914'
}
}
},
// merges with the settings in default
// used with "embark run privatenet"
privatenet: {
},
// merges with the settings in default
// used with "embark run testnet"
testnet: {
},
// merges with the settings in default
// used with "embark run livenet"
livenet: {
},
// you can name an environment with specific settings and then specify with
// "embark run custom_name" or "embark blockchain custom_name"
//custom_name: {
//}
};

View File

@ -0,0 +1,18 @@
{
"config": {
"homesteadBlock": 0,
"byzantiumBlock": 0,
"daoForkSupport": true
},
"nonce": "0x0000000000000042",
"difficulty": "0x0",
"alloc": {
"0x3333333333333333333333333333333333333333": {"balance": "15000000000000000000"}
},
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x3333333333333333333333333333333333333333",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x7a1200"
}

View File

@ -0,0 +1 @@
dev_password

View File

@ -0,0 +1,59 @@
module.exports = {
// default applies to all environments
default: {
enabled: true,
ipfs_bin: "ipfs",
provider: "ipfs",
available_providers: ["ipfs"],
upload: {
host: "localhost",
port: 5001
},
dappConnection: [
{
provider:"ipfs",
host: "localhost",
port: 5001,
getUrl: "http://localhost:8080/ipfs/"
}
]
// Configuration to start Swarm in the same terminal as `embark run`
/*,account: {
address: "YOUR_ACCOUNT_ADDRESS", // Address of account accessing Swarm
password: "PATH/TO/PASSWORD/FILE" // File containing the password of the account
},
swarmPath: "PATH/TO/SWARM/EXECUTABLE" // Path to swarm executable (default: swarm)*/
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run`
development: {
enabled: true,
provider: "ipfs",
upload: {
host: "localhost",
port: 5001,
getUrl: "http://localhost:8080/ipfs/"
}
},
// merges with the settings in default
// used with "embark run privatenet"
privatenet: {
},
// merges with the settings in default
// used with "embark run testnet"
testnet: {
},
// merges with the settings in default
// used with "embark run livenet"
livenet: {
},
// you can name an environment with specific settings and then specify with
// "embark run custom_name"
//custom_name: {
//}
};

View File

@ -0,0 +1 @@
test_password

View File

@ -0,0 +1,6 @@
module.exports = {
enabled: true,
host: "localhost",
openBrowser: true,
port: 8000
};

View File

@ -0,0 +1,22 @@
pragma solidity ^0.4.25;
contract SimpleStorage {
uint public storedData;
address owner;
constructor(uint initialValue) public {
storedData = initialValue;
owner = msg.sender;
}
function set(uint x) public {
storedData = x;
require(msg.sender != owner);
storedData = x + 2;
}
function get() public view returns (uint retVal) {
return storedData;
}
}

View File

@ -0,0 +1,23 @@
{
"contracts": ["contracts/**"],
"app": {
"js/dapp.js": ["app/dapp.js"],
"index.html": "app/index.html",
"images/": ["app/images/**"]
},
"buildDir": "dist/",
"config": "config/",
"versions": {
"web3": "1.0.0-beta",
"solc": "0.4.25",
"ipfs-api": "17.2.4"
},
"plugins": {
},
"options": {
"solc": {
"optimize": true,
"optimize-runs": 200
}
}
}

278
test_apps/embark_demo/package-lock.json generated Normal file
View File

@ -0,0 +1,278 @@
{
"name": "app_name",
"version": "0.0.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"requires": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
},
"dependencies": {
"core-js": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
}
}
},
"classnames": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
},
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
},
"dom-helpers": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.3.1.tgz",
"integrity": "sha512-2Sm+JaYn74OiTM2wHvxJOo3roiq/h25Yi69Fqk269cNUwIXsCvATB6CRSFC9Am/20G2b28hGv/+7NiWydIrPvg=="
},
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
"requires": {
"iconv-lite": "~0.4.13"
}
},
"fbjs": {
"version": "0.8.17",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
"integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
"requires": {
"core-js": "^1.0.0",
"isomorphic-fetch": "^2.1.1",
"loose-envify": "^1.0.0",
"object-assign": "^4.1.0",
"promise": "^7.1.1",
"setimmediate": "^1.0.5",
"ua-parser-js": "^0.7.18"
}
},
"iconv-lite": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"requires": {
"loose-envify": "^1.0.0"
}
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
"requires": {
"node-fetch": "^1.0.1",
"whatwg-fetch": ">=0.10.0"
}
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"keycode": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
"integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ="
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
},
"prop-types": {
"version": "15.6.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
"integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
"requires": {
"loose-envify": "^1.3.1",
"object-assign": "^4.1.1"
}
},
"prop-types-extra": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.0.tgz",
"integrity": "sha512-QFyuDxvMipmIVKD2TwxLVPzMnO4e5oOf1vr3tJIomL8E7d0lr6phTHd5nkPhFIzTD1idBLLEPeylL9g+rrTzRg==",
"requires": {
"react-is": "^16.3.2",
"warning": "^3.0.0"
}
},
"react": {
"version": "16.4.2",
"resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
"integrity": "sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg==",
"requires": {
"fbjs": "^0.8.16",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
}
},
"react-bootstrap": {
"version": "0.32.1",
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.32.1.tgz",
"integrity": "sha512-RbfzKUbsukWsToWqGHfCCyMFq9QQI0TznutdyxyJw6dih2NvIne25Mrssg8LZsprqtPpyQi8bN0L0Fx3fUsL8Q==",
"requires": {
"babel-runtime": "^6.11.6",
"classnames": "^2.2.5",
"dom-helpers": "^3.2.0",
"invariant": "^2.2.1",
"keycode": "^2.1.2",
"prop-types": "^15.5.10",
"prop-types-extra": "^1.0.1",
"react-overlays": "^0.8.0",
"react-prop-types": "^0.4.0",
"react-transition-group": "^2.0.0",
"uncontrollable": "^4.1.0",
"warning": "^3.0.0"
}
},
"react-dom": {
"version": "16.4.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.2.tgz",
"integrity": "sha512-Usl73nQqzvmJN+89r97zmeUpQDKDlh58eX6Hbs/ERdDHzeBzWy+ENk7fsGQ+5KxArV1iOFPT46/VneklK9zoWw==",
"requires": {
"fbjs": "^0.8.16",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
}
},
"react-is": {
"version": "16.4.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.2.tgz",
"integrity": "sha512-rI3cGFj/obHbBz156PvErrS5xc6f1eWyTwyV4mo0vF2lGgXgS+mm7EKD5buLJq6jNgIagQescGSVG2YzgXt8Yg=="
},
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-overlays": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-0.8.3.tgz",
"integrity": "sha512-h6GT3jgy90PgctleP39Yu3eK1v9vaJAW73GOA/UbN9dJ7aAN4BTZD6793eI1D5U+ukMk17qiqN/wl3diK1Z5LA==",
"requires": {
"classnames": "^2.2.5",
"dom-helpers": "^3.2.1",
"prop-types": "^15.5.10",
"prop-types-extra": "^1.0.1",
"react-transition-group": "^2.2.0",
"warning": "^3.0.0"
}
},
"react-prop-types": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz",
"integrity": "sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=",
"requires": {
"warning": "^3.0.0"
}
},
"react-transition-group": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.4.0.tgz",
"integrity": "sha512-Xv5d55NkJUxUzLCImGSanK8Cl/30sgpOEMGc5m86t8+kZwrPxPCPcFqyx83kkr+5Lz5gs6djuvE5By+gce+VjA==",
"requires": {
"dom-helpers": "^3.3.1",
"loose-envify": "^1.3.1",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4"
}
},
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"ua-parser-js": {
"version": "0.7.18",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
"integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA=="
},
"uncontrollable": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-4.1.0.tgz",
"integrity": "sha1-4DWCkSUuGGUiLZCTmxny9J+Bwak=",
"requires": {
"invariant": "^2.1.0"
}
},
"warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
"requires": {
"loose-envify": "^1.0.0"
}
},
"whatwg-fetch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
}
}
}

View File

@ -0,0 +1,17 @@
{
"name": "app_name",
"version": "0.0.1",
"description": "",
"main": "Gruntfile.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"homepage": "",
"dependencies": {
"react": "^16.3.2",
"react-bootstrap": "0.32.1",
"react-dom": "^16.3.2"
}
}

View File

@ -0,0 +1,41 @@
/*global contract, config, it, assert*/
const SimpleStorage = require('Embark/contracts/SimpleStorage');
let accounts;
// For documentation please see https://embark.status.im/docs/contracts_testing.html
config({
//deployment: {
// accounts: [
// // you can configure custom accounts with a custom balance
// // see https://embark.status.im/docs/contracts_testing.html#Configuring-accounts
// ]
//},
contracts: {
"SimpleStorage": {
args: [100]
}
}
}, (_err, web3_accounts) => {
accounts = web3_accounts
});
contract("SimpleStorage", function () {
this.timeout(0);
it("should set constructor value", async function () {
let result = await SimpleStorage.methods.storedData().call();
assert.strictEqual(parseInt(result, 10), 100);
});
it("set storage value", async function () {
await SimpleStorage.methods.set(150).send();
let result = await SimpleStorage.methods.get().call();
assert.strictEqual(parseInt(result, 10), 150);
});
it("should have account with balance", async function() {
let balance = await web3.eth.getBalance(accounts[0]);
assert.ok(parseInt(balance, 10) > 0);
});
});

View File

@ -1,46 +1,22 @@
pragma solidity ^0.4.17; pragma solidity ^0.4.25;
import "ownable.sol"; contract SimpleStorage {
library Assert {
event TestEvent(bool passed, string message);
function triggerEvent(bool passed, string message) internal {
emit TestEvent(passed, message);
}
}
contract SimpleStorage is Ownable {
uint public storedData; uint public storedData;
address public registar; address owner;
event EventOnSet2(bool passed, string message);
function() public payable { }
constructor(uint initialValue) public { constructor(uint initialValue) public {
storedData = initialValue; storedData = initialValue;
owner = msg.sender;
} }
function set(uint x) public { function set(uint x) public {
storedData = x; storedData = x;
Assert.triggerEvent(true, "hi"); require(msg.sender == 0x0);
} storedData = x + 2;
function set2(uint x) public onlyOwner {
storedData = x;
emit EventOnSet2(true, "hi");
} }
function get() public view returns (uint retVal) { function get() public view returns (uint retVal) {
return storedData; return storedData;
} }
function getS() public pure returns (string d) {
return "hello";
}
function setRegistar(address x) public {
registar = x;
}
} }

View File

@ -0,0 +1,34 @@
pragma solidity ^0.4.25;
import "ownable.sol";
contract SimpleStorageTest is Ownable {
uint public storedData;
address owner;
constructor(uint initialValue) public {
storedData = initialValue;
owner = msg.sender;
}
function set(uint x) public onlyOwner {
storedData = x;
require(msg.sender != owner);
storedData = x + 2;
}
function test(uint x) public {
uint value = 1;
assembly {
let a := 1
let b := 2
revert(0, 0)
}
value = 2;
}
function get() public view returns (uint retVal) {
return storedData;
}
}

View File

@ -4,7 +4,10 @@ import React, { Component } from 'react';
import EmbarkJS from 'Embark/EmbarkJS'; import EmbarkJS from 'Embark/EmbarkJS';
import SimpleStorage from 'Embark/contracts/SimpleStorage'; import SimpleStorage from 'Embark/contracts/SimpleStorage';
import Test from 'Embark/contracts/Test'; import Test from 'Embark/contracts/Test';
import Assert from 'Embark/contracts/Assert'; //import Assert from 'Embark/contracts/Assert';
import SimpleStorageTest from 'Embark/contracts/SimpleStorageTest';
window.SimpleStorageTest = SimpleStorageTest
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
@ -23,7 +26,7 @@ import { Navbar, Jumbotron, Button } from 'react-bootstrap';
window.EmbarkJS = EmbarkJS; window.EmbarkJS = EmbarkJS;
window.SimpleStorage = SimpleStorage; window.SimpleStorage = SimpleStorage;
window.Test = Test; window.Test = Test;
window.Assert = Assert; //window.Assert = Assert;
window.React = React; window.React = React;

View File

@ -3,7 +3,13 @@ module.exports = {
deployment: { deployment: {
host: "localhost", host: "localhost",
port: 8546, port: 8546,
type: "ws" type: "ws",
accounts: [
{
mnemonic: "example exile argue silk regular smile grass bomb merge arm assist farm",
balance: "5 ether"
}
]
}, },
dappConnection: [ dappConnection: [
"ws://localhost:8546", "ws://localhost:8546",
@ -17,6 +23,9 @@ module.exports = {
Ownable: { Ownable: {
deploy: false deploy: false
}, },
SimpleStorageTest: {
args: [100]
},
SimpleStorage: { SimpleStorage: {
fromIndex: 0, fromIndex: 0,
args: [100], args: [100],

View File

@ -15,7 +15,7 @@
"buildDir": "dist/", "buildDir": "dist/",
"config": "config/", "config": "config/",
"versions": { "versions": {
"solc": "0.4.24", "solc": "0.4.25",
"web3": "1.0.0-beta", "web3": "1.0.0-beta",
"ipfs-api": "17.2.7" "ipfs-api": "17.2.7"
}, },

BIN
test_apps/test_app/test.file Executable file

Binary file not shown.