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

Merge pull request #224 from MetaMask/PendingTxList

Add pending txs to tx list
This commit is contained in:
Dan Finlay 2016-05-26 15:19:07 -07:00
commit f1fb7ff42c
10 changed files with 175 additions and 62 deletions

View File

@ -2,6 +2,9 @@
## Current Master
- Added pending transactions to transaction list on account screen.
- Clicking a pending transaction takes you back to the transaction approval screen.
## 2.1.0 2016-05-26
- Added copy address button to account list.

View File

@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "Metamask",
"version": "2.0.1",
"version": "2.1.0",
"manifest_version": 2,
"description": "__MSG_appDescription__",
"icons": {

View File

@ -201,6 +201,9 @@ AccountDetailScreen.prototype.transactionList = function() {
network,
unconfTxs,
unconfMsgs,
viewPendingTx:(txId) => {
this.props.dispatch(actions.viewPendingTx(txId))
}
})
}

View File

@ -76,6 +76,8 @@ var actions = {
txError: txError,
nextTx: nextTx,
previousTx: previousTx,
viewPendingTx: viewPendingTx,
VIEW_PENDING_TX: 'VIEW_PENDING_TX',
// app messages
showAccountDetail: showAccountDetail,
BACK_TO_ACCOUNT_DETAIL: 'BACK_TO_ACCOUNT_DETAIL',
@ -387,6 +389,13 @@ function nextTx() {
}
}
function viewPendingTx(txId) {
return {
type: actions.VIEW_PENDING_TX,
value: txId,
}
}
function previousTx() {
return {
type: actions.PREVIOUS_TX,

View File

@ -0,0 +1,46 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const Identicon = require('./identicon')
module.exports = TransactionIcon
inherits(TransactionIcon, Component)
function TransactionIcon() {
Component.call(this)
}
TransactionIcon.prototype.render = function() {
const { transaction, txParams, isTx, isMsg } = this.props
if (transaction.status === 'rejected') {
return h('i.fa.fa-exclamation-triangle.fa-lg.error', {
style: {
width: '24px',
}
})
}
if (isMsg) {
return h('i.fa.fa-certificate.fa-lg', {
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',
}
})
}
}

View File

@ -2,13 +2,14 @@ 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'))
const TransactionIcon = require('./transaction-list-item-icon')
module.exports = TransactionListItem
@ -18,20 +19,36 @@ function TransactionListItem() {
}
TransactionListItem.prototype.render = function() {
const { transaction, i } = this.props
const { transaction, i, network } = this.props
var date = formatDate(transaction.time)
let isLinkable = false
const numericNet = parseInt(network)
isLinkable = numericNet === 1 || numericNet === 2
var isMsg = ('msgParams' in transaction)
var isTx = ('txParams' in transaction)
var isPending = transaction.status === 'unconfirmed'
var txParams = transaction.txParams
let txParams
if (isTx) {
txParams = transaction.txParams
} else if (isMsg) {
txParams = transaction.msgParams
}
const isClickable = ('hash' in transaction && isLinkable) || isPending
return (
h(`.transaction-list-item.flex-row.flex-space-between${transaction.hash ? '.pointer' : ''}`, {
h(`.transaction-list-item.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, {
key: `tx-${transaction.id + i}`,
onClick: (event) => {
if (!transaction.hash) return
if (isPending) {
this.props.showTx(transaction.id)
}
if (!transaction.hash || !isLinkable) return
var url = explorerLink(transaction.hash, parseInt(network))
chrome.tabs.create({ url })
},
@ -42,38 +59,44 @@ TransactionListItem.prototype.render = function() {
// large identicon
h('.identicon-wrapper.flex-column.flex-center.select-none', [
identicon(txParams, transaction),
transaction.status === 'unconfirmed' ? h('.red-dot', ' ') :
h(TransactionIcon, { txParams, transaction, isTx, isMsg }),
]),
h('.flex-column', [
domainField(txParams),
h('div', date),
recipientField(txParams, transaction),
recipientField(txParams, transaction, isTx, isMsg),
]),
h(EtherBalance, {
isTx ? h(EtherBalance, {
value: txParams.value,
}),
}) : h('.flex-column'),
])
)
}
function recipientField(txParams, transaction) {
if (txParams.to) {
function domainField(txParams) {
return h('div', {
style: {
fontSize: 'small',
color: '#ABA9AA',
},
}, [
addressSummary(txParams.to),
failIfFailed(transaction),
},[
txParams.origin,
])
}
function recipientField(txParams, transaction, isTx, isMsg) {
let message
if (isMsg) {
message = 'Signature Requested'
} else if (txParams.to) {
message = addressSummary(txParams.to)
} else {
message = 'Contract Published'
}
return h('div', {
style: {
@ -81,14 +104,14 @@ function recipientField(txParams, transaction) {
color: '#ABA9AA',
},
},[
'Contract Published',
message,
failIfFailed(transaction),
])
}
}
TransactionListItem.prototype.renderMessage = function() {
const { transaction, i } = this.props
const { transaction, i, network } = this.props
return h('div', 'wowie, thats a message')
}
@ -96,31 +119,11 @@ 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', ' (Rejected)')
}
if (transaction.status === 'failed') {
return h('span.error', ' (Failed)')
}
}

View File

@ -14,7 +14,8 @@ function TransactionList() {
TransactionList.prototype.render = function() {
const { txsToRender, network, unconfTxs, unconfMsgs } = this.props
const transactions = txsToRender
const transactions = txsToRender.concat(unconfMsgs)
.sort((a, b) => b.time - a.time)
return (
@ -51,7 +52,10 @@ TransactionList.prototype.render = function() {
transactions.length ?
transactions.map((transaction, i) => {
return h(TransactionListItem, {
transaction, i
transaction, i, network,
showTx:(txId) => {
this.props.viewPendingTx(txId)
},
})
})
:

View File

@ -296,6 +296,8 @@ input.large-input {
.identity-panel .identicon-wrapper {
margin: 4px;
margin-top: 8px;
display: flex;
align-items: center;
}
.identity-panel .identicon-wrapper span {

View File

@ -167,6 +167,20 @@ hr.horizontal-line {
background: white;
}
.red-dot {
position: inherit;
background: red;
color: white;
border-radius: 10px;
height: 12px;
min-width: 12px;
margin-left: 6px;
display: flex;
align-items: center;
justify-content: center;
padding: 4px;
}
.pending-dot {
background: red;
left: 57px;
@ -180,3 +194,8 @@ hr.horizontal-line {
justify-content: center;
padding: 4px;
}
.ether-balance {
display: flex;
align-items: center;
}

View File

@ -12,10 +12,10 @@ function reduceApp(state, action) {
const pendingTxs = hasPendingTxs(state)
let name = 'accounts'
if (selectedAccount) {
defaultView = 'accountDetail'
name = 'accountDetail'
}
if (pendingTxs) {
defaultView = 'confTx'
name = 'confTx'
}
var defaultView = {
@ -270,6 +270,17 @@ function reduceApp(state, action) {
}
})
case actions.VIEW_PENDING_TX:
const context = indexForPending(state, action.value)
return extend(appState, {
transForward: true,
currentView: {
name: 'confTx',
context,
warning: null,
}
})
case actions.PREVIOUS_TX:
return extend(appState, {
transForward: false,
@ -366,3 +377,16 @@ function hasPendingTxs (state) {
var unconfTxList = txHelper(unconfTxs, unconfMsgs)
return unconfTxList.length > 0
}
function indexForPending(state, txId) {
var unconfTxs = state.metamask.unconfTxs
var unconfMsgs = state.metamask.unconfMsgs
var unconfTxList = txHelper(unconfTxs, unconfMsgs)
let idx
unconfTxList.forEach((tx, i) => {
if (tx.id === txId) {
idx = i
}
})
return idx
}