Merge branch 'master' into optimized-indexer

pull/162/head
Luke Imhoff 7 years ago
commit cc5175d8f5
  1. 35
      apps/explorer/lib/explorer/exchange_rates/exchange_rates.ex
  2. 2
      apps/explorer/lib/explorer/exchange_rates/token.ex
  3. 11
      apps/explorer/lib/explorer/market/market.ex
  4. 29
      apps/explorer/test/explorer/exchange_rates/exchange_rates_test.exs
  5. 9
      apps/explorer/test/support/factory.ex
  6. 10
      apps/explorer/test/support/fakes/no_op_source.ex
  7. 0
      apps/explorer_web/assets/.babelrc
  8. 5
      apps/explorer_web/assets/css/app.scss
  9. 58
      apps/explorer_web/assets/css/components/_chain.scss
  10. 1
      apps/explorer_web/assets/js/app.js
  11. 100
      apps/explorer_web/assets/js/lib/market_history_chart.js
  12. 51
      apps/explorer_web/assets/package-lock.json
  13. 4
      apps/explorer_web/assets/package.json
  14. 14
      apps/explorer_web/lib/explorer_web/controllers/chain_controller.ex
  15. 58
      apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex
  16. 29
      apps/explorer_web/lib/explorer_web/views/chain_view.ex
  17. 47
      apps/explorer_web/priv/gettext/default.pot
  18. 47
      apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
  19. 10
      apps/explorer_web/test/explorer_web/controllers/chain_controller_test.exs
  20. 4
      config/test.exs

@ -31,7 +31,9 @@ defmodule Explorer.ExchangeRates do
{symbol, token} {symbol, token}
end end
if store() == :ets do
:ets.insert(table_name(), records) :ets.insert(table_name(), records)
end
{:noreply, state} {:noreply, state}
end end
@ -65,7 +67,9 @@ defmodule Explorer.ExchangeRates do
write_concurrency: true write_concurrency: true
] ]
if store() == :ets do
:ets.new(table_name(), table_opts) :ets.new(table_name(), table_opts)
end
{:ok, %{}} {:ok, %{}}
end end
@ -79,10 +83,20 @@ defmodule Explorer.ExchangeRates do
""" """
@spec list :: [Token.t()] @spec list :: [Token.t()]
def list do def list do
table_name() list_from_store(store())
|> :ets.tab2list() end
|> Enum.map(fn {_, rate} -> rate end)
|> Enum.sort_by(fn %Token{symbol: symbol} -> symbol end) @doc """
Returns a specific rate from the tracked tickers by symbol
"""
@spec lookup(String.t()) :: Token.t()
def lookup(symbol) do
if store() == :ets do
case :ets.lookup(table_name(), symbol) do
[{_key, token} | _] -> token
_ -> nil
end
end
end end
@doc false @doc false
@ -105,4 +119,17 @@ defmodule Explorer.ExchangeRates do
exchange_rates_source().fetch_exchange_rates() exchange_rates_source().fetch_exchange_rates()
end) end)
end end
defp list_from_store(:ets) do
table_name()
|> :ets.tab2list()
|> Enum.map(fn {_, rate} -> rate end)
|> Enum.sort_by(fn %Token{symbol: symbol} -> symbol end)
end
defp list_from_store(_), do: []
defp store do
config(:store) || :ets
end
end end

@ -29,4 +29,6 @@ defmodule Explorer.ExchangeRates.Token do
} }
defstruct ~w(available_supply btc_value id last_updated market_cap_usd name symbol usd_value volume_24h_usd)a defstruct ~w(available_supply btc_value id last_updated market_cap_usd name symbol usd_value volume_24h_usd)a
def null, do: %__MODULE__{}
end end

@ -5,8 +5,17 @@ defmodule Explorer.Market do
import Ecto.Query import Ecto.Query
alias Explorer.{ExchangeRates, Repo}
alias Explorer.ExchangeRates.Token
alias Explorer.Market.MarketHistory alias Explorer.Market.MarketHistory
alias Explorer.Repo
@doc """
Get most recent exchange rate for the given symbol.
"""
@spec get_exchange_rate(String.t()) :: Token.t()
def get_exchange_rate(symbol) do
ExchangeRates.lookup(symbol)
end
@doc """ @doc """
Retrieves the history for the recent specified amount of days. Retrieves the history for the recent specified amount of days.

@ -11,6 +11,16 @@ defmodule Explorer.ExchangeRatesTest do
setup :verify_on_exit! setup :verify_on_exit!
setup do
# Use TestSource mock and ets table for this test set
configuration = Application.get_env(:explorer, Explorer.ExchangeRates)
Application.put_env(:explorer, Explorer.ExchangeRates, source: TestSource)
on_exit(fn ->
Application.put_env(:explorer, Explorer.ExchangeRates, configuration)
end)
end
test "start_link" do test "start_link" do
stub(TestSource, :fetch_exchange_rates, fn -> {:ok, [%Token{}]} end) stub(TestSource, :fetch_exchange_rates, fn -> {:ok, [%Token{}]} end)
set_mox_global() set_mox_global()
@ -87,13 +97,26 @@ defmodule Explorer.ExchangeRatesTest do
ExchangeRates.init([]) ExchangeRates.init([])
rates = [ rates = [
%Token{id: "z", symbol: "z"}, %Token{symbol: "z"},
%Token{id: "a", symbol: "a"} %Token{symbol: "a"}
] ]
expected_rates = Enum.reverse(rates) expected_rates = Enum.reverse(rates)
for rate <- rates, do: :ets.insert(ExchangeRates.table_name(), {rate.id, rate}) for rate <- rates, do: :ets.insert(ExchangeRates.table_name(), {rate.symbol, rate})
assert expected_rates == ExchangeRates.list() assert expected_rates == ExchangeRates.list()
end end
test "lookup/1" do
ExchangeRates.init([])
z = %Token{symbol: "z"}
rates = [z, %Token{symbol: "a"}]
for rate <- rates, do: :ets.insert(ExchangeRates.table_name(), {rate.symbol, rate})
assert z == ExchangeRates.lookup("z")
assert nil == ExchangeRates.lookup("nope")
end
end end

@ -2,6 +2,7 @@ defmodule Explorer.Factory do
use ExMachina.Ecto, repo: Explorer.Repo use ExMachina.Ecto, repo: Explorer.Repo
alias Explorer.Chain.{Address, Block, Hash, InternalTransaction, Log, Receipt, Transaction} alias Explorer.Chain.{Address, Block, Hash, InternalTransaction, Log, Receipt, Transaction}
alias Explorer.Market.MarketHistory
alias Explorer.Repo alias Explorer.Repo
@dialyzer {:nowarn_function, fields_for: 1} @dialyzer {:nowarn_function, fields_for: 1}
@ -71,6 +72,14 @@ defmodule Explorer.Factory do
} }
end end
def market_history_factory do
%MarketHistory{
closing_price: Decimal.new(Enum.random(1..10_000) / 100),
opening_price: Decimal.new(Enum.random(1..10_000) / 100),
date: Date.utc_today()
}
end
def receipt_factory do def receipt_factory do
%Receipt{ %Receipt{
cumulative_gas_used: Enum.random(21_000..100_000), cumulative_gas_used: Enum.random(21_000..100_000),

@ -0,0 +1,10 @@
defmodule Explorer.ExchangeRates.Source.NoOpSource do
@moduledoc false
alias Explorer.ExchangeRates.Source
@behaviour Source
@impl Source
def fetch_exchange_rates, do: {:ok, []}
end

@ -32,3 +32,8 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
@import "components/sidebar"; @import "components/sidebar";
@import "explorer/button"; @import "explorer/button";
@import "explorer/filter"; @import "explorer/filter";
:export {
primary: $primary;
secondary: $secondary;
}

@ -1,9 +1,5 @@
.chain { .chain {
@extend %paper; @extend %paper;
display: flex;
justify-conntent: space-around;
align-items: flex-start;
padding: explorer-size(0) 0; padding: explorer-size(0) 0;
&__container { &__container {
@ -25,6 +21,43 @@
} }
} }
.container__stats {
@extend %paper;
display: flex;
padding: 15px;
width: 100%;
font-size: 12px;
text-align: center;
flex-direction: row;
justify-content: space-around;
img {
display: inline-block;
height: explorer-size(1);
margin-bottom: explorer-size(-2);
text-align: center;
}
}
.graph__squares {
width: 12px;
height: 12px;
display: inline-block;
&--price {
background-color: explorer-color("blue", "500");
}
&--mcap {
background-color: explorer-color("gray", "500");
}
}
.flex {
display: flex;
justify-content: space-between;
}
@media (min-width: $explorer-breakpoint-sm) { @media (min-width: $explorer-breakpoint-sm) {
.chain { .chain {
&__image { &__image {
@ -38,6 +71,23 @@
} }
@media (min-width: $explorer-breakpoint-md) { @media (min-width: $explorer-breakpoint-md) {
.container__stats {
width: 18%;
flex-direction: column;
align-content: space-between;
img {
display: inline-block;
height: explorer-size(1);
margin-bottom: explorer-size(-2);
text-align: center;
}
div {
flex-grow: 1;
}
}
.chain { .chain {
&__image { &__image {
height: explorer-size(1); height: explorer-size(1);

@ -20,3 +20,4 @@ import 'bootstrap'
// import socket from "./socket" // import socket from "./socket"
import './lib/sidebar' import './lib/sidebar'
import './lib/market_history_chart'

@ -0,0 +1,100 @@
import $ from 'jquery'
import Chart from 'chart.js'
import humps from 'humps'
import moment from 'moment'
import numeral from 'numeral'
import sassVariables from '../../css/app.scss'
function formatPrice (price) {
return '$' + price.toFixed(2)
}
function formatMarketCap (marketCap) {
return numeral(marketCap).format('($0,0a)')
}
function createMarketHistoryChart (ctx) {
const currentExchangeRate = ctx.dataset.current_exchange_rate
const availableSupply = ctx.dataset.available_supply
const marketHistoryData = humps.camelizeKeys(JSON.parse(ctx.dataset.market_history_data))
const today = moment().format('YYYY-MM-DD')
const currentMarketHistoryData = marketHistoryData.map(({date, closingPrice}) => ({
date,
closingPrice: date === today ? currentExchangeRate : closingPrice
}))
return new Chart(ctx, {
type: 'line',
responsive: true,
data: {
datasets: [{
label: 'Price',
yAxisID: 'price',
data: currentMarketHistoryData.map(({ date, closingPrice }) => ({x: date, y: closingPrice})),
fill: false,
pointRadius: 0,
backgroundColor: sassVariables.primary,
borderColor: sassVariables.primary,
lineTension: 0
}, {
label: 'Market Cap',
yAxisID: 'marketCap',
data: currentMarketHistoryData.map(({ date, closingPrice }) => ({x: date, y: closingPrice * availableSupply})),
fill: false,
pointRadius: 0.5,
backgroundColor: sassVariables.secondary,
borderColor: sassVariables.secondary,
lineTension: 0
}]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'week',
displayFormats: {
week: 'MMM D'
}
}
}],
yAxes: [{
id: 'price',
ticks: {
beginAtZero: true,
callback: (value, index, values) => formatPrice(value),
maxTicksLimit: 6
}
}, {
id: 'marketCap',
position: 'right',
ticks: {
callback: (value, index, values) => formatMarketCap(value),
maxTicksLimit: 6
}
}]
},
tooltips: {
mode: 'index',
intersect: false,
callbacks: {
label: ({datasetIndex, yLabel}, {datasets}) => {
const label = datasets[datasetIndex].label
if (datasets[datasetIndex].label === 'Price') {
return `${label}: ${formatPrice(yLabel)}`
} else if (datasets[datasetIndex].label === 'Market Cap') {
return `${label}: ${formatMarketCap(yLabel)}`
} else {
return yLabel
}
}
}
}
}
})
}
$('[data-chart="marketHistoryChart"]').each((i, ctx) => createMarketHistoryChart(ctx))

@ -1673,6 +1673,39 @@
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"dev": true "dev": true
}, },
"chart.js": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.2.tgz",
"integrity": "sha512-90wl3V9xRZ8tnMvMlpcW+0Yg13BelsGS9P9t0ClaDxv/hdypHDr/YAGf+728m11P5ljwyB0ZHfPKCapZFqSqYA==",
"requires": {
"chartjs-color": "2.2.0",
"moment": "2.22.1"
}
},
"chartjs-color": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz",
"integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=",
"requires": {
"chartjs-color-string": "0.5.0",
"color-convert": "0.5.3"
},
"dependencies": {
"color-convert": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
"integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
}
}
},
"chartjs-color-string": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz",
"integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==",
"requires": {
"color-name": "1.1.3"
}
},
"chokidar": { "chokidar": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
@ -2004,8 +2037,7 @@
"color-name": { "color-name": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
"dev": true
}, },
"color-string": { "color-string": {
"version": "0.3.0", "version": "0.3.0",
@ -4719,6 +4751,11 @@
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
"dev": true "dev": true
}, },
"humps": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz",
"integrity": "sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao="
},
"iconv-lite": { "iconv-lite": {
"version": "0.4.19", "version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
@ -6427,6 +6464,11 @@
"minimist": "0.0.8" "minimist": "0.0.8"
} }
}, },
"moment": {
"version": "2.22.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.1.tgz",
"integrity": "sha512-shJkRTSebXvsVqk56I+lkb2latjBs8I+pc2TzWc545y2iFnSjm7Wg0QMh+ZWcdSLQyGEau5jI8ocnmkyTgr9YQ=="
},
"move-concurrently": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@ -6737,6 +6779,11 @@
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true "dev": true
}, },
"numeral": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/numeral/-/numeral-2.0.6.tgz",
"integrity": "sha1-StCAk21EPCVhrtnyGX7//iX05QY="
},
"oauth-sign": { "oauth-sign": {
"version": "0.8.2", "version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",

@ -20,7 +20,11 @@
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^5.1.0-4", "@fortawesome/fontawesome-free": "^5.1.0-4",
"bootstrap": "^4.1.0", "bootstrap": "^4.1.0",
"chart.js": "^2.7.2",
"humps": "^2.0.1",
"jquery": "^3.3.1", "jquery": "^3.3.1",
"moment": "^2.22.1",
"numeral": "^2.0.6",
"phoenix": "file:../../../deps/phoenix", "phoenix": "file:../../../deps/phoenix",
"phoenix_html": "file:../../../deps/phoenix_html", "phoenix_html": "file:../../../deps/phoenix_html",
"popper.js": "^1.14.3" "popper.js": "^1.14.3"

@ -2,10 +2,18 @@ defmodule ExplorerWeb.ChainController do
use ExplorerWeb, :controller use ExplorerWeb, :controller
alias Explorer.Chain.{Address, Block, Statistics, Transaction} alias Explorer.Chain.{Address, Block, Statistics, Transaction}
alias Explorer.ExchangeRates.Token
alias Explorer.Market
alias ExplorerWeb.Chain alias ExplorerWeb.Chain
def show(conn, _params) do def show(conn, _params) do
render(conn, "show.html", chain: Statistics.fetch()) render(
conn,
"show.html",
chain: Statistics.fetch(),
market_history_data: Market.fetch_recent_history(30),
exchange_rate: Market.get_exchange_rate(coin()) || Token.null()
)
end end
def search(conn, %{"q" => query}) do def search(conn, %{"q" => query}) do
@ -21,6 +29,10 @@ defmodule ExplorerWeb.ChainController do
end end
end end
defp coin do
Application.get_env(:explorer, :coin)
end
defp redirect_search_results(conn, %Address{} = item) do defp redirect_search_results(conn, %Address{} = item) do
redirect(conn, to: address_path(conn, :show, Gettext.get_locale(), item)) redirect(conn, to: address_path(conn, :show, Gettext.get_locale(), item))
end end

@ -1,50 +1,38 @@
<section> <section>
<section class="container__section container__section--partitioned"> <section class="container__section container__section--partitioned">
<div class="chain container__subsection"> <div class="container__stats">
<div class="chain__container"> <div>
<img class="chain__image" src="<%= static_path(@conn, "/images/blocks.svg") %>" />
<div class="chain__title"><%= gettext("Skipped") %></div>
<div class="chain__title chain__title--data"><%= @chain.skipped_blocks |> Cldr.Number.to_string! %></div>
</div>
<div class="chain__container">
<img class="chain__image" src="<%= static_path(@conn, "/images/last_block.svg") %>" />
<div class="chain__title"><%= gettext("Lag") %></div>
<div class="chain__title chain__title--data"><%= @chain.lag |> Timex.format_duration(:humanized) %></div>
</div>
<div class="chain__container chain__container--secondary">
<img class="chain__image" src="<%= static_path(@conn, "/images/average_time.svg") %>" />
<div class="chain__title"><%= gettext("BPM") %></div>
<div class="chain__title chain__title--data"><%= @chain.block_velocity |> Cldr.Number.to_string! %></div>
</div>
<div class="chain__container">
<img class="chain__image" src="<%= static_path(@conn, "/images/transactions.svg") %>" />
<div class="chain__title"><%= gettext("TPM") %></div>
<div class="chain__title chain__title--data"><%= @chain.transaction_velocity |> Cldr.Number.to_string! %></div>
</div>
</div>
<div class="chain container__subsection">
<div class="chain__container">
<img class="chain__image" src="<%= static_path(@conn, "/images/blocks.svg") %>" /> <img class="chain__image" src="<%= static_path(@conn, "/images/blocks.svg") %>" />
<div class="chain__title"><%= gettext("Block") %></div> <div class="chain__title"><%= gettext("Block") %></div>
<div class="chain__title chain__title--data">#<%= @chain.number %></div> <div class="chain__title chain__title--data">#<%= @chain.number %></div>
</div> </div>
<div class="chain__container"> <div>
<img class="chain__image" src="<%= static_path(@conn, "/images/last_block.svg") %>" /> <img class="" src="<%= static_path(@conn, "/images/last_block.svg") %>" />
<div class="chain__title"><%= gettext("Last Block") %></div> <div class="chain__title"><%= gettext("Last Block") %></div>
<div class="chain__title chain__title--data"><%= @chain.timestamp |> Timex.from_now() %></div> <div class="chain__title chain__title--data"><%= @chain.timestamp |> Timex.from_now() %></div>
</div> </div>
<div class="chain__container chain__container--secondary"> <div>
<img class="chain__image" src="<%= static_path(@conn, "/images/average_time.svg") %>" /> <img class="" src="<%= static_path(@conn, "/images/average_time.svg") %>" />
<div class="chain__title"><%= gettext("Average Block Time") %></div> <div class=""><%= gettext("Avg Block Time") %></div>
<div class="chain__title chain__title--data">
<%= @chain.average_time |> Timex.format_duration(:humanized) %> <%= @chain.average_time |> Timex.format_duration(:humanized) %>
</div> </div>
</div> </div>
<div class="chain__container"> <div class="chain container__subsection u-push-sm-left">
<img class="chain__image" src="<%= static_path(@conn, "/images/transactions.svg") %>" /> <canvas data-chart="marketHistoryChart" data-current_exchange_rate ='<%= @exchange_rate.usd_value %>' data-available_supply='<%= @exchange_rate.available_supply %>' data-market_history_data='<%=raw encode_market_history_data(@market_history_data) %>' width="400" height="200"></canvas>
<div class="chain__title"><%= gettext("Transactions") %></div> <div class="flex">
<div class="chain__title chain__title--data"> <div class="u-push-md-left">
<%= gettext("%{count} per day", count: Cldr.Number.to_string!(@chain.transaction_count)) %> <div class="graph__squares graph__squares--price"></div>
<%= gettext "Price" %> </br>
$<%= format_exchange_rate(@exchange_rate) %> <%= gettext "USD" %>
</div>
<div>
<div class="graph__squares graph__squares--mcap"></div>
<%= gettext "Market Cap" %> </br>
$<%= format_market_cap(@exchange_rate) %> <%= gettext "USD" %>
</div>
<div class="u-push-md-right">
<%= gettext "24h Volume" %> </br>
$<%= format_volume_24h(@exchange_rate) %> <%= gettext "USD" %>
</div> </div>
</div> </div>
</div> </div>

@ -1,3 +1,32 @@
defmodule ExplorerWeb.ChainView do defmodule ExplorerWeb.ChainView do
use ExplorerWeb, :view use ExplorerWeb, :view
alias Explorer.ExchangeRates.Token
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
def format_exchange_rate(%Token{usd_value: nil}), do: nil
def format_exchange_rate(%Token{usd_value: usd_value}) do
Cldr.Number.to_string!(usd_value, fractional_digits: 6)
end
def format_volume_24h(%Token{volume_24h_usd: volume_24h}) do
format_number(volume_24h)
end
def format_market_cap(%Token{market_cap_usd: market_cap}) do
format_number(market_cap)
end
defp format_number(nil), do: nil
defp format_number(number), do: Cldr.Number.to_string!(number)
end end

@ -2,8 +2,8 @@
#: lib/explorer_web/templates/address_transaction/index.html.eex:69 #: lib/explorer_web/templates/address_transaction/index.html.eex:69
#: lib/explorer_web/templates/block/index.html.eex:30 #: lib/explorer_web/templates/block/index.html.eex:30
#: lib/explorer_web/templates/block_transaction/index.html.eex:99 #: lib/explorer_web/templates/block_transaction/index.html.eex:99
#: lib/explorer_web/templates/chain/show.html.eex:71 #: lib/explorer_web/templates/chain/show.html.eex:59
#: lib/explorer_web/templates/chain/show.html.eex:110 #: lib/explorer_web/templates/chain/show.html.eex:98
#: lib/explorer_web/templates/transaction/index.html.eex:36 #: lib/explorer_web/templates/transaction/index.html.eex:36
#: lib/explorer_web/templates/transaction/overview.html.eex:37 #: lib/explorer_web/templates/transaction/overview.html.eex:37
msgid "Age" msgid "Age"
@ -12,13 +12,13 @@ msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:64 #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:64
#: lib/explorer_web/templates/address_transaction/index.html.eex:68 #: lib/explorer_web/templates/address_transaction/index.html.eex:68
#: lib/explorer_web/templates/block_transaction/index.html.eex:98 #: lib/explorer_web/templates/block_transaction/index.html.eex:98
#: lib/explorer_web/templates/chain/show.html.eex:28 #: lib/explorer_web/templates/chain/show.html.eex:6
#: lib/explorer_web/templates/chain/show.html.eex:109 #: lib/explorer_web/templates/chain/show.html.eex:97
#: lib/explorer_web/templates/transaction/index.html.eex:35 #: lib/explorer_web/templates/transaction/index.html.eex:35
msgid "Block" msgid "Block"
msgstr "" msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:58 #: lib/explorer_web/templates/chain/show.html.eex:46
#: lib/explorer_web/templates/layout/app.html.eex:25 #: lib/explorer_web/templates/layout/app.html.eex:25
msgid "Blocks" msgid "Blocks"
msgstr "" msgstr ""
@ -29,21 +29,21 @@ msgstr ""
#: lib/explorer_web/templates/block/index.html.eex:32 #: lib/explorer_web/templates/block/index.html.eex:32
#: lib/explorer_web/templates/block_transaction/index.html.eex:60 #: lib/explorer_web/templates/block_transaction/index.html.eex:60
#: lib/explorer_web/templates/chain/show.html.eex:73 #: lib/explorer_web/templates/chain/show.html.eex:61
msgid "Gas Used" msgid "Gas Used"
msgstr "" msgstr ""
#: lib/explorer_web/templates/address_transaction/index.html.eex:67 #: lib/explorer_web/templates/address_transaction/index.html.eex:67
#: lib/explorer_web/templates/block_transaction/index.html.eex:22 #: lib/explorer_web/templates/block_transaction/index.html.eex:22
#: lib/explorer_web/templates/block_transaction/index.html.eex:97 #: lib/explorer_web/templates/block_transaction/index.html.eex:97
#: lib/explorer_web/templates/chain/show.html.eex:108 #: lib/explorer_web/templates/chain/show.html.eex:96
#: lib/explorer_web/templates/pending_transaction/index.html.eex:34 #: lib/explorer_web/templates/pending_transaction/index.html.eex:34
#: lib/explorer_web/templates/transaction/index.html.eex:34 #: lib/explorer_web/templates/transaction/index.html.eex:34
msgid "Hash" msgid "Hash"
msgstr "" msgstr ""
#: lib/explorer_web/templates/block/index.html.eex:29 #: lib/explorer_web/templates/block/index.html.eex:29
#: lib/explorer_web/templates/chain/show.html.eex:70 #: lib/explorer_web/templates/chain/show.html.eex:58
msgid "Height" msgid "Height"
msgstr "" msgstr ""
@ -56,9 +56,8 @@ msgstr ""
#: lib/explorer_web/templates/block/index.html.eex:31 #: lib/explorer_web/templates/block/index.html.eex:31
#: lib/explorer_web/templates/block_transaction/index.html.eex:16 #: lib/explorer_web/templates/block_transaction/index.html.eex:16
#: lib/explorer_web/templates/block_transaction/index.html.eex:84 #: lib/explorer_web/templates/block_transaction/index.html.eex:84
#: lib/explorer_web/templates/chain/show.html.eex:45 #: lib/explorer_web/templates/chain/show.html.eex:60
#: lib/explorer_web/templates/chain/show.html.eex:72 #: lib/explorer_web/templates/chain/show.html.eex:87
#: lib/explorer_web/templates/chain/show.html.eex:99
#: lib/explorer_web/templates/layout/app.html.eex:31 #: lib/explorer_web/templates/layout/app.html.eex:31
#: lib/explorer_web/templates/pending_transaction/index.html.eex:12 #: lib/explorer_web/templates/pending_transaction/index.html.eex:12
#: lib/explorer_web/templates/transaction/index.html.eex:12 #: lib/explorer_web/templates/transaction/index.html.eex:12
@ -68,7 +67,7 @@ msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:68 #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:68
#: lib/explorer_web/templates/address_transaction/index.html.eex:72 #: lib/explorer_web/templates/address_transaction/index.html.eex:72
#: lib/explorer_web/templates/block_transaction/index.html.eex:102 #: lib/explorer_web/templates/block_transaction/index.html.eex:102
#: lib/explorer_web/templates/chain/show.html.eex:111 #: lib/explorer_web/templates/chain/show.html.eex:99
#: lib/explorer_web/templates/pending_transaction/index.html.eex:38 #: lib/explorer_web/templates/pending_transaction/index.html.eex:38
#: lib/explorer_web/templates/transaction/index.html.eex:39 #: lib/explorer_web/templates/transaction/index.html.eex:39
#: lib/explorer_web/templates/transaction/overview.html.eex:43 #: lib/explorer_web/templates/transaction/overview.html.eex:43
@ -288,7 +287,7 @@ msgstr ""
msgid "Lag" msgid "Lag"
msgstr "" msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:33 #: lib/explorer_web/templates/chain/show.html.eex:11
msgid "Last Block" msgid "Last Block"
msgstr "" msgstr ""
@ -401,3 +400,25 @@ msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:63 #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:63
msgid "Parent Tx Hash" msgid "Parent Tx Hash"
msgstr "" msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:34
msgid "24h Volume"
msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:16
msgid "Avg Block Time"
msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:30
msgid "Market Cap"
msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:25
msgid "Price"
msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:26
#: lib/explorer_web/templates/chain/show.html.eex:31
#: lib/explorer_web/templates/chain/show.html.eex:35
msgid "USD"
msgstr ""

@ -14,8 +14,8 @@ msgstr ""
#: lib/explorer_web/templates/address_transaction/index.html.eex:69 #: lib/explorer_web/templates/address_transaction/index.html.eex:69
#: lib/explorer_web/templates/block/index.html.eex:30 #: lib/explorer_web/templates/block/index.html.eex:30
#: lib/explorer_web/templates/block_transaction/index.html.eex:99 #: lib/explorer_web/templates/block_transaction/index.html.eex:99
#: lib/explorer_web/templates/chain/show.html.eex:71 #: lib/explorer_web/templates/chain/show.html.eex:59
#: lib/explorer_web/templates/chain/show.html.eex:110 #: lib/explorer_web/templates/chain/show.html.eex:98
#: lib/explorer_web/templates/transaction/index.html.eex:36 #: lib/explorer_web/templates/transaction/index.html.eex:36
#: lib/explorer_web/templates/transaction/overview.html.eex:37 #: lib/explorer_web/templates/transaction/overview.html.eex:37
msgid "Age" msgid "Age"
@ -24,13 +24,13 @@ msgstr "Age"
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:64 #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:64
#: lib/explorer_web/templates/address_transaction/index.html.eex:68 #: lib/explorer_web/templates/address_transaction/index.html.eex:68
#: lib/explorer_web/templates/block_transaction/index.html.eex:98 #: lib/explorer_web/templates/block_transaction/index.html.eex:98
#: lib/explorer_web/templates/chain/show.html.eex:28 #: lib/explorer_web/templates/chain/show.html.eex:6
#: lib/explorer_web/templates/chain/show.html.eex:109 #: lib/explorer_web/templates/chain/show.html.eex:97
#: lib/explorer_web/templates/transaction/index.html.eex:35 #: lib/explorer_web/templates/transaction/index.html.eex:35
msgid "Block" msgid "Block"
msgstr "Block" msgstr "Block"
#: lib/explorer_web/templates/chain/show.html.eex:58 #: lib/explorer_web/templates/chain/show.html.eex:46
#: lib/explorer_web/templates/layout/app.html.eex:25 #: lib/explorer_web/templates/layout/app.html.eex:25
msgid "Blocks" msgid "Blocks"
msgstr "Blocks" msgstr "Blocks"
@ -41,21 +41,21 @@ msgstr "%{year} POA Network Ltd. All rights reserved"
#: lib/explorer_web/templates/block/index.html.eex:32 #: lib/explorer_web/templates/block/index.html.eex:32
#: lib/explorer_web/templates/block_transaction/index.html.eex:60 #: lib/explorer_web/templates/block_transaction/index.html.eex:60
#: lib/explorer_web/templates/chain/show.html.eex:73 #: lib/explorer_web/templates/chain/show.html.eex:61
msgid "Gas Used" msgid "Gas Used"
msgstr "Gas Used" msgstr "Gas Used"
#: lib/explorer_web/templates/address_transaction/index.html.eex:67 #: lib/explorer_web/templates/address_transaction/index.html.eex:67
#: lib/explorer_web/templates/block_transaction/index.html.eex:22 #: lib/explorer_web/templates/block_transaction/index.html.eex:22
#: lib/explorer_web/templates/block_transaction/index.html.eex:97 #: lib/explorer_web/templates/block_transaction/index.html.eex:97
#: lib/explorer_web/templates/chain/show.html.eex:108 #: lib/explorer_web/templates/chain/show.html.eex:96
#: lib/explorer_web/templates/pending_transaction/index.html.eex:34 #: lib/explorer_web/templates/pending_transaction/index.html.eex:34
#: lib/explorer_web/templates/transaction/index.html.eex:34 #: lib/explorer_web/templates/transaction/index.html.eex:34
msgid "Hash" msgid "Hash"
msgstr "Hash" msgstr "Hash"
#: lib/explorer_web/templates/block/index.html.eex:29 #: lib/explorer_web/templates/block/index.html.eex:29
#: lib/explorer_web/templates/chain/show.html.eex:70 #: lib/explorer_web/templates/chain/show.html.eex:58
msgid "Height" msgid "Height"
msgstr "Height" msgstr "Height"
@ -68,9 +68,8 @@ msgstr "POA Network Explorer"
#: lib/explorer_web/templates/block/index.html.eex:31 #: lib/explorer_web/templates/block/index.html.eex:31
#: lib/explorer_web/templates/block_transaction/index.html.eex:16 #: lib/explorer_web/templates/block_transaction/index.html.eex:16
#: lib/explorer_web/templates/block_transaction/index.html.eex:84 #: lib/explorer_web/templates/block_transaction/index.html.eex:84
#: lib/explorer_web/templates/chain/show.html.eex:45 #: lib/explorer_web/templates/chain/show.html.eex:60
#: lib/explorer_web/templates/chain/show.html.eex:72 #: lib/explorer_web/templates/chain/show.html.eex:87
#: lib/explorer_web/templates/chain/show.html.eex:99
#: lib/explorer_web/templates/layout/app.html.eex:31 #: lib/explorer_web/templates/layout/app.html.eex:31
#: lib/explorer_web/templates/pending_transaction/index.html.eex:12 #: lib/explorer_web/templates/pending_transaction/index.html.eex:12
#: lib/explorer_web/templates/transaction/index.html.eex:12 #: lib/explorer_web/templates/transaction/index.html.eex:12
@ -80,7 +79,7 @@ msgstr "Transactions"
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:68 #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:68
#: lib/explorer_web/templates/address_transaction/index.html.eex:72 #: lib/explorer_web/templates/address_transaction/index.html.eex:72
#: lib/explorer_web/templates/block_transaction/index.html.eex:102 #: lib/explorer_web/templates/block_transaction/index.html.eex:102
#: lib/explorer_web/templates/chain/show.html.eex:111 #: lib/explorer_web/templates/chain/show.html.eex:99
#: lib/explorer_web/templates/pending_transaction/index.html.eex:38 #: lib/explorer_web/templates/pending_transaction/index.html.eex:38
#: lib/explorer_web/templates/transaction/index.html.eex:39 #: lib/explorer_web/templates/transaction/index.html.eex:39
#: lib/explorer_web/templates/transaction/overview.html.eex:43 #: lib/explorer_web/templates/transaction/overview.html.eex:43
@ -300,7 +299,7 @@ msgstr ""
msgid "Lag" msgid "Lag"
msgstr "" msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:33 #: lib/explorer_web/templates/chain/show.html.eex:11
msgid "Last Block" msgid "Last Block"
msgstr "" msgstr ""
@ -413,3 +412,25 @@ msgstr ""
#: lib/explorer_web/templates/address_internal_transaction/index.html.eex:63 #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:63
msgid "Parent Tx Hash" msgid "Parent Tx Hash"
msgstr "" msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:34
msgid "24h Volume"
msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:16
msgid "Avg Block Time"
msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:30
msgid "Market Cap"
msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:25
msgid "Price"
msgstr ""
#: lib/explorer_web/templates/chain/show.html.eex:26
#: lib/explorer_web/templates/chain/show.html.eex:31
#: lib/explorer_web/templates/chain/show.html.eex:35
msgid "USD"
msgstr ""

@ -56,6 +56,16 @@ defmodule ExplorerWeb.ChainControllerTest do
assert(List.first(conn.assigns.chain.transactions).hash == transaction.hash) assert(List.first(conn.assigns.chain.transactions).hash == transaction.hash)
end 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, "/en")
assert Map.has_key?(conn.assigns, :market_history_data)
assert length(conn.assigns.market_history_data) == 30
end
end end
describe "GET q/2" do describe "GET q/2" do

@ -3,4 +3,6 @@ use Mix.Config
# Print only warnings and errors during test # Print only warnings and errors during test
config :logger, level: :warn config :logger, level: :warn
config :explorer, Explorer.ExchangeRates, source: Explorer.ExchangeRates.Source.TestSource config :explorer, Explorer.ExchangeRates,
source: Explorer.ExchangeRates.Source.NoOpSource,
store: :none

Loading…
Cancel
Save