Merge pull request #1812 from poanetwork/ab-paginate-addresses

add pagination to addresses page
pull/1881/head
Victor Baranov 6 years ago committed by GitHub
commit cb894aa43f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 17
      apps/block_scout_web/lib/block_scout_web/chain.ex
  3. 57
      apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex
  4. 29
      apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex
  5. 42
      apps/block_scout_web/priv/gettext/default.pot
  6. 42
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  7. 22
      apps/explorer/lib/explorer/chain.ex
  8. 27
      apps/explorer/test/explorer/chain_test.exs

@ -2,6 +2,7 @@
### Features
- [#1812](https://github.com/poanetwork/blockscout/pull/1812) - add pagination to addresses page
- [#1874](https://github.com/poanetwork/blockscout/pull/1874) - add changes to ethereum theme and ethereum logo
- [#1815](https://github.com/poanetwork/blockscout/pull/1815) - able to search without prefix "0x"
- [#1813](https://github.com/poanetwork/blockscout/pull/1813) - add total blocks counter to the main page

@ -25,7 +25,8 @@ defmodule BlockScoutWeb.Chain do
InternalTransaction,
Log,
TokenTransfer,
Transaction
Transaction,
Wei
}
alias Explorer.PagingOptions
@ -87,6 +88,16 @@ defmodule BlockScoutWeb.Chain do
Map.merge(params, paging_params(List.last(list)))
end
def paging_options(%{"hash" => hash, "fetched_coin_balance" => fetched_coin_balance}) do
with {coin_balance, ""} <- Integer.parse(fetched_coin_balance),
{:ok, address_hash} <- string_to_address_hash(hash) do
[paging_options: %{@default_paging_options | key: {%Wei{value: Decimal.new(coin_balance)}, address_hash}}]
else
_ ->
[paging_options: @default_paging_options]
end
end
def paging_options(%{
"block_number" => block_number_string,
"transaction_index" => transaction_index_string,
@ -177,6 +188,10 @@ defmodule BlockScoutWeb.Chain do
end
end
defp paging_params({%Address{hash: hash, fetched_coin_balance: fetched_coin_balance}, _}) do
%{"hash" => hash, "fetched_coin_balance" => Decimal.to_string(fetched_coin_balance.value)}
end
defp paging_params({%Reward{block: %{number: number}}, _}) do
%{"block_number" => number, "index" => 0}
end

@ -1,16 +1,55 @@
defmodule BlockScoutWeb.AddressController do
use BlockScoutWeb, :controller
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias Explorer.{Chain, Market}
alias Explorer.Chain.Address
alias Explorer.ExchangeRates.Token
def index(conn, _params) do
def index(conn, params) do
addresses =
params
|> paging_options()
|> Chain.list_top_addresses()
{addresses_page, next_page} = split_list_by_page(addresses)
cur_page_number =
cond do
!params["prev_page_number"] -> 1
params["next_page"] -> String.to_integer(params["prev_page_number"]) + 1
params["prev_page"] -> String.to_integer(params["prev_page_number"]) - 1
end
next_page_path =
case next_page_params(next_page, addresses_page, params) do
nil ->
nil
next_page_params ->
next_params =
next_page_params
|> Map.put("prev_page_path", cur_page_path(conn, params))
|> Map.put("next_page", true)
|> Map.put("prev_page_number", cur_page_number)
address_path(
conn,
:index,
next_params
)
end
render(conn, "index.html",
address_tx_count_pairs: Chain.list_top_addresses(),
address_tx_count_pairs: addresses_page,
page_address_count: Enum.count(addresses_page),
address_count: Chain.count_addresses_with_balance_from_cache(),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
total_supply: Chain.total_supply()
total_supply: Chain.total_supply(),
next_page_path: next_page_path,
prev_page_path: params["prev_page_path"],
cur_page_number: cur_page_number
)
end
@ -25,4 +64,16 @@ defmodule BlockScoutWeb.AddressController do
def validation_count(%Address{} = address) do
Chain.address_to_validation_count(address)
end
defp cur_page_path(conn, %{"hash" => _hash, "fetched_coin_balance" => _balance} = params) do
new_params = Map.put(params, "next_page", false)
address_path(
conn,
:index,
new_params
)
end
defp cur_page_path(conn, _), do: address_path(conn, :index)
end

@ -1,12 +1,28 @@
<section class="container">
<div class="card">
<div class="card-body">
<%= if @next_page_path do %>
<a href="<%= "#{@next_page_path}" %>" class="button button-secondary button-small float-right ml-1">
<%= gettext("Next") %>
</a>
<% end %>
<%= if @prev_page_path do %>
<a href="<%= "#{@prev_page_path}" %>" class="button button-secondary button-small float-right">
<%= gettext("Back") %>
</a>
<% end %>
<h1 class="card-title margin-bottom-0"><%= gettext "Addresses" %></h1>
<p class="card-subtitle">
<%= gettext "Showing 250 addresses of" %>
<%= gettext "Showing " %>
<%= Cldr.Number.to_string!(@page_address_count, format: "#,###") %>
<%= gettext " addresses of" %>
<%= Cldr.Number.to_string!(@address_count, format: "#,###") %>
<%= gettext "total addresses with a balance" %>
<%= gettext " (page" %>
<%= Cldr.Number.to_string!(@cur_page_number, format: "#,###)") %>
</p>
<span data-selector="top-addresses-list">
<%= for {{address, tx_count}, index} <- Enum.with_index(@address_tx_count_pairs, 1) do %>
<%= render "_tile.html",
@ -14,6 +30,17 @@
total_supply: @total_supply, tx_count: tx_count,
validation_count: validation_count(address) %>
<% end %>
<br>
<%= if @next_page_path do %>
<a href="<%= "#{@next_page_path}" %>" class="button button-secondary button-small float-right mt-0 mb-0 ml-1">
<%= gettext("Next") %>
</a>
<% end %>
<%= if @prev_page_path do %>
<a href="<%= "#{@prev_page_path}" %>" class="button button-secondary button-small float-right mt-0 mb-0">
<%= gettext("Back") %>
</a>
<% end %>
</span>
</div>
</div>

@ -104,7 +104,7 @@ msgid "Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:4
#: lib/block_scout_web/templates/address/index.html.eex:15
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:59
msgid "Addresses"
msgstr ""
@ -578,6 +578,8 @@ msgid "Newer"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:6
#: lib/block_scout_web/templates/address/index.html.eex:36
#: lib/block_scout_web/templates/address_token/index.html.eex:22
msgid "Next"
msgstr ""
@ -739,11 +741,6 @@ msgstr ""
msgid "Showing"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:6
msgid "Showing 250 addresses of"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8
#: lib/block_scout_web/views/transaction_view.ex:210
@ -1078,7 +1075,7 @@ msgid "string"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:8
#: lib/block_scout_web/templates/address/index.html.eex:21
msgid "total addresses with a balance"
msgstr ""
@ -1708,11 +1705,6 @@ msgstr ""
msgid "ERC-721"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:64
msgid "Total blocks"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/index.html.eex:4
msgid "API Documentation"
@ -1739,3 +1731,29 @@ msgstr ""
#: lib/block_scout_web/views/transaction_view.ex:341
msgid "Raw Trace"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:22
msgid " (page"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:19
msgid " addresses of"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:11
#: lib/block_scout_web/templates/address/index.html.eex:41
msgid "Back"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:17
msgid "Showing "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:64
msgid "Total blocks"
msgstr ""

@ -104,7 +104,7 @@ msgid "Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:4
#: lib/block_scout_web/templates/address/index.html.eex:15
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:59
msgid "Addresses"
msgstr ""
@ -578,6 +578,8 @@ msgid "Newer"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:6
#: lib/block_scout_web/templates/address/index.html.eex:36
#: lib/block_scout_web/templates/address_token/index.html.eex:22
msgid "Next"
msgstr ""
@ -739,11 +741,6 @@ msgstr ""
msgid "Showing"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:6
msgid "Showing 250 addresses of"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8
#: lib/block_scout_web/views/transaction_view.ex:210
@ -1078,7 +1075,7 @@ msgid "string"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:8
#: lib/block_scout_web/templates/address/index.html.eex:21
msgid "total addresses with a balance"
msgstr ""
@ -1708,11 +1705,6 @@ msgstr ""
msgid "ERC-721"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:64
msgid "Total blocks"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/index.html.eex:4
msgid "API Documentation"
@ -1739,3 +1731,29 @@ msgstr ""
#: lib/block_scout_web/views/transaction_view.ex:341
msgid "Raw Trace"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:22
msgid " (page"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:19
msgid " addresses of"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:11
#: lib/block_scout_web/templates/address/index.html.eex:41
msgid "Back"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/index.html.eex:17
msgid "Showing "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:64
msgid "Total blocks"
msgstr ""

@ -1143,21 +1143,25 @@ defmodule Explorer.Chain do
end
@doc """
Lists the top 250 `t:Explorer.Chain.Address.t/0`'s' in descending order based on coin balance.
Lists the top `t:Explorer.Chain.Address.t/0`'s' in descending order based on coin balance and address hash.
"""
@spec list_top_addresses :: [{Address.t(), non_neg_integer()}]
def list_top_addresses do
query =
def list_top_addresses(options \\ []) do
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
base_query =
from(a in Address,
where: a.fetched_coin_balance > ^0,
order_by: [desc: a.fetched_coin_balance, asc: a.hash],
preload: [:names],
select: {a, fragment("coalesce(1 + ?, 0)", a.nonce)},
limit: 250
select: {a, fragment("coalesce(1 + ?, 0)", a.nonce)}
)
Repo.all(query)
base_query
|> page_addresses(paging_options)
|> limit(^paging_options.page_size)
|> Repo.all()
end
@doc """
@ -2293,6 +2297,12 @@ defmodule Explorer.Chain do
end)
end
defp page_addresses(query, %PagingOptions{key: nil}), do: query
defp page_addresses(query, %PagingOptions{key: {coin_balance, hash}}) do
where(query, [address], address.fetched_coin_balance <= ^coin_balance and address.hash > ^hash)
end
defp page_blocks(query, %PagingOptions{key: nil}), do: query
defp page_blocks(query, %PagingOptions{key: {block_number}}) do

@ -1415,6 +1415,33 @@ defmodule Explorer.ChainTest do
|> Enum.map(fn {address, _transaction_count} -> address end)
|> Enum.map(& &1.hash)
end
test "paginates addresses" do
test_hashes =
4..0
|> Enum.map(&Explorer.Chain.Hash.cast(Explorer.Chain.Hash.Address, &1))
|> Enum.map(&elem(&1, 1))
result =
4..1
|> Enum.map(&insert(:address, fetched_coin_balance: &1, hash: Enum.fetch!(test_hashes, &1 - 1)))
|> Enum.map(& &1.hash)
options = [paging_options: %PagingOptions{page_size: 1}]
[{top_address, _}] = Chain.list_top_addresses(options)
assert top_address.hash == List.first(result)
tail_options = [
paging_options: %PagingOptions{key: {top_address.fetched_coin_balance.value, top_address.hash}, page_size: 3}
]
tail_result = tail_options |> Chain.list_top_addresses() |> Enum.map(fn {address, _} -> address.hash end)
[_ | expected_tail] = result
assert tail_result == expected_tail
end
end
describe "stream_blocks_without_rewards/2" do

Loading…
Cancel
Save