Merge pull request #1278 from poanetwork/gsf-market-history-chart-load-async

market history chart load async
pull/1282/head
Gustavo 6 years ago committed by GitHub
commit e9e6d3444d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/block_scout_web/assets/css/components/_dashboard-banner.scss
  2. 29
      apps/block_scout_web/assets/js/lib/market_history_chart.js
  3. 2
      apps/block_scout_web/assets/js/pages/chain.js
  4. 51
      apps/block_scout_web/lib/block_scout_web/controllers/chain/market_history_chart_controller.ex
  5. 22
      apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
  6. 2
      apps/block_scout_web/lib/block_scout_web/router.ex
  7. 12
      apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex
  8. 10
      apps/block_scout_web/lib/block_scout_web/views/chain_view.ex
  9. 30
      apps/block_scout_web/priv/gettext/default.pot
  10. 30
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  11. 24
      apps/block_scout_web/test/block_scout_web/controllers/chain/market_history_chart_controller_test.exs
  12. 10
      apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs
  13. 19
      apps/block_scout_web/test/block_scout_web/views/chain_view_test.exs
  14. 28
      apps/explorer/lib/explorer/exchange_rates/source.ex
  15. 8
      apps/explorer/lib/explorer/exchange_rates/source/coin_market_cap.ex

@ -63,6 +63,8 @@
.dashboard-banner-chart {
grid-area: chart;
padding: 1rem 1rem 1rem 0;
width: calc(350px + 1rem);
height: calc(152px + 1rem);
}
.dashboard-banner-chart-legend {

@ -1,3 +1,4 @@
import $ from 'jquery'
import Chart from 'chart.js'
import humps from 'humps'
import numeral from 'numeral'
@ -122,8 +123,28 @@ class MarketHistoryChart {
}
export function createMarketHistoryChart (el) {
const availableSupply = JSON.parse(el.dataset.available_supply)
const marketHistoryData = humps.camelizeKeys(JSON.parse(el.dataset.market_history_data))
return new MarketHistoryChart(el, availableSupply, marketHistoryData)
const dataPath = el.dataset.market_history_chart_path
const $chartLoading = $('[data-chart-loading-message]')
const $chartError = $('[data-chart-error-message]')
const chart = new MarketHistoryChart(el, 0, [])
$.getJSON(dataPath, {type: 'JSON'})
.done(data => {
const availableSupply = JSON.parse(data.supply_data)
const marketHistoryData = humps.camelizeKeys(JSON.parse(data.history_data))
$(el).show()
chart.update(availableSupply, marketHistoryData)
})
.fail(() => {
$chartError.show()
})
.always(() => {
$chartLoading.hide()
})
return chart
}
$('[data-chart-error-message]').on('click', _event => {
$('[data-chart-loading-message]').show()
$('[data-chart-error-message]').hide()
createMarketHistoryChart($('[data-chart="marketHistoryChart"]')[0])
})

@ -139,7 +139,7 @@ const elements = {
chart = createMarketHistoryChart($el[0])
},
render ($el, state, oldState) {
if (oldState.availableSupply === state.availableSupply && oldState.marketHistoryData === state.marketHistoryData) return
if (!chart || (oldState.availableSupply === state.availableSupply && oldState.marketHistoryData === state.marketHistoryData)) return
chart.update(state.availableSupply, state.marketHistoryData)
}
},

@ -0,0 +1,51 @@
defmodule BlockScoutWeb.Chain.MarketHistoryChartController do
use BlockScoutWeb, :controller
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
def show(conn, _params) do
with true <- ajax?(conn) do
exchange_rate = Market.get_exchange_rate(Explorer.coin()) || Token.null()
market_history_data =
30
|> Market.fetch_recent_history()
|> case do
[today | the_rest] -> [%{today | closing_price: exchange_rate.usd_value} | the_rest]
data -> data
end
|> encode_market_history_data()
json(conn, %{
history_data: market_history_data,
supply_data: available_supply(Chain.supply_for_days(30), exchange_rate)
})
else
_ -> unprocessable_entity(conn)
end
end
defp available_supply(:ok, exchange_rate) do
to_string(exchange_rate.available_supply || 0)
end
defp available_supply({:ok, supply_for_days}, _exchange_rate) do
supply_for_days
|> Jason.encode()
|> case do
{:ok, data} -> data
_ -> []
end
end
defp encode_market_history_data(market_history_data) do
market_history_data
|> Enum.map(fn day -> Map.take(day, [:closing_price, :date]) end)
|> Jason.encode()
|> case do
{:ok, data} -> data
_ -> []
end
end
end

@ -13,20 +13,13 @@ defmodule BlockScoutWeb.ChainController do
exchange_rate = Market.get_exchange_rate(Explorer.coin()) || Token.null()
market_history_data =
case Market.fetch_recent_history(30) do
[today | the_rest] -> [%{today | closing_price: exchange_rate.usd_value} | the_rest]
data -> data
end
render(
conn,
"show.html",
address_count: Chain.count_addresses_with_balance_from_cache(),
average_block_time: Chain.average_block_time(),
exchange_rate: exchange_rate,
available_supply: available_supply(Chain.supply_for_days(30), exchange_rate),
market_history_data: market_history_data,
chart_data_path: market_history_chart_path(conn, :show),
transaction_estimated_count: transaction_estimated_count,
transactions_path: recent_transactions_path(conn, :index)
)
@ -88,17 +81,4 @@ defmodule BlockScoutWeb.ChainController do
)
)
end
defp available_supply(:ok, exchange_rate) do
to_string(exchange_rate.available_supply || 0)
end
defp available_supply({:ok, supply_for_days}, _exchange_rate) do
supply_for_days
|> Jason.encode()
|> case do
{:ok, data} -> data
_ -> []
end
end
end

@ -66,6 +66,8 @@ defmodule BlockScoutWeb.Router do
resources("/", ChainController, only: [:show], singleton: true, as: :chain)
resources("/market_history_chart", Chain.MarketHistoryChartController, only: [:show], singleton: true)
resources "/blocks", BlockController, only: [:index, :show], param: "hash_or_number" do
resources("/transactions", BlockTransactionController, only: [:index], as: :transaction)
end

@ -3,7 +3,17 @@
<div class="container">
<div class="dashboard-banner">
<div class="dashboard-banner-chart">
<canvas data-chart="marketHistoryChart" data-available_supply='<%=raw @available_supply %>' data-market_history_data='<%=raw encode_market_history_data(@market_history_data) %>' width="350" height="152"></canvas>
<div data-chart-loading-message class="tile tile-muted text-center mt-5">
<span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span>
</span>
<%= gettext("Loading chart") %>...
</div>
<button data-chart-error-message class="alert alert-danger col-12 text-left mt-5" style="display: none;">
<span><%= gettext("There was a problem loading the chart.") %></span>
</button>
<canvas data-chart="marketHistoryChart" data-market_history_chart_path="<%= @chart_data_path %>" width="350" height="152" style="display: none;"></canvas>
</div>
<div class="dashboard-banner-chart-legend">
<div class="dashboard-banner-chart-legend-item">

@ -2,14 +2,4 @@ defmodule BlockScoutWeb.ChainView do
use BlockScoutWeb, :view
alias BlockScoutWeb.LayoutView
def encode_market_history_data(market_history_data) do
market_history_data
|> Enum.map(fn day -> Map.take(day, [:closing_price, :date]) end)
|> Jason.encode()
|> case do
{:ok, data} -> data
_ -> []
end
end
end

@ -118,7 +118,7 @@ msgid "All"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:27
#: lib/block_scout_web/templates/chain/show.html.eex:37
msgid "Average block time"
msgstr ""
@ -175,7 +175,7 @@ msgid "BlockScout provides analytics data, API, and Smart Contract tools for the
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:57
#: lib/block_scout_web/templates/chain/show.html.eex:67
#: lib/block_scout_web/templates/layout/_topnav.html.eex:16
#: lib/block_scout_web/templates/layout/_topnav.html.eex:20
msgid "Blocks"
@ -540,7 +540,7 @@ msgid "Logs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:28
#: lib/block_scout_web/templates/layout/app.html.eex:49
#: lib/block_scout_web/views/address_view.ex:117
msgid "Market Cap"
@ -574,7 +574,7 @@ msgid "More internal transactions have come in"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:81
#: lib/block_scout_web/templates/chain/show.html.eex:91
#: 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"
@ -703,7 +703,7 @@ msgid "Position %{index}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:11
#: lib/block_scout_web/templates/chain/show.html.eex:21
#: lib/block_scout_web/templates/layout/app.html.eex:50
msgid "Price"
msgstr ""
@ -951,7 +951,7 @@ msgid "Total Supply"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:35
#: lib/block_scout_web/templates/chain/show.html.eex:45
msgid "Total transactions"
msgstr ""
@ -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:78
#: lib/block_scout_web/templates/chain/show.html.eex:88
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35
#: lib/block_scout_web/views/address_view.ex:253
msgid "Transactions"
@ -1060,12 +1060,12 @@ msgid "Verify & publish"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:56
#: lib/block_scout_web/templates/chain/show.html.eex:66
msgid "View All Blocks →"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:77
#: lib/block_scout_web/templates/chain/show.html.eex:87
msgid "View All Transactions →"
msgstr ""
@ -1105,7 +1105,7 @@ msgid "WEI"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:43
#: lib/block_scout_web/templates/chain/show.html.eex:53
msgid "Wallet addresses"
msgstr ""
@ -1189,8 +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:69
#: lib/block_scout_web/templates/chain/show.html.eex:95
#: lib/block_scout_web/templates/chain/show.html.eex:79
#: lib/block_scout_web/templates/chain/show.html.eex:105
#: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:25
msgid "Loading..."
msgstr ""
@ -1416,7 +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/chain/show.html.eex:71
#: 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
@ -1458,6 +1458,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:24
#: lib/block_scout_web/templates/chain/show.html.eex:11
msgid "Loading chart"
msgstr ""
@ -1468,6 +1469,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:27
#: lib/block_scout_web/templates/chain/show.html.eex:14
msgid "There was a problem loading the chart."
msgstr ""
@ -1537,6 +1539,6 @@ msgid "Emission Contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:87
#: lib/block_scout_web/templates/chain/show.html.eex:97
msgid "Something went wrong, click to retry."
msgstr ""

@ -118,7 +118,7 @@ msgid "All"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:27
#: lib/block_scout_web/templates/chain/show.html.eex:37
msgid "Average block time"
msgstr ""
@ -175,7 +175,7 @@ msgid "BlockScout provides analytics data, API, and Smart Contract tools for the
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:57
#: lib/block_scout_web/templates/chain/show.html.eex:67
#: lib/block_scout_web/templates/layout/_topnav.html.eex:16
#: lib/block_scout_web/templates/layout/_topnav.html.eex:20
msgid "Blocks"
@ -540,7 +540,7 @@ msgid "Logs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:28
#: lib/block_scout_web/templates/layout/app.html.eex:49
#: lib/block_scout_web/views/address_view.ex:117
msgid "Market Cap"
@ -574,7 +574,7 @@ msgid "More internal transactions have come in"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:81
#: lib/block_scout_web/templates/chain/show.html.eex:91
#: 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"
@ -703,7 +703,7 @@ msgid "Position %{index}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:11
#: lib/block_scout_web/templates/chain/show.html.eex:21
#: lib/block_scout_web/templates/layout/app.html.eex:50
msgid "Price"
msgstr ""
@ -951,7 +951,7 @@ msgid "Total Supply"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:35
#: lib/block_scout_web/templates/chain/show.html.eex:45
msgid "Total transactions"
msgstr ""
@ -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:78
#: lib/block_scout_web/templates/chain/show.html.eex:88
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35
#: lib/block_scout_web/views/address_view.ex:253
msgid "Transactions"
@ -1060,12 +1060,12 @@ msgid "Verify & publish"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:56
#: lib/block_scout_web/templates/chain/show.html.eex:66
msgid "View All Blocks →"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:77
#: lib/block_scout_web/templates/chain/show.html.eex:87
msgid "View All Transactions →"
msgstr ""
@ -1105,7 +1105,7 @@ msgid "WEI"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:43
#: lib/block_scout_web/templates/chain/show.html.eex:53
msgid "Wallet addresses"
msgstr ""
@ -1189,8 +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:69
#: lib/block_scout_web/templates/chain/show.html.eex:95
#: lib/block_scout_web/templates/chain/show.html.eex:79
#: lib/block_scout_web/templates/chain/show.html.eex:105
#: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:25
msgid "Loading..."
msgstr ""
@ -1416,7 +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/chain/show.html.eex:71
#: 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
@ -1458,6 +1458,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:24
#: lib/block_scout_web/templates/chain/show.html.eex:11
msgid "Loading chart"
msgstr ""
@ -1468,6 +1469,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:27
#: lib/block_scout_web/templates/chain/show.html.eex:14
msgid "There was a problem loading the chart."
msgstr ""
@ -1537,6 +1539,6 @@ msgid "Emission Contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:87
#: lib/block_scout_web/templates/chain/show.html.eex:97
msgid "Something went wrong, click to retry."
msgstr ""

@ -0,0 +1,24 @@
defmodule BlockScoutWeb.Chain.MarketHistoryChartControllerTest do
use BlockScoutWeb.ConnCase
describe "GET show/2" do
test "returns error when not an ajax request" do
path = market_history_chart_path(BlockScoutWeb.Endpoint, :show)
conn = get(build_conn(), path)
assert conn.status == 422
end
test "returns ok when request is ajax" do
path = market_history_chart_path(BlockScoutWeb.Endpoint, :show)
conn =
build_conn()
|> put_req_header("x-requested-with", "xmlhttprequest")
|> get(path)
assert json_response(conn, 200)
end
end
end

@ -49,16 +49,6 @@ defmodule BlockScoutWeb.ChainControllerTest do
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))
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" do
miner_name = "POA Miner Pool"
%{address: miner_address} = insert(:address_name, name: miner_name, primary: true)

@ -1,19 +0,0 @@
defmodule BlockScoutWeb.ChainViewTest do
use BlockScoutWeb.ConnCase, async: true
alias BlockScoutWeb.ChainView
describe "encode_market_history_data/1" do
test "returns a JSON encoded market history data" do
market_history_data = [
%Explorer.Market.MarketHistory{
closing_price: Decimal.new("0.078"),
date: ~D[2018-08-20]
}
]
assert "[{\"closing_price\":\"0.078\",\"date\":\"2018-08-20\"}]" ==
ChainView.encode_market_history_data(market_history_data)
end
end
end

@ -3,6 +3,7 @@ defmodule Explorer.ExchangeRates.Source do
Behaviour for fetching exchange rates from external sources.
"""
alias Explorer.ExchangeRates.Source.CoinMarketCap
alias Explorer.ExchangeRates.Token
alias HTTPoison.{Error, Response}
@ -11,6 +12,31 @@ defmodule Explorer.ExchangeRates.Source do
"""
@spec fetch_exchange_rates(module) :: {:ok, [Token.t()]} | {:error, any}
def fetch_exchange_rates(source \\ exchange_rates_source()) do
if(source == CoinMarketCap) do
fetch_exchange_rates_from_paginable_source(source)
else
fetch_exchange_rates_request(source)
end
end
defp fetch_exchange_rates_from_paginable_source(source, page \\ 1) do
case HTTPoison.get(source.source_url(page), headers()) do
{:ok, %Response{body: body, status_code: 200}} ->
cond do
body =~ Explorer.coin() -> {:ok, source.format_data(body)}
page == source.max_page_number -> {:error, "exchange rates not found for this network"}
true -> fetch_exchange_rates_from_paginable_source(source, page + 1)
end
{:ok, %Response{body: body, status_code: status_code}} when status_code in 400..499 ->
{:error, decode_json(body)["error"]}
{:error, %Error{reason: reason}} ->
{:error, reason}
end
end
defp fetch_exchange_rates_request(source) do
case HTTPoison.get(source.source_url(), headers()) do
{:ok, %Response{body: body, status_code: 200}} ->
{:ok, source.format_data(body)}
@ -43,6 +69,8 @@ defmodule Explorer.ExchangeRates.Source do
def to_decimal(nil), do: nil
def to_decimal(%Decimal{} = value), do: value
def to_decimal(value) when is_float(value) do
Decimal.from_float(value)
end

@ -31,9 +31,15 @@ defmodule Explorer.ExchangeRates.Source.CoinMarketCap do
@impl Source
def source_url do
"#{base_url()}/v1/ticker/?limit=0"
source_url(1)
end
def source_url(page) do
"#{base_url()}/v1/ticker/?start=#{page - 1}00"
end
def max_page_number, do: 10
defp base_url do
config(:base_url) || "https://api.coinmarketcap.com"
end

Loading…
Cancel
Save