Merge pull request #1281 from poanetwork/ams-home-blocks-async

Async loading to block list in the home page
pull/1282/head
Amanda 6 years ago committed by GitHub
commit 1e00990166
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      apps/block_scout_web/assets/README.md
  2. 72
      apps/block_scout_web/assets/js/pages/chain.js
  3. 32
      apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
  4. 2
      apps/block_scout_web/lib/block_scout_web/router.ex
  5. 17
      apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex
  6. 12
      apps/block_scout_web/priv/gettext/default.pot
  7. 12
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  8. 50
      apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs

@ -0,0 +1,9 @@
# Javascript structure files
## lib
* This folder is used to place `component` files, that may span in multiple pages.
## pages
* This folder is used to place `page` specific files, that won't be reusable in other locations.

@ -17,6 +17,8 @@ export const initialState = {
averageBlockTime: null,
marketHistoryData: null,
blocks: [],
blocksLoading: true,
blocksError: false,
transactions: [],
transactionsBatch: [],
transactionsError: false,
@ -52,6 +54,18 @@ function baseReducer (state = initialState, action) {
})
}
}
case 'START_BLOCKS_FETCH': {
return Object.assign({}, state, { blocksError: false, blocksLoading: true })
}
case 'BLOCKS_FINISH_REQUEST': {
return Object.assign({}, state, { blocksLoading: false })
}
case 'BLOCKS_FETCHED': {
return Object.assign({}, state, { blocks: [...action.msg.blocks] })
}
case 'BLOCKS_REQUEST_ERROR': {
return Object.assign({}, state, { blocksError: true })
}
case 'RECEIVED_NEW_EXCHANGE_RATE': {
return Object.assign({}, state, {
availableSupply: action.msg.exchangeRate.availableSupply,
@ -159,17 +173,36 @@ const elements = {
'[data-selector="chain-block-list"]': {
load ($el) {
return {
blocks: $el.children().map((index, el) => ({
blockNumber: parseInt(el.dataset.blockNumber),
chainBlockHtml: el.outerHTML
})).toArray()
blocksPath: $el[0].dataset.url
}
},
render ($el, state, oldState) {
if (oldState.blocks === state.blocks) return
const container = $el[0]
const newElements = _.map(state.blocks, ({ chainBlockHtml }) => $(chainBlockHtml)[0])
listMorph(container, newElements, { key: 'dataset.blockNumber', horizontal: true })
if (state.blocksLoading === false) {
const blocks = _.map(state.blocks, ({ chainBlockHtml }) => $(chainBlockHtml)[0])
listMorph(container, blocks, { key: 'dataset.blockNumber', horizontal: true })
}
}
},
'[data-selector="chain-block-list"] [data-selector="error-message"]': {
render ($el, state, oldState) {
if (state.blocksError) {
$el.show()
} else {
$el.hide()
}
}
},
'[data-selector="chain-block-list"] [data-selector="loading-message"]': {
render ($el, state, oldState) {
if (state.blocksLoading) {
$el.show()
} else {
$el.hide()
}
}
},
'[data-selector="transactions-list"] [data-selector="error-message"]': {
@ -207,8 +240,12 @@ const $chainDetailsPage = $('[data-page="chain-details"]')
if ($chainDetailsPage.length) {
const store = createStore(reducer)
connectElements({ store, elements })
loadTransactions(store)
$('[data-selector="transactions-list"] [data-selector="error-message"]').on('click', _event => loadTransactions(store))
bindTransactionErrorMessage(store)
loadBlocks(store)
bindBlockErrorMessage(store)
exchangeRateChannel.on('new_rate', (msg) => store.dispatch({
type: 'RECEIVED_NEW_EXCHANGE_RATE',
@ -246,6 +283,10 @@ function loadTransactions (store) {
.always(() => store.dispatch({type: 'FINISH_TRANSACTIONS_FETCH'}))
}
function bindTransactionErrorMessage (store) {
$('[data-selector="transactions-list"] [data-selector="error-message"]').on('click', _event => loadTransactions(store))
}
export function placeHolderBlock (blockNumber) {
return `
<div
@ -270,3 +311,20 @@ export function placeHolderBlock (blockNumber) {
</div>
`
}
function loadBlocks (store) {
const url = store.getState().blocksPath
store.dispatch({type: 'START_BLOCKS_FETCH'})
$.getJSON(url)
.done(response => {
store.dispatch({type: 'BLOCKS_FETCHED', msg: humps.camelizeKeys(response)})
})
.fail(() => store.dispatch({type: 'BLOCKS_REQUEST_ERROR'}))
.always(() => store.dispatch({type: 'BLOCKS_FINISH_REQUEST'}))
}
function bindBlockErrorMessage (store) {
$('[data-selector="chain-block-list"] [data-selector="error-message"]').on('click', _event => loadBlocks(store))
}

@ -1,17 +1,14 @@
defmodule BlockScoutWeb.ChainController do
use BlockScoutWeb, :controller
alias BlockScoutWeb.ChainView
alias Explorer.{Chain, PagingOptions, Repo}
alias Explorer.Chain.{Address, Block, Transaction}
alias Explorer.ExchangeRates.Token
alias Explorer.Market
alias Phoenix.View
def show(conn, _params) do
blocks =
[paging_options: %PagingOptions{page_size: 4}]
|> Chain.list_blocks()
|> Repo.preload([[miner: :names], :transactions, :rewards])
transaction_estimated_count = Chain.transaction_estimated_count()
exchange_rate = Market.get_exchange_rate(Explorer.coin()) || Token.null()
@ -27,7 +24,6 @@ defmodule BlockScoutWeb.ChainController do
"show.html",
address_count: Chain.count_addresses_with_balance_from_cache(),
average_block_time: Chain.average_block_time(),
blocks: blocks,
exchange_rate: exchange_rate,
available_supply: available_supply(Chain.supply_for_days(30), exchange_rate),
market_history_data: market_history_data,
@ -49,6 +45,30 @@ defmodule BlockScoutWeb.ChainController do
end
end
def chain_blocks(conn, _params) do
if ajax?(conn) do
blocks =
[paging_options: %PagingOptions{page_size: 4}]
|> Chain.list_blocks()
|> Repo.preload([[miner: :names], :transactions, :rewards])
|> Enum.map(fn block ->
%{
chain_block_html:
View.render_to_string(
ChainView,
"_block.html",
block: block
),
block_number: block.number
}
end)
json(conn, %{blocks: blocks})
else
unprocessable_entity(conn)
end
end
defp redirect_search_results(conn, %Address{} = item) do
redirect(conn, to: address_path(conn, :show, item))
end

@ -206,6 +206,8 @@ defmodule BlockScoutWeb.Router do
get("/search", ChainController, :search)
get("/chain_blocks", ChainController, :chain_blocks, as: :chain_blocks)
get("/api_docs", APIDocsController, :index)
end
end

@ -55,10 +55,19 @@
<div class="card-body">
<%= link(gettext("View All Blocks →"), to: block_path(BlockScoutWeb.Endpoint, :index), class: "button button-secondary button-xsmall float-right") %>
<h2 class="card-title"><%= gettext "Blocks" %></h2>
<div class="row" data-selector="chain-block-list">
<%= for block <- @blocks do %>
<%= render BlockScoutWeb.ChainView, "_block.html", block: block %>
<% end %>
<div class="row" data-selector="chain-block-list" data-url="<%= chain_blocks_path(@conn, :chain_blocks) %>">
<button data-selector="error-message" class="alert alert-danger col-12 text-left" style="display: none;">
<span class="alert-link">
<%= gettext "Something went wrong, click to reload." %>
</span>
</button>
<div data-selector="loading-message" class="tile tile-muted text-center mt-3 w-100">
<span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span>
</span>
<%= gettext("Loading...") %>
</div>
</div>
</div>
</div>

@ -574,7 +574,7 @@ msgid "More internal transactions have come in"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:72
#: lib/block_scout_web/templates/chain/show.html.eex:81
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:14
#: lib/block_scout_web/templates/transaction/index.html.eex:14
msgid "More transactions have come in"
@ -985,7 +985,7 @@ msgstr ""
#: 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:69
#: lib/block_scout_web/templates/chain/show.html.eex:78
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35
#: lib/block_scout_web/views/address_view.ex:253
msgid "Transactions"
@ -1065,7 +1065,7 @@ msgid "View All Blocks →"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:68
#: lib/block_scout_web/templates/chain/show.html.eex:77
msgid "View All Transactions →"
msgstr ""
@ -1189,7 +1189,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:19
#: lib/block_scout_web/templates/address_validation/index.html.eex:63
#: lib/block_scout_web/templates/address_validation/index.html.eex:82
#: lib/block_scout_web/templates/chain/show.html.eex:86
#: lib/block_scout_web/templates/chain/show.html.eex:69
#: lib/block_scout_web/templates/chain/show.html.eex:95
#: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:25
msgid "Loading..."
msgstr ""
@ -1415,6 +1416,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:26
#: lib/block_scout_web/templates/address_transaction/index.html.eex:55
#: lib/block_scout_web/templates/address_validation/index.html.eex:70
#: lib/block_scout_web/templates/chain/show.html.eex:61
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:23
#: lib/block_scout_web/templates/tokens/holder/index.html.eex:23
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:21
@ -1535,6 +1537,6 @@ msgid "Emission Contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:78
#: lib/block_scout_web/templates/chain/show.html.eex:87
msgid "Something went wrong, click to retry."
msgstr ""

@ -574,7 +574,7 @@ msgid "More internal transactions have come in"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:72
#: lib/block_scout_web/templates/chain/show.html.eex:81
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:14
#: lib/block_scout_web/templates/transaction/index.html.eex:14
msgid "More transactions have come in"
@ -985,7 +985,7 @@ msgstr ""
#: 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:69
#: lib/block_scout_web/templates/chain/show.html.eex:78
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35
#: lib/block_scout_web/views/address_view.ex:253
msgid "Transactions"
@ -1065,7 +1065,7 @@ msgid "View All Blocks →"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:68
#: lib/block_scout_web/templates/chain/show.html.eex:77
msgid "View All Transactions →"
msgstr ""
@ -1189,7 +1189,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:19
#: lib/block_scout_web/templates/address_validation/index.html.eex:63
#: lib/block_scout_web/templates/address_validation/index.html.eex:82
#: lib/block_scout_web/templates/chain/show.html.eex:86
#: lib/block_scout_web/templates/chain/show.html.eex:69
#: lib/block_scout_web/templates/chain/show.html.eex:95
#: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:25
msgid "Loading..."
msgstr ""
@ -1415,6 +1416,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:26
#: lib/block_scout_web/templates/address_transaction/index.html.eex:55
#: lib/block_scout_web/templates/address_validation/index.html.eex:70
#: lib/block_scout_web/templates/chain/show.html.eex:61
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:23
#: lib/block_scout_web/templates/tokens/holder/index.html.eex:23
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:21
@ -1535,6 +1537,6 @@ msgid "Emission Contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:78
#: lib/block_scout_web/templates/chain/show.html.eex:87
msgid "Something went wrong, click to retry."
msgstr ""

@ -8,63 +8,71 @@ defmodule BlockScoutWeb.ChainControllerTest do
alias Explorer.Chain.{Block, Hash}
alias Explorer.Counters.AddressesWithBalanceCounter
setup do
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
:ok
end
describe "GET index/2" do
test "returns a welcome message", %{conn: conn} do
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn = get(conn, chain_path(BlockScoutWeb.Endpoint, :show))
assert(html_response(conn, 200) =~ "POA")
end
test "returns a block", %{conn: conn} do
test "returns a block" do
insert(:block, %{number: 23})
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn =
build_conn()
|> put_req_header("x-requested-with", "xmlhttprequest")
|> get("/chain_blocks")
conn = get(conn, "/")
response = json_response(conn, 200)
assert(List.first(conn.assigns.blocks).number == 23)
assert(List.first(response["blocks"])["block_number"] == 23)
end
test "excludes all but the most recent five blocks", %{conn: conn} do
test "excludes all but the most recent five blocks" do
old_block = insert(:block)
insert_list(5, :block)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn =
build_conn()
|> put_req_header("x-requested-with", "xmlhttprequest")
|> get("/chain_blocks")
conn = get(conn, "/")
response = json_response(conn, 200)
refute(Enum.member?(conn.assigns.blocks, old_block))
refute(Enum.member?(response["blocks"], old_block))
end
test "returns market history data", %{conn: conn} do
today = Date.utc_today()
for day <- -40..0, do: insert(:market_history, date: Date.add(today, day))
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn = get(conn, "/")
assert Map.has_key?(conn.assigns, :market_history_data)
assert length(conn.assigns.market_history_data) == 30
end
test "displays miner primary address names", %{conn: conn} do
test "displays miner primary address names" do
miner_name = "POA Miner Pool"
%{address: miner_address} = insert(:address_name, name: miner_name, primary: true)
insert(:block, miner: miner_address, miner_hash: nil)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn =
build_conn()
|> put_req_header("x-requested-with", "xmlhttprequest")
|> get("/chain_blocks")
response = List.first(json_response(conn, 200)["blocks"])
conn = get(conn, chain_path(conn, :show))
assert html_response(conn, 200) =~ miner_name
assert response["chain_block_html"] =~ miner_name
end
end

Loading…
Cancel
Save