diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex
index fc8a228664..d81dfc308c 100644
--- a/apps/explorer/lib/explorer/chain.ex
+++ b/apps/explorer/lib/explorer/chain.ex
@@ -587,9 +587,9 @@ defmodule Explorer.Chain do
iex> [%Transaction{hash: hash1}, %Transaction{hash: hash2}] = insert_list(2, :transaction)
iex> [%Explorer.Chain.Transaction{hash: found_hash1}, %Explorer.Chain.Transaction{hash: found_hash2}] =
...> Explorer.Chain.hashes_to_transactions([hash1, hash2])
- iex> found_hash1 == hash1
+ iex> found_hash1 in [hash1, hash2]
true
- iex> found_hash2 == hash2
+ iex> found_hash2 in [hash1, hash2]
true
Returns `[]` if not found
diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs
index 6dad44b353..a8af458790 100644
--- a/apps/explorer/test/explorer/chain_test.exs
+++ b/apps/explorer/test/explorer/chain_test.exs
@@ -529,11 +529,9 @@ defmodule Explorer.ChainTest do
necessity_by_association: %{block: :required}
)
- assert [%Transaction{hash: ^hash_without_index1}, %Transaction{hash: ^hash_without_index2}] =
- Chain.hashes_to_transactions(
- [hash_without_index1, hash_without_index2],
- necessity_by_association: %{block: :optional}
- )
+ assert [hash_without_index1, hash_without_index2]
+ |> Chain.hashes_to_transactions(necessity_by_association: %{block: :optional})
+ |> Enum.all?(&(&1.hash in [hash_without_index1, hash_without_index2]))
end
end
diff --git a/apps/explorer_web/assets/__tests__/pages/address.js b/apps/explorer_web/assets/__tests__/pages/address.js
index c4a55398df..78bc3b84dd 100644
--- a/apps/explorer_web/assets/__tests__/pages/address.js
+++ b/apps/explorer_web/assets/__tests__/pages/address.js
@@ -100,6 +100,7 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
expect(output.newTransactions).toEqual(['test'])
expect(output.batchCountAccumulator).toEqual(0)
+ expect(output.transactionCount).toEqual(1)
})
test('large batch of transactions', () => {
const state = initialState
@@ -133,6 +134,7 @@ describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
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, {
diff --git a/apps/explorer_web/assets/__tests__/pages/chain.js b/apps/explorer_web/assets/__tests__/pages/chain.js
index c33e3bbc0d..86c84ad572 100644
--- a/apps/explorer_web/assets/__tests__/pages/chain.js
+++ b/apps/explorer_web/assets/__tests__/pages/chain.js
@@ -1,19 +1,9 @@
import { reducer, initialState } from '../../js/pages/chain'
-test('CHANNEL_DISCONNECTED', () => {
- const state = initialState
- const action = {
- type: 'CHANNEL_DISCONNECTED'
- }
- const output = reducer(state, action)
-
- expect(output.channelDisconnected).toBe(true)
-})
-
test('RECEIVED_NEW_BLOCK', () => {
- const state = Object.assign({}, initialState, {
- newBlock: 'last new block'
- })
+ const state = Object.assign({}, initialState, {
+ newBlock: 'last new block'
+ })
const action = {
type: 'RECEIVED_NEW_BLOCK',
msg: {
@@ -24,3 +14,121 @@ test('RECEIVED_NEW_BLOCK', () => {
expect(output.newBlock).toEqual('new block')
})
+
+describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
+ test('single transaction', () => {
+ const state = initialState
+ const action = {
+ type: 'RECEIVED_NEW_TRANSACTION_BATCH',
+ msgs: [{
+ 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: [{
+ 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)
+ })
+})
diff --git a/apps/explorer_web/assets/__tests__/pages/transaction.js b/apps/explorer_web/assets/__tests__/pages/transaction.js
index ec380fbe01..20da637dae 100644
--- a/apps/explorer_web/assets/__tests__/pages/transaction.js
+++ b/apps/explorer_web/assets/__tests__/pages/transaction.js
@@ -1,9 +1,9 @@
import { reducer, initialState } from '../../js/pages/transaction'
-test('RECEIVED_UPDATED_CONFIRMATIONS', () => {
+test('RECEIVED_NEW_BLOCK', () => {
const state = { ...initialState, blockNumber: 1 }
const action = {
- type: 'RECEIVED_UPDATED_CONFIRMATIONS',
+ type: 'RECEIVED_NEW_BLOCK',
msg: {
blockNumber: 5
}
@@ -12,3 +12,151 @@ test('RECEIVED_UPDATED_CONFIRMATIONS', () => {
expect(output.confirmations).toBe(4)
})
+
+describe('RECEIVED_NEW_TRANSACTION_BATCH', () => {
+ test('single transaction', () => {
+ const state = initialState
+ const action = {
+ type: 'RECEIVED_NEW_TRANSACTION_BATCH',
+ msgs: [{
+ 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: [{
+ 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('after disconnection', () => {
+ const state = Object.assign({}, initialState, {
+ channelDisconnected: true
+ })
+ const action = {
+ type: 'RECEIVED_NEW_TRANSACTION_BATCH',
+ msgs: [{
+ 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, {
+ beyondPageOne: true
+ })
+ const action = {
+ type: 'RECEIVED_NEW_TRANSACTION_BATCH',
+ msgs: [{
+ transactionHtml: 'test'
+ }]
+ }
+ const output = reducer(state, action)
+
+ expect(output.newTransactions).toEqual([])
+ expect(output.batchCountAccumulator).toEqual(0)
+ })
+})
diff --git a/apps/explorer_web/assets/css/components/_animations.scss b/apps/explorer_web/assets/css/components/_animations.scss
index d01ac6579d..22cd004011 100644
--- a/apps/explorer_web/assets/css/components/_animations.scss
+++ b/apps/explorer_web/assets/css/components/_animations.scss
@@ -3,7 +3,7 @@
100% {opacity: 1;}
}
-@keyframes fade-up {
+@keyframes fade-up-blocks-homepage {
0% {
flex-basis: 0%;
width: 0%;
@@ -23,13 +23,36 @@
}
}
+@keyframes fade-up {
+ 0% {
+ height: 0;
+ opacity: 0;
+ }
+ 25% {
+ opacity: 0;
+ transform: translateY(10px) scale(0.97);
+ }
+ 50% {
+ height: 98px;
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+}
+
.fade-in {
animation: fade-in 1s ease-out forwards;
}
+.fade-up-blocks-homepage {
+ will-change: transform, opacity, width;
+ max-height: 98px;
+ animation: fade-up-blocks-homepage 0.6s cubic-bezier(0.455, 0.03, 0.515, 0.955);
+}
.fade-up {
- will-change: transform, opacity, width;
+ will-change: transform, opacity, height;
max-height: 98px;
- animation: fade-up 0.55s cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ animation: fade-up 0.6s cubic-bezier(0.455, 0.03, 0.515, 0.955);
}
diff --git a/apps/explorer_web/assets/js/app.js b/apps/explorer_web/assets/js/app.js
index 0fbcfcbd28..7066c283c9 100644
--- a/apps/explorer_web/assets/js/app.js
+++ b/apps/explorer_web/assets/js/app.js
@@ -26,5 +26,6 @@ import './lib/tooltip'
import './lib/smart_contract/read_function'
import './pages/address'
+import './pages/block'
import './pages/chain'
import './pages/transaction'
diff --git a/apps/explorer_web/assets/js/pages/address.js b/apps/explorer_web/assets/js/pages/address.js
index 3ee81ebd7f..37057903ae 100644
--- a/apps/explorer_web/assets/js/pages/address.js
+++ b/apps/explorer_web/assets/js/pages/address.js
@@ -5,6 +5,7 @@ import 'numeral/locales'
import socket from '../socket'
import router from '../router'
import { batchChannel, initRedux } from '../utils'
+import { updateAllAges } from '../lib/from_now'
const BATCH_THRESHOLD = 10
@@ -108,6 +109,7 @@ router.when('/addresses/:addressHash').then((params) => initRedux(reducer, {
}
if (oldState.newTransactions !== state.newTransactions && $transactionsList.length) {
$transactionsList.prepend(state.newTransactions.slice(oldState.newTransactions.length).reverse().join(''))
+ updateAllAges()
}
}
}))
diff --git a/apps/explorer_web/assets/js/pages/block.js b/apps/explorer_web/assets/js/pages/block.js
new file mode 100644
index 0000000000..2c32d9ffae
--- /dev/null
+++ b/apps/explorer_web/assets/js/pages/block.js
@@ -0,0 +1,60 @@
+import $ from 'jquery'
+import humps from 'humps'
+import socket from '../socket'
+import router from '../router'
+import { updateAllAges } from '../lib/from_now'
+import { initRedux } from '../utils'
+
+export const initialState = {
+ beyondPageOne: null,
+ channelDisconnected: false,
+ newBlock: null
+}
+
+export function reducer (state = initialState, action) {
+ switch (action.type) {
+ case 'PAGE_LOAD': {
+ return Object.assign({}, state, {
+ beyondPageOne: !!action.blockNumber
+ })
+ }
+ case 'CHANNEL_DISCONNECTED': {
+ if (state.beyondPageOne) return state
+
+ return Object.assign({}, state, {
+ channelDisconnected: true
+ })
+ }
+ case 'RECEIVED_NEW_BLOCK': {
+ if (state.channelDisconnected || state.beyondPageOne) return state
+
+ return Object.assign({}, state, {
+ newBlock: action.msg.blockHtml
+ })
+ }
+ default:
+ return state
+ }
+}
+
+router.when('/blocks', { exactPathMatch: true }).then(({ blockNumber }) => initRedux(reducer, {
+ main (store) {
+ const blocksChannel = socket.channel(`blocks:new_block`, {})
+ store.dispatch({ type: 'PAGE_LOAD', blockNumber })
+ blocksChannel.join()
+ blocksChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' }))
+ blocksChannel.on('new_block', (msg) =>
+ store.dispatch({ type: 'RECEIVED_NEW_BLOCK', msg: humps.camelizeKeys(msg) })
+ )
+ },
+ render (state, oldState) {
+ const $channelDisconnected = $('[data-selector="channel-disconnected-message"]')
+ const $blocksList = $('[data-selector="blocks-list"]')
+
+ if (state.channelDisconnected) $channelDisconnected.show()
+ if (oldState.newBlock !== state.newBlock) {
+ $blocksList.prepend(state.newBlock)
+ updateAllAges()
+ }
+ }
+}))
diff --git a/apps/explorer_web/assets/js/pages/chain.js b/apps/explorer_web/assets/js/pages/chain.js
index 3a6d4f7fe1..20b9772fe8 100644
--- a/apps/explorer_web/assets/js/pages/chain.js
+++ b/apps/explorer_web/assets/js/pages/chain.js
@@ -1,46 +1,99 @@
import $ from 'jquery'
import humps from 'humps'
+import numeral from 'numeral'
+import 'numeral/locales'
import router from '../router'
import socket from '../socket'
import { updateAllAges } from '../lib/from_now'
-import { initRedux } from '../utils'
+import { batchChannel, initRedux } from '../utils'
+
+const BATCH_THRESHOLD = 10
export const initialState = {
+ batchCountAccumulator: 0,
newBlock: null,
- channelDisconnected: false
+ newTransactions: [],
+ transactionCount: null
}
export function reducer (state = initialState, action) {
switch (action.type) {
- case 'CHANNEL_DISCONNECTED': {
+ case 'PAGE_LOAD': {
return Object.assign({}, state, {
- channelDisconnected: true
+ transactionCount: numeral(action.transactionCount).value()
})
}
case 'RECEIVED_NEW_BLOCK': {
return Object.assign({}, state, {
- newBlock: humps.camelizeKeys(action.msg).homepageBlockHtml
+ newBlock: action.msg.homepageBlockHtml
})
}
+ 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
+ })
+ }
+ }
default:
return state
}
}
-router.when('', { exactPathMatch: true }).then(() => initRedux(reducer, {
+router.when('', { exactPathMatch: true }).then(({ locale }) => initRedux(reducer, {
main (store) {
const blocksChannel = socket.channel(`blocks:new_block`)
+ numeral.locale(locale)
+ store.dispatch({
+ type: 'PAGE_LOAD',
+ transactionCount: $('[data-selector="transaction-count"]').text()
+ })
blocksChannel.join()
- blocksChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' }))
- blocksChannel.on('new_block', msg => store.dispatch({ type: 'RECEIVED_NEW_BLOCK', msg }))
+ blocksChannel.on('new_block', msg => store.dispatch({ type: 'RECEIVED_NEW_BLOCK', msg: humps.camelizeKeys(msg) }))
+
+ const transactionsChannel = socket.channel(`transactions:new_transaction`)
+ transactionsChannel.join()
+ transactionsChannel.on('new_transaction', batchChannel((msgs) =>
+ store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) }))
+ )
},
render (state, oldState) {
const $blockList = $('[data-selector="chain-block-list"]')
+ const $channelBatching = $('[data-selector="channel-batching-message"]')
+ const $channelBatchingCount = $('[data-selector="channel-batching-count"]')
+ const $transactionsList = $('[data-selector="transactions-list"]')
+ const $transactionCount = $('[data-selector="transaction-count"]')
if (oldState.newBlock !== state.newBlock) {
$blockList.children().last().remove()
$blockList.prepend(state.newBlock)
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 (oldState.newTransactions !== state.newTransactions) {
+ const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length)
+ $transactionsList
+ .children()
+ .slice($transactionsList.children().length - newTransactionsToInsert.length, $transactionsList.children().length)
+ .remove()
+ $transactionsList.prepend(newTransactionsToInsert.reverse().join(''))
+
+ updateAllAges()
+ }
}
}))
diff --git a/apps/explorer_web/assets/js/pages/transaction.js b/apps/explorer_web/assets/js/pages/transaction.js
index 3cbe9ebb55..02a178d2ce 100644
--- a/apps/explorer_web/assets/js/pages/transaction.js
+++ b/apps/explorer_web/assets/js/pages/transaction.js
@@ -4,27 +4,63 @@ import numeral from 'numeral'
import 'numeral/locales'
import socket from '../socket'
import router from '../router'
-import { initRedux } from '../utils'
+import { updateAllAges } from '../lib/from_now'
+import { batchChannel, initRedux } from '../utils'
+
+const BATCH_THRESHOLD = 10
export const initialState = {
+ batchCountAccumulator: 0,
+ beyondPageOne: null,
blockNumber: null,
- confirmations: null
+ channelDisconnected: false,
+ confirmations: null,
+ newTransactions: [],
+ transactionCount: null
}
export function reducer (state = initialState, action) {
switch (action.type) {
case 'PAGE_LOAD': {
return Object.assign({}, state, {
- blockNumber: parseInt(action.blockNumber, 10)
+ beyondPageOne: !!action.index,
+ blockNumber: parseInt(action.blockNumber, 10),
+ transactionCount: numeral(action.transactionCount).value()
+ })
+ }
+ case 'CHANNEL_DISCONNECTED': {
+ if (state.beyondPageOne) return state
+
+ return Object.assign({}, state, {
+ channelDisconnected: true,
+ batchCountAccumulator: 0
})
}
- case 'RECEIVED_UPDATED_CONFIRMATIONS': {
+ case 'RECEIVED_NEW_BLOCK': {
if ((action.msg.blockNumber - state.blockNumber) > state.confirmations) {
return Object.assign({}, state, {
confirmations: action.msg.blockNumber - state.blockNumber
})
} else return state
}
+ case 'RECEIVED_NEW_TRANSACTION_BATCH': {
+ if (state.channelDisconnected || state.beyondPageOne) return state
+
+ 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
+ })
+ }
+ }
default:
return state
}
@@ -32,17 +68,65 @@ export function reducer (state = initialState, action) {
router.when('/transactions/:transactionHash').then(({ locale }) => initRedux(reducer, {
main (store) {
- const channel = socket.channel(`transactions:confirmations`, {})
+ const blocksChannel = socket.channel(`blocks:new_block`, {})
const $transactionBlockNumber = $('[data-selector="block-number"]')
numeral.locale(locale)
- store.dispatch({ type: 'PAGE_LOAD', blockNumber: $transactionBlockNumber.text() })
- channel.join()
- channel.on('update', (msg) => store.dispatch({ type: 'RECEIVED_UPDATED_CONFIRMATIONS', msg: humps.camelizeKeys(msg) }))
+ store.dispatch({
+ type: 'PAGE_LOAD',
+ blockNumber: $transactionBlockNumber.text()
+ })
+ blocksChannel.join()
+ blocksChannel.on('new_block', (msg) => store.dispatch({ type: 'RECEIVED_NEW_BLOCK', msg: humps.camelizeKeys(msg) }))
},
render (state, oldState) {
const $blockConfirmations = $('[data-selector="block-confirmations"]')
+
if (oldState.confirmations !== state.confirmations) {
$blockConfirmations.empty().append(numeral(state.confirmations).format())
}
}
}))
+
+router.when('/transactions', { exactPathMatch: true }).then((params) => initRedux(reducer, {
+ main (store) {
+ const { locale, index } = params
+ const transactionsChannel = socket.channel(`transactions:new_transaction`)
+ numeral.locale(locale)
+ store.dispatch({
+ type: 'PAGE_LOAD',
+ transactionCount: $('[data-selector="transaction-count"]').text(),
+ index
+ })
+ transactionsChannel.join()
+ transactionsChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' }))
+ transactionsChannel.on('new_transaction', batchChannel((msgs) =>
+ store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) }))
+ )
+ },
+ render (state, oldState) {
+ const $channelBatching = $('[data-selector="channel-batching-message"]')
+ const $channelBatchingCount = $('[data-selector="channel-batching-count"]')
+ const $channelDisconnected = $('[data-selector="channel-disconnected-message"]')
+ const $transactionsList = $('[data-selector="transactions-list"]')
+ const $transactionCount = $('[data-selector="transaction-count"]')
+
+ if (state.channelDisconnected) $channelDisconnected.show()
+ 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 (oldState.newTransactions !== state.newTransactions) {
+ const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length)
+ $transactionsList
+ .children()
+ .slice($transactionsList.children().length - newTransactionsToInsert.length, $transactionsList.children().length)
+ .remove()
+ $transactionsList.prepend(newTransactionsToInsert.reverse().join(''))
+
+ updateAllAges()
+ }
+ }
+}))
diff --git a/apps/explorer_web/lib/explorer_web/channels/block_channel.ex b/apps/explorer_web/lib/explorer_web/channels/block_channel.ex
index de32f4fba8..24ca952827 100644
--- a/apps/explorer_web/lib/explorer_web/channels/block_channel.ex
+++ b/apps/explorer_web/lib/explorer_web/channels/block_channel.ex
@@ -4,7 +4,7 @@ defmodule ExplorerWeb.BlockChannel do
"""
use ExplorerWeb, :channel
- alias ExplorerWeb.ChainView
+ alias ExplorerWeb.{BlockView, ChainView}
alias Phoenix.View
intercept(["new_block"])
@@ -16,6 +16,14 @@ defmodule ExplorerWeb.BlockChannel do
def handle_out("new_block", %{block: block}, socket) do
Gettext.put_locale(ExplorerWeb.Gettext, socket.assigns.locale)
+ rendered_block =
+ View.render_to_string(
+ BlockView,
+ "_tile.html",
+ locale: socket.assigns.locale,
+ block: block
+ )
+
rendered_homepage_block =
View.render_to_string(
ChainView,
@@ -25,7 +33,9 @@ defmodule ExplorerWeb.BlockChannel do
)
push(socket, "new_block", %{
- homepage_block_html: rendered_homepage_block
+ homepage_block_html: rendered_homepage_block,
+ block_html: rendered_block,
+ blockNumber: block.number
})
{:noreply, socket}
diff --git a/apps/explorer_web/lib/explorer_web/channels/transaction_channel.ex b/apps/explorer_web/lib/explorer_web/channels/transaction_channel.ex
index 75bd4f3f96..dfa8900302 100644
--- a/apps/explorer_web/lib/explorer_web/channels/transaction_channel.ex
+++ b/apps/explorer_web/lib/explorer_web/channels/transaction_channel.ex
@@ -1,10 +1,33 @@
defmodule ExplorerWeb.TransactionChannel do
@moduledoc """
- Establishes pub/sub channel for transaction page live updates.
+ Establishes pub/sub channel for live updates of transaction events.
"""
use ExplorerWeb, :channel
- def join("transactions:confirmations", _params, socket) do
+ alias ExplorerWeb.TransactionView
+ alias Phoenix.View
+
+ intercept(["new_transaction"])
+
+ def join("transactions:new_transaction", _params, socket) do
{:ok, %{}, socket}
end
+
+ def handle_out("new_transaction", %{transaction: transaction}, socket) do
+ Gettext.put_locale(ExplorerWeb.Gettext, socket.assigns.locale)
+
+ rendered_transaction =
+ View.render_to_string(
+ TransactionView,
+ "_tile.html",
+ locale: socket.assigns.locale,
+ transaction: transaction
+ )
+
+ push(socket, "new_transaction", %{
+ transaction_html: rendered_transaction
+ })
+
+ {:noreply, socket}
+ end
end
diff --git a/apps/explorer_web/lib/explorer_web/notifier.ex b/apps/explorer_web/lib/explorer_web/notifier.ex
index 88617f2739..81ea019d59 100644
--- a/apps/explorer_web/lib/explorer_web/notifier.ex
+++ b/apps/explorer_web/lib/explorer_web/notifier.ex
@@ -15,9 +15,6 @@ defmodule ExplorerWeb.Notifier do
end
def handle_event({:chain_event, :blocks, blocks}) do
- max_numbered_block = Enum.max_by(blocks, & &1.number).number
- Endpoint.broadcast("transactions:confirmations", "update", %{block_number: max_numbered_block})
-
Enum.each(blocks, &broadcast_block/1)
end
@@ -47,6 +44,10 @@ defmodule ExplorerWeb.Notifier do
end
defp broadcast_transaction(transaction) do
+ Endpoint.broadcast("transactions:new_transaction", "new_transaction", %{
+ transaction: transaction
+ })
+
Endpoint.broadcast("addresses:#{transaction.from_address_hash}", "transaction", %{
address: transaction.from_address,
transaction: transaction
diff --git a/apps/explorer_web/lib/explorer_web/templates/address/overview.html.eex b/apps/explorer_web/lib/explorer_web/templates/address/overview.html.eex
index e681600ad3..57bb132f7c 100644
--- a/apps/explorer_web/lib/explorer_web/templates/address/overview.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/address/overview.html.eex
@@ -18,7 +18,7 @@
<%= address_title(@address) %> Details
<%= @address %>
-
<%= Cldr.Number.to_string!(@transaction_count) %> <%= gettext "Transactions" %>
+
<%= Cldr.Number.to_string!(@transaction_count, format: "#,###") %> <%= gettext "Transactions" %>
<%= if contract?(@address) do %>
diff --git a/apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex b/apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex
index 571dcf2b24..409f4500ca 100644
--- a/apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/address_transaction/index.html.eex
@@ -81,7 +81,7 @@
diff --git a/apps/explorer_web/lib/explorer_web/templates/block/_tile.html.eex b/apps/explorer_web/lib/explorer_web/templates/block/_tile.html.eex
new file mode 100644
index 0000000000..e12e553188
--- /dev/null
+++ b/apps/explorer_web/lib/explorer_web/templates/block/_tile.html.eex
@@ -0,0 +1,48 @@
+
+
+
+
+ <%= link(
+ @block,
+ class: "tile-title",
+ to: block_path(ExplorerWeb.Endpoint, :show, @locale, @block),
+ "data-test": "block_number",
+ "data-block-number": to_string(@block.number)
+ ) %>
+
+
+
+ <%= ngettext("%{count} transaction", "%{count} transactions", Enum.count(@block.transactions)) %>
+
+
+ <%= Cldr.Unit.new(:byte, @block.size) |> Cldr.Unit.to_string! %>
+
+
+
+
+
+ <%= gettext "Miner" %>
+
+ <%= link to: address_path(ExplorerWeb.Endpoint, :show, @locale, @block.miner_hash) do %>
+ <%= @block.miner_hash %>
+ <% end %>
+
+
+
+
+
+
+ <%= formatted_gas(@block.gas_used) %>
+ (<%= formatted_gas(@block.gas_used / @block.gas_limit, format: "#.#%") %>)
+ <%= gettext "Gas Used" %>
+
+
+
;" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
+
+
+
+
+
<%= formatted_gas(@block.gas_limit) %> <%= gettext "Gas Limit" %>
+
+
+
diff --git a/apps/explorer_web/lib/explorer_web/templates/block/index.html.eex b/apps/explorer_web/lib/explorer_web/templates/block/index.html.eex
index 54b43bec24..d5edf5020a 100644
--- a/apps/explorer_web/lib/explorer_web/templates/block/index.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/block/index.html.eex
@@ -3,64 +3,12 @@
Blocks
-
- <%= gettext(
- "Showing #%{start_block} to #%{end_block}",
- start_block: List.first(@blocks).number,
- end_block: List.last(@blocks).number
- ) %>
-
- <%= for block <- @blocks do %>
-
-
-
-
- <%= link(
- block,
- class: "tile-title",
- to: block_path(@conn, :show, @conn.assigns.locale, block),
- "data-test": "block_number",
- "data-block-number": to_string(block.number)
- ) %>
-
-
-
- <%= ngettext("%{count} transaction", "%{count} transactions", Enum.count(block.transactions)) %>
-
-
- <%= Cldr.Unit.new(:byte, block.size) |> Cldr.Unit.to_string! %>
-
-
-
-
-
- <%= gettext "Miner" %>
-
- <%= link to: address_path(ExplorerWeb.Endpoint, :show, @locale, block.miner_hash) do %>
- <%= block.miner_hash %>
- <% end %>
-
-
-
-
-
-
- <%= formatted_gas(block.gas_used) %>
- (<%= formatted_gas(block.gas_used / block.gas_limit, format: "#.#%") %>)
- <%= gettext "Gas Used" %>
-
-
-
;" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
-
-
-
-
-
<%= formatted_gas(block.gas_limit) %> <%= gettext "Gas Limit" %>
-
-
-
- <% end %>
+
+ <%= for block <- @blocks do %>
+ <%= render ExplorerWeb.BlockView, "_tile.html", locale: @locale, block: block %>
+ <% end %>
+
<%= if @next_page_params do %>
<%= link(
diff --git a/apps/explorer_web/lib/explorer_web/templates/block_transaction/index.html.eex b/apps/explorer_web/lib/explorer_web/templates/block_transaction/index.html.eex
index 2079e5bdc0..ef4b70f9ca 100644
--- a/apps/explorer_web/lib/explorer_web/templates/block_transaction/index.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/block_transaction/index.html.eex
@@ -36,7 +36,7 @@
<%= gettext "Transactions" %>
<%= for transaction <- @transactions do %>
- <%= render "_transaction.html", locale: @locale, transaction: transaction %>
+ <%= render ExplorerWeb.TransactionView, "_tile.html", locale: @locale, transaction: transaction %>
<% end %>
<% else %>
diff --git a/apps/explorer_web/lib/explorer_web/templates/chain/_block.html.eex b/apps/explorer_web/lib/explorer_web/templates/chain/_block.html.eex
index ee9ba26f85..88cbe9d301 100644
--- a/apps/explorer_web/lib/explorer_web/templates/chain/_block.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/chain/_block.html.eex
@@ -1,4 +1,4 @@
-
+
<%= link(@block, to: block_path(ExplorerWeb.Endpoint, :show, @locale, @block), class: "tile-title") %>
diff --git a/apps/explorer_web/lib/explorer_web/templates/chain/_transactions.html.eex b/apps/explorer_web/lib/explorer_web/templates/chain/_transactions.html.eex
deleted file mode 100644
index bceaeffa1f..0000000000
--- a/apps/explorer_web/lib/explorer_web/templates/chain/_transactions.html.eex
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
- <%= link(gettext("View All Transactions →"), to: transaction_path(@conn, :index, Gettext.get_locale), class: "button button--secondary button--xsmall float-right") %>
-
<%= gettext "Transactions" %>
- <%= for transaction <- @chain.transactions do %>
-
-
-
-
-
<%= ExplorerWeb.TransactionView.transaction_display_type(transaction) %>
-
<%= ExplorerWeb.TransactionView.formatted_status(transaction) %>
-
-
-
- <%= render ExplorerWeb.TransactionView, "_link.html", locale: @locale, transaction_hash: transaction.hash %>
-
- <%= render ExplorerWeb.AddressView, "_link.html", address_hash: transaction.from_address_hash, contract: ExplorerWeb.AddressView.contract?(transaction.from_address), locale: @locale %>
- →
- <%= render ExplorerWeb.AddressView, "_link.html", address_hash: ExplorerWeb.TransactionView.to_address_hash(transaction), contract: ExplorerWeb.AddressView.contract?(transaction.to_address), locale: @locale %>
-
-
-
-
- <%= link(
- gettext("Block #%{number}", number: to_string(transaction.block.number)),
- to: block_path(@conn, :show, @conn.assigns.locale, transaction.block)
- ) %>
-
-
-
-
-
- <%= ExplorerWeb.TransactionView.value(transaction, include_label: false) %> <%= gettext "Ether" %>
-
- <%= ExplorerWeb.TransactionView.formatted_fee(transaction, denomination: :ether) %> <%= gettext "Fee" %>
-
-
-
- <% end %>
-
-
-
diff --git a/apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex b/apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex
index 88cfca0ecf..15ee6be8ae 100644
--- a/apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex
@@ -35,8 +35,8 @@
<%= gettext "Total transactions" %>
-
- <%= @transaction_estimated_count |> Cldr.Number.to_string!(format: "#,###") %>
+
+ <%= Cldr.Number.to_string!(@transaction_estimated_count, format: "#,###") %>
@@ -54,7 +54,7 @@
- <%= link(gettext("View All Blocks →"), to: block_path(@conn, :index, Gettext.get_locale), class: "button button--secondary button--xsmall float-right") %>
+ <%= link(gettext("View All Blocks →"), to: block_path(ExplorerWeb.Endpoint, :index, Gettext.get_locale), class: "button button--secondary button--xsmall float-right") %>
<%= gettext "Blocks" %>
<%= for block <- @chain.blocks do %>
@@ -63,5 +63,21 @@
- <%= render ExplorerWeb.ChainView, "_transactions.html", assigns %>
+
+
+
+
+ <%= link(gettext("View All Transactions →"), to: transaction_path(ExplorerWeb.Endpoint, :index, Gettext.get_locale), class: "button button--secondary button--xsmall float-right") %>
+
<%= gettext "Transactions" %>
+
+ <%= for transaction <- @chain.transactions do %>
+ <%= render ExplorerWeb.TransactionView, "_tile.html", locale: @locale, transaction: transaction %>
+ <% end %>
+
+
+
diff --git a/apps/explorer_web/lib/explorer_web/templates/block_transaction/_transaction.html.eex b/apps/explorer_web/lib/explorer_web/templates/transaction/_tile.html.eex
similarity index 64%
rename from apps/explorer_web/lib/explorer_web/templates/block_transaction/_transaction.html.eex
rename to apps/explorer_web/lib/explorer_web/templates/transaction/_tile.html.eex
index e376e109d1..c2b5dd41aa 100644
--- a/apps/explorer_web/lib/explorer_web/templates/block_transaction/_transaction.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/transaction/_tile.html.eex
@@ -1,22 +1,15 @@
-
-
+
+
-
- <%= ExplorerWeb.TransactionView.transaction_display_type(@transaction) %>
-
-
- <%= ExplorerWeb.TransactionView.formatted_status(@transaction) %>
-
+
<%= ExplorerWeb.TransactionView.transaction_display_type(@transaction) %>
+
<%= ExplorerWeb.TransactionView.formatted_status(@transaction) %>
- <%= render ExplorerWeb.TransactionView, "_link.html", locale: @locale, transaction_hash: @transaction.hash %>
+ <%= render ExplorerWeb.TransactionView, "_link.html", locale: @locale, transaction_hash: @transaction.hash %>
<%= render ExplorerWeb.AddressView, "_link.html", address_hash: @transaction.from_address_hash, contract: ExplorerWeb.AddressView.contract?(@transaction.from_address), locale: @locale %>
-
→
-
<%= render ExplorerWeb.AddressView, "_link.html", address_hash: ExplorerWeb.TransactionView.to_address_hash(@transaction), contract: ExplorerWeb.AddressView.contract?(@transaction.to_address), locale: @locale %>
-
@@ -28,11 +21,11 @@
-
+
<%= ExplorerWeb.TransactionView.value(@transaction, include_label: false) %> <%= gettext "Ether" %>
- <%= ExplorerWeb.TransactionView.formatted_fee(@transaction, denomination: :ether) %> <%= gettext "Fee" %>
+ <%= ExplorerWeb.TransactionView.formatted_fee(@transaction, denomination: :ether) %> <%= gettext "Fee" %>
diff --git a/apps/explorer_web/lib/explorer_web/templates/transaction/index.html.eex b/apps/explorer_web/lib/explorer_web/templates/transaction/index.html.eex
index eff3762f30..d406397c97 100644
--- a/apps/explorer_web/lib/explorer_web/templates/transaction/index.html.eex
+++ b/apps/explorer_web/lib/explorer_web/templates/transaction/index.html.eex
@@ -43,42 +43,24 @@
+
+
<%= gettext "Transactions" %>
-
<%= gettext("Showing %{count} Validated Transactions", count: Cldr.Number.to_string!(@transaction_estimated_count, format: "#,###")) %>
+
<%= gettext("Showing") %> <%= Cldr.Number.to_string!(@transaction_estimated_count, format: "#,###") %> <%= gettext("Validated Transactions") %>
+
+ <%= for transaction <- @transactions do %>
+ <%= render ExplorerWeb.TransactionView, "_tile.html", locale: @locale, transaction: transaction %>
+ <% end %>
+
- <%= for transaction <- @transactions do %>
-
-
-
-
-
<%= ExplorerWeb.TransactionView.transaction_display_type(transaction) %>
-
<%= ExplorerWeb.TransactionView.formatted_status(transaction) %>
-
-
-
- <%= render ExplorerWeb.TransactionView, "_link.html", locale: @locale, transaction_hash: transaction.hash %>
-
- <%= render ExplorerWeb.AddressView, "_link.html", address_hash: transaction.from_address_hash, contract: ExplorerWeb.AddressView.contract?(transaction.from_address), locale: @locale %>
- →
- <%= render ExplorerWeb.AddressView, "_link.html", address_hash: ExplorerWeb.TransactionView.to_address_hash(transaction), contract: ExplorerWeb.AddressView.contract?(transaction.to_address), locale: @locale %>
-
-
-
-
- <%= link(
- gettext("Block #%{number}", number: to_string(transaction.block.number)),
- to: block_path(@conn, :show, @conn.assigns.locale, transaction.block)
- ) %>
-
-
-
-
- <%= ExplorerWeb.TransactionView.value(transaction, include_label: false) %> <%= gettext "Ether" %>
- <%= ExplorerWeb.TransactionView.formatted_fee(transaction, denomination: :ether) %> <%= gettext "Fee" %>
-
-
-
- <% end %>
<%= if @next_page_params do %>
<%= link(
gettext("Older"),
diff --git a/apps/explorer_web/priv/gettext/default.pot b/apps/explorer_web/priv/gettext/default.pot
index 3d0d13cfde..bc1573317f 100644
--- a/apps/explorer_web/priv/gettext/default.pot
+++ b/apps/explorer_web/priv/gettext/default.pot
@@ -15,7 +15,7 @@ msgstr ""
msgid "Copyright %{year} POA"
msgstr ""
-#: lib/explorer_web/templates/block/index.html.eex:51
+#: lib/explorer_web/templates/block/_tile.html.eex:37
#: lib/explorer_web/templates/block/overview.html.eex:84
msgid "Gas Used"
msgstr ""
@@ -43,10 +43,10 @@ msgstr ""
#: lib/explorer_web/templates/block_transaction/index.html.eex:13
#: lib/explorer_web/templates/block_transaction/index.html.eex:26
#: lib/explorer_web/templates/block_transaction/index.html.eex:36
-#: lib/explorer_web/templates/chain/_transactions.html.eex:4
+#: lib/explorer_web/templates/chain/show.html.eex:75
#: lib/explorer_web/templates/layout/_topnav.html.eex:18
#: lib/explorer_web/templates/pending_transaction/index.html.eex:46
-#: lib/explorer_web/templates/transaction/index.html.eex:46
+#: lib/explorer_web/templates/transaction/index.html.eex:56
msgid "Transactions"
msgstr ""
@@ -62,12 +62,12 @@ msgstr ""
msgid "Difficulty"
msgstr ""
-#: lib/explorer_web/templates/block/index.html.eex:59
+#: lib/explorer_web/templates/block/_tile.html.eex:45
#: lib/explorer_web/templates/block/overview.html.eex:92
msgid "Gas Limit"
msgstr ""
-#: lib/explorer_web/templates/block/index.html.eex:38
+#: lib/explorer_web/templates/block/_tile.html.eex:24
#: lib/explorer_web/templates/block/overview.html.eex:70
#: lib/explorer_web/templates/chain/_block.html.eex:9
msgid "Miner"
@@ -285,10 +285,8 @@ msgstr ""
#:
#: lib/explorer_web/templates/address_internal_transaction/_internal_transaction.html.eex:29
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:60
-#: lib/explorer_web/templates/block_transaction/_transaction.html.eex:33
-#: lib/explorer_web/templates/chain/_transactions.html.eex:33
#: lib/explorer_web/templates/pending_transaction/index.html.eex:71
-#: lib/explorer_web/templates/transaction/index.html.eex:76
+#: lib/explorer_web/templates/transaction/_tile.html.eex:26
#: lib/explorer_web/templates/transaction/overview.html.eex:81
#: lib/explorer_web/templates/transaction_internal_transaction/_internal_transaction.html.eex:16
#: lib/explorer_web/views/wei_helpers.ex:71
@@ -355,10 +353,8 @@ msgid "All"
msgstr ""
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:62
-#: lib/explorer_web/templates/block_transaction/_transaction.html.eex:35
-#: lib/explorer_web/templates/chain/_transactions.html.eex:35
#: lib/explorer_web/templates/pending_transaction/index.html.eex:72
-#: lib/explorer_web/templates/transaction/index.html.eex:77
+#: lib/explorer_web/templates/transaction/_tile.html.eex:28
msgid "Fee"
msgstr ""
@@ -469,10 +465,10 @@ msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:133
#: lib/explorer_web/templates/address_transaction/index.html.eex:146
-#: lib/explorer_web/templates/block/index.html.eex:67
+#: lib/explorer_web/templates/block/index.html.eex:15
#: lib/explorer_web/templates/block_transaction/index.html.eex:51
#: lib/explorer_web/templates/pending_transaction/index.html.eex:79
-#: lib/explorer_web/templates/transaction/index.html.eex:84
+#: lib/explorer_web/templates/transaction/index.html.eex:66
msgid "Older"
msgstr ""
@@ -547,7 +543,7 @@ msgid "View All Blocks →"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/chain/_transactions.html.eex:3
+#: lib/explorer_web/templates/chain/show.html.eex:74
msgid "View All Transactions →"
msgstr ""
@@ -568,6 +564,7 @@ msgstr ""
#, elixir-format
#: lib/explorer_web/templates/address_transaction/index.html.eex:89
+#: lib/explorer_web/templates/transaction/index.html.eex:53
msgid "Connection Lost, click to load newer transactions"
msgstr ""
@@ -583,11 +580,6 @@ msgstr ""
msgid "Internal Transaction"
msgstr ""
-#, elixir-format
-#: lib/explorer_web/templates/address_transaction/index.html.eex:84
-msgid "More messages have come in"
-msgstr ""
-
#, elixir-format
#: lib/explorer_web/templates/address/overview.html.eex:13
#: lib/explorer_web/templates/address/overview.html.eex:66
@@ -629,9 +621,7 @@ msgstr ""
#, elixir-format
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:49
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:111
-#: lib/explorer_web/templates/block_transaction/_transaction.html.eex:25
-#: lib/explorer_web/templates/chain/_transactions.html.eex:25
-#: lib/explorer_web/templates/transaction/index.html.eex:69
+#: lib/explorer_web/templates/transaction/_tile.html.eex:18
msgid "Block #%{number}"
msgstr ""
@@ -725,8 +715,25 @@ msgid "Transfers"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/block/index.html.eex:29
+#: lib/explorer_web/templates/block/_tile.html.eex:15
msgid "%{count} transaction"
msgid_plural "%{count} transactions"
msgstr[0] ""
msgstr[1] ""
+
+#, elixir-format
+#: lib/explorer_web/templates/address_transaction/index.html.eex:84
+#: lib/explorer_web/templates/chain/show.html.eex:71
+#: lib/explorer_web/templates/transaction/index.html.eex:48
+msgid "More transactions have come in"
+msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/transaction/index.html.eex:57
+msgid "Showing"
+msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/transaction/index.html.eex:57
+msgid "Validated Transactions"
+msgstr ""
diff --git a/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
index f00a37e331..ae1e2d7481 100644
--- a/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
+++ b/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
@@ -27,7 +27,7 @@ msgstr "Blocks"
msgid "Copyright %{year} POA"
msgstr "%{year} POA Network Ltd. All rights reserved"
-#: lib/explorer_web/templates/block/index.html.eex:51
+#: lib/explorer_web/templates/block/_tile.html.eex:37
#: lib/explorer_web/templates/block/overview.html.eex:84
msgid "Gas Used"
msgstr "Gas Used"
@@ -55,10 +55,10 @@ msgstr "POA Network Explorer"
#: lib/explorer_web/templates/block_transaction/index.html.eex:13
#: lib/explorer_web/templates/block_transaction/index.html.eex:26
#: lib/explorer_web/templates/block_transaction/index.html.eex:36
-#: lib/explorer_web/templates/chain/_transactions.html.eex:4
+#: lib/explorer_web/templates/chain/show.html.eex:75
#: lib/explorer_web/templates/layout/_topnav.html.eex:18
#: lib/explorer_web/templates/pending_transaction/index.html.eex:46
-#: lib/explorer_web/templates/transaction/index.html.eex:46
+#: lib/explorer_web/templates/transaction/index.html.eex:56
msgid "Transactions"
msgstr "Transactions"
@@ -74,12 +74,12 @@ msgstr "Block #%{number} Details"
msgid "Difficulty"
msgstr "Difficulty"
-#: lib/explorer_web/templates/block/index.html.eex:59
+#: lib/explorer_web/templates/block/_tile.html.eex:45
#: lib/explorer_web/templates/block/overview.html.eex:92
msgid "Gas Limit"
msgstr "Gas Limit"
-#: lib/explorer_web/templates/block/index.html.eex:38
+#: lib/explorer_web/templates/block/_tile.html.eex:24
#: lib/explorer_web/templates/block/overview.html.eex:70
#: lib/explorer_web/templates/chain/_block.html.eex:9
msgid "Miner"
@@ -297,10 +297,8 @@ msgstr ""
#:
#: lib/explorer_web/templates/address_internal_transaction/_internal_transaction.html.eex:29
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:60
-#: lib/explorer_web/templates/block_transaction/_transaction.html.eex:33
-#: lib/explorer_web/templates/chain/_transactions.html.eex:33
#: lib/explorer_web/templates/pending_transaction/index.html.eex:71
-#: lib/explorer_web/templates/transaction/index.html.eex:76
+#: lib/explorer_web/templates/transaction/_tile.html.eex:26
#: lib/explorer_web/templates/transaction/overview.html.eex:81
#: lib/explorer_web/templates/transaction_internal_transaction/_internal_transaction.html.eex:16
#: lib/explorer_web/views/wei_helpers.ex:71
@@ -367,10 +365,8 @@ msgid "All"
msgstr ""
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:62
-#: lib/explorer_web/templates/block_transaction/_transaction.html.eex:35
-#: lib/explorer_web/templates/chain/_transactions.html.eex:35
#: lib/explorer_web/templates/pending_transaction/index.html.eex:72
-#: lib/explorer_web/templates/transaction/index.html.eex:77
+#: lib/explorer_web/templates/transaction/_tile.html.eex:28
msgid "Fee"
msgstr ""
@@ -481,10 +477,10 @@ msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:133
#: lib/explorer_web/templates/address_transaction/index.html.eex:146
-#: lib/explorer_web/templates/block/index.html.eex:67
+#: lib/explorer_web/templates/block/index.html.eex:15
#: lib/explorer_web/templates/block_transaction/index.html.eex:51
#: lib/explorer_web/templates/pending_transaction/index.html.eex:79
-#: lib/explorer_web/templates/transaction/index.html.eex:84
+#: lib/explorer_web/templates/transaction/index.html.eex:66
msgid "Older"
msgstr ""
@@ -559,7 +555,7 @@ msgid "View All Blocks →"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/chain/_transactions.html.eex:3
+#: lib/explorer_web/templates/chain/show.html.eex:74
msgid "View All Transactions →"
msgstr ""
@@ -580,6 +576,7 @@ msgstr ""
#, elixir-format
#: lib/explorer_web/templates/address_transaction/index.html.eex:89
+#: lib/explorer_web/templates/transaction/index.html.eex:53
msgid "Connection Lost, click to load newer transactions"
msgstr ""
@@ -595,11 +592,6 @@ msgstr ""
msgid "Internal Transaction"
msgstr ""
-#, elixir-format
-#: lib/explorer_web/templates/address_transaction/index.html.eex:84
-msgid "More messages have come in"
-msgstr ""
-
#, elixir-format
#: lib/explorer_web/templates/address/overview.html.eex:13
#: lib/explorer_web/templates/address/overview.html.eex:66
@@ -641,9 +633,7 @@ msgstr ""
#, elixir-format
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:49
#: lib/explorer_web/templates/address_transaction/_transaction.html.eex:111
-#: lib/explorer_web/templates/block_transaction/_transaction.html.eex:25
-#: lib/explorer_web/templates/chain/_transactions.html.eex:25
-#: lib/explorer_web/templates/transaction/index.html.eex:69
+#: lib/explorer_web/templates/transaction/_tile.html.eex:18
msgid "Block #%{number}"
msgstr ""
@@ -737,8 +727,25 @@ msgid "Transfers"
msgstr ""
#, elixir-format
-#: lib/explorer_web/templates/block/index.html.eex:29
+#: lib/explorer_web/templates/block/_tile.html.eex:15
msgid "%{count} transaction"
msgid_plural "%{count} transactions"
msgstr[0] ""
msgstr[1] ""
+
+#, elixir-format
+#: lib/explorer_web/templates/address_transaction/index.html.eex:84
+#: lib/explorer_web/templates/chain/show.html.eex:71
+#: lib/explorer_web/templates/transaction/index.html.eex:48
+msgid "More transactions have come in"
+msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/transaction/index.html.eex:57
+msgid "Showing"
+msgstr ""
+
+#, elixir-format
+#: lib/explorer_web/templates/transaction/index.html.eex:57
+msgid "Validated Transactions"
+msgstr ""
diff --git a/apps/explorer_web/test/explorer_web/features/pages/address_page.ex b/apps/explorer_web/test/explorer_web/features/pages/address_page.ex
index a8ad4d8e17..88edbadd6d 100644
--- a/apps/explorer_web/test/explorer_web/features/pages/address_page.ex
+++ b/apps/explorer_web/test/explorer_web/features/pages/address_page.ex
@@ -43,6 +43,10 @@ defmodule ExplorerWeb.AddressPage do
css("[data-internal-transaction-id='#{id}'] [data-address-hash='#{address_hash}'][data-test='address_hash_link']")
end
+ def non_loaded_transaction_count(count) do
+ css("[data-selector='channel-batching-count']", text: count)
+ end
+
def transaction(%Transaction{hash: transaction_hash}), do: transaction(transaction_hash)
def transaction(%Hash{} = hash) do
diff --git a/apps/explorer_web/test/explorer_web/features/pages/home_page.ex b/apps/explorer_web/test/explorer_web/features/pages/home_page.ex
index c27d044273..f9e799788c 100644
--- a/apps/explorer_web/test/explorer_web/features/pages/home_page.ex
+++ b/apps/explorer_web/test/explorer_web/features/pages/home_page.ex
@@ -29,6 +29,10 @@ defmodule ExplorerWeb.HomePage do
css("[data-test='chain_transaction']", count: count)
end
+ def transaction(%Transaction{hash: transaction_hash}) do
+ css("[data-transaction-hash='#{transaction_hash}']")
+ end
+
def transaction_status(%Transaction{hash: transaction_hash}) do
css("[data-transaction-hash='#{transaction_hash}'] [data-test='transaction_status']")
end
diff --git a/apps/explorer_web/test/explorer_web/features/pages/transaction_list_page.ex b/apps/explorer_web/test/explorer_web/features/pages/transaction_list_page.ex
index 68963594e8..53927f15b5 100644
--- a/apps/explorer_web/test/explorer_web/features/pages/transaction_list_page.ex
+++ b/apps/explorer_web/test/explorer_web/features/pages/transaction_list_page.ex
@@ -19,6 +19,10 @@ defmodule ExplorerWeb.TransactionListPage do
css("[data-transaction-hash='#{hash}'] [data-test='transaction_type']", text: "Contract Creation")
end
+ def non_loaded_transaction_count(count) do
+ css("[data-selector='channel-batching-count']", text: count)
+ end
+
def transaction(%Transaction{hash: transaction_hash}) do
css("[data-transaction-hash='#{transaction_hash}']")
end
diff --git a/apps/explorer_web/test/explorer_web/features/viewing_addresses_test.exs b/apps/explorer_web/test/explorer_web/features/viewing_addresses_test.exs
index 834649b23f..29f210398d 100644
--- a/apps/explorer_web/test/explorer_web/features/viewing_addresses_test.exs
+++ b/apps/explorer_web/test/explorer_web/features/viewing_addresses_test.exs
@@ -250,6 +250,24 @@ defmodule ExplorerWeb.ViewingAddressesTest do
|> assert_has(AddressPage.transaction(transaction2))
end
+ test "count of non-loaded transactions on live update when batch overflow", %{addresses: addresses, session: session} do
+ transaction_hashes =
+ 30
+ |> insert_list(:transaction, from_address: addresses.lincoln)
+ |> with_block()
+ |> Repo.preload([:block, :from_address, :to_address])
+ |> Enum.map(& &1.hash)
+
+ session
+ |> AddressPage.visit_page(addresses.lincoln)
+ |> assert_has(AddressPage.balance())
+
+ Notifier.handle_event({:chain_event, :transactions, transaction_hashes})
+
+ session
+ |> assert_has(AddressPage.non_loaded_transaction_count("30"))
+ end
+
test "transaction count live updates", %{addresses: addresses, session: session} do
session
|> AddressPage.visit_page(addresses.lincoln)
diff --git a/apps/explorer_web/test/explorer_web/features/viewing_blocks_test.exs b/apps/explorer_web/test/explorer_web/features/viewing_blocks_test.exs
index 9b4b9a2a3e..b56b4fc63e 100644
--- a/apps/explorer_web/test/explorer_web/features/viewing_blocks_test.exs
+++ b/apps/explorer_web/test/explorer_web/features/viewing_blocks_test.exs
@@ -93,4 +93,13 @@ defmodule ExplorerWeb.ViewingBlocksTest do
|> BlockListPage.visit_page()
|> assert_has(BlockListPage.block(block))
end
+
+ test "viewing new blocks via live update on list page", %{session: session} do
+ BlockListPage.visit_page(session)
+
+ block = insert(:block, number: 42)
+ Notifier.handle_event({:chain_event, :blocks, [block]})
+
+ assert_has(session, BlockListPage.block(block))
+ end
end
diff --git a/apps/explorer_web/test/explorer_web/features/viewing_transactions_test.exs b/apps/explorer_web/test/explorer_web/features/viewing_transactions_test.exs
index 5e51ac69d4..e395a75081 100644
--- a/apps/explorer_web/test/explorer_web/features/viewing_transactions_test.exs
+++ b/apps/explorer_web/test/explorer_web/features/viewing_transactions_test.exs
@@ -14,9 +14,10 @@ defmodule ExplorerWeb.ViewingTransactionsTest do
gas_used: 123_987
})
- 4
- |> insert_list(:transaction)
- |> with_block()
+ [oldest_transaction | _] =
+ 3
+ |> insert_list(:transaction)
+ |> with_block()
pending = insert(:transaction, block_hash: nil, gas: 5891, index: nil)
pending_contract = insert(:transaction, to_address: nil, block_hash: nil, gas: 5891, index: nil)
@@ -24,7 +25,13 @@ defmodule ExplorerWeb.ViewingTransactionsTest do
lincoln = insert(:address)
taft = insert(:address)
- transaction =
+ # From Lincoln to Taft.
+ txn_from_lincoln =
+ :transaction
+ |> insert(from_address: lincoln, to_address: taft)
+ |> with_block(block)
+
+ newest_transaction =
:transaction
|> insert(
value: Wei.from(Decimal.new(5656), :ether),
@@ -39,15 +46,9 @@ defmodule ExplorerWeb.ViewingTransactionsTest do
)
|> with_block(block, gas_used: Decimal.new(1_230_000_000_000_123_000), status: :ok)
- insert(:log, address: lincoln, index: 0, transaction: transaction)
+ insert(:log, address: lincoln, index: 0, transaction: newest_transaction)
- # From Lincoln to Taft.
- txn_from_lincoln =
- :transaction
- |> insert(from_address: lincoln, to_address: taft)
- |> with_block(block)
-
- internal = insert(:internal_transaction, index: 0, transaction: transaction)
+ internal = insert(:internal_transaction, index: 0, transaction: newest_transaction)
{:ok,
%{
@@ -56,7 +57,8 @@ defmodule ExplorerWeb.ViewingTransactionsTest do
internal: internal,
lincoln: lincoln,
taft: taft,
- transaction: transaction,
+ first_shown_transaction: newest_transaction,
+ last_shown_transaction: oldest_transaction,
txn_from_lincoln: txn_from_lincoln
}}
end
@@ -71,10 +73,47 @@ defmodule ExplorerWeb.ViewingTransactionsTest do
end
describe "viewing transaction lists" do
- test "transactions on the home page", %{session: session} do
+ test "transactions on the homepage", %{session: session} do
+ session
+ |> HomePage.visit_page()
+ |> assert_has(HomePage.transactions(count: 5))
+ end
+
+ test "viewing new transactions via live update on the homepage", %{
+ session: session,
+ last_shown_transaction: last_shown_transaction
+ } do
+ session
+ |> HomePage.visit_page()
+ |> assert_has(HomePage.transactions(count: 5))
+
+ transaction =
+ :transaction
+ |> insert()
+ |> with_block()
+
+ Notifier.handle_event({:chain_event, :transactions, [transaction.hash]})
+
+ session
+ |> assert_has(HomePage.transactions(count: 5))
+ |> assert_has(HomePage.transaction(transaction))
+ |> refute_has(HomePage.transaction(last_shown_transaction))
+ end
+
+ test "count of non-loaded transactions on homepage live update when batch overflow", %{session: session} do
+ transaction_hashes =
+ 30
+ |> insert_list(:transaction)
+ |> with_block()
+ |> Enum.map(& &1.hash)
+
session
|> HomePage.visit_page()
|> assert_has(HomePage.transactions(count: 5))
+
+ Notifier.handle_event({:chain_event, :transactions, transaction_hashes})
+
+ assert_has(session, AddressPage.non_loaded_transaction_count("30"))
end
test "contract creation is shown for to_address on home page", %{session: session} do
@@ -90,7 +129,11 @@ defmodule ExplorerWeb.ViewingTransactionsTest do
|> assert_has(HomePage.contract_creation(internal_transaction))
end
- test "viewing the default transactions tab", %{session: session, transaction: transaction, pending: pending} do
+ test "viewing the default transactions tab", %{
+ session: session,
+ first_shown_transaction: transaction,
+ pending: pending
+ } do
session
|> TransactionListPage.visit_page()
|> assert_has(TransactionListPage.transaction(transaction))
@@ -119,23 +162,50 @@ defmodule ExplorerWeb.ViewingTransactionsTest do
|> TransactionListPage.visit_page()
|> assert_has(TransactionListPage.contract_creation(transaction))
end
+
+ test "viewing new transactions via live update on list page", %{session: session} do
+ TransactionListPage.visit_page(session)
+
+ transaction =
+ :transaction
+ |> insert()
+ |> with_block()
+
+ Notifier.handle_event({:chain_event, :transactions, [transaction.hash]})
+
+ assert_has(session, TransactionListPage.transaction(transaction))
+ end
+
+ test "count of non-loaded transactions on list page live update when batch overflow", %{session: session} do
+ transaction_hashes =
+ 30
+ |> insert_list(:transaction)
+ |> with_block()
+ |> Enum.map(& &1.hash)
+
+ TransactionListPage.visit_page(session)
+
+ Notifier.handle_event({:chain_event, :transactions, transaction_hashes})
+
+ assert_has(session, TransactionListPage.non_loaded_transaction_count("30"))
+ end
end
describe "viewing a transaction page" do
- test "can navigate to transaction show from list page", %{session: session, transaction: transaction} do
+ test "can navigate to transaction show from list page", %{session: session, first_shown_transaction: transaction} do
session
|> TransactionListPage.visit_page()
|> TransactionListPage.click_transaction(transaction)
|> assert_has(TransactionPage.detail_hash(transaction))
end
- test "can see a transaction's details", %{session: session, transaction: transaction} do
+ test "can see a transaction's details", %{session: session, first_shown_transaction: transaction} do
session
|> TransactionPage.visit_page(transaction)
|> assert_has(TransactionPage.detail_hash(transaction))
end
- test "can view a transaction's logs", %{session: session, transaction: transaction} do
+ test "can view a transaction's logs", %{session: session, first_shown_transaction: transaction} do
session
|> TransactionPage.visit_page(transaction)
|> TransactionPage.click_logs()
@@ -145,7 +215,7 @@ defmodule ExplorerWeb.ViewingTransactionsTest do
test "can visit an address from the transaction logs page", %{
lincoln: lincoln,
session: session,
- transaction: transaction
+ first_shown_transaction: transaction
} do
session
|> TransactionLogsPage.visit_page(transaction)
@@ -153,7 +223,7 @@ defmodule ExplorerWeb.ViewingTransactionsTest do
|> assert_has(AddressPage.detail_hash(lincoln))
end
- test "block confirmations via live update", %{session: session, transaction: transaction} do
+ test "block confirmations via live update", %{session: session, first_shown_transaction: transaction} do
blocks = [insert(:block, number: transaction.block_number + 10)]
TransactionPage.visit_page(session, transaction)