Merge pull request #949 from poanetwork/881-hide-pending-transactions

Make address pending transactions collapsable
pull/958/head
John Stamates 6 years ago committed by GitHub
commit 05c8142e0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 403
      apps/block_scout_web/assets/__tests__/pages/address.js
  2. 102
      apps/block_scout_web/assets/__tests__/pages/chain.js
  3. 9
      apps/block_scout_web/assets/js/app.js
  4. 20
      apps/block_scout_web/assets/js/lib/pending_transactions_toggle.js
  5. 2
      apps/block_scout_web/assets/js/lib/token_balance_dropdown.js
  6. 139
      apps/block_scout_web/assets/js/pages/address.js
  7. 6
      apps/block_scout_web/assets/js/pages/block.js
  8. 30
      apps/block_scout_web/assets/js/pages/chain.js
  9. 26
      apps/block_scout_web/assets/js/pages/transaction.js
  10. 92
      apps/block_scout_web/assets/js/utils.js
  11. 10
      apps/block_scout_web/lib/block_scout_web/templates/address/_balance_card.html.eex
  12. 2
      apps/block_scout_web/lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex
  13. 22
      apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex
  14. 5
      apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex
  15. 34
      apps/block_scout_web/priv/gettext/default.pot
  16. 34
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  17. 4
      apps/block_scout_web/test/block_scout_web/features/pages/address_page.ex
  18. 2
      apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs

@ -6,26 +6,30 @@ describe('PAGE_LOAD', () => {
const action = { const action = {
type: 'PAGE_LOAD', type: 'PAGE_LOAD',
addressHash: '1234', addressHash: '1234',
beyondPageOne: false beyondPageOne: false,
pendingTransactionHashes: ['1']
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.addressHash).toBe('1234') expect(output.addressHash).toBe('1234')
expect(output.beyondPageOne).toBe(false) expect(output.beyondPageOne).toBe(false)
expect(output.filter).toBe(undefined) expect(output.filter).toBe(undefined)
expect(output.pendingTransactionHashes).toEqual(['1'])
}) })
test('page 2 without filter', () => { test('page 2 without filter', () => {
const state = initialState const state = initialState
const action = { const action = {
type: 'PAGE_LOAD', type: 'PAGE_LOAD',
addressHash: '1234',
beyondPageOne: true, beyondPageOne: true,
addressHash: '1234' pendingTransactionHashes: ['1']
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.addressHash).toBe('1234') expect(output.addressHash).toBe('1234')
expect(output.filter).toBe(undefined)
expect(output.beyondPageOne).toBe(true) expect(output.beyondPageOne).toBe(true)
expect(output.filter).toBe(undefined)
expect(output.pendingTransactionHashes).toEqual(['1'])
}) })
test('page 1 with "to" filter', () => { test('page 1 with "to" filter', () => {
const state = initialState const state = initialState
@ -38,22 +42,22 @@ describe('PAGE_LOAD', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.addressHash).toBe('1234') expect(output.addressHash).toBe('1234')
expect(output.filter).toBe('to')
expect(output.beyondPageOne).toBe(false) expect(output.beyondPageOne).toBe(false)
expect(output.filter).toBe('to')
}) })
test('page 2 with "to" filter', () => { test('page 2 with "to" filter', () => {
const state = initialState const state = initialState
const action = { const action = {
type: 'PAGE_LOAD', type: 'PAGE_LOAD',
beyondPageOne: true,
addressHash: '1234', addressHash: '1234',
beyondPageOne: true,
filter: 'to' filter: 'to'
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.addressHash).toBe('1234') expect(output.addressHash).toBe('1234')
expect(output.filter).toBe('to')
expect(output.beyondPageOne).toBe(true) expect(output.beyondPageOne).toBe(true)
expect(output.filter).toBe('to')
}) })
}) })
@ -65,7 +69,6 @@ test('CHANNEL_DISCONNECTED', () => {
const output = reducer(state, action) const output = reducer(state, action)
expect(output.channelDisconnected).toBe(true) expect(output.channelDisconnected).toBe(true)
expect(output.batchCountAccumulator).toBe(0)
}) })
test('RECEIVED_UPDATED_BALANCE', () => { test('RECEIVED_UPDATED_BALANCE', () => {
@ -81,68 +84,19 @@ test('RECEIVED_UPDATED_BALANCE', () => {
expect(output.balance).toBe('hello world') expect(output.balance).toBe('hello world')
}) })
describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => { describe('RECEIVED_NEW_PENDING_TRANSACTION', () => {
test('single transaction', () => { test('single transaction', () => {
const state = initialState const state = initialState
const action = { const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', type: 'RECEIVED_NEW_PENDING_TRANSACTION',
msgs: [{ msg: {
transactionHash: '0x00', transactionHash: '0x00',
transactionHtml: 'test' transactionHtml: 'test'
}]
} }
const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual(['test'])
expect(output.batchCountAccumulator).toEqual(0)
expect(output.transactionCount).toEqual(null)
})
test('large batch of transactions', () => {
const state = initialState
const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
msgs: [{
transactionHash: '0x01',
transactionHtml: 'test 1'
},{
transactionHash: '0x02',
transactionHtml: 'test 2'
},{
transactionHash: '0x03',
transactionHtml: 'test 3'
},{
transactionHash: '0x04',
transactionHtml: 'test 4'
},{
transactionHash: '0x05',
transactionHtml: 'test 5'
},{
transactionHash: '0x06',
transactionHtml: 'test 6'
},{
transactionHash: '0x07',
transactionHtml: 'test 7'
},{
transactionHash: '0x08',
transactionHtml: 'test 8'
},{
transactionHash: '0x09',
transactionHtml: 'test 9'
},{
transactionHash: '0x10',
transactionHtml: 'test 10'
},{
transactionHash: '0x11',
transactionHtml: 'test 11'
}]
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([]) expect(output.newPendingTransactions).toEqual(['test'])
expect(output.newPendingTransactionHashesBatch).toEqual([
"0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x10", "0x11"
])
expect(output.batchCountAccumulator).toEqual(0)
expect(output.transactionCount).toEqual(null) expect(output.transactionCount).toEqual(null)
}) })
test('single transaction after single transaction', () => { test('single transaction after single transaction', () => {
@ -150,273 +104,97 @@ describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
newPendingTransactions: ['test 1'] newPendingTransactions: ['test 1']
}) })
const action = { const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', type: 'RECEIVED_NEW_PENDING_TRANSACTION',
msgs: [{ msg: {
transactionHash: '0x02', transactionHash: '0x02',
transactionHtml: 'test 2' transactionHtml: 'test 2'
}]
}
const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual(['test 1', 'test 2'])
expect(output.newPendingTransactionHashesBatch.length).toEqual(0)
})
test('single transaction after large batch of transactions', () => {
const state = Object.assign({}, initialState, {
newPendingTransactionHashesBatch: [
"0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x10", "0x11"
]
})
const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
msgs: [{
transactionHash: '0x12',
transactionHtml: 'test 12'
}]
} }
const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([])
expect(output.newPendingTransactionHashesBatch.length).toEqual(12)
expect(output.newPendingTransactionHashesBatch).toContain('0x12')
})
test('large batch of transactions after large batch of transactions', () => {
const state = Object.assign({}, initialState, {
newPendingTransactionHashesBatch: [
"0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x10", "0x11"
]
})
const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
msgs: [{
transactionHash: '0x12',
transactionHtml: 'test 12'
},{
transactionHash: '0x13',
transactionHtml: 'test 13'
},{
transactionHash: '0x14',
transactionHtml: 'test 14'
},{
transactionHash: '0x15',
transactionHtml: 'test 15'
},{
transactionHash: '0x16',
transactionHtml: 'test 16'
},{
transactionHash: '0x17',
transactionHtml: 'test 17'
},{
transactionHash: '0x18',
transactionHtml: 'test 18'
},{
transactionHash: '0x19',
transactionHtml: 'test 19'
},{
transactionHash: '0x20',
transactionHtml: 'test 20'
},{
transactionHash: '0x21',
transactionHtml: 'test 21'
},{
transactionHash: '0x22',
transactionHtml: 'test 22'
}]
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([]) expect(output.newPendingTransactions).toEqual(['test 1', 'test 2'])
expect(output.newPendingTransactionHashesBatch.length).toEqual(22) expect(output.pendingTransactionHashes.length).toEqual(1)
}) })
test('after disconnection', () => { test('after disconnection', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
channelDisconnected: true channelDisconnected: true
}) })
const action = { const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', type: 'RECEIVED_NEW_PENDING_TRANSACTION',
msgs: [{ msg: {
transactionHash: '0x00', transactionHash: '0x00',
transactionHtml: 'test' transactionHtml: 'test'
}] }
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([]) expect(output.newPendingTransactions).toEqual([])
expect(output.newPendingTransactionHashesBatch).toEqual([]) expect(output.pendingTransactionHashes).toEqual([])
}) })
test('on page 2', () => { test('on page 2', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
beyondPageOne: true beyondPageOne: true
}) })
const action = { const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', type: 'RECEIVED_NEW_PENDING_TRANSACTION',
msgs: [{ msg: {
transactionHash: '0x00', transactionHash: '0x00',
transactionHtml: 'test' transactionHtml: 'test'
}] }
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([]) expect(output.newPendingTransactions).toEqual([])
expect(output.newPendingTransactionHashesBatch).toEqual([]) expect(output.pendingTransactionHashes).toEqual([])
expect(output.batchCountAccumulator).toEqual(0)
}) })
}) })
describe('RECEIVED_NEW_TRANSACTION_BATCH', () => { describe('RECEIVED_NEW_TRANSACTION', () => {
test('single transaction', () => { test('single transaction', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
addressHash: '0x111' addressHash: '0x111'
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
transactionHtml: 'test', transactionHtml: 'test'
fromAddressHash: '0x111'
}]
} }
const output = reducer(state, action)
expect(output.newTransactions).toEqual(['test'])
expect(output.batchCountAccumulator).toEqual(0)
expect(output.transactionCount).toEqual(1)
})
test('large batch of transactions', () => {
const state = initialState
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
transactionHtml: 'test 1'
},{
transactionHtml: 'test 2'
},{
transactionHtml: 'test 3'
},{
transactionHtml: 'test 4'
},{
transactionHtml: 'test 5'
},{
transactionHtml: 'test 6'
},{
transactionHtml: 'test 7'
},{
transactionHtml: 'test 8'
},{
transactionHtml: 'test 9'
},{
transactionHtml: 'test 10'
},{
transactionHtml: 'test 11'
}]
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual([]) expect(output.newTransactions).toEqual([{ transactionHtml: 'test' }])
expect(output.batchCountAccumulator).toEqual(11) expect(output.transactionCount).toEqual(null)
}) })
test('single transaction after single transaction', () => { test('single transaction after single transaction', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
newTransactions: ['test 1'] newTransactions: [{ transactionHtml: 'test 1' }]
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
transactionHtml: 'test 2' transactionHtml: 'test 2'
}]
} }
const output = reducer(state, action)
expect(output.newTransactions).toEqual(['test 1', 'test 2'])
expect(output.batchCountAccumulator).toEqual(0)
})
test('single transaction after large batch of transactions', () => {
const state = Object.assign({}, initialState, {
newTransactions: [],
batchCountAccumulator: 11
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
transactionHtml: 'test 12'
}]
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual([]) expect(output.newTransactions).toEqual([
expect(output.batchCountAccumulator).toEqual(12) { transactionHtml: 'test 1' },
}) { transactionHtml: 'test 2' }
test('large batch of transactions after large batch of transactions', () => { ])
const state = Object.assign({}, initialState, {
newTransactions: [],
batchCountAccumulator: 11
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
transactionHtml: 'test 12'
},{
transactionHtml: 'test 13'
},{
transactionHtml: 'test 14'
},{
transactionHtml: 'test 15'
},{
transactionHtml: 'test 16'
},{
transactionHtml: 'test 17'
},{
transactionHtml: 'test 18'
},{
transactionHtml: 'test 19'
},{
transactionHtml: 'test 20'
},{
transactionHtml: 'test 21'
},{
transactionHtml: 'test 22'
}]
}
const output = reducer(state, action)
expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(22)
})
test('increments the transactions count only when the address sent transactions', () => {
const state = Object.assign({}, initialState, {
newTransactions: [],
addressHash: '0x111',
transactionCount: 1
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
transactionHtml: 'test 12',
fromAddressHash: '0x111',
toAddressHash: '0x222'
},{
transactionHtml: 'test 13',
fromAddressHash: '0x222',
toAddressHash: '0x111'
}]
}
const output = reducer(state, action)
expect(output.transactionCount).toEqual(2)
}) })
test('after disconnection', () => { test('after disconnection', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
channelDisconnected: true channelDisconnected: true
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
transactionHtml: 'test' transactionHtml: 'test'
}] }
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual([]) expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(0)
}) })
test('on page 2', () => { test('on page 2', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
@ -425,17 +203,15 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
addressHash: '0x111' addressHash: '0x111'
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
transactionHtml: 'test', transactionHtml: 'test'
fromAddressHash: '0x111' }
}]
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual([]) expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(0) expect(output.transactionCount).toEqual(1)
expect(output.transactionCount).toEqual(2)
}) })
test('transaction from current address with "from" filter', () => { test('transaction from current address with "from" filter', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
@ -443,15 +219,17 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
filter: 'from' filter: 'from'
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
fromAddressHash: '1234', fromAddressHash: '1234',
transactionHtml: 'test' transactionHtml: 'test'
}] }
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual(['test']) expect(output.newTransactions).toEqual([
{ fromAddressHash: '1234', transactionHtml: 'test' }
])
}) })
test('transaction from current address with "to" filter', () => { test('transaction from current address with "to" filter', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
@ -459,11 +237,11 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
filter: 'to' filter: 'to'
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
fromAddressHash: '1234', fromAddressHash: '1234',
transactionHtml: 'test' transactionHtml: 'test'
}] }
} }
const output = reducer(state, action) const output = reducer(state, action)
@ -475,15 +253,17 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
filter: 'to' filter: 'to'
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
toAddressHash: '1234', toAddressHash: '1234',
transactionHtml: 'test' transactionHtml: 'test'
}] }
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual(['test']) expect(output.newTransactions).toEqual([
{ toAddressHash: '1234', transactionHtml: 'test' }
])
}) })
test('transaction to current address with "from" filter', () => { test('transaction to current address with "from" filter', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
@ -491,11 +271,11 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
filter: 'from' filter: 'from'
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
toAddressHash: '1234', toAddressHash: '1234',
transactionHtml: 'test' transactionHtml: 'test'
}] }
} }
const output = reducer(state, action) const output = reducer(state, action)
@ -504,58 +284,17 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
test('single transaction collated from pending', () => { test('single transaction collated from pending', () => {
const state = initialState const state = initialState
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
transactionHash: '0x00', transactionHash: '0x00',
transactionHtml: 'test' transactionHtml: 'test'
}]
} }
const output = reducer(state, action)
expect(output.newTransactions).toEqual(['test'])
expect(output.batchCountAccumulator).toEqual(0)
})
test('large batch of transactions', () => {
const state = initialState
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
transactionHash: '0x01',
transactionHtml: 'test 1'
},{
transactionHash: '0x02',
transactionHtml: 'test 2'
},{
transactionHash: '0x03',
transactionHtml: 'test 3'
},{
transactionHash: '0x04',
transactionHtml: 'test 4'
},{
transactionHash: '0x05',
transactionHtml: 'test 5'
},{
transactionHash: '0x06',
transactionHtml: 'test 6'
},{
transactionHash: '0x07',
transactionHtml: 'test 7'
},{
transactionHash: '0x08',
transactionHtml: 'test 8'
},{
transactionHash: '0x09',
transactionHtml: 'test 9'
},{
transactionHash: '0x10',
transactionHtml: 'test 10'
},{
transactionHash: '0x11',
transactionHtml: 'test 11'
}]
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual([]) expect(output.newTransactions).toEqual([
{ transactionHash: '0x00', transactionHtml: 'test' }
])
expect(output.transactionCount).toEqual(null)
}) })
}) })

@ -195,120 +195,32 @@ test('RECEIVED_NEW_EXCHANGE_RATE', () => {
expect(output.usdMarketCap).toEqual(1230000) expect(output.usdMarketCap).toEqual(1230000)
}) })
describe('RECEIVED_NEW_TRANSACTION_BATCH', () => { describe('RECEIVED_NEW_TRANSACTION', () => {
test('single transaction', () => { test('single transaction', () => {
const state = initialState const state = initialState
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
transactionHtml: 'test' transactionHtml: 'test'
}] }
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual(['test']) expect(output.newTransactions).toEqual(['test'])
expect(output.batchCountAccumulator).toEqual(0)
expect(output.transactionCount).toEqual(1) expect(output.transactionCount).toEqual(1)
}) })
test('large batch of transactions', () => {
const state = initialState
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
transactionHtml: 'test 1'
},{
transactionHtml: 'test 2'
},{
transactionHtml: 'test 3'
},{
transactionHtml: 'test 4'
},{
transactionHtml: 'test 5'
},{
transactionHtml: 'test 6'
},{
transactionHtml: 'test 7'
},{
transactionHtml: 'test 8'
},{
transactionHtml: 'test 9'
},{
transactionHtml: 'test 10'
},{
transactionHtml: 'test 11'
}]
}
const output = reducer(state, action)
expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(11)
expect(output.transactionCount).toEqual(11)
})
test('single transaction after single transaction', () => { test('single transaction after single transaction', () => {
const state = Object.assign({}, initialState, { const state = Object.assign({}, initialState, {
newTransactions: ['test 1'] newTransactions: ['test 1']
}) })
const action = { const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH', type: 'RECEIVED_NEW_TRANSACTION',
msgs: [{ msg: {
transactionHtml: 'test 2' transactionHtml: 'test 2'
}]
} }
const output = reducer(state, action)
expect(output.newTransactions).toEqual(['test 1', 'test 2'])
expect(output.batchCountAccumulator).toEqual(0)
})
test('single transaction after large batch of transactions', () => {
const state = Object.assign({}, initialState, {
newTransactions: [],
batchCountAccumulator: 11
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
transactionHtml: 'test 12'
}]
}
const output = reducer(state, action)
expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(12)
})
test('large batch of transactions after large batch of transactions', () => {
const state = Object.assign({}, initialState, {
newTransactions: [],
batchCountAccumulator: 11
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
transactionHtml: 'test 12'
},{
transactionHtml: 'test 13'
},{
transactionHtml: 'test 14'
},{
transactionHtml: 'test 15'
},{
transactionHtml: 'test 16'
},{
transactionHtml: 'test 17'
},{
transactionHtml: 'test 18'
},{
transactionHtml: 'test 19'
},{
transactionHtml: 'test 20'
},{
transactionHtml: 'test 21'
},{
transactionHtml: 'test 22'
}]
} }
const output = reducer(state, action) const output = reducer(state, action)
expect(output.newTransactions).toEqual([]) expect(output.newTransactions).toEqual(['test 1', 'test 2'])
expect(output.batchCountAccumulator).toEqual(22)
}) })
}) })

@ -26,16 +26,17 @@ import './lib/from_now'
import './lib/indexing' import './lib/indexing'
import './lib/loading_element' import './lib/loading_element'
import './lib/market_history_chart' import './lib/market_history_chart'
import './lib/pending_transactions_toggle'
import './lib/pretty_json'
import './lib/reload_button' import './lib/reload_button'
import './lib/tooltip'
import './lib/smart_contract/read_only_functions' import './lib/smart_contract/read_only_functions'
import './lib/smart_contract/wei_ether_converter' import './lib/smart_contract/wei_ether_converter'
import './lib/pretty_json' import './lib/stop_propagation'
import './lib/try_api'
import './lib/token_balance_dropdown' import './lib/token_balance_dropdown'
import './lib/token_balance_dropdown_search' import './lib/token_balance_dropdown_search'
import './lib/token_transfers_toggle' import './lib/token_transfers_toggle'
import './lib/stop_propagation' import './lib/tooltip'
import './lib/try_api'
import './pages/address' import './pages/address'
import './pages/block' import './pages/block'

@ -0,0 +1,20 @@
import $ from 'jquery'
const pendingTransactionToggle = (element) => {
const $element = $(element)
const $pendingTransactionsClose = $element.find("[data-selector='pending-transactions-close']")
const $pendingTransactionsOpen = $element.find("[data-selector='pending-transactions-open']")
$element.on('show.bs.collapse', () => {
$pendingTransactionsOpen.addClass('d-none')
$pendingTransactionsClose.removeClass('d-none')
})
$element.on('hide.bs.collapse', () => {
$pendingTransactionsClose.addClass('d-none')
$pendingTransactionsOpen.removeClass('d-none')
})
}
// Initialize the script scoped for each instance.
$("[data-selector='pending-transactions-toggle']").each((_index, element) => pendingTransactionToggle(element))

@ -6,8 +6,6 @@ const tokenBalanceDropdown = (element) => {
const $errorMessage = $element.find('[data-error-message]') const $errorMessage = $element.find('[data-error-message]')
const apiPath = element.dataset.api_path const apiPath = element.dataset.api_path
$loading.show()
$.get(apiPath) $.get(apiPath)
.done(response => $element.html(response)) .done(response => $element.html(response))
.fail(() => { .fail(() => {

@ -4,25 +4,13 @@ import URI from 'urijs'
import humps from 'humps' import humps from 'humps'
import numeral from 'numeral' import numeral from 'numeral'
import socket from '../socket' import socket from '../socket'
import { batchChannel, initRedux, prependWithClingBottom } from '../utils' import { batchChannel, initRedux, slideDownPrepend, slideUpRemove } from '../utils'
import { updateAllAges } from '../lib/from_now' import { updateAllAges } from '../lib/from_now'
import { updateAllCalculatedUsdValues } from '../lib/currency.js' import { updateAllCalculatedUsdValues } from '../lib/currency.js'
import { loadTokenBalanceDropdown } from '../lib/token_balance_dropdown' import { loadTokenBalanceDropdown } from '../lib/token_balance_dropdown'
const BATCH_THRESHOLD = 10 const BATCH_THRESHOLD = 10
const incrementTransactionsCount = (transactions, addressHash, currentValue) => {
const reducer = (accumulator, {fromAddressHash}) => {
if (fromAddressHash === addressHash) {
accumulator++
}
return accumulator
}
return transactions.reduce(reducer, currentValue)
}
export const initialState = { export const initialState = {
addressHash: null, addressHash: null,
balance: null, balance: null,
@ -34,8 +22,7 @@ export const initialState = {
newInternalTransactions: [], newInternalTransactions: [],
newPendingTransactions: [], newPendingTransactions: [],
newTransactions: [], newTransactions: [],
newTransactionHashes: [], pendingTransactionHashes: [],
newPendingTransactionHashesBatch: [],
transactionCount: null, transactionCount: null,
validationCount: null validationCount: null
} }
@ -47,6 +34,7 @@ export function reducer (state = initialState, action) {
addressHash: action.addressHash, addressHash: action.addressHash,
beyondPageOne: action.beyondPageOne, beyondPageOne: action.beyondPageOne,
filter: action.filter, filter: action.filter,
pendingTransactionHashes: action.pendingTransactionHashes,
transactionCount: numeral(action.transactionCount).value(), transactionCount: numeral(action.transactionCount).value(),
validationCount: action.validationCount ? numeral(action.validationCount).value() : null validationCount: action.validationCount ? numeral(action.validationCount).value() : null
}) })
@ -93,66 +81,47 @@ export function reducer (state = initialState, action) {
}) })
} }
} }
case 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH': { case 'RECEIVED_NEW_PENDING_TRANSACTION': {
if (state.channelDisconnected || state.beyondPageOne) return state if (state.channelDisconnected || state.beyondPageOne) return state
const incomingPendingTransactions = action.msgs if ((state.filter === 'to' && action.msg.toAddressHash !== state.addressHash) ||
.filter(({toAddressHash, fromAddressHash}) => ( (state.filter === 'from' && action.msg.fromAddressHash !== state.addressHash)) {
!state.filter || return state
(state.filter === 'to' && toAddressHash === state.addressHash) || }
(state.filter === 'from' && fromAddressHash === state.addressHash)
))
if (!state.newPendingTransactionHashesBatch.length && incomingPendingTransactions.length < BATCH_THRESHOLD) {
return Object.assign({}, state, { return Object.assign({}, state, {
newPendingTransactions: [ newPendingTransactions: [
...state.newPendingTransactions, ...state.newPendingTransactions,
..._.map(incomingPendingTransactions, 'transactionHtml') action.msg.transactionHtml
] ],
}) pendingTransactionHashes: [
} else { ...state.pendingTransactionHashes,
return Object.assign({}, state, { action.msg.transactionHash
newPendingTransactionHashesBatch: [
...state.newPendingTransactionHashesBatch,
..._.map(incomingPendingTransactions, 'transactionHash')
] ]
}) })
} }
} case 'RECEIVED_NEW_TRANSACTION': {
case 'RECEIVED_NEW_TRANSACTION_BATCH': {
if (state.channelDisconnected) return state if (state.channelDisconnected) return state
const transactionCount = incrementTransactionsCount(action.msgs, state.addressHash, state.transactionCount) const transactionCount = (action.msg.fromAddressHash === state.addressHash) ? state.transactionCount + 1 : state.transactionCount
if (state.beyondPageOne) return Object.assign({}, state, { transactionCount })
const incomingTransactions = action.msgs if (state.beyondPageOne ||
.filter(({toAddressHash, fromAddressHash}) => ( (state.filter === 'to' && action.msg.toAddressHash !== state.addressHash) ||
!state.filter || (state.filter === 'from' && action.msg.fromAddressHash !== state.addressHash)) {
(state.filter === 'to' && toAddressHash === state.addressHash) || return Object.assign({}, state, { transactionCount })
(state.filter === 'from' && fromAddressHash === state.addressHash) }
))
const updatedPendingTransactionHashesBatch = const updatedPendingTransactionHashes =
_.difference(state.newPendingTransactionHashesBatch, _.map(incomingTransactions, 'transactionHash')) _.without(state.pendingTransactionHashes, action.msg.transactionHash)
if (!state.batchCountAccumulator && incomingTransactions.length < BATCH_THRESHOLD) {
return Object.assign({}, state, { return Object.assign({}, state, {
newTransactions: [ newTransactions: [
...state.newTransactions, ...state.newTransactions,
..._.map(incomingTransactions, 'transactionHtml') action.msg
], ],
newTransactionHashes: _.map(incomingTransactions, 'transactionHash'), pendingTransactionHashes: updatedPendingTransactionHashes,
newPendingTransactionHashesBatch: updatedPendingTransactionHashesBatch,
transactionCount: transactionCount transactionCount: transactionCount
}) })
} else {
return Object.assign({}, state, {
batchCountAccumulator: state.batchCountAccumulator + incomingTransactions.length,
newTransactionHashes: _.map(incomingTransactions, 'transactionHash'),
newPendingTransactionHashesBatch: updatedPendingTransactionHashesBatch,
transactionCount: transactionCount
})
}
} }
case 'RECEIVED_UPDATED_BALANCE': { case 'RECEIVED_UPDATED_BALANCE': {
return Object.assign({}, state, { return Object.assign({}, state, {
@ -176,6 +145,8 @@ if ($addressDetailsPage.length) {
addressHash, addressHash,
beyondPageOne: !!blockNumber, beyondPageOne: !!blockNumber,
filter, filter,
pendingTransactionHashes: $('[data-selector="pending-transactions-list"]').children()
.map((index, el) => el.dataset.transactionHash).toArray(),
transactionCount: $('[data-selector="transaction-count"]').text(), transactionCount: $('[data-selector="transaction-count"]').text(),
validationCount: $('[data-selector="validation-count"]') ? $('[data-selector="validation-count"]').text() : null validationCount: $('[data-selector="validation-count"]') ? $('[data-selector="validation-count"]').text() : null
}) })
@ -187,29 +158,22 @@ if ($addressDetailsPage.length) {
addressChannel.on('internal_transaction', batchChannel((msgs) => addressChannel.on('internal_transaction', batchChannel((msgs) =>
store.dispatch({ type: 'RECEIVED_NEW_INTERNAL_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) }) store.dispatch({ type: 'RECEIVED_NEW_INTERNAL_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) })
)) ))
addressChannel.on('pending_transaction', batchChannel((msgs) => addressChannel.on('pending_transaction', (msg) => store.dispatch({ type: 'RECEIVED_NEW_PENDING_TRANSACTION', msg: humps.camelizeKeys(msg) }))
store.dispatch({ type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) }) addressChannel.on('transaction', (msg) => store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION', msg: humps.camelizeKeys(msg) }))
))
addressChannel.on('transaction', batchChannel((msgs) =>
store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) })
))
const blocksChannel = socket.channel(`blocks:${addressHash}`, {}) const blocksChannel = socket.channel(`blocks:${addressHash}`, {})
blocksChannel.join() blocksChannel.join()
blocksChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' })) blocksChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' }))
blocksChannel.on('new_block', (msg) => { blocksChannel.on('new_block', (msg) => store.dispatch({ type: 'RECEIVED_NEW_BLOCK', msg: humps.camelizeKeys(msg) }))
store.dispatch({ type: 'RECEIVED_NEW_BLOCK', msg: humps.camelizeKeys(msg) })
})
}, },
render (state, oldState) { render (state, oldState) {
const $balance = $('[data-selector="balance-card"]') const $balance = $('[data-selector="balance-card"]')
const $channelBatching = $('[data-selector="channel-batching-message"]') const $channelBatching = $('[data-selector="channel-batching-message"]')
const $channelBatchingCount = $('[data-selector="channel-batching-count"]') const $channelBatchingCount = $('[data-selector="channel-batching-count"]')
const $channelPendingBatching = $('[data-selector="channel-pending-batching-message"]')
const $channelPendingBatchingCount = $('[data-selector="channel-pending-batching-count"]')
const $channelDisconnected = $('[data-selector="channel-disconnected-message"]') const $channelDisconnected = $('[data-selector="channel-disconnected-message"]')
const $emptyInternalTransactionsList = $('[data-selector="empty-internal-transactions-list"]') const $emptyInternalTransactionsList = $('[data-selector="empty-internal-transactions-list"]')
const $emptyTransactionsList = $('[data-selector="empty-transactions-list"]') const $emptyTransactionsList = $('[data-selector="empty-transactions-list"]')
const $internalTransactionsList = $('[data-selector="internal-transactions-list"]') const $internalTransactionsList = $('[data-selector="internal-transactions-list"]')
const $pendingTransactionsCount = $('[data-selector="pending-transactions-count"]')
const $pendingTransactionsList = $('[data-selector="pending-transactions-list"]') const $pendingTransactionsList = $('[data-selector="pending-transactions-list"]')
const $transactionCount = $('[data-selector="transaction-count"]') const $transactionCount = $('[data-selector="transaction-count"]')
const $transactionsList = $('[data-selector="transactions-list"]') const $transactionsList = $('[data-selector="transactions-list"]')
@ -232,34 +196,39 @@ if ($addressDetailsPage.length) {
} else { } else {
$channelBatching.hide() $channelBatching.hide()
} }
if (oldState.newPendingTransactionHashesBatch !== state.newPendingTransactionHashesBatch && state.newPendingTransactionHashesBatch.length > 0) {
$channelPendingBatching.show()
$channelPendingBatchingCount[0].innerHTML = numeral(state.newPendingTransactionHashesBatch.length).format()
} else {
$channelPendingBatching.hide()
}
if (oldState.newTransactionHashes !== state.newTransactionHashes && state.newTransactionHashes.length > 0) {
let $transaction
_.each(state.newTransactionHashes, (hash) => {
$transaction = $(`[data-selector="pending-transactions-list"] [data-transaction-hash="${hash}"]`)
$transaction.addClass('shrink-out')
setTimeout(() => $transaction.slideUp({ complete: () => $transaction.remove() }), 400)
})
}
if (oldState.newInternalTransactions !== state.newInternalTransactions && $internalTransactionsList.length) { if (oldState.newInternalTransactions !== state.newInternalTransactions && $internalTransactionsList.length) {
prependWithClingBottom($internalTransactionsList, state.newInternalTransactions.slice(oldState.newInternalTransactions.length).reverse().join('')) slideDownPrepend($internalTransactionsList, state.newInternalTransactions.slice(oldState.newInternalTransactions.length).reverse().join(''))
updateAllAges() updateAllAges()
} }
if (oldState.pendingTransactionHashes.length !== state.pendingTransactionHashes.length && $pendingTransactionsCount.length) {
$pendingTransactionsCount[0].innerHTML = numeral(state.pendingTransactionHashes.length).format()
}
if (oldState.newPendingTransactions !== state.newPendingTransactions && $pendingTransactionsList.length) { if (oldState.newPendingTransactions !== state.newPendingTransactions && $pendingTransactionsList.length) {
prependWithClingBottom($pendingTransactionsList, state.newPendingTransactions.slice(oldState.newPendingTransactions.length).reverse().join('')) slideDownPrepend($pendingTransactionsList, state.newPendingTransactions.slice(oldState.newPendingTransactions.length).reverse().join(''))
updateAllAges() updateAllAges()
} }
if (oldState.newTransactions !== state.newTransactions && $transactionsList.length) { if (oldState.newTransactions !== state.newTransactions && $transactionsList.length) {
prependWithClingBottom($transactionsList, state.newTransactions.slice(oldState.newTransactions.length).reverse().join('')) const newlyValidatedTransactions = state.newTransactions.slice(oldState.newTransactions.length).reverse()
newlyValidatedTransactions.forEach(({ transactionHash, transactionHtml }) => {
let $transaction = $(`[data-selector="pending-transactions-list"] [data-transaction-hash="${transactionHash}"]`)
$transaction.html($(transactionHtml).html())
if ($transaction.is(':visible')) {
setTimeout(() => {
$transaction.addClass('shrink-out')
setTimeout(() => {
slideUpRemove($transaction)
slideDownPrepend($transactionsList, transactionHtml)
}, 400)
}, 1000)
} else {
$transaction.remove()
slideDownPrepend($transactionsList, transactionHtml)
}
})
updateAllAges() updateAllAges()
} }
if (oldState.newBlock !== state.newBlock) { if (oldState.newBlock !== state.newBlock) {
prependWithClingBottom($validationsList, state.newBlock) slideDownPrepend($validationsList, state.newBlock)
updateAllAges() updateAllAges()
} }
} }

@ -4,7 +4,7 @@ import URI from 'urijs'
import humps from 'humps' import humps from 'humps'
import socket from '../socket' import socket from '../socket'
import { updateAllAges } from '../lib/from_now' import { updateAllAges } from '../lib/from_now'
import { buildFullBlockList, initRedux, beforeWithClingBottom, skippedBlockListBuilder } from '../utils' import { buildFullBlockList, initRedux, slideDownBefore, skippedBlockListBuilder } from '../utils'
export const initialState = { export const initialState = {
blockNumbers: [], blockNumbers: [],
@ -97,10 +97,10 @@ if ($blockListPage.length) {
} else { } else {
if (skippedBlockNumbers.length) { if (skippedBlockNumbers.length) {
_.forEachRight(skippedBlockNumbers, (skippedBlockNumber) => { _.forEachRight(skippedBlockNumbers, (skippedBlockNumber) => {
beforeWithClingBottom($(`[data-block-number="${skippedBlockNumber - 1}"]`), placeHolderBlock(skippedBlockNumber)) slideDownBefore($(`[data-block-number="${skippedBlockNumber - 1}"]`), placeHolderBlock(skippedBlockNumber))
}) })
} }
beforeWithClingBottom($(`[data-block-number="${state.blockNumbers[0] - 1}"]`), state.newBlock) slideDownBefore($(`[data-block-number="${state.blockNumbers[0] - 1}"]`), state.newBlock)
} }
updateAllAges() updateAllAges()
} }

@ -5,16 +5,13 @@ import numeral from 'numeral'
import socket from '../socket' import socket from '../socket'
import { updateAllAges } from '../lib/from_now' import { updateAllAges } from '../lib/from_now'
import { exchangeRateChannel, formatUsdValue } from '../lib/currency' import { exchangeRateChannel, formatUsdValue } from '../lib/currency'
import { batchChannel, buildFullBlockList, initRedux, skippedBlockListBuilder, slideDownPrepend } from '../utils' import { buildFullBlockList, initRedux, skippedBlockListBuilder, slideDownPrepend } from '../utils'
import { createMarketHistoryChart } from '../lib/market_history_chart' import { createMarketHistoryChart } from '../lib/market_history_chart'
const BATCH_THRESHOLD = 10
export const initialState = { export const initialState = {
addressCount: null, addressCount: null,
availableSupply: null, availableSupply: null,
averageBlockTime: null, averageBlockTime: null,
batchCountAccumulator: 0,
blockNumbers: [], blockNumbers: [],
marketHistoryData: null, marketHistoryData: null,
newBlock: null, newBlock: null,
@ -85,22 +82,15 @@ export function reducer (state = initialState, action) {
usdMarketCap: action.msg.exchangeRate.marketCapUsd usdMarketCap: action.msg.exchangeRate.marketCapUsd
}) })
} }
case 'RECEIVED_NEW_TRANSACTION_BATCH': { case 'RECEIVED_NEW_TRANSACTION': {
if (!state.batchCountAccumulator && action.msgs.length < BATCH_THRESHOLD) {
return Object.assign({}, state, { return Object.assign({}, state, {
newTransactions: [ newTransactions: [
...state.newTransactions, ...state.newTransactions,
...action.msgs.map(({transactionHtml}) => transactionHtml) action.msg.transactionHtml
], ],
transactionCount: state.transactionCount + action.msgs.length transactionCount: state.transactionCount + 1
})
} else {
return Object.assign({}, state, {
batchCountAccumulator: state.batchCountAccumulator + action.msgs.length,
transactionCount: state.transactionCount + action.msgs.length
}) })
} }
}
default: default:
return state return state
} }
@ -128,9 +118,7 @@ if ($chainDetailsPage.length) {
const transactionsChannel = socket.channel(`transactions:new_transaction`) const transactionsChannel = socket.channel(`transactions:new_transaction`)
transactionsChannel.join() transactionsChannel.join()
transactionsChannel.on('transaction', batchChannel((msgs) => transactionsChannel.on('transaction', (msg) => store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION', msg: humps.camelizeKeys(msg) }))
store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) }))
)
chart = createMarketHistoryChart($('[data-chart="marketHistoryChart"]')[0]) chart = createMarketHistoryChart($('[data-chart="marketHistoryChart"]')[0])
}, },
@ -138,8 +126,6 @@ if ($chainDetailsPage.length) {
const $addressCount = $('[data-selector="address-count"]') const $addressCount = $('[data-selector="address-count"]')
const $averageBlockTime = $('[data-selector="average-block-time"]') const $averageBlockTime = $('[data-selector="average-block-time"]')
const $blockList = $('[data-selector="chain-block-list"]') const $blockList = $('[data-selector="chain-block-list"]')
const $channelBatching = $('[data-selector="channel-batching-message"]')
const $channelBatchingCount = $('[data-selector="channel-batching-count"]')
const $marketCap = $('[data-selector="market-cap"]') const $marketCap = $('[data-selector="market-cap"]')
const $transactionsList = $('[data-selector="transactions-list"]') const $transactionsList = $('[data-selector="transactions-list"]')
const $transactionCount = $('[data-selector="transaction-count"]') const $transactionCount = $('[data-selector="transaction-count"]')
@ -176,12 +162,6 @@ if ($chainDetailsPage.length) {
updateAllAges() updateAllAges()
} }
if (oldState.transactionCount !== state.transactionCount) $transactionCount.empty().append(numeral(state.transactionCount).format()) if (oldState.transactionCount !== state.transactionCount) $transactionCount.empty().append(numeral(state.transactionCount).format())
if (state.batchCountAccumulator) {
$channelBatching.show()
$channelBatchingCount[0].innerHTML = numeral(state.batchCountAccumulator).format()
} else {
$channelBatching.hide()
}
if (newTransactions.length) { if (newTransactions.length) {
const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length) const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length)
$transactionsList $transactionsList

@ -5,7 +5,7 @@ import humps from 'humps'
import numeral from 'numeral' import numeral from 'numeral'
import socket from '../socket' import socket from '../socket'
import { updateAllAges } from '../lib/from_now' import { updateAllAges } from '../lib/from_now'
import { batchChannel, initRedux, prependWithClingBottom } from '../utils' import { batchChannel, initRedux, slideDownPrepend, slideUpRemove } from '../utils'
const BATCH_THRESHOLD = 10 const BATCH_THRESHOLD = 10
@ -171,15 +171,13 @@ if ($transactionPendingListPage.length) {
if (oldState.newTransactionHashes !== state.newTransactionHashes && state.newTransactionHashes.length > 0) { if (oldState.newTransactionHashes !== state.newTransactionHashes && state.newTransactionHashes.length > 0) {
const $transaction = $(`[data-transaction-hash="${state.newTransactionHashes[0]}"]`) const $transaction = $(`[data-transaction-hash="${state.newTransactionHashes[0]}"]`)
$transaction.addClass('shrink-out') $transaction.addClass('shrink-out')
setTimeout(() => $transaction.slideUp({ setTimeout(() => {
complete: () => { if ($transaction.length === 1 && $transaction.siblings().length === 0 && state.pendingTransactionCount > 0) {
if ($pendingTransactionsList.children().length < 2 && state.pendingTransactionCount > 0) {
window.location.href = URI(window.location).removeQuery('inserted_at').removeQuery('hash').toString() window.location.href = URI(window.location).removeQuery('inserted_at').removeQuery('hash').toString()
} else { } else {
$transaction.remove() slideUpRemove($transaction)
} }
} }, 400)
}), 400)
} }
if (state.newPendingTransactionHashesBatch.length) { if (state.newPendingTransactionHashesBatch.length) {
$channelBatching.show() $channelBatching.show()
@ -189,13 +187,7 @@ if ($transactionPendingListPage.length) {
} }
if (oldState.newPendingTransactions !== state.newPendingTransactions) { if (oldState.newPendingTransactions !== state.newPendingTransactions) {
const newTransactionsToInsert = state.newPendingTransactions.slice(oldState.newPendingTransactions.length) const newTransactionsToInsert = state.newPendingTransactions.slice(oldState.newPendingTransactions.length)
$pendingTransactionsList slideDownPrepend($pendingTransactionsList, newTransactionsToInsert.reverse().join(''))
.children()
.slice($pendingTransactionsList.children().length - newTransactionsToInsert.length,
$pendingTransactionsList.children().length
)
.remove()
prependWithClingBottom($pendingTransactionsList, newTransactionsToInsert.reverse().join(''))
updateAllAges() updateAllAges()
} }
@ -236,11 +228,7 @@ if ($transactionListPage.length) {
} }
if (oldState.newTransactions !== state.newTransactions) { if (oldState.newTransactions !== state.newTransactions) {
const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length) const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length)
$transactionsList slideDownPrepend($transactionsList, newTransactionsToInsert.reverse().join(''))
.children()
.slice($transactionsList.children().length - newTransactionsToInsert.length, $transactionsList.children().length)
.remove()
prependWithClingBottom($transactionsList, newTransactionsToInsert.reverse().join(''))
updateAllAges() updateAllAges()
} }

@ -45,61 +45,63 @@ export function skippedBlockListBuilder (skippedBlockNumbers, newestBlock, oldes
return skippedBlockNumbers return skippedBlockNumbers
} }
export function slideDownPrepend ($el, content, callback) { export function slideDownPrepend ($container, content) {
const $content = $(content) smarterSlideDown($(content), {
$el.prepend($content.hide()) insert ($el) {
$content.slideDown({ complete: callback }) $container.prepend($el)
} }
export function slideDownBefore ($el, content, callback) { })
const $content = $(content)
$el.before($content.hide())
$content.slideDown({ complete: callback })
} }
export function prependWithClingBottom ($el, content) { export function slideDownBefore ($container, content) {
return slideDownPrepend($el, content, clingBottom($el, content)) smarterSlideDown($(content), {
insert ($el) {
$container.before($el)
}
})
} }
export function beforeWithClingBottom ($el, content) { export function slideUpRemove ($el) {
return slideDownBefore($el, content, clingBottom($el, content)) smarterSlideUp($el, {
complete () {
$el.remove()
}
})
} }
function clingBottom ($el, content) { function smarterSlideDown ($el, { insert = _.noop } = {}) {
function userAtTop () { if (!$el.length) return
return window.scrollY < $('[data-selector="navbar"]').outerHeight() const originalScrollHeight = document.body.scrollHeight
} const scrollPosition = window.scrollY
if (userAtTop()) return true
let isAnimating insert($el)
function setIsAnimating () {
isAnimating = true const isAboveViewport = $el.offset().top < scrollPosition
}
$el.on('animationstart', setIsAnimating)
let startingScrollPosition = window.scrollY if (isAboveViewport) {
let endingScrollPosition = window.scrollY const heightDiffAfterInsert = document.body.scrollHeight - originalScrollHeight
function userIsScrolling () { const scrollPositionToMaintainViewport = scrollPosition + heightDiffAfterInsert
return window.scrollY < startingScrollPosition || endingScrollPosition < window.scrollY
$(window).scrollTop(scrollPositionToMaintainViewport)
} else {
$el.hide()
$el.slideDown({ easing: 'linear' })
} }
}
const clingDistanceFromBottom = document.body.scrollHeight - window.scrollY function smarterSlideUp ($el, { complete = _.noop } = {}) {
let clingBottomLoop = window.requestAnimationFrame(function clingBottom () { if (!$el.length) return
if (userIsScrolling()) return stopClinging() const originalScrollHeight = document.body.scrollHeight
const scrollPosition = window.scrollY
const isAboveViewport = $el.offset().top + $el.outerHeight(true) < scrollPosition
startingScrollPosition = window.scrollY if (isAboveViewport) {
endingScrollPosition = document.body.scrollHeight - clingDistanceFromBottom $el.hide()
$(window).scrollTop(endingScrollPosition)
clingBottomLoop = window.requestAnimationFrame(clingBottom)
})
function stopClinging () { const heightDiffAfterHide = document.body.scrollHeight - originalScrollHeight
window.cancelAnimationFrame(clingBottomLoop) const scrollPositionToMaintainViewport = scrollPosition + heightDiffAfterHide
$el.off('animationstart', setIsAnimating)
$el.off('animationend animationcancel', stopClinging)
}
return { $(window).scrollTop(scrollPositionToMaintainViewport)
function () { complete()
$el.on('animationend animationcancel', stopClinging) } else {
setTimeout(() => !isAnimating && stopClinging(), 100) $el.slideUp({ complete, easing: 'linear' })
}
} }
} }

@ -10,14 +10,14 @@
</span> </span>
<div class="mt-3" data-token-balance-dropdown data-api_path="<%= address_token_balance_path(BlockScoutWeb.Endpoint, :index, @address.hash) %>"> <div class="mt-3" data-token-balance-dropdown data-api_path="<%= address_token_balance_path(BlockScoutWeb.Endpoint, :index, @address.hash) %>">
<p data-loading class="mb-0 text-white text-faded" style="display: none;"> <h5 data-loading class="mb-0 text-white text-faded">
<i class="fa fa-spinner fa-spin"></i> <i class="fa fa-spinner fa-spin mr-2"></i>
<%= gettext("Fetching tokens...") %> <%= gettext("Fetching tokens...") %>
</p> </h5>
<p data-error-message class="mb-0 text-white text-faded" style="display: none;"> <h5 data-error-message class="mb-0 text-white text-faded" style="display: none;">
<%= gettext("Error trying to fetch balances.") %> <%= gettext("Error trying to fetch balances.") %>
</p> </h5>
</div> </div>
</div> </div>
</div> </div>

@ -12,6 +12,8 @@
<i class="fas fa-chevron-down mr-2"></i> <i class="fas fa-chevron-down mr-2"></i>
<h5 data-tokens-count class="d-inline"><%= tokens_count_title(@token_balances) %></h5> <h5 data-tokens-count class="d-inline"><%= tokens_count_title(@token_balances) %></h5>
</a> </a>
<% else %>
<h5 data-tokens-count class="d-inline text-white"><%= tokens_count_title(@token_balances) %></h5>
<% end %> <% end %>
<div class="dropdown-menu dropdown-menu-right token-balance-dropdown p-0" aria-labelledby="dropdown-tokens"> <div class="dropdown-menu dropdown-menu-right token-balance-dropdown p-0" aria-labelledby="dropdown-tokens">

@ -9,16 +9,6 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<div data-selector="channel-pending-batching-message" class="d-none">
<div data-selector="reload-button" class="alert alert-info">
<a href="#" class="alert-link"><span data-selector="channel-pending-batching-count"></span> <%= gettext "More pending transactions have come in" %></a>
</div>
</div>
<div data-selector="channel-batching-message" class="d-none">
<div data-selector="reload-button" class="alert alert-info">
<a href="#" class="alert-link"><span data-selector="channel-batching-count"></span> <%= gettext "More transactions have come in" %></a>
</div>
</div>
<div data-selector="channel-disconnected-message" class="d-none"> <div data-selector="channel-disconnected-message" class="d-none">
<div data-selector="reload-button" class="alert alert-danger"> <div data-selector="reload-button" class="alert alert-danger">
<a href="#" class="alert-link"><%= gettext "Connection Lost, click to load newer transactions" %></a> <a href="#" class="alert-link"><%= gettext "Connection Lost, click to load newer transactions" %></a>
@ -61,10 +51,20 @@
</div> </div>
</div> </div>
<h2 class="card-title"><%= gettext "Transactions" %></h2> <h2 class="card-title"><%= gettext "Transactions" %></h2>
<div class="mb-3" data-selector="pending-transactions-list"> <div data-selector="pending-transactions-toggle">
<%= link to: "#pending-transactions", class: "d-inline-block mb-3", "data-toggle": "collapse" do %>
<span data-selector="pending-transactions-open">
<%= gettext("Show") %></span>
<span data-selector="pending-transactions-close" class="d-none"><%= gettext("Hide") %></span>
<span data-selector="pending-transactions-count"><%= length(@pending_transactions) %></span>
<%= gettext("Pending Transactions") %>
<% end %>
<div class="mb-3 collapse" id="pending-transactions" data-selector="pending-transactions-list">
<%= for pending_transaction <- @pending_transactions do %> <%= for pending_transaction <- @pending_transactions do %>
<%= render(BlockScoutWeb.TransactionView, "_tile.html", current_address: @address, transaction: pending_transaction) %> <%= render(BlockScoutWeb.TransactionView, "_tile.html", current_address: @address, transaction: pending_transaction) %>
<% end %> <% end %>
<hr />
</div>
</div> </div>
<%= if Enum.count(@transactions) > 0 do %> <%= if Enum.count(@transactions) > 0 do %>
<span data-selector="transactions-list"> <span data-selector="transactions-list">

@ -67,11 +67,6 @@
<div class="card card-chain-transactions"> <div class="card card-chain-transactions">
<div class="card-body"> <div class="card-body">
<div data-selector="channel-batching-message" class="d-none">
<div data-selector="reload-button" class="alert alert-info">
<a href="#" class="alert-link"><span data-selector="channel-batching-count"></span> <%= gettext "More transactions have come in" %></a>
</div>
</div>
<%= link(gettext("View All Transactions →"), to: transaction_path(BlockScoutWeb.Endpoint, :index), class: "button button-secondary button-xsmall float-right") %> <%= link(gettext("View All Transactions →"), to: transaction_path(BlockScoutWeb.Endpoint, :index), class: "button button-secondary button-xsmall float-right") %>
<h2 class="card-title"><%= gettext "Transactions" %></h2> <h2 class="card-title"><%= gettext "Transactions" %></h2>
<span data-selector="transactions-list"> <span data-selector="transactions-list">

@ -121,7 +121,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:28 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:28
#: lib/block_scout_web/templates/address_transaction/index.html.eex:34 #: lib/block_scout_web/templates/address_transaction/index.html.eex:24
#: lib/block_scout_web/views/address_internal_transaction_view.ex:8 #: lib/block_scout_web/views/address_internal_transaction_view.ex:8
#: lib/block_scout_web/views/address_transaction_view.ex:8 #: lib/block_scout_web/views/address_transaction_view.ex:8
msgid "All" msgid "All"
@ -257,7 +257,7 @@ msgid "Connection Lost, click to load newer internal transactions"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:24 #: lib/block_scout_web/templates/address_transaction/index.html.eex:14
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:53 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:53
#: lib/block_scout_web/templates/transaction/index.html.eex:53 #: lib/block_scout_web/templates/transaction/index.html.eex:53
msgid "Connection Lost, click to load newer transactions" msgid "Connection Lost, click to load newer transactions"
@ -434,7 +434,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:45 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:45
#: lib/block_scout_web/templates/address_transaction/index.html.eex:51 #: lib/block_scout_web/templates/address_transaction/index.html.eex:41
#: lib/block_scout_web/views/address_internal_transaction_view.ex:7 #: lib/block_scout_web/views/address_internal_transaction_view.ex:7
#: lib/block_scout_web/views/address_transaction_view.ex:7 #: lib/block_scout_web/views/address_transaction_view.ex:7
msgid "From" msgid "From"
@ -574,13 +574,6 @@ msgid "More internal transactions have come in"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:14
msgid "More pending transactions have come in"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:19
#: lib/block_scout_web/templates/chain/show.html.eex:72
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:48 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:48
#: lib/block_scout_web/templates/transaction/index.html.eex:48 #: lib/block_scout_web/templates/transaction/index.html.eex:48
msgid "More transactions have come in" msgid "More transactions have come in"
@ -699,6 +692,7 @@ msgid "Pending"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:60
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:60 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:60
msgid "Pending Transactions" msgid "Pending Transactions"
msgstr "" msgstr ""
@ -773,7 +767,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: #:
#: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:26 #: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:28
msgid "Search tokens" msgid "Search tokens"
msgstr "" msgstr ""
@ -883,7 +877,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:34 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:34
#: lib/block_scout_web/templates/address_transaction/index.html.eex:40 #: lib/block_scout_web/templates/address_transaction/index.html.eex:30
#: lib/block_scout_web/views/address_internal_transaction_view.ex:6 #: lib/block_scout_web/views/address_internal_transaction_view.ex:6
#: lib/block_scout_web/views/address_transaction_view.ex:6 #: lib/block_scout_web/views/address_transaction_view.ex:6
msgid "To" msgid "To"
@ -991,14 +985,14 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:5 #: lib/block_scout_web/templates/address/_tabs.html.eex:5
#: lib/block_scout_web/templates/address/_tabs.html.eex:71 #: lib/block_scout_web/templates/address/_tabs.html.eex:71
#: lib/block_scout_web/templates/address_transaction/index.html.eex:63 #: lib/block_scout_web/templates/address_transaction/index.html.eex:53
#: lib/block_scout_web/templates/address_validation/index.html.eex:11 #: lib/block_scout_web/templates/address_validation/index.html.eex:11
#: lib/block_scout_web/templates/address_validation/index.html.eex:65 #: lib/block_scout_web/templates/address_validation/index.html.eex:65
#: lib/block_scout_web/templates/block_transaction/index.html.eex:13 #: lib/block_scout_web/templates/block_transaction/index.html.eex:13
#: lib/block_scout_web/templates/block_transaction/index.html.eex:23 #: lib/block_scout_web/templates/block_transaction/index.html.eex:23
#: lib/block_scout_web/templates/block_transaction/index.html.eex:26 #: lib/block_scout_web/templates/block_transaction/index.html.eex:26
#: lib/block_scout_web/templates/block_transaction/index.html.eex:35 #: lib/block_scout_web/templates/block_transaction/index.html.eex:35
#: lib/block_scout_web/templates/chain/show.html.eex:76 #: lib/block_scout_web/templates/chain/show.html.eex:71
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35 #: lib/block_scout_web/templates/layout/_topnav.html.eex:35
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:56 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:56
#: lib/block_scout_web/templates/transaction/index.html.eex:56 #: lib/block_scout_web/templates/transaction/index.html.eex:56
@ -1083,7 +1077,7 @@ msgid "View All Blocks →"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:75 #: lib/block_scout_web/templates/chain/show.html.eex:70
msgid "View All Transactions →" msgid "View All Transactions →"
msgstr "" msgstr ""
@ -1190,3 +1184,13 @@ msgstr ""
#: lib/block_scout_web/views/address_contract_view.ex:15 #: lib/block_scout_web/views/address_contract_view.ex:15
msgid "true" msgid "true"
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:58
msgid "Hide"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:57
msgid "Show"
msgstr ""

@ -121,7 +121,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:28 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:28
#: lib/block_scout_web/templates/address_transaction/index.html.eex:34 #: lib/block_scout_web/templates/address_transaction/index.html.eex:24
#: lib/block_scout_web/views/address_internal_transaction_view.ex:8 #: lib/block_scout_web/views/address_internal_transaction_view.ex:8
#: lib/block_scout_web/views/address_transaction_view.ex:8 #: lib/block_scout_web/views/address_transaction_view.ex:8
msgid "All" msgid "All"
@ -257,7 +257,7 @@ msgid "Connection Lost, click to load newer internal transactions"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:24 #: lib/block_scout_web/templates/address_transaction/index.html.eex:14
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:53 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:53
#: lib/block_scout_web/templates/transaction/index.html.eex:53 #: lib/block_scout_web/templates/transaction/index.html.eex:53
msgid "Connection Lost, click to load newer transactions" msgid "Connection Lost, click to load newer transactions"
@ -434,7 +434,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:45 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:45
#: lib/block_scout_web/templates/address_transaction/index.html.eex:51 #: lib/block_scout_web/templates/address_transaction/index.html.eex:41
#: lib/block_scout_web/views/address_internal_transaction_view.ex:7 #: lib/block_scout_web/views/address_internal_transaction_view.ex:7
#: lib/block_scout_web/views/address_transaction_view.ex:7 #: lib/block_scout_web/views/address_transaction_view.ex:7
msgid "From" msgid "From"
@ -574,13 +574,6 @@ msgid "More internal transactions have come in"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:14
msgid "More pending transactions have come in"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:19
#: lib/block_scout_web/templates/chain/show.html.eex:72
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:48 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:48
#: lib/block_scout_web/templates/transaction/index.html.eex:48 #: lib/block_scout_web/templates/transaction/index.html.eex:48
msgid "More transactions have come in" msgid "More transactions have come in"
@ -699,6 +692,7 @@ msgid "Pending"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:60
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:60 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:60
msgid "Pending Transactions" msgid "Pending Transactions"
msgstr "" msgstr ""
@ -773,7 +767,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: #:
#: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:26 #: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:28
msgid "Search tokens" msgid "Search tokens"
msgstr "" msgstr ""
@ -883,7 +877,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:34 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:34
#: lib/block_scout_web/templates/address_transaction/index.html.eex:40 #: lib/block_scout_web/templates/address_transaction/index.html.eex:30
#: lib/block_scout_web/views/address_internal_transaction_view.ex:6 #: lib/block_scout_web/views/address_internal_transaction_view.ex:6
#: lib/block_scout_web/views/address_transaction_view.ex:6 #: lib/block_scout_web/views/address_transaction_view.ex:6
msgid "To" msgid "To"
@ -991,14 +985,14 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:5 #: lib/block_scout_web/templates/address/_tabs.html.eex:5
#: lib/block_scout_web/templates/address/_tabs.html.eex:71 #: lib/block_scout_web/templates/address/_tabs.html.eex:71
#: lib/block_scout_web/templates/address_transaction/index.html.eex:63 #: lib/block_scout_web/templates/address_transaction/index.html.eex:53
#: lib/block_scout_web/templates/address_validation/index.html.eex:11 #: lib/block_scout_web/templates/address_validation/index.html.eex:11
#: lib/block_scout_web/templates/address_validation/index.html.eex:65 #: lib/block_scout_web/templates/address_validation/index.html.eex:65
#: lib/block_scout_web/templates/block_transaction/index.html.eex:13 #: lib/block_scout_web/templates/block_transaction/index.html.eex:13
#: lib/block_scout_web/templates/block_transaction/index.html.eex:23 #: lib/block_scout_web/templates/block_transaction/index.html.eex:23
#: lib/block_scout_web/templates/block_transaction/index.html.eex:26 #: lib/block_scout_web/templates/block_transaction/index.html.eex:26
#: lib/block_scout_web/templates/block_transaction/index.html.eex:35 #: lib/block_scout_web/templates/block_transaction/index.html.eex:35
#: lib/block_scout_web/templates/chain/show.html.eex:76 #: lib/block_scout_web/templates/chain/show.html.eex:71
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35 #: lib/block_scout_web/templates/layout/_topnav.html.eex:35
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:56 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:56
#: lib/block_scout_web/templates/transaction/index.html.eex:56 #: lib/block_scout_web/templates/transaction/index.html.eex:56
@ -1083,7 +1077,7 @@ msgid "View All Blocks →"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:75 #: lib/block_scout_web/templates/chain/show.html.eex:70
msgid "View All Transactions →" msgid "View All Transactions →"
msgstr "" msgstr ""
@ -1190,3 +1184,13 @@ msgstr ""
#: lib/block_scout_web/views/address_contract_view.ex:15 #: lib/block_scout_web/views/address_contract_view.ex:15
msgid "true" msgid "true"
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:58
msgid "Hide"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:57
msgid "Show"
msgstr ""

@ -63,6 +63,10 @@ defmodule BlockScoutWeb.AddressPage do
click(session, css("[data-test='token_transfers_#{contract_address_hash}']")) click(session, css("[data-test='token_transfers_#{contract_address_hash}']"))
end end
def click_show_pending_transactions(session) do
click(session, css("[data-selector='pending-transactions-open']"))
end
def contract_creation(%InternalTransaction{created_contract_address_hash: hash}) do def contract_creation(%InternalTransaction{created_contract_address_hash: hash}) do
css("[data-address-hash='#{hash}']", text: to_string(hash)) css("[data-address-hash='#{hash}']", text: to_string(hash))
end end

@ -132,6 +132,7 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
session session
|> AddressPage.visit_page(addresses.lincoln) |> AddressPage.visit_page(addresses.lincoln)
|> AddressPage.click_show_pending_transactions()
|> assert_has(AddressPage.pending_transaction(pending)) |> assert_has(AddressPage.pending_transaction(pending))
|> assert_has(AddressPage.transaction(transactions.from_taft)) |> assert_has(AddressPage.transaction(transactions.from_taft))
|> assert_has(AddressPage.transaction(transactions.from_lincoln)) |> assert_has(AddressPage.transaction(transactions.from_lincoln))
@ -143,6 +144,7 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
session session
|> AddressPage.visit_page(addresses.lincoln) |> AddressPage.visit_page(addresses.lincoln)
|> AddressPage.click_show_pending_transactions()
|> assert_has(AddressPage.pending_transaction(pending)) |> assert_has(AddressPage.pending_transaction(pending))
new_pending = insert(:transaction, from_address: addresses.lincoln) new_pending = insert(:transaction, from_address: addresses.lincoln)

Loading…
Cancel
Save