1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Merge pull request #220 from MetaMask/FixTransactionBackButton

SignTransaction return button broken
This commit is contained in:
kumavis 2016-05-25 18:08:21 -07:00
commit 7c7fa23374
9 changed files with 225 additions and 178 deletions

View File

@ -3,6 +3,8 @@
## Current Master ## Current Master
- Added copy address button to account list. - Added copy address button to account list.
- Fixed back button on confirm transaction screen.
- Add indication of pending transactions to account list screen.
- Fixed bug where error warning was sometimes not cleared on view transition. - Fixed bug where error warning was sometimes not cleared on view transition.
## 2.0.0 2016-05-23 ## 2.0.0 2016-05-23

View File

@ -7,10 +7,11 @@ const copyToClipboard = require('copy-to-clipboard')
const actions = require('./actions') const actions = require('./actions')
const addressSummary = require('./util').addressSummary const addressSummary = require('./util').addressSummary
const ReactCSSTransitionGroup = require('react-addons-css-transition-group') const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
const valuesFor = require('./util').valuesFor
const Identicon = require('./components/identicon') const Identicon = require('./components/identicon')
const EtherBalance = require('./components/eth-balance') const EtherBalance = require('./components/eth-balance')
const transactionList = require('./components/transaction-list') const TransactionList = require('./components/transaction-list')
const ExportAccountView = require('./components/account-export') const ExportAccountView = require('./components/account-export')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const EditableLabel = require('./components/editable-label') const EditableLabel = require('./components/editable-label')
@ -24,7 +25,9 @@ function mapStateToProps(state) {
address: state.metamask.selectedAccount, address: state.metamask.selectedAccount,
accountDetail: state.appState.accountDetail, accountDetail: state.appState.accountDetail,
transactions: state.metamask.transactions, transactions: state.metamask.transactions,
networkVersion: state.metamask.network, network: state.metamask.network,
unconfTxs: valuesFor(state.metamask.unconfTxs),
unconfMsgs: valuesFor(state.metamask.unconfMsgs),
} }
} }
@ -139,7 +142,7 @@ AccountDetailScreen.prototype.render = function() {
}), }),
h('button', { h('button', {
onClick: () => this.props.dispatch(actions.showSendPage()), onClick: () => props.dispatch(actions.showSendPage()),
style: { style: {
margin: 10, margin: 10,
}, },
@ -183,18 +186,22 @@ AccountDetailScreen.prototype.subview = function() {
} }
AccountDetailScreen.prototype.transactionList = function() { AccountDetailScreen.prototype.transactionList = function() {
var state = this.props const { transactions, unconfTxs, unconfMsgs, address, network } = this.props
var transactions = state.transactions
var txsToRender = transactions var txsToRender = transactions
// only transactions that are from the current address // only transactions that are from the current address
.filter(tx => tx.txParams.from === state.address) .filter(tx => tx.txParams.from === address)
// only transactions that are on the current network // only transactions that are on the current network
.filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion) .filter(tx => tx.txParams.metamaskNetworkId === network)
// sort by recency // sort by recency
.sort((a, b) => b.time - a.time) .sort((a, b) => b.time - a.time)
return transactionList(txsToRender, state.networkVersion) return h(TransactionList, {
txsToRender,
network,
unconfTxs,
unconfMsgs,
})
} }
AccountDetailScreen.prototype.navigateToAccounts = function(event){ AccountDetailScreen.prototype.navigateToAccounts = function(event){

View File

@ -34,6 +34,7 @@ NewComponent.prototype.render = function() {
}, [ }, [
h('.identicon-wrapper.flex-column.flex-center.select-none', [ h('.identicon-wrapper.flex-column.flex-center.select-none', [
this.pendingOrNot(),
h(Identicon, { h(Identicon, {
address: identity.address address: identity.address
}), }),
@ -61,3 +62,9 @@ NewComponent.prototype.render = function() {
]) ])
) )
} }
NewComponent.prototype.pendingOrNot = function() {
const pending = this.props.pending
if (pending.length === 0) return null
return h('.pending-dot', pending.length)
}

View File

@ -12,6 +12,10 @@ module.exports = connect(mapStateToProps)(AccountsScreen)
function mapStateToProps(state) { function mapStateToProps(state) {
const pendingTxs = valuesFor(state.metamask.unconfTxs)
const pendingMsgs = valuesFor(state.metamask.unconfMsgs)
const pending = pendingTxs.concat(pendingMsgs)
return { return {
accounts: state.metamask.accounts, accounts: state.metamask.accounts,
identities: state.metamask.identities, identities: state.metamask.identities,
@ -19,6 +23,7 @@ function mapStateToProps(state) {
selectedAddress: state.metamask.selectedAddress, selectedAddress: state.metamask.selectedAddress,
currentDomain: state.appState.currentDomain, currentDomain: state.appState.currentDomain,
scrollToBottom: state.appState.scrollToBottom, scrollToBottom: state.appState.scrollToBottom,
pending,
} }
} }
@ -62,12 +67,23 @@ AccountsScreen.prototype.render = function() {
}, },
[ [
identityList.map((identity) => { identityList.map((identity) => {
const pending = this.props.pending.filter((txOrMsg) => {
if ('txParams' in txOrMsg) {
return txOrMsg.txParams.from === identity.address
} else if ('msgParams' in txOrMsg) {
return txOrMsg.msgParams.from === identity.address
} else {
return false
}
})
return h(AccountPanel, { return h(AccountPanel, {
key: `acct-panel-${identity.address}`, key: `acct-panel-${identity.address}`,
identity, identity,
selectedAddress: this.props.selectedAddress, selectedAddress: this.props.selectedAddress,
accounts: this.props.accounts, accounts: this.props.accounts,
onShowDetail: this.onShowDetail.bind(this), onShowDetail: this.onShowDetail.bind(this),
pending,
}) })
}), }),

View File

@ -86,43 +86,6 @@ App.prototype.render = function() {
this.renderPrimary(), this.renderPrimary(),
]), ]),
]), ]),
// footer
// h('.app-footer.flex-row.flex-space-around', {
// style: {
// display: shouldHaveFooter ? 'flex' : 'none',
// alignItems: 'center',
// height: '56px',
// }
// }, [
// // settings icon
// h('i.fa.fa-cog.fa-lg' + (view === 'config' ? '.active' : '.cursor-pointer'), {
// style: {
// opacity: state.isUnlocked ? '1.0' : '0.0',
// transition: 'opacity 200ms ease-in',
// //transform: `translateX(${state.isUnlocked ? '0px' : '-100px'})`,
// },
// onClick: function(ev) {
// state.dispatch(actions.showConfigPage())
// },
// }),
// // toggle
// onOffToggle({
// toggleMetamaskActive: this.toggleMetamaskActive.bind(this),
// isUnlocked: state.isUnlocked,
// }),
// // help
// h('i.fa.fa-question.fa-lg.cursor-pointer', {
// style: {
// opacity: state.isUnlocked ? '1.0' : '0.0',
// },
// onClick() { state.dispatch(actions.showInfoPage()) }
// }),
// ]),
]) ])
) )
} }
@ -276,11 +239,7 @@ App.prototype.renderPrimary = function(){
return h(CreateVaultScreen, {key: 'createVault'}) return h(CreateVaultScreen, {key: 'createVault'})
default: default:
if (this.hasPendingTxs()) { return h(AccountDetailScreen, {key: 'account-detail'})
return h(ConfirmTxScreen, {key: 'confirm-tx'})
} else {
return h(AccountDetailScreen, {key: 'account-detail'})
}
} }
} }
@ -296,14 +255,6 @@ App.prototype.toggleMetamaskActive = function(){
} }
} }
App.prototype.hasPendingTxs = function() {
var state = this.props
var unconfTxs = state.unconfTxs
var unconfMsgs = state.unconfMsgs
var unconfTxList = txHelper(unconfTxs, unconfMsgs)
return unconfTxList.length > 0
}
function onOffToggle(state){ function onOffToggle(state){
var buttonSize = '50px'; var buttonSize = '50px';
var lockWidth = '20px'; var lockWidth = '20px';

View File

@ -0,0 +1,126 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const Identicon = require('./identicon')
const EtherBalance = require('./eth-balance')
const addressSummary = require('../util').addressSummary
const explorerLink = require('../../lib/explorer-link')
const formatBalance = require('../util').formatBalance
const vreme = new (require('vreme'))
module.exports = TransactionListItem
inherits(TransactionListItem, Component)
function TransactionListItem() {
Component.call(this)
}
TransactionListItem.prototype.render = function() {
const { transaction, i } = this.props
var date = formatDate(transaction.time)
var isMsg = ('msgParams' in transaction)
var isTx = ('txParams' in transaction)
var txParams = transaction.txParams
return (
h(`.transaction-list-item.flex-row.flex-space-between${transaction.hash ? '.pointer' : ''}`, {
key: `tx-${transaction.id + i}`,
onClick: (event) => {
if (!transaction.hash) return
var url = explorerLink(transaction.hash, parseInt(network))
chrome.tabs.create({ url })
},
style: {
padding: '20px 0',
},
}, [
// large identicon
h('.identicon-wrapper.flex-column.flex-center.select-none', [
identicon(txParams, transaction),
]),
h('.flex-column', [
h('div', date),
recipientField(txParams, transaction),
]),
h(EtherBalance, {
value: txParams.value,
}),
])
)
}
function recipientField(txParams, transaction) {
if (txParams.to) {
return h('div', {
style: {
fontSize: 'small',
color: '#ABA9AA',
},
}, [
addressSummary(txParams.to),
failIfFailed(transaction),
])
} else {
return h('div', {
style: {
fontSize: 'small',
color: '#ABA9AA',
},
},[
'Contract Published',
failIfFailed(transaction),
])
}
}
TransactionListItem.prototype.renderMessage = function() {
const { transaction, i } = this.props
return h('div', 'wowie, thats a message')
}
function formatDate(date){
return vreme.format(new Date(date), 'March 16 2014 14:30')
}
function identicon(txParams, transaction) {
if (transaction.status === 'rejected') {
return h('i.fa.fa-exclamation-triangle.fa-lg.error', {
style: {
width: '24px',
}
})
}
if (txParams.to) {
return h(Identicon, {
diameter: 24,
address: txParams.to || transaction.hash,
})
} else {
return h('i.fa.fa-file-text-o.fa-lg', {
style: {
width: '24px',
}
})
}
}
function failIfFailed(transaction) {
if (transaction.status === 'rejected') {
return h('span.error', ' (Failed)')
}
}

View File

@ -1,14 +1,21 @@
const Component = require('react').Component
const h = require('react-hyperscript') const h = require('react-hyperscript')
const vreme = new (require('vreme')) const inherits = require('util').inherits
const formatBalance = require('../util').formatBalance
const addressSummary = require('../util').addressSummary const TransactionListItem = require('./transaction-list-item')
const explorerLink = require('../../lib/explorer-link')
const Panel = require('./panel') module.exports = TransactionList
const Identicon = require('./identicon')
const EtherBalance = require('./eth-balance')
module.exports = function(transactions, network) { inherits(TransactionList, Component)
function TransactionList() {
Component.call(this)
}
TransactionList.prototype.render = function() {
const { txsToRender, network, unconfTxs, unconfMsgs } = this.props
const transactions = txsToRender
return ( return (
h('section.transaction-list', [ h('section.transaction-list', [
@ -42,118 +49,19 @@ module.exports = function(transactions, network) {
}, ( }, (
transactions.length ? transactions.length ?
transactions.map(renderTransaction) transactions.map((transaction, i) => {
return h(TransactionListItem, {
transaction, i
})
})
: :
[h('.flex-center', { [h('.flex-center', {
style: { style: {
height: '100%', height: '100%',
}, },
}, 'No transaction history...')] }, 'No transaction history...')]
)) ))
]) ])
) )
function renderTransaction(transaction, i){
var txParams = transaction.txParams
var date = formatDate(transaction.time)
return (
h(`.transaction-list-item.flex-row.flex-space-between${transaction.hash ? '.pointer' : ''}`, {
key: `tx-${transaction.id + i}`,
onClick: (event) => {
if (!transaction.hash) return
var url = explorerLink(transaction.hash, parseInt(network))
chrome.tabs.create({ url })
},
style: {
padding: '20px 0',
},
}, [
// large identicon
h('.identicon-wrapper.flex-column.flex-center.select-none', [
identicon(txParams, transaction),
]),
h('.flex-column', [
h('div', date),
recipientField(txParams, transaction),
]),
h(EtherBalance, {
value: txParams.value,
}),
])
)
}
} }
function recipientField(txParams, transaction) {
if (txParams.to) {
return h('div', {
style: {
fontSize: 'small',
color: '#ABA9AA',
},
}, [
addressSummary(txParams.to),
failIfFailed(transaction),
])
} else {
return h('div', {
style: {
fontSize: 'small',
color: '#ABA9AA',
},
},[
'Contract Published',
failIfFailed(transaction),
])
}
}
function formatDate(date){
return vreme.format(new Date(date), 'March 16 2014 14:30')
}
function identicon(txParams, transaction) {
if (transaction.status === 'rejected') {
return h('i.fa.fa-exclamation-triangle.fa-lg.error', {
style: {
width: '24px',
}
})
}
if (txParams.to) {
return h(Identicon, {
diameter: 24,
address: txParams.to || transaction.hash,
})
} else {
return h('i.fa.fa-file-text-o.fa-lg', {
style: {
width: '24px',
}
})
}
}
function failIfFailed(transaction) {
if (transaction.status === 'rejected') {
return h('span.error', ' (Failed)')
}
}

View File

@ -166,3 +166,17 @@ hr.horizontal-line {
.hover-white:hover { .hover-white:hover {
background: white; background: white;
} }
.pending-dot {
background: red;
left: 57px;
color: white;
border-radius: 10px;
height: 20px;
min-width: 20px;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
padding: 4px;
}

View File

@ -9,8 +9,17 @@ function reduceApp(state, action) {
// clone and defaults // clone and defaults
const selectedAccount = state.metamask.selectedAccount const selectedAccount = state.metamask.selectedAccount
const pendingTxs = hasPendingTxs(state)
let name = 'accounts'
if (selectedAccount) {
defaultView = 'accountDetail'
}
if (pendingTxs) {
defaultView = 'confTx'
}
var defaultView = { var defaultView = {
name: selectedAccount ? 'accountDetail' : 'accounts', name,
detailView: null, detailView: null,
context: selectedAccount, context: selectedAccount,
} }
@ -122,7 +131,6 @@ function reduceApp(state, action) {
case actions.UNLOCK_METAMASK: case actions.UNLOCK_METAMASK:
return extend(appState, { return extend(appState, {
currentView: {},
detailView: {}, detailView: {},
transForward: true, transForward: true,
isLoading: false, isLoading: false,
@ -145,7 +153,9 @@ function reduceApp(state, action) {
case actions.GO_HOME: case actions.GO_HOME:
return extend(appState, { return extend(appState, {
currentView: {}, currentView: extend(appState.currentView, {
name: 'accountDetail',
}),
accountDetail: { accountDetail: {
subview: 'transactions', subview: 'transactions',
accountExport: 'none', accountExport: 'none',
@ -347,6 +357,12 @@ function reduceApp(state, action) {
default: default:
return appState return appState
} }
} }
function hasPendingTxs (state) {
var unconfTxs = state.metamask.unconfTxs
var unconfMsgs = state.metamask.unconfMsgs
var unconfTxList = txHelper(unconfTxs, unconfMsgs)
return unconfTxList.length > 0
}