Began reworking tx conf view

feature/default_network_editable
Dan Finlay 9 years ago
parent 2c89cd722e
commit 7058dc4ee3
  1. 74
      app/images/forward-carrat.svg
  2. 2
      development/states.js
  3. 1
      development/states/confirm_tx.json
  4. 84
      development/states/empty-account-detail.json
  5. 1
      development/states/pending_crash.json
  6. 6
      test/unit/util_test.js
  7. 17
      ui-dev.js
  8. 2
      ui/app/components/account-panel.js
  9. 105
      ui/app/components/mini-account-panel.js
  10. 83
      ui/app/components/pending-tx-details.js
  11. 6
      ui/app/css/lib.css
  12. 1
      ui/app/reducers.js
  13. 14
      ui/app/util.js
  14. 17
      ui/lib/contract-namer.js

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="4.2333331mm"
height="12.800793mm"
viewBox="0 0 14.999999 45.357139"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="forward-carrat.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="17.87049"
inkscape:cy="17.678567"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
showguides="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1276"
inkscape:window-height="755"
inkscape:window-x="4"
inkscape:window-y="1"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid4136"
originx="-180"
originy="-602.14286" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-180,-404.8622)">
<path
style="fill:#f7861c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 180,404.8622 0,7.5 10,15 -10,15 0,7.85714 15,-22.85714 z"
id="path4138"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,84 @@
{
"metamask": {
"isInitialized": true,
"isUnlocked": true,
"currentDomain": "example.com",
"rpcTarget": "https://rawtestrpc.metamask.io/",
"identities": {
"0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {
"name": "Wallet 1",
"address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"mayBeFauceting": false
},
"0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": {
"name": "Wallet 2",
"address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b",
"mayBeFauceting": false
},
"0xeb9e64b93097bc15f01f13eae97015c57ab64823": {
"name": "Wallet 3",
"address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823",
"mayBeFauceting": false
},
"0x704107d04affddd9b66ab9de3dd7b095852e9b69": {
"name": "Wallet 4",
"address": "0x704107d04affddd9b66ab9de3dd7b095852e9b69",
"mayBeFauceting": false
}
},
"unconfTxs": {},
"accounts": {
"0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {
"code": "0x",
"balance": "0x01",
"nonce": "0x0",
"address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
},
"0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": {
"code": "0x",
"nonce": "0x0",
"balance": "0x01",
"address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b"
},
"0xeb9e64b93097bc15f01f13eae97015c57ab64823": {
"code": "0x",
"nonce": "0x0",
"balance": "0x01",
"address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823"
},
"0x704107d04affddd9b66ab9de3dd7b095852e9b69": {
"code": "0x",
"balance": "0x0",
"nonce": "0x0",
"address": "0x704107d04affddd9b66ab9de3dd7b095852e9b69"
}
},
"transactions": [],
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "2",
"seedWords": null,
"isConfirmed": true,
"unconfMsgs": {},
"messages": [],
"provider": {
"type": "testnet"
},
"selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
},
"appState": {
"menuOpen": false,
"currentView": {
"name": "accountDetail",
"detailView": null,
"context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
},
"accountDetail": {
"subview": "transactions"
},
"currentDomain": "127.0.0.1:9966",
"transForward": true,
"isLoading": false,
"warning": null
},
"identities": {}
}

File diff suppressed because one or more lines are too long

@ -52,6 +52,12 @@ describe('util', function() {
var result = util.addressSummary(address) var result = util.addressSummary(address)
assert.equal(result, '0xFDEa65C8...b825') assert.equal(result, '0xFDEa65C8...b825')
}) })
it('should accept arguments for firstseg, lastseg, and keepPrefix', function() {
var address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825'
var result = util.addressSummary(address, 4, 4, false)
assert.equal(result, 'FDEa...b825')
})
}) })
describe('isValidAddress', function() { describe('isValidAddress', function() {

@ -1,3 +1,20 @@
/* UI DEV
*
* This is a utility module.
* It initializes a minimalist browserifiable project
* that contains the Metamask UI, with a mocked state.
*
* Includes a state menu for switching between different
* mocked states, along with query param support,
* so those states are preserved when live-reloading.
*
* This is a convenient way to develop on the UI
* without having to re-enter your password
* every time the plugin rebuilds.
*
* To use, run `npm run ui`.
*/
const render = require('react-dom').render const render = require('react-dom').render
const h = require('react-hyperscript') const h = require('react-hyperscript')
const Root = require('./ui/app/root') const Root = require('./ui/app/root')

@ -22,7 +22,7 @@ AccountPanel.prototype.render = function () {
var panelState = { var panelState = {
key: `accountPanel${identity.address}`, key: `accountPanel${identity.address}`,
identiconKey: identity.address, identiconKey: identity.address,
identiconLabel: identity.name, identiconLabel: identity.name || '',
attributes: [ attributes: [
{ {
key: 'ADDRESS', key: 'ADDRESS',

@ -0,0 +1,105 @@
const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const Identicon = require('./identicon')
const formatBalance = require('../util').formatBalance
const TransactionIcon = require('./transaction-list-item-icon')
module.exports = AccountPanel
inherits(AccountPanel, Component)
function AccountPanel () {
Component.call(this)
}
AccountPanel.prototype.render = function () {
var props = this.props
var picOrder = props.picOrder || 'left'
var isFauceting = props.isFauceting
const { attrs, imageSeed } = props
return (
h('.identity-panel.flex-row.flex-left', {
style: {
cursor: props.onClick ? 'pointer' : undefined,
},
onClick: props.onClick,
}, [
this.genIcon(imageSeed, picOrder),
h('div.flex-column.flex-justify-center', {
style: {
lineHeight: '15px',
order: 2,
display: 'flex',
alignItems: picOrder === 'left' ? 'flex-begin' : 'flex-end',
},
}, [
props.attrs.map((attr) => {
return h('span.font-small', {
key: `mini-${attr}`,
style: {
fontFamily: 'Montserrat UltraLight, Montserrat Light, Montserrat',
},
}, attr)
}),
]),
])
)
}
AccountPanel.prototype.genIcon= function(seed, picOrder) {
const props = this.props
// When there is no seed value, this is a contract creation.
// We then show the contract icon.
if (!seed) {
return h('.identicon-wrapper.flex-column.select-none', {
style: {
order: picOrder === 'left' ? 1 : 3,
},
}, [
h('i.fa.fa-file-text-o.fa-lg', {
style: {
fontSize: '42px',
transform: 'translate(0px, -16px)',
},
})
])
}
// If there was a seed, we return an identicon for that address.
return h('.identicon-wrapper.flex-column.select-none', {
style: {
order: picOrder === 'left' ? 1 : 3,
},
}, [
h(Identicon, {
address: seed,
imageify: props.imageifyIdenticons,
}),
])
}
function balanceOrFaucetingIndication (account, isFauceting) {
// Temporarily deactivating isFauceting indication
// because it shows fauceting for empty restored accounts.
if (/* isFauceting*/ false) {
return {
key: 'Account is auto-funding.',
value: 'Please wait.',
}
} else {
return {
key: 'BALANCE',
value: formatBalance(account.balance),
}
}
}

@ -2,10 +2,11 @@ const Component = require('react').Component
const h = require('react-hyperscript') const h = require('react-hyperscript')
const inherits = require('util').inherits const inherits = require('util').inherits
const AccountPanel = require('./account-panel') const MiniAccountPanel = require('./mini-account-panel')
const addressSummary = require('../util').addressSummary const addressSummary = require('../util').addressSummary
const readableDate = require('../util').readableDate const readableDate = require('../util').readableDate
const formatBalance = require('../util').formatBalance const formatBalance = require('../util').formatBalance
const nameForAddress = require('../../lib/contract-namer')
module.exports = PendingTxDetails module.exports = PendingTxDetails
@ -14,12 +15,10 @@ function PendingTxDetails () {
Component.call(this) Component.call(this)
} }
PendingTxDetails.prototype.render = function () { const PTXP = PendingTxDetails.prototype
var state = this.props
return this.renderGeneric(h, state)
}
PendingTxDetails.prototype.renderGeneric = function (h, state) { PTXP.render = function () {
var state = this.props
var txData = state.txData var txData = state.txData
var txParams = txData.txParams || {} var txParams = txData.txParams || {}
@ -27,17 +26,39 @@ PendingTxDetails.prototype.renderGeneric = function (h, state) {
var identity = state.identities[address] || { address: address } var identity = state.identities[address] || { address: address }
var account = state.accounts[address] || { address: address } var account = state.accounts[address] || { address: address }
return ( var isContractDeploy = !('to' in txParams)
return (
h('div', [ h('div', [
// account that will sign h('.flex-row.flex-center', {
h(AccountPanel, { style: {
showFullAddress: true, maxWidth: '100%',
identity: identity, },
account: account, }, [
imageifyIdenticons: state.imageifyIdenticons,
}), h(MiniAccountPanel, {
attrs: [
identity.name,
addressSummary(address, 6, 4, false),
formatBalance(identity.balance),
],
imageSeed: address,
imageifyIdenticons: state.imageifyIdenticons,
picOrder: 'right',
}),
h('img', {
src: 'images/forward-carrat.svg',
style: {
padding: '5px 6px 0px 10px',
height: '48px',
},
}),
this.miniAccountPanelForRecipient(),
]),
// tx data // tx data
h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [ h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [
@ -59,7 +80,39 @@ PendingTxDetails.prototype.renderGeneric = function (h, state) {
]), ]),
]) ])
) )
}
PTXP.miniAccountPanelForRecipient = function() {
var state = this.props
var txData = state.txData
var txParams = txData.txParams || {}
var address = txParams.from || state.selectedAddress
var identity = state.identities[address] || { address: address }
var account = state.accounts[address] || { address: address }
var isContractDeploy = !('to' in txParams)
// If it's not a contract deploy, send to the account
if (!isContractDeploy) {
return h(MiniAccountPanel, {
attrs: [
nameForAddress(txParams.to),
addressSummary(txParams.to, 6, 4, false),
],
imageSeed: address,
imageifyIdenticons: state.imageifyIdenticons,
picOrder: 'left',
})
} else {
return h(MiniAccountPanel, {
attrs: [
'New Contract'
],
imageifyIdenticons: state.imageifyIdenticons,
picOrder: 'left',
})
}
} }

@ -220,3 +220,9 @@ hr.horizontal-line {
.invisible { .invisible {
visibility: hidden; visibility: hidden;
} }
.one-line-concat {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

@ -35,6 +35,7 @@ function rootReducer (state, action) {
state.appState = reduceApp(state, action) state.appState = reduceApp(state, action)
console.log(JSON.stringify(state))
return state return state
} }

@ -21,6 +21,7 @@ for (var currency in valueTable) {
module.exports = { module.exports = {
valuesFor: valuesFor, valuesFor: valuesFor,
addressSummary: addressSummary, addressSummary: addressSummary,
miniAddressSummary: miniAddressSummary,
isAllOneCase: isAllOneCase, isAllOneCase: isAllOneCase,
isValidAddress: isValidAddress, isValidAddress: isValidAddress,
numericBalance: numericBalance, numericBalance: numericBalance,
@ -43,10 +44,19 @@ function valuesFor (obj) {
.map(function (key) { return obj[key] }) .map(function (key) { return obj[key] })
} }
function addressSummary (address) { function addressSummary (address, firstSegLength = 10, lastSegLength = 4, includeHex = true) {
if (!address) return ''
let checked = ethUtil.toChecksumAddress(address)
if (!includeHex) {
checked = ethUtil.stripHexPrefix(checked)
}
return checked ? checked.slice(0, firstSegLength) + '...' + checked.slice(checked.length - lastSegLength) : '...'
}
function miniAddressSummary (address) {
if (!address) return '' if (!address) return ''
var checked = ethUtil.toChecksumAddress(address) var checked = ethUtil.toChecksumAddress(address)
return checked ? checked.slice(0, 2 + 8) + '...' + checked.slice(-4) : '...' return checked ? checked.slice(0, 4) + '...' + checked.slice(-4) : '...'
} }
function isValidAddress (address) { function isValidAddress (address) {

@ -0,0 +1,17 @@
/* CONTRACT NAMER
*
* Takes an address,
* Returns a nicname if we have one stored,
* otherwise returns null.
*/
const nicknames = {}
module.exports = function(address) {
if (address in nicknames) {
return nicknames[address]
}
return null
}
Loading…
Cancel
Save