Merge pull request #755 from ethereum/ux-terminal

UI terminal
pull/1/head
yann300 8 years ago committed by GitHub
commit 5878bd71eb
  1. 2
      assets/css/universal-dapp.css
  2. 7
      src/app/execution/txListener.js
  3. 253
      src/app/execution/txLogger.js
  4. 2
      src/app/tabs/run-tab.js
  5. 1
      src/lib/helper.js
  6. 2
      test-browser/tests/compiling.js

@ -215,7 +215,7 @@
padding: 0 0.4em;
box-sizing: border-box;
float: left;
word-wrap: break-word;
min-width: 100%;
}
#runTabView .contractProperty.hasArgs input {

@ -249,7 +249,12 @@ class TxListener {
for (var i = 0; i < abi.inputs.length; i++) {
inputTypes.push(abi.inputs[i].type)
}
return ethJSABI.rawDecode(inputTypes, data)
var decoded = ethJSABI.rawDecode(inputTypes, data)
var ret = {}
for (var k in abi.inputs) {
ret[abi.inputs[k].type + ' ' + abi.inputs[k].name] = decoded[k]
}
return ret
}
}

@ -1,12 +1,64 @@
'use strict'
var yo = require('yo-yo')
// -------------- styling ----------------------
var csjs = require('csjs-inject')
var remix = require('ethereum-remix')
var styleGuide = remix.ui.styleGuide
var styles = styleGuide()
var EventManager = remix.lib.EventManager
var helper = require('../../lib/helper')
var ethJSUtil = require('ethereumjs-util')
var BN = ethJSUtil.BN
var executionContext = require('../../execution-context')
var css = csjs`
.log {
display: flex;
align-items: baseline;
justify-content: space-between;
}
.tx {
color: ${styles.colors.violet};
width: 45%;
}
.txTable, .tr, .td {
border-collapse: collapse;
font-size: 10px;
color: ${styles.colors.grey};
border: 1px dashed ${styles.colors.black};
}
#txTable {
margin-top: 1%;
margin-bottom: 5%;
align-self: center;
}
.tr, .td {
padding: 4px;
}
.tableTitle {
width: 25%;
}
.buttons {
display: flex;
}
.debug, .details {
${styles.button}
min-height: 18px;
max-height: 18px;
width: 45px;
min-width: 45px;
font-size: 10px;
margin-left: 5px;
}
.debug {
background-color: ${styles.colors.lightOrange};
}
.details {
background-color: ${styles.colors.lightGrey};
}
`
/**
* This just export a function that register to `newTransaction` and forward them to the logger.
* Emit debugRequested
@ -59,47 +111,131 @@ function log (self, tx, api) {
}
function renderKnownTransaction (self, data) {
var to = data.tx.to
if (to) to = helper.shortenAddress(data.tx.to)
var from = data.tx.from
var to = data.resolvedData.contractName + '.' + data.resolvedData.fn
function debug () {
self.event.trigger('debugRequested', [data.tx.hash])
}
function detail () {
// @TODO here should open a modal containing some info (e.g input params, logs, ...)
var tx = yo`
<span class=${css.container} id="tx${data.tx.hash}">
<div class="${css.log}">
${context(self, {from, to, data})}
<div class=${css.buttons}>
<button class=${css.details} onclick=${txDetails}>Details</button>
<button class=${css.debug} onclick=${debug}>Debug</button>
</div>
</div>
</span>
`
var table
function txDetails () {
if (table && table.parentNode) {
tx.removeChild(table)
} else {
table = createTable({
contractAddress: data.tx.contractAddress,
data: data.tx,
from,
to,
gas: data.tx.gas,
hash: data.tx.hash,
input: data.tx.input,
'decoded input': data.resolvedData && data.resolvedData.params ? JSON.stringify(value(data.resolvedData.params), null, '\t') : ' - ',
logs: JSON.stringify(data.logs, null, '\t') || '0',
val: data.tx.value
})
tx.appendChild(table)
}
}
return yo`<span id="tx${data.tx.hash}">${context(self, data.tx)}: from:${helper.shortenAddress(data.tx.from)}, to:${to}, ${data.resolvedData.contractName}.${data.resolvedData.fn}, value:${value(data.tx.value)} wei, data:${helper.shortenHexData(data.tx.input)}, ${data.logs.length} logs, hash:${helper.shortenHexData((data.tx.hash))},<button onclick=${detail}>Details</button> <button onclick=${debug}>Debug</button></span>`
return tx
}
function renderUnknownTransaction (self, data) {
var from = data.tx.from
var to = data.tx.to
if (to) to = helper.shortenAddress(data.tx.to)
function debug () {
self.event.trigger('debugRequested', [data.tx.hash])
}
function detail () {
// @TODO here should open a modal containing some info (e.g input params, logs, ...)
var tx = yo`
<span class=${css.container} id="tx${data.tx.hash}">
<div class="${css.log}">
${context(self, {from, to, data})}
<div class=${css.buttons}>
<button class=${css.details} onclick=${txDetails}>Details</button>
<button class=${css.debug} onclick=${debug}>Debug</button>
</div>
</div>
</span>
`
var table
function txDetails () {
if (table && table.parentNode) {
tx.removeChild(table)
} else {
table = createTable({
data: data.tx,
from,
to,
val: data.tx.value,
input: data.tx.input,
hash: data.tx.hash,
gas: data.tx.gas,
logs: JSON.stringify(data.logs) || '0'
})
tx.appendChild(table)
}
}
return yo`<span id="tx${data.tx.hash}">${context(self, data.tx)}: from:${helper.shortenAddress(data.tx.from)}, to:${to}, value:${value(data.tx.value)} wei, data:${helper.shortenHexData((data.tx.input))}, hash:${helper.shortenHexData((data.tx.hash))}, <button onclick=${detail}>Details</button> <button onclick=${debug}>Debug</button></span>`
return tx
}
function renderEmptyBlock (self, data) {
return yo`<span>block ${data.block.number} - O transactions</span>`
}
function context (self, tx) {
function context (self, opts) {
var data = opts.data || ''
var from = opts.from ? helper.shortenHexData(opts.from) : ''
var to = opts.to
if (data.tx.to) to = to + ' ' + helper.shortenHexData(data.tx.to)
var val = data.tx.value
var hash = data.tx.hash ? helper.shortenHexData(data.tx.hash) : ''
var input = data.tx.input ? helper.shortenHexData(data.tx.input) : ''
var logs = data.logs ? data.logs.length : 0
var block = data.tx.blockNumber || ''
var i = data.tx.transactionIndex
if (executionContext.getProvider() === 'vm') {
return yo`<span>(vm)</span>`
return yo`<span><span class=${css.tx}>[vm]</span> from:${from}, to:${to}, value:${value(val)} wei, data:${input}, ${logs} logs, hash:${hash}</span>`
} else if (executionContext.getProvider() !== 'vm' && data.resolvedData) {
return yo`<span><span class='${css.tx}'>[block:${block} txIndex:${i}]</span> from:${from}, to:${to}, value:${value(val)} wei</span>`
} else {
return yo`<span>block:${tx.blockNumber}, txIndex:${tx.transactionIndex}</span>`
to = helper.shortenHexData(to)
hash = helper.shortenHexData(data.tx.blockHash)
return yo`<span><span class='${css.tx}'>[block:${block} txIndex:${i}]</span> from:${from}, to:${to}, value:${value(val)} wei</span>`
}
}
function value (v) {
try {
if (v.indexOf && v.indexOf('0x') === 0) {
if (v instanceof Array) {
var ret = []
for (var k in v) {
ret.push(value(v[k]))
}
return ret
} else if (BN.isBN(v)) {
return v.toString(10)
} else if (v.indexOf && v.indexOf('0x') === 0) {
return (new BN(v.replace('0x', ''), 16)).toString(10)
} else if (typeof v === 'object') {
var retObject = {}
for (var i in v) {
retObject[i] = value(v[i])
}
return retObject
} else {
return v.toString(10)
return v
}
} catch (e) {
console.log(e)
@ -108,3 +244,92 @@ function value (v) {
}
module.exports = TxLogger
// helpers
function createTable (opts) {
var table = yo`<table class="${css.txTable}" id="txTable"></table>`
var contractAddress = yo`
<tr class="${css.tr}">
<td class="${css.td}"> contractAddress </td>
<td class="${css.td}">${opts.contractAddress}</td>
</tr class="${css.tr}">
`
if (opts.contractAddress) table.appendChild(contractAddress)
var from = yo`
<tr class="${css.tr}">
<td class="${css.td} ${css.tableTitle}"> from </td>
<td class="${css.td}">${opts.from}</td>
</tr class="${css.tr}">
`
if (opts.from) table.appendChild(from)
var toHash
var data = opts.data // opts.data = data.tx
if (data.to) {
toHash = opts.to + ' ' + data.to
} else {
toHash = opts.to
}
var to = yo`
<tr class="${css.tr}">
<td class="${css.td}"> to </td>
<td class="${css.td}">${toHash}</td>
</tr class="${css.tr}">
`
if (opts.to) table.appendChild(to)
var gas = yo`
<tr class="${css.tr}">
<td class="${css.td}"> gas </td>
<td class="${css.td}">${opts.gas}</td>
</tr class="${css.tr}">
`
if (opts.gas) table.appendChild(gas)
var hash = yo`
<tr class="${css.tr}">
<td class="${css.td}"> hash </td>
<td class="${css.td}">${opts.hash}</td>
</tr class="${css.tr}">
`
if (opts.hash) table.appendChild(hash)
var input = yo`
<tr class="${css.tr}">
<td class="${css.td}"> input </td>
<td class="${css.td}">${opts.input}</td>
</tr class="${css.tr}">
`
if (opts.input) table.appendChild(input)
if (opts['decoded input']) {
var inputDecoded = yo`
<tr class="${css.tr}">
<td class="${css.td}"> decoded input </td>
<td class="${css.td}">${opts['decoded input']}</td>
</tr class="${css.tr}">`
table.appendChild(inputDecoded)
}
var logs = yo`
<tr class="${css.tr}">
<td class="${css.td}"> logs </td>
<td class="${css.td}">${opts.logs || '0'}</td>
</tr class="${css.tr}">
`
if (opts.logs) table.appendChild(logs)
var val = value(opts.val)
val = yo`
<tr class="${css.tr}">
<td class="${css.td}"> value </td>
<td class="${css.td}">${val} wei</td>
</tr class="${css.tr}">
`
if (opts.val) table.appendChild(val)
return table
}

@ -300,7 +300,7 @@ function contractDropdown (appAPI, appEvents, instanceContainer) {
var args = createButtonInput.value
txFormat.buildData(contract, contracts, true, constructor, args, appAPI.udapp(), (error, data) => {
if (!error) {
appAPI.logMessage('transaction added ...')
appAPI.logMessage('Transaction added ...')
txExecution.createContract(data, appAPI.udapp(), (error, txResult) => {
if (!error) {
var isVM = executionContext.isVM()

@ -4,6 +4,7 @@ module.exports = {
return address.slice(0, 5) + '...' + address.slice(len - 5, len) + (etherBalance ? ' (' + etherBalance.toString() + ' ether)' : '')
},
shortenHexData: function (data) {
if (!data) return ''
if (data.length < 5) return data
var len = data.length
return data.slice(0, 5) + '...' + data.slice(len - 5, len)

@ -33,7 +33,7 @@ function runTests (browser) {
.waitForElementPresent('.instance button[title="f - transact (not payable)"]')
.click('.instance button[title="f - transact (not payable)"]')
.waitForElementPresent('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]')
.assert.containsText('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]', '(vm): from:0xca3...a733c, to:0x692...77b3a, browser/Untitled.sol:TestContract.f(), value:0 wei, data:0x261...21ff0, 0 logs, hash:0xa17...523bc,DetailsDebug')
.assert.containsText('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]', '[vm] from:0xca3...a733c, to:browser/Untitled.sol:TestContract.f() 0x692...77b3a, value:0 wei, data:0x261...21ff0, 0 logs, hash:0xa17...523bc')
.end()
/*
@TODO: need to check now the return value of the function

Loading…
Cancel
Save