Merge pull request #1103 from poanetwork/gsf-async-load-token-transfers

async load token transfers
pull/1126/head
Gustavo 6 years ago committed by GitHub
commit dcccca556c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      apps/block_scout_web/assets/.eslintrc
  2. 1
      apps/block_scout_web/assets/js/app.js
  3. 85
      apps/block_scout_web/assets/js/lib/async_listing_load.js
  4. 42
      apps/block_scout_web/lib/block_scout_web/controllers/tokens/transfer_controller.ex
  5. 49
      apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex
  6. 11
      apps/block_scout_web/priv/gettext/default.pot
  7. 11
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  8. 6
      apps/block_scout_web/test/block_scout_web/features/pages/token_page.ex
  9. 1
      apps/block_scout_web/test/block_scout_web/features/viewing_tokens_test.exs

@ -1,3 +1,6 @@
{ {
"extends": "standard" "extends": "standard",
"env": {
"browser": true
}
} }

@ -44,6 +44,7 @@ import './lib/stop_propagation'
import './lib/token_balance_dropdown' import './lib/token_balance_dropdown'
import './lib/token_balance_dropdown_search' import './lib/token_balance_dropdown_search'
import './lib/token_transfers_toggle' import './lib/token_transfers_toggle'
import './lib/async_listing_load'
import './lib/tooltip' import './lib/tooltip'
import './lib/try_api' import './lib/try_api'
import './lib/swappable_item' import './lib/swappable_item'

@ -0,0 +1,85 @@
import $ from 'jquery'
/**
* This script is a generic function to load list within a tab async. See token transfers tab at Token's page as example.
*
* To get it working the markup must follow the pattern below:
*
* <div data-async-listing="path">
* <div data-loading-message> message </div>
* <div data-empty-response-message style="display: none;"> message </div>
* <div data-error-message style="display: none;"> message </div>
* <div data-items></div>
* <a data-next-page-button style="display: none;"> button text </a>
* <div data-loading-button style="display: none;"> loading text </div>
* </div>
*
*/
const $element = $('[data-async-listing]')
function asyncListing (element, path) {
const $mainElement = $(element)
const $items = $mainElement.find('[data-items]')
const $loading = $mainElement.find('[data-loading-message]')
const $nextPageButton = $mainElement.find('[data-next-page-button]')
const $loadingButton = $mainElement.find('[data-loading-button]')
const $errorMessage = $mainElement.find('[data-error-message]')
const $emptyResponseMessage = $mainElement.find('[data-empty-response-message]')
$.getJSON(path, {type: 'JSON'})
.done(response => {
if (!response.items || response.items.length === 0) {
$emptyResponseMessage.show()
$items.empty()
} else {
$items.html(response.items)
}
if (response.next_page_path) {
$nextPageButton.attr('href', response.next_page_path)
$nextPageButton.show()
} else {
$nextPageButton.hide()
}
})
.fail(() => $errorMessage.show())
.always(() => {
$loading.hide()
$loadingButton.hide()
})
}
if ($element.length === 1) {
$element.on('click', '[data-next-page-button]', (event) => {
event.preventDefault()
const $button = $(event.target)
const path = $button.attr('href')
const $loadingButton = $element.find('[data-loading-button]')
// change url to the next page link before loading the next page
history.pushState({}, null, path)
$button.hide()
$loadingButton.show()
asyncListing($element, path)
})
$element.on('click', '[data-error-message]', (event) => {
event.preventDefault()
// event.target had a weird behavior here
// it hid the <a> tag but left the red div showing
const $link = $element.find('[data-error-message]')
const $loading = $element.find('[data-loading-message]')
const path = $element.data('async-listing')
$link.hide()
$loading.show()
asyncListing($element, path)
})
// force browser to reload when the user goes back a page
$(window).on('popstate', () => location.reload())
asyncListing($element, $element.data('async-listing'))
}

@ -1,25 +1,59 @@
defmodule BlockScoutWeb.Tokens.TransferController do defmodule BlockScoutWeb.Tokens.TransferController do
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
alias BlockScoutWeb.Tokens.TransferView
alias Explorer.Chain alias Explorer.Chain
alias Phoenix.View
import BlockScoutWeb.Chain, only: [split_list_by_page: 1, paging_options: 1, next_page_params: 3] import BlockScoutWeb.Chain, only: [split_list_by_page: 1, paging_options: 1, next_page_params: 3]
def index(conn, %{"token_id" => address_hash_string} = params) do def index(conn, %{"token_id" => address_hash_string, "type" => "JSON"} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, token} <- Chain.token_from_address_hash(address_hash), {:ok, token} <- Chain.token_from_address_hash(address_hash),
token_transfers <- Chain.fetch_token_transfers_from_token_hash(address_hash, paging_options(params)) do token_transfers <- Chain.fetch_token_transfers_from_token_hash(address_hash, paging_options(params)) do
{token_transfers_paginated, next_page} = split_list_by_page(token_transfers) {token_transfers_paginated, next_page} = split_list_by_page(token_transfers)
next_page_path =
case next_page_params(next_page, token_transfers_paginated, params) do
nil ->
nil
next_page_params ->
token_transfer_path(conn, :index, token.contract_address_hash, Map.delete(next_page_params, "type"))
end
transfers_json =
Enum.map(token_transfers_paginated, fn transfer ->
View.render_to_string(
TransferView,
"_token_transfer.html",
conn: conn,
token: token,
transfer: transfer
)
end)
json(conn, %{items: transfers_json, next_page_path: next_page_path})
else
:error ->
unprocessable_entity(conn)
{:error, :not_found} ->
not_found(conn)
end
end
def index(conn, %{"token_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, token} <- Chain.token_from_address_hash(address_hash) do
render( render(
conn, conn,
"index.html", "index.html",
transfers: token_transfers_paginated, current_path: current_path(conn),
token: token, token: token,
holders_count_consolidation_enabled: Chain.token_holders_counter_consolidation_enabled?(), holders_count_consolidation_enabled: Chain.token_holders_counter_consolidation_enabled?(),
total_token_transfers: Chain.count_token_transfers_from_token_hash(address_hash), total_token_transfers: Chain.count_token_transfers_from_token_hash(address_hash),
total_token_holders: Chain.count_token_holders_from_token_hash(address_hash), total_token_holders: Chain.count_token_holders_from_token_hash(address_hash)
next_page_params: next_page_params(next_page, token_transfers_paginated, params)
) )
else else
:error -> :error ->

@ -15,28 +15,35 @@
<%= render OverviewView, "_tabs.html", assigns %> <%= render OverviewView, "_tabs.html", assigns %>
</div> </div>
<div class="card-body"> <div class="card-body" data-async-listing="<%= @current_path %>">
<h2 class="card-title"><%= gettext "Token Transfers" %></h2> <h2 class="card-title"><%= gettext "Token Transfers" %></h2>
<button data-error-message class="alert alert-danger col-12 text-left" style="display: none;">
<%= if Enum.any?(@transfers) do %> <span href="#" class="alert-link"><%= gettext("Something went wrong, click to reload.") %></span>
<%= for transfer <- @transfers do %> </button>
<%= render("_token_transfer.html", conn: @conn, token: @token, transfer: transfer) %> <div data-empty-response-message class="tile tile-muted text-center" style="display: none;">
<% end %> <span data-selector="empty-transactions-list">
<% else %> <%= gettext "There are no transfers for this Token." %>
<div class="tile tile-muted text-center"> </span>
<span data-selector="empty-transactions-list"> </div>
<%= gettext "There are no transfers for this Token." %> <div data-loading-message class="tile tile-muted text-center mt-3">
</span> <span class="loading-spinner-small mr-2">
</div> <span class="loading-spinner-block-1"></span>
<% end %> <span class="loading-spinner-block-2"></span>
</span>
<%= if @next_page_params do %> <%= gettext("Loading") %>...
<%= link( </div>
gettext("Older"), <div data-items>
class: "button button-secondary button-small float-right mt-4", </div>
to: token_path(@conn, :show, @token.contract_address_hash, @next_page_params) <a href="#" class="button button-secondary button-small float-right mt-4" data-next-page-button style="display: none;">
) %> <%= gettext("Older") %>
<% end %> </a>
<div class="button button-secondary button-small float-right mt-4" data-loading-button style="display: none;">
<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> </div>
</section> </section>

@ -643,7 +643,7 @@ msgstr ""
#: lib/block_scout_web/templates/block/index.html.eex:30 #: lib/block_scout_web/templates/block/index.html.eex:30
#: lib/block_scout_web/templates/block_transaction/index.html.eex:50 #: lib/block_scout_web/templates/block_transaction/index.html.eex:50
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:41 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:41
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:35 #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:38
#: lib/block_scout_web/templates/transaction/index.html.eex:41 #: lib/block_scout_web/templates/transaction/index.html.eex:41
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:24 #: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:24
msgid "Older" msgid "Older"
@ -861,7 +861,7 @@ msgid "There are no transactions for this block."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:28 #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:25
msgid "There are no transfers for this Token." msgid "There are no transfers for this Token."
msgstr "" msgstr ""
@ -1217,6 +1217,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_transaction/index.html.eex:61 #: lib/block_scout_web/templates/address_transaction/index.html.eex:61
#: lib/block_scout_web/templates/block/index.html.eex:22 #: lib/block_scout_web/templates/block/index.html.eex:22
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:33 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:33
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:33
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:45
#: lib/block_scout_web/templates/transaction/index.html.eex:33 #: lib/block_scout_web/templates/transaction/index.html.eex:33
msgid "Loading" msgid "Loading"
msgstr "" msgstr ""
@ -1405,3 +1407,8 @@ msgstr ""
#: lib/block_scout_web/templates/transaction_log/index.html.eex:54 #: lib/block_scout_web/templates/transaction_log/index.html.eex:54
msgid "Log Data" msgid "Log Data"
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:21
msgid "Something went wrong, click to reload."
msgstr ""

@ -643,7 +643,7 @@ msgstr ""
#: lib/block_scout_web/templates/block/index.html.eex:30 #: lib/block_scout_web/templates/block/index.html.eex:30
#: lib/block_scout_web/templates/block_transaction/index.html.eex:50 #: lib/block_scout_web/templates/block_transaction/index.html.eex:50
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:41 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:41
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:35 #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:38
#: lib/block_scout_web/templates/transaction/index.html.eex:41 #: lib/block_scout_web/templates/transaction/index.html.eex:41
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:24 #: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:24
msgid "Older" msgid "Older"
@ -861,7 +861,7 @@ msgid "There are no transactions for this block."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:28 #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:25
msgid "There are no transfers for this Token." msgid "There are no transfers for this Token."
msgstr "" msgstr ""
@ -1217,6 +1217,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_transaction/index.html.eex:61 #: lib/block_scout_web/templates/address_transaction/index.html.eex:61
#: lib/block_scout_web/templates/block/index.html.eex:22 #: lib/block_scout_web/templates/block/index.html.eex:22
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:33 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:33
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:33
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:45
#: lib/block_scout_web/templates/transaction/index.html.eex:33 #: lib/block_scout_web/templates/transaction/index.html.eex:33
msgid "Loading" msgid "Loading"
msgstr "" msgstr ""
@ -1405,3 +1407,8 @@ msgstr ""
#: lib/block_scout_web/templates/transaction_log/index.html.eex:54 #: lib/block_scout_web/templates/transaction_log/index.html.eex:54
msgid "Log Data" msgid "Log Data"
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:21
msgid "Something went wrong, click to reload."
msgstr ""

@ -10,7 +10,11 @@ defmodule BlockScoutWeb.TokenPage do
end end
def visit_page(session, contract_address_hash) do def visit_page(session, contract_address_hash) do
visit(session, "tokens/#{contract_address_hash}") visit(session, "tokens/#{contract_address_hash}/token_holders")
end
def token_holders_tab(count: count) do
css("[data-test='token_holders_tab']", count: count)
end end
def click_tokens_holders(session) do def click_tokens_holders(session) do

@ -15,7 +15,6 @@ defmodule BlockScoutWeb.ViewingTokensTest do
session session
|> TokenPage.visit_page(token.contract_address) |> TokenPage.visit_page(token.contract_address)
|> TokenPage.click_tokens_holders()
|> assert_has(TokenPage.token_holders(count: 2)) |> assert_has(TokenPage.token_holders(count: 2))
end end
end end

Loading…
Cancel
Save