Change to last seen paging and hide paging button on last page for block_transactions

pull/306/head
Stamates 7 years ago
parent f7df4971f7
commit ef6a478741
  1. 24
      apps/explorer/lib/explorer/chain.ex
  2. 44
      apps/explorer/test/explorer/chain_test.exs
  3. 46
      apps/explorer_web/lib/explorer_web/controllers/block_transaction_controller.ex
  4. 26
      apps/explorer_web/lib/explorer_web/templates/block_transaction/index.html.eex
  5. 11
      apps/explorer_web/test/explorer_web/controllers/address_transaction_controller_test.exs
  6. 30
      apps/explorer_web/test/explorer_web/controllers/block_transaction_controller_test.exs

@ -419,22 +419,21 @@ defmodule Explorer.Chain do
end end
@doc """ @doc """
Finds all `t:Explorer.Chain.Transaction.t/0` in the `t:Explorer.Chain.Block.t/0`. Finds all `t:Explorer.Chain.Transaction.t/0`s in the `t:Explorer.Chain.Block.t/0`.
## Options ## Options
* `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is * `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is
`:required`, and the `t:Explorer.Chain.Transaction.t/0` has no associated record for that association, then the `:required`, and the `t:Explorer.Chain.Transaction.t/0` has no associated record for that association, then the
`t:Explorer.Chain.Transaction.t/0` will not be included in the page `entries`. `t:Explorer.Chain.Transaction.t/0` will not be included in the page `entries`.
* `:pagination` - pagination params to pass to scrivener. * `:paging_options` - a `t:Explorer.PagingOptions.t/0` used to specify the `:page_size` and
`:key` (a tuple of the lowest/oldest {index}) and. Results will be the transactions older than
the index that are passed.
""" """
@spec block_to_transactions(Block.t()) :: %Scrivener.Page{entries: [Transaction.t()]} @spec block_to_transactions(Block.t(), [paging_options | necessity_by_association_option]) :: [Transaction.t()]
@spec block_to_transactions(Block.t(), [necessity_by_association_option | pagination_option]) :: %Scrivener.Page{
entries: [Transaction.t()]
}
def block_to_transactions(%Block{hash: block_hash}, options \\ []) when is_list(options) do def block_to_transactions(%Block{hash: block_hash}, options \\ []) when is_list(options) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
pagination = Keyword.get(options, :pagination, %{}) paging_options = Keyword.get(options, :paging_options, %PagingOptions{page_size: 50})
Transaction Transaction
|> load_contract_creation() |> load_contract_creation()
@ -443,9 +442,11 @@ defmodule Explorer.Chain do
}) })
|> join(:inner, [transaction], block in assoc(transaction, :block)) |> join(:inner, [transaction], block in assoc(transaction, :block))
|> where([_, _, block], block.hash == ^block_hash) |> where([_, _, block], block.hash == ^block_hash)
|> order_by([transaction], desc: transaction.inserted_at, desc: transaction.hash) |> page_transaction(paging_options)
|> limit(^paging_options.page_size)
|> order_by([transaction], desc: transaction.index)
|> join_associations(necessity_by_association) |> join_associations(necessity_by_association)
|> Repo.paginate(pagination) |> Repo.all()
end end
@doc """ @doc """
@ -2550,6 +2551,11 @@ defmodule Explorer.Chain do
) )
end end
defp page_transaction(query, %PagingOptions{key: {index}}) do
query
|> where([transaction], transaction.index < ^index)
end
defp run_addresses(multi, ecto_schema_module_to_changes_list, options) defp run_addresses(multi, ecto_schema_module_to_changes_list, options)
when is_map(ecto_schema_module_to_changes_list) and is_list(options) do when is_map(ecto_schema_module_to_changes_list) and is_list(options) do
case ecto_schema_module_to_changes_list do case ecto_schema_module_to_changes_list do

@ -122,11 +122,7 @@ defmodule Explorer.ChainTest do
assert Repo.aggregate(Transaction, :count, :hash) == 0 assert Repo.aggregate(Transaction, :count, :hash) == 0
assert %Scrivener.Page{ assert [] = Chain.block_to_transactions(block)
entries: [],
page_number: 1,
total_entries: 0
} = Chain.block_to_transactions(block)
end end
test "with transactions" do test "with transactions" do
@ -135,40 +131,28 @@ defmodule Explorer.ChainTest do
|> insert() |> insert()
|> with_block() |> with_block()
assert %Scrivener.Page{ assert [%Transaction{hash: ^transaction_hash}] = Chain.block_to_transactions(block)
entries: [%Transaction{hash: ^transaction_hash}],
page_number: 1,
total_entries: 1
} = Chain.block_to_transactions(block)
end end
test "with transactions can be paginated" do test "with transactions can be paginated" do
block = insert(:block) block = insert(:block)
transactions = second_page_hashes =
Enum.map(0..1, fn _ -> 50
|> insert_list(:transaction)
|> with_block(block)
|> Enum.map(& &1.hash)
%Transaction{block_number: block_number, index: index} =
:transaction :transaction
|> insert() |> insert()
|> with_block(block) |> with_block(block)
end)
[%Transaction{hash: first_transaction_hash}, %Transaction{hash: second_transaction_hash}] = transactions
assert %Scrivener.Page{ assert second_page_hashes ==
entries: [%Transaction{hash: ^second_transaction_hash}], block
page_number: 1, |> Chain.block_to_transactions(paging_options: %PagingOptions{key: {block_number, index}, page_size: 50})
page_size: 1, |> Enum.map(& &1.hash)
total_entries: 2, |> Enum.reverse()
total_pages: 2
} = Chain.block_to_transactions(block, pagination: %{page_size: 1})
assert %Scrivener.Page{
entries: [%Transaction{hash: ^first_transaction_hash}],
page_number: 2,
page_size: 1,
total_entries: 2,
total_pages: 2
} = Chain.block_to_transactions(block, pagination: %{page: 2, page_size: 1})
end end
end end

@ -3,24 +3,37 @@ defmodule ExplorerWeb.BlockTransactionController do
import ExplorerWeb.Chain, only: [param_to_block_number: 1] import ExplorerWeb.Chain, only: [param_to_block_number: 1]
alias Explorer.Chain alias Explorer.{Chain, PagingOptions}
@page_size 50
@default_paging_options %PagingOptions{page_size: @page_size + 1}
def index(conn, %{"block_id" => formatted_block_number} = params) do def index(conn, %{"block_id" => formatted_block_number} = params) do
with {:ok, block_number} <- param_to_block_number(formatted_block_number), with {:ok, block_number} <- param_to_block_number(formatted_block_number),
{:ok, block} <- Chain.number_to_block(block_number, necessity_by_association: %{miner: :required}), {:ok, block} <- Chain.number_to_block(block_number, necessity_by_association: %{miner: :required}),
block_transaction_count <- Chain.block_to_transaction_count(block) do block_transaction_count <- Chain.block_to_transaction_count(block) do
page = full_options =
Chain.block_to_transactions( [
block,
necessity_by_association: %{ necessity_by_association: %{
block: :required, block: :required,
from_address: :required, from_address: :required,
to_address: :optional to_address: :optional
}, }
pagination: params ]
) |> Keyword.merge(paging_options(params))
transactions_plus_one = Chain.block_to_transactions(block, full_options)
render(conn, "index.html", block: block, block_transaction_count: block_transaction_count, page: page) {transactions, next_page} = Enum.split(transactions_plus_one, @page_size)
render(
conn,
"index.html",
block: block,
block_transaction_count: block_transaction_count,
next_page_params: next_page_params(next_page, transactions),
transactions: transactions
)
else else
{:error, :invalid} -> {:error, :invalid} ->
not_found(conn) not_found(conn)
@ -29,4 +42,21 @@ defmodule ExplorerWeb.BlockTransactionController do
not_found(conn) not_found(conn)
end end
end end
defp next_page_params([], _transactions), do: nil
defp next_page_params(_, transactions) do
last = List.last(transactions)
%{block_number: last.block_number, index: last.index}
end
defp paging_options(params) do
with %{"index" => index_string} <- params,
{index, ""} <- Integer.parse(index_string) do
[paging_options: %{@default_paging_options | key: {index}}]
else
_ ->
[paging_options: @default_paging_options]
end
end
end end

@ -129,7 +129,7 @@
</ul> </ul>
</div> </div>
<div class="card-body"> <div class="card-body">
<%= if Enum.count(@page) > 0 do %> <%= if Enum.count(@transactions) > 0 do %>
<table class="table table-responsive-sm table-font"> <table class="table table-responsive-sm table-font">
<thead> <thead>
<tr> <tr>
@ -146,7 +146,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<%= for transaction <- @page do %> <%= for transaction <- @transactions do %>
<tr> <tr>
<td> <td>
<div class="transaction__dot transaction__dot--<%= status(transaction) %>"></div> <div class="transaction__dot transaction__dot--<%= status(transaction) %>"></div>
@ -195,21 +195,17 @@
<% end %> <% end %>
</div> </div>
</div> </div>
<%= if @next_page_params do %>
<%= if Enum.count(@page) > 0 do %> <%= link(
<div class="blocks__pagination"> gettext("Older"),
<%= pagination_links( class: "button button--secondary button--sm u-float-right mt-3",
to: transaction_path(
@conn, @conn,
@page, :index,
["en", @conn.params["block_id"]], @conn.assigns.locale,
distance: 1, @next_page_params
first: true, )
next: Phoenix.HTML.raw("&rsaquo;"),
path: &block_transaction_path/5,
previous: Phoenix.HTML.raw("&lsaquo;"),
view_style: :bulma
) %> ) %>
</div>
<% end %> <% end %>
</section> </section>
</section> </section>

@ -114,16 +114,7 @@ defmodule ExplorerWeb.AddressTransactionControllerTest do
|> insert(from_address_hash: address.hash) |> insert(from_address_hash: address.hash)
|> with_block() |> with_block()
%Transaction{block_number: block_number, index: index} = conn = get(conn, address_transaction_path(ExplorerWeb.Endpoint, :index, :en, address.hash))
:transaction
|> insert(from_address_hash: address.hash)
|> with_block()
conn =
get(conn, address_transaction_path(ExplorerWeb.Endpoint, :index, :en, address.hash), %{
"block_number" => Integer.to_string(block_number),
"index" => Integer.to_string(index)
})
refute conn.assigns.next_page_params refute conn.assigns.next_page_params
end end

@ -25,7 +25,7 @@ defmodule ExplorerWeb.BlockTransactionControllerTest do
conn = get(conn, block_transaction_path(ExplorerWeb.Endpoint, :index, :en, block.number)) conn = get(conn, block_transaction_path(ExplorerWeb.Endpoint, :index, :en, block.number))
assert html_response(conn, 200) assert html_response(conn, 200)
assert 2 == Enum.count(conn.assigns.page) assert 2 == Enum.count(conn.assigns.transactions)
end end
test "does not return unrelated transactions", %{conn: conn} do test "does not return unrelated transactions", %{conn: conn} do
@ -35,7 +35,7 @@ defmodule ExplorerWeb.BlockTransactionControllerTest do
conn = get(conn, block_transaction_path(ExplorerWeb.Endpoint, :index, :en, block)) conn = get(conn, block_transaction_path(ExplorerWeb.Endpoint, :index, :en, block))
assert html_response(conn, 200) assert html_response(conn, 200)
assert Enum.empty?(conn.assigns.page) assert Enum.empty?(conn.assigns.transactions)
end end
test "does not return related transactions without a block", %{conn: conn} do test "does not return related transactions without a block", %{conn: conn} do
@ -45,7 +45,31 @@ defmodule ExplorerWeb.BlockTransactionControllerTest do
conn = get(conn, block_transaction_path(ExplorerWeb.Endpoint, :index, :en, block)) conn = get(conn, block_transaction_path(ExplorerWeb.Endpoint, :index, :en, block))
assert html_response(conn, 200) assert html_response(conn, 200)
assert Enum.empty?(conn.assigns.page) assert Enum.empty?(conn.assigns.transactions)
end
test "next_page_params exist if not on last page", %{conn: conn} do
block = insert(:block)
60
|> insert_list(:transaction)
|> with_block(block)
conn = get(conn, block_transaction_path(ExplorerWeb.Endpoint, :index, :en, block))
assert conn.assigns.next_page_params
end
test "next_page_params are empty if on last page", %{conn: conn} do
block = insert(:block)
:transaction
|> insert()
|> with_block(block)
conn = get(conn, block_transaction_path(ExplorerWeb.Endpoint, :index, :en, block))
refute conn.assigns.next_page_params
end end
end end
end end

Loading…
Cancel
Save