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. 409
      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. 159
      apps/block_scout_web/assets/js/pages/address.js
  7. 6
      apps/block_scout_web/assets/js/pages/block.js
  8. 40
      apps/block_scout_web/assets/js/pages/chain.js
  9. 30
      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. 26
      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 = {
type: 'PAGE_LOAD',
addressHash: '1234',
beyondPageOne: false
beyondPageOne: false,
pendingTransactionHashes: ['1']
}
const output = reducer(state, action)
expect(output.addressHash).toBe('1234')
expect(output.beyondPageOne).toBe(false)
expect(output.filter).toBe(undefined)
expect(output.pendingTransactionHashes).toEqual(['1'])
})
test('page 2 without filter', () => {
const state = initialState
const action = {
type: 'PAGE_LOAD',
addressHash: '1234',
beyondPageOne: true,
addressHash: '1234'
pendingTransactionHashes: ['1']
}
const output = reducer(state, action)
expect(output.addressHash).toBe('1234')
expect(output.filter).toBe(undefined)
expect(output.beyondPageOne).toBe(true)
expect(output.filter).toBe(undefined)
expect(output.pendingTransactionHashes).toEqual(['1'])
})
test('page 1 with "to" filter', () => {
const state = initialState
@ -38,22 +42,22 @@ describe('PAGE_LOAD', () => {
const output = reducer(state, action)
expect(output.addressHash).toBe('1234')
expect(output.filter).toBe('to')
expect(output.beyondPageOne).toBe(false)
expect(output.filter).toBe('to')
})
test('page 2 with "to" filter', () => {
const state = initialState
const action = {
type: 'PAGE_LOAD',
beyondPageOne: true,
addressHash: '1234',
beyondPageOne: true,
filter: 'to'
}
const output = reducer(state, action)
expect(output.addressHash).toBe('1234')
expect(output.filter).toBe('to')
expect(output.beyondPageOne).toBe(true)
expect(output.filter).toBe('to')
})
})
@ -65,7 +69,6 @@ test('CHANNEL_DISCONNECTED', () => {
const output = reducer(state, action)
expect(output.channelDisconnected).toBe(true)
expect(output.batchCountAccumulator).toBe(0)
})
test('RECEIVED_UPDATED_BALANCE', () => {
@ -81,68 +84,19 @@ test('RECEIVED_UPDATED_BALANCE', () => {
expect(output.balance).toBe('hello world')
})
describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
describe('RECEIVED_NEW_PENDING_TRANSACTION', () => {
test('single transaction', () => {
const state = initialState
const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_PENDING_TRANSACTION',
msg: {
transactionHash: '0x00',
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)
expect(output.newPendingTransactions).toEqual([])
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)
})
test('single transaction after single transaction', () => {
@ -150,273 +104,97 @@ describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => {
newPendingTransactions: ['test 1']
})
const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_PENDING_TRANSACTION',
msg: {
transactionHash: '0x02',
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)
expect(output.newPendingTransactions).toEqual([])
expect(output.newPendingTransactionHashesBatch.length).toEqual(22)
expect(output.pendingTransactionHashes.length).toEqual(1)
})
test('after disconnection', () => {
const state = Object.assign({}, initialState, {
channelDisconnected: true
})
const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_PENDING_TRANSACTION',
msg: {
transactionHash: '0x00',
transactionHtml: 'test'
}]
}
}
const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([])
expect(output.newPendingTransactionHashesBatch).toEqual([])
expect(output.pendingTransactionHashes).toEqual([])
})
test('on page 2', () => {
const state = Object.assign({}, initialState, {
beyondPageOne: true
})
const action = {
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_PENDING_TRANSACTION',
msg: {
transactionHash: '0x00',
transactionHtml: 'test'
}]
}
}
const output = reducer(state, action)
expect(output.newPendingTransactions).toEqual([])
expect(output.newPendingTransactionHashesBatch).toEqual([])
expect(output.batchCountAccumulator).toEqual(0)
expect(output.pendingTransactionHashes).toEqual([])
})
})
describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
describe('RECEIVED_NEW_TRANSACTION', () => {
test('single transaction', () => {
const state = Object.assign({}, initialState, {
addressHash: '0x111'
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
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'
}]
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
transactionHtml: 'test'
}
}
const output = reducer(state, action)
expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(11)
expect(output.newTransactions).toEqual([{ transactionHtml: 'test' }])
expect(output.transactionCount).toEqual(null)
})
test('single transaction after single transaction', () => {
const state = Object.assign({}, initialState, {
newTransactions: ['test 1']
newTransactions: [{ transactionHtml: 'test 1' }]
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
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)
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)
expect(output.newTransactions).toEqual([
{ transactionHtml: 'test 1' },
{ transactionHtml: 'test 2' }
])
})
test('after disconnection', () => {
const state = Object.assign({}, initialState, {
channelDisconnected: true
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
transactionHtml: 'test'
}]
}
}
const output = reducer(state, action)
expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(0)
})
test('on page 2', () => {
const state = Object.assign({}, initialState, {
@ -425,17 +203,15 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
addressHash: '0x111'
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
transactionHtml: 'test',
fromAddressHash: '0x111'
}]
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
transactionHtml: 'test'
}
}
const output = reducer(state, action)
expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(0)
expect(output.transactionCount).toEqual(2)
expect(output.transactionCount).toEqual(1)
})
test('transaction from current address with "from" filter', () => {
const state = Object.assign({}, initialState, {
@ -443,15 +219,17 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
filter: 'from'
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
fromAddressHash: '1234',
transactionHtml: 'test'
}]
}
}
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', () => {
const state = Object.assign({}, initialState, {
@ -459,11 +237,11 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
filter: 'to'
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
fromAddressHash: '1234',
transactionHtml: 'test'
}]
}
}
const output = reducer(state, action)
@ -475,15 +253,17 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
filter: 'to'
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
toAddressHash: '1234',
transactionHtml: 'test'
}]
}
}
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', () => {
const state = Object.assign({}, initialState, {
@ -491,11 +271,11 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
filter: 'from'
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
toAddressHash: '1234',
transactionHtml: 'test'
}]
}
}
const output = reducer(state, action)
@ -504,58 +284,17 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
test('single transaction collated from pending', () => {
const state = initialState
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
transactionHash: '0x00',
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)
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)
})
describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
describe('RECEIVED_NEW_TRANSACTION', () => {
test('single transaction', () => {
const state = initialState
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
transactionHtml: 'test'
}]
}
}
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)
expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(11)
expect(output.transactionCount).toEqual(11)
})
test('single transaction after single transaction', () => {
const state = Object.assign({}, initialState, {
newTransactions: ['test 1']
})
const action = {
type: 'RECEIVED_NEW_TRANSACTION_BATCH',
msgs: [{
type: 'RECEIVED_NEW_TRANSACTION',
msg: {
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)
expect(output.newTransactions).toEqual([])
expect(output.batchCountAccumulator).toEqual(22)
})
})

@ -26,16 +26,17 @@ import './lib/from_now'
import './lib/indexing'
import './lib/loading_element'
import './lib/market_history_chart'
import './lib/pending_transactions_toggle'
import './lib/pretty_json'
import './lib/reload_button'
import './lib/tooltip'
import './lib/smart_contract/read_only_functions'
import './lib/smart_contract/wei_ether_converter'
import './lib/pretty_json'
import './lib/try_api'
import './lib/stop_propagation'
import './lib/token_balance_dropdown'
import './lib/token_balance_dropdown_search'
import './lib/token_transfers_toggle'
import './lib/stop_propagation'
import './lib/tooltip'
import './lib/try_api'
import './pages/address'
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 apiPath = element.dataset.api_path
$loading.show()
$.get(apiPath)
.done(response => $element.html(response))
.fail(() => {

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

@ -4,7 +4,7 @@ import URI from 'urijs'
import humps from 'humps'
import socket from '../socket'
import { updateAllAges } from '../lib/from_now'
import { buildFullBlockList, initRedux, beforeWithClingBottom, skippedBlockListBuilder } from '../utils'
import { buildFullBlockList, initRedux, slideDownBefore, skippedBlockListBuilder } from '../utils'
export const initialState = {
blockNumbers: [],
@ -97,10 +97,10 @@ if ($blockListPage.length) {
} else {
if (skippedBlockNumbers.length) {
_.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()
}

@ -5,16 +5,13 @@ import numeral from 'numeral'
import socket from '../socket'
import { updateAllAges } from '../lib/from_now'
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'
const BATCH_THRESHOLD = 10
export const initialState = {
addressCount: null,
availableSupply: null,
averageBlockTime: null,
batchCountAccumulator: 0,
blockNumbers: [],
marketHistoryData: null,
newBlock: null,
@ -85,21 +82,14 @@ export function reducer (state = initialState, action) {
usdMarketCap: action.msg.exchangeRate.marketCapUsd
})
}
case 'RECEIVED_NEW_TRANSACTION_BATCH': {
if (!state.batchCountAccumulator && action.msgs.length < BATCH_THRESHOLD) {
return Object.assign({}, state, {
newTransactions: [
...state.newTransactions,
...action.msgs.map(({transactionHtml}) => transactionHtml)
],
transactionCount: state.transactionCount + action.msgs.length
})
} else {
return Object.assign({}, state, {
batchCountAccumulator: state.batchCountAccumulator + action.msgs.length,
transactionCount: state.transactionCount + action.msgs.length
})
}
case 'RECEIVED_NEW_TRANSACTION': {
return Object.assign({}, state, {
newTransactions: [
...state.newTransactions,
action.msg.transactionHtml
],
transactionCount: state.transactionCount + 1
})
}
default:
return state
@ -128,9 +118,7 @@ if ($chainDetailsPage.length) {
const transactionsChannel = socket.channel(`transactions:new_transaction`)
transactionsChannel.join()
transactionsChannel.on('transaction', batchChannel((msgs) =>
store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) }))
)
transactionsChannel.on('transaction', (msg) => store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION', msg: humps.camelizeKeys(msg) }))
chart = createMarketHistoryChart($('[data-chart="marketHistoryChart"]')[0])
},
@ -138,8 +126,6 @@ if ($chainDetailsPage.length) {
const $addressCount = $('[data-selector="address-count"]')
const $averageBlockTime = $('[data-selector="average-block-time"]')
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 $transactionsList = $('[data-selector="transactions-list"]')
const $transactionCount = $('[data-selector="transaction-count"]')
@ -176,12 +162,6 @@ if ($chainDetailsPage.length) {
updateAllAges()
}
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) {
const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length)
$transactionsList

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

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

@ -10,14 +10,14 @@
</span>
<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;">
<i class="fa fa-spinner fa-spin"></i>
<h5 data-loading class="mb-0 text-white text-faded">
<i class="fa fa-spinner fa-spin mr-2"></i>
<%= 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.") %>
</p>
</h5>
</div>
</div>
</div>

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

@ -9,16 +9,6 @@
</div>
<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="reload-button" class="alert alert-danger">
<a href="#" class="alert-link"><%= gettext "Connection Lost, click to load newer transactions" %></a>
@ -61,10 +51,20 @@
</div>
</div>
<h2 class="card-title"><%= gettext "Transactions" %></h2>
<div class="mb-3" data-selector="pending-transactions-list">
<%= for pending_transaction <- @pending_transactions do %>
<%= render(BlockScoutWeb.TransactionView, "_tile.html", current_address: @address, transaction: pending_transaction) %>
<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 %>
<%= render(BlockScoutWeb.TransactionView, "_tile.html", current_address: @address, transaction: pending_transaction) %>
<% end %>
<hr />
</div>
</div>
<%= if Enum.count(@transactions) > 0 do %>
<span data-selector="transactions-list">

@ -67,11 +67,6 @@
<div class="card card-chain-transactions">
<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") %>
<h2 class="card-title"><%= gettext "Transactions" %></h2>
<span data-selector="transactions-list">

@ -121,7 +121,7 @@ msgstr ""
#, elixir-format
#: 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_transaction_view.ex:8
msgid "All"
@ -257,7 +257,7 @@ msgid "Connection Lost, click to load newer internal transactions"
msgstr ""
#, 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/transaction/index.html.eex:53
msgid "Connection Lost, click to load newer transactions"
@ -434,7 +434,7 @@ msgstr ""
#, elixir-format
#: 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_transaction_view.ex:7
msgid "From"
@ -574,13 +574,6 @@ msgid "More internal transactions have come in"
msgstr ""
#, 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/transaction/index.html.eex:48
msgid "More transactions have come in"
@ -699,6 +692,7 @@ msgid "Pending"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:60
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:60
msgid "Pending Transactions"
msgstr ""
@ -773,7 +767,7 @@ msgstr ""
#, 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"
msgstr ""
@ -883,7 +877,7 @@ msgstr ""
#, elixir-format
#: 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_transaction_view.ex:6
msgid "To"
@ -991,14 +985,14 @@ msgstr ""
#, elixir-format
#: 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_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:65
#: 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:26
#: 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/pending_transaction/index.html.eex:56
#: lib/block_scout_web/templates/transaction/index.html.eex:56
@ -1083,7 +1077,7 @@ msgid "View All Blocks →"
msgstr ""
#, 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 →"
msgstr ""
@ -1190,3 +1184,13 @@ msgstr ""
#: lib/block_scout_web/views/address_contract_view.ex:15
msgid "true"
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
#: 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_transaction_view.ex:8
msgid "All"
@ -257,7 +257,7 @@ msgid "Connection Lost, click to load newer internal transactions"
msgstr ""
#, 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/transaction/index.html.eex:53
msgid "Connection Lost, click to load newer transactions"
@ -434,7 +434,7 @@ msgstr ""
#, elixir-format
#: 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_transaction_view.ex:7
msgid "From"
@ -574,13 +574,6 @@ msgid "More internal transactions have come in"
msgstr ""
#, 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/transaction/index.html.eex:48
msgid "More transactions have come in"
@ -699,6 +692,7 @@ msgid "Pending"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:60
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:60
msgid "Pending Transactions"
msgstr ""
@ -773,7 +767,7 @@ msgstr ""
#, 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"
msgstr ""
@ -883,7 +877,7 @@ msgstr ""
#, elixir-format
#: 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_transaction_view.ex:6
msgid "To"
@ -991,14 +985,14 @@ msgstr ""
#, elixir-format
#: 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_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:65
#: 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:26
#: 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/pending_transaction/index.html.eex:56
#: lib/block_scout_web/templates/transaction/index.html.eex:56
@ -1083,7 +1077,7 @@ msgid "View All Blocks →"
msgstr ""
#, 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 →"
msgstr ""
@ -1190,3 +1184,13 @@ msgstr ""
#: lib/block_scout_web/views/address_contract_view.ex:15
msgid "true"
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}']"))
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
css("[data-address-hash='#{hash}']", text: to_string(hash))
end

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

Loading…
Cancel
Save