From 7389f9d0a0e1f798607ea8eea25583f8af854358 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 18 Aug 2016 15:40:56 -0700 Subject: [PATCH 1/9] Enforce tx history limit --- app/scripts/lib/config-manager.js | 6 ++++++ test/unit/config-manager-test.js | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js index c56f52e48..2ecdbb0c7 100644 --- a/app/scripts/lib/config-manager.js +++ b/app/scripts/lib/config-manager.js @@ -5,6 +5,7 @@ const rp = require('request-promise') const TESTNET_RPC = MetamaskConfig.network.testnet const MAINNET_RPC = MetamaskConfig.network.mainnet +const txLimit = 40 /* The config-manager is a convenience object * wrapping a pojo-migrator. @@ -15,6 +16,8 @@ const MAINNET_RPC = MetamaskConfig.network.mainnet */ module.exports = ConfigManager function ConfigManager (opts) { + this.txLimit = txLimit + // ConfigManager is observable and will emit updates this._subs = [] @@ -181,6 +184,9 @@ ConfigManager.prototype._saveTxList = function (txList) { ConfigManager.prototype.addTx = function (tx) { var transactions = this.getTxList() + while (transactions.length > this.txLimit - 1) { + transactions.shift() + } transactions.push(tx) this._saveTxList(transactions) } diff --git a/test/unit/config-manager-test.js b/test/unit/config-manager-test.js index b34089163..eaa5376fd 100644 --- a/test/unit/config-manager-test.js +++ b/test/unit/config-manager-test.js @@ -233,6 +233,17 @@ describe('config-manager', function() { assert.equal(result.length, 1) assert.equal(result[0].id, 1) }) + + it('cuts off early txs beyond a limit', function() { + const limit = configManager.txLimit + for (let i = 0; i < limit + 1; i++) { + let tx = { id: i } + configManager.addTx(tx) + } + var result = configManager.getTxList() + assert.equal(result.length, limit, `limit of ${limit} txs enforced`) + assert.equal(result[0].id, 1, 'early txs truncted') + }) }) describe('#confirmTx', function() { From bd9d89826c2bbd6e91a088040b7708de89658d1a Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 18 Aug 2016 16:23:12 -0700 Subject: [PATCH 2/9] Added `view more` button to transaction list Visible at the end of the transaction list, or if no transactions are listed, displayed right after the `No Transactions` message. --- CHANGELOG.md | 2 ++ test/unit/account-link-test.js | 12 ++++++++++ ui/app/account-detail.js | 1 + ui/app/components/transaction-list.js | 33 +++++++++++++++++++++------ ui/lib/account-link.js | 18 +++++++++++++++ 5 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 test/unit/account-link-test.js create mode 100644 ui/lib/account-link.js diff --git a/CHANGELOG.md b/CHANGELOG.md index b7833e9d1..1c5c457b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## Current Master - Added feature to reflect current conversion rates of current vault balance. +- Transaction history now has a hard limit. +- Added a link to view more account info after transaction history. ## 2.8.0 2016-08-15 diff --git a/test/unit/account-link-test.js b/test/unit/account-link-test.js new file mode 100644 index 000000000..39889b6be --- /dev/null +++ b/test/unit/account-link-test.js @@ -0,0 +1,12 @@ +var assert = require('assert') +var linkGen = require('../../ui/lib/account-link') + +describe('account-link', function() { + + it('adds testnet prefix to morden test network', function() { + var result = linkGen('account', '2') + assert.notEqual(result.indexOf('testnet'), -1, 'testnet injected') + assert.notEqual(result.indexOf('account'), -1, 'account included') + }) + +}) diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 2c98af0dd..cafc03503 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -248,6 +248,7 @@ AccountDetailScreen.prototype.transactionList = function () { network, unconfTxs, unconfMsgs, + address, viewPendingTx: (txId) => { this.props.dispatch(actions.viewPendingTx(txId)) }, diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 886aa7c00..eae1965ff 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -1,6 +1,8 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits +const genAccountLink = require('../../lib/account-link') +const extension = require('../../../app/scripts/lib/extension') const TransactionListItem = require('./transaction-list-item') @@ -13,9 +15,10 @@ function TransactionList () { } TransactionList.prototype.render = function () { - const { txsToRender, network, unconfMsgs } = this.props + const { txsToRender, network, unconfMsgs, address } = this.props const transactions = txsToRender.concat(unconfMsgs) .sort((a, b) => b.time - a.time) + const accountLink = genAccountLink(address, network) return ( @@ -45,11 +48,11 @@ TransactionList.prototype.render = function () { h('.tx-list', { style: { overflowY: 'auto', - height: '305px', + height: '300px', padding: '0 20px', textAlign: 'center', }, - }, ( + }, [ transactions.length ? transactions.map((transaction, i) => { @@ -59,13 +62,29 @@ TransactionList.prototype.render = function () { this.props.viewPendingTx(txId) }, }) - }) - : [h('.flex-center', { + }).concat(viewMoreButton(accountLink)) + : h('.flex-center', { style: { + flexDirection: 'column', height: '100%', }, - }, 'No transaction history...')] - )), + }, [ + 'No transaction history.', + viewMoreButton(accountLink), + ]), + ]), ]) ) } + +function viewMoreButton(url) { + return url ? h('button', { + style: { + margin: '10px', + }, + onClick: (ev) => { + ev.preventDefault() + extension.tabs.create({ url }) + } + }, 'View More') : null +} diff --git a/ui/lib/account-link.js b/ui/lib/account-link.js new file mode 100644 index 000000000..eb958e22d --- /dev/null +++ b/ui/lib/account-link.js @@ -0,0 +1,18 @@ +module.exports = function(address, network) { + const net = parseInt(network) + let link + + switch (net) { + case 1: // main net + link = `http://etherscan.io/address/${address}` + break + case 2: // morden test net + link = `http://testnet.etherscan.io/address/${address}` + break + default: + link = '' + break + } + + return link +} From 4f857e297b2309a8056b6c33cc7eef67e3c2b2f8 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 18 Aug 2016 16:27:25 -0700 Subject: [PATCH 3/9] Linted --- ui/app/components/transaction-list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index eae1965ff..fbe4d41a8 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -85,6 +85,6 @@ function viewMoreButton(url) { onClick: (ev) => { ev.preventDefault() extension.tabs.create({ url }) - } + }, }, 'View More') : null } From fe5fff3248bd40803db3b9f3553728d9693e740d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 18 Aug 2016 17:47:42 -0700 Subject: [PATCH 4/9] Change 'View More' to 'Show More' --- ui/app/components/transaction-list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index fbe4d41a8..85744381d 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -86,5 +86,5 @@ function viewMoreButton(url) { ev.preventDefault() extension.tabs.create({ url }) }, - }, 'View More') : null + }, 'Show More') : null } From c223ba2e00ff80913c5b1fe3a339167d4489ec6a Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 22 Aug 2016 11:59:26 -0700 Subject: [PATCH 5/9] Add builds.zip to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 689cc3240..fa8a9151f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ builds/ notes.txt app/.DS_Store development/bundle.js +builds.zip From f57cbe59fc9e0d3cfb3ee54da749470248fe2b8b Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 22 Aug 2016 14:36:21 -0700 Subject: [PATCH 6/9] Removed view more button, added account info button. Also: - Also fixed bug that caused React warning when rendering the tx history. - Renamed 'Transactions' to 'History', since it now has more than that. --- CHANGELOG.md | 5 +-- ui/app/account-detail.js | 14 +++++--- ui/app/components/account-info-link.js | 42 ++++++++++++++++++++++ ui/app/components/shift-list-item.js | 4 +++ ui/app/components/transaction-list-item.js | 1 - ui/app/components/transaction-list.js | 28 +++++++-------- 6 files changed, 70 insertions(+), 24 deletions(-) create mode 100644 ui/app/components/account-info-link.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 23d5b3af3..95f9174eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,14 @@ ## Current Master +- Transaction history now has a hard limit. +- Added info link on account screen that visits Etherscan. + ## 2.9.0 2016-08-22 - Added ShapeShift to the transaction history - Added affiliate key to Shapeshift requests - Added feature to reflect current conversion rates of current vault balance. -- Transaction history now has a hard limit. -- Added a link to view more account info after transaction history. - Modify balance display logic. ## 2.8.0 2016-08-15 diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index e00a34c4a..4316ff54e 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -4,6 +4,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect const CopyButton = require('./components/copyButton') +const AccountInfoLink = require('./components/account-info-link') const actions = require('./actions') const ReactCSSTransitionGroup = require('react-addons-css-transition-group') const valuesFor = require('./util').valuesFor @@ -44,6 +45,7 @@ AccountDetailScreen.prototype.render = function () { var selected = props.address || Object.keys(props.accounts)[0] var identity = props.identities[selected] var account = props.accounts[selected] + const { network } = props return ( @@ -127,6 +129,9 @@ AccountDetailScreen.prototype.render = function () { bottom: '15px', }, }, [ + + h(AccountInfoLink, { selected, network }), + h(CopyButton, { value: ethUtil.toChecksumAddress(selected), }), @@ -136,16 +141,15 @@ AccountDetailScreen.prototype.render = function () { }, [ h('div', { style: { - margin: '5px', - }, + display: 'flex', + alignItems: 'center', + } }, [ h('img.cursor-pointer.color-orange', { src: 'images/key-32.png', onClick: () => this.requestAccountExport(selected), style: { - margin: '0px 5px', - width: '20px', - height: '20px', + height: '19px', }, }), ]), diff --git a/ui/app/components/account-info-link.js b/ui/app/components/account-info-link.js new file mode 100644 index 000000000..4fe3b8b5d --- /dev/null +++ b/ui/app/components/account-info-link.js @@ -0,0 +1,42 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const Tooltip = require('./tooltip') +const genAccountLink = require('../../lib/account-link') +const extension = require('../../../app/scripts/lib/extension') + +module.exports = AccountInfoLink + +inherits(AccountInfoLink, Component) +function AccountInfoLink () { + Component.call(this) +} + +AccountInfoLink.prototype.render = function () { + const { selected, network } = this.props + const title = 'View account on etherscan' + const url = genAccountLink(selected, network) + + if (!url) { + return null + } + + return h('.account-info-link', { + style: { + display: 'flex', + alignItems: 'center', + }, + }, [ + + h(Tooltip, { + title, + }, [ + h('i.fa.fa-info-circle.cursor-pointer.color-orange', { + style: { + margin: '5px', + }, + onClick () { extension.tabs.create({ url }) }, + }), + ]), + ]) +} diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index 11e11cd37..c92181d5d 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -26,6 +26,10 @@ function ShiftListItem () { } ShiftListItem.prototype.render = function () { + var props = this.props + const { depositAddress, time, i, response } = props + const { transaction } = response + return ( h('.transaction-list-item.flex-row', { style: { diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index b03ca11ad..2cd0f0897 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -44,7 +44,6 @@ TransactionListItem.prototype.render = function () { return ( h(`.transaction-list-item.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, { - key: `tx-${transaction.id + i}`, onClick: (event) => { if (isPending) { this.props.showTx(transaction.id) diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 9348b9fc4..8b9004e69 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -16,7 +16,6 @@ function TransactionList () { TransactionList.prototype.render = function () { const { txsToRender, network, unconfMsgs, address } = this.props - const transactions = txsToRender.concat(unconfMsgs) var shapeShiftTxList if (network === '1'){ shapeShiftTxList = this.props.shapeShiftTxList @@ -47,7 +46,7 @@ TransactionList.prototype.render = function () { paddingBottom: '4px', }, }, [ - 'Transactions', + 'History', ]), h('.tx-list', { @@ -61,13 +60,22 @@ TransactionList.prototype.render = function () { transactions.length ? transactions.map((transaction, i) => { + let key + switch (transaction.key) { + case 'shapeshift': + const { depositAddress, time } = transaction + key = `shift-tx-${depositAddress}-${time}-${i}` + break + default: + key = `tx-${transaction.id}-${i}` + } return h(TransactionListItem, { - transaction, i, network, + transaction, i, network, key, showTx: (txId) => { this.props.viewPendingTx(txId) }, }) - }).concat(viewMoreButton(accountLink)) + }) : h('.flex-center', { style: { flexDirection: 'column', @@ -75,21 +83,9 @@ TransactionList.prototype.render = function () { }, }, [ 'No transaction history.', - viewMoreButton(accountLink), ]), ]), ]) ) } -function viewMoreButton(url) { - return url ? h('button', { - style: { - margin: '10px', - }, - onClick: (ev) => { - ev.preventDefault() - extension.tabs.create({ url }) - }, - }, 'Show More') : null -} From 17f3f90d805d91aedac517c8d6607a1f337c6525 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 22 Aug 2016 17:21:54 -0700 Subject: [PATCH 7/9] Linted --- ui/app/account-detail.js | 2 +- ui/app/components/shift-list-item.js | 4 +--- ui/app/components/transaction-list-item.js | 2 +- ui/app/components/transaction-list.js | 4 +--- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 4316ff54e..486a1a633 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -143,7 +143,7 @@ AccountDetailScreen.prototype.render = function () { style: { display: 'flex', alignItems: 'center', - } + }, }, [ h('img.cursor-pointer.color-orange', { src: 'images/key-32.png', diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index c92181d5d..1c64a86b2 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -27,8 +27,7 @@ function ShiftListItem () { ShiftListItem.prototype.render = function () { var props = this.props - const { depositAddress, time, i, response } = props - const { transaction } = response + const { response } = props return ( h('.transaction-list-item.flex-row', { @@ -117,7 +116,6 @@ ShiftListItem.prototype.renderUtilComponents = function () { default: return '' } - } ShiftListItem.prototype.renderInfo = function () { diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index 2cd0f0897..1b85464e1 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -19,7 +19,7 @@ function TransactionListItem () { } TransactionListItem.prototype.render = function () { - const { transaction, i, network } = this.props + const { transaction, network } = this.props if (transaction.key === 'shapeshift') { if (network === '1') return h(ShiftListItem, transaction) } diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 8b9004e69..fac289a80 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -2,7 +2,6 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const genAccountLink = require('../../lib/account-link') -const extension = require('../../../app/scripts/lib/extension') const TransactionListItem = require('./transaction-list-item') @@ -17,12 +16,11 @@ function TransactionList () { TransactionList.prototype.render = function () { const { txsToRender, network, unconfMsgs, address } = this.props var shapeShiftTxList - if (network === '1'){ + if (network === '1') { shapeShiftTxList = this.props.shapeShiftTxList } const transactions = !shapeShiftTxList ? txsToRender.concat(unconfMsgs) : txsToRender.concat(unconfMsgs, shapeShiftTxList) .sort((a, b) => b.time - a.time) - const accountLink = genAccountLink(address, network) return ( From 5d24621b56427bffde26ab9281bd6990a04bbfef Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 22 Aug 2016 17:37:16 -0700 Subject: [PATCH 8/9] More linting --- ui/app/components/shift-list-item.js | 2 -- ui/app/components/transaction-list.js | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index 1c64a86b2..38c19eb28 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -26,8 +26,6 @@ function ShiftListItem () { } ShiftListItem.prototype.render = function () { - var props = this.props - const { response } = props return ( h('.transaction-list-item.flex-row', { diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index fac289a80..7e1bedb05 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -1,7 +1,6 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const genAccountLink = require('../../lib/account-link') const TransactionListItem = require('./transaction-list-item') @@ -14,7 +13,7 @@ function TransactionList () { } TransactionList.prototype.render = function () { - const { txsToRender, network, unconfMsgs, address } = this.props + const { txsToRender, network, unconfMsgs } = this.props var shapeShiftTxList if (network === '1') { shapeShiftTxList = this.props.shapeShiftTxList From a0d0245343a48e16baddf3db9e509a0f8d98c2fe Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 22 Aug 2016 17:37:23 -0700 Subject: [PATCH 9/9] Add gulp tasks as npm scripts --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 4093751b6..9263d1aaf 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "private": true, "scripts": { "start": "gulp dev", + "lint": "gulp lint", + "dev": "gulp dev", + "dist": "gulp dist", "test": "npm run fastTest && npm run ci", "fastTest": "mocha --require test/helper.js --compilers js:babel-register --recursive \"test/unit/**/*.js\"", "watch": "mocha watch --compilers js:babel-register --recursive \"test/unit/**/*.js\"",