From d3f8e6a15774134b38825b9ba41e30242c03f9fd Mon Sep 17 00:00:00 2001
From: Stamates
Date: Wed, 1 Aug 2018 11:39:03 -0400
Subject: [PATCH] Live reload blocks on block list page
---
apps/explorer_web/assets/js/app.js | 1 +
apps/explorer_web/assets/js/pages/block.js | 60 +++++++++++++++++++
apps/explorer_web/assets/js/pages/chain.js | 4 +-
.../explorer_web/channels/block_channel.ex | 11 +++-
.../templates/block/_tile.html.eex | 48 +++++++++++++++
.../templates/block/index.html.eex | 55 ++---------------
.../features/viewing_blocks_test.exs | 9 +++
7 files changed, 135 insertions(+), 53 deletions(-)
create mode 100644 apps/explorer_web/assets/js/pages/block.js
create mode 100644 apps/explorer_web/lib/explorer_web/templates/block/_tile.html.eex
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/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 dbe1873731..dbc5441fa9 100644
--- a/apps/explorer_web/assets/js/pages/chain.js
+++ b/apps/explorer_web/assets/js/pages/chain.js
@@ -19,7 +19,7 @@ export function reducer (state = initialState, action) {
switch (action.type) {
case 'RECEIVED_NEW_BLOCK': {
return Object.assign({}, state, {
- newBlock: humps.camelizeKeys(action.msg).homepageBlockHtml
+ newBlock: action.msg.homepageBlockHtml
})
}
case 'RECEIVED_NEW_TRANSACTION_BATCH': {
@@ -46,7 +46,7 @@ router.when('', { exactPathMatch: true }).then(({ locale }) => initRedux(reducer
const blocksChannel = socket.channel(`blocks:new_block`)
numeral.locale(locale)
blocksChannel.join()
- 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()
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 3a947ed9d0..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,
@@ -26,6 +34,7 @@ defmodule ExplorerWeb.BlockChannel do
push(socket, "new_block", %{
homepage_block_html: rendered_homepage_block,
+ block_html: rendered_block,
blockNumber: block.number
})
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..b24e9005d8
--- /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..49c827566c 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
@@ -11,56 +11,11 @@
) %>
- <%= 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/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