Refresh staking page top panel when new blocks arrive (#2407)
Top panel is entirely rendered on server-side using a dedicated controller function for proper gettext support and reduced fiddling with jQuery. Reducer is simplified and made pure as per Redux guidelines. Co-Authored-By: Anatoly Nikiforov <anatolyniky@gmail.com> Co-Authored-By: Kirill Andreev <hindmost.one@gmail.com>staking
parent
26715dcf00
commit
c64f77fe94
@ -1 +1,42 @@ |
|||||||
import '../../css/stakes.scss' |
import '../../css/stakes.scss' |
||||||
|
|
||||||
|
import $ from 'jquery' |
||||||
|
import _ from 'lodash' |
||||||
|
import { subscribeChannel } from '../socket' |
||||||
|
import { connectElements } from '../lib/redux_helpers.js' |
||||||
|
import { createAsyncLoadStore } from '../lib/async_listing_load' |
||||||
|
|
||||||
|
export const initialState = { |
||||||
|
channel: null |
||||||
|
} |
||||||
|
|
||||||
|
export function reducer (state = initialState, action) { |
||||||
|
switch (action.type) { |
||||||
|
case 'PAGE_LOAD': |
||||||
|
case 'ELEMENTS_LOAD': { |
||||||
|
return Object.assign({}, state, _.omit(action, 'type')) |
||||||
|
} |
||||||
|
case 'CHANNEL_CONNECTED': { |
||||||
|
return Object.assign({}, state, { channel: action.channel }) |
||||||
|
} |
||||||
|
default: |
||||||
|
return state |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const elements = { |
||||||
|
} |
||||||
|
|
||||||
|
const $stakesPage = $('[data-page="stakes"]') |
||||||
|
if ($stakesPage.length) { |
||||||
|
const store = createAsyncLoadStore(reducer, initialState, 'dataset.identifierPool') |
||||||
|
connectElements({ store, elements }) |
||||||
|
|
||||||
|
const channel = subscribeChannel('stakes:staking_update') |
||||||
|
channel.on('staking_update', msg => onStakingUpdate(msg, store)) |
||||||
|
store.dispatch({ type: 'CHANNEL_CONNECTED', channel }) |
||||||
|
} |
||||||
|
|
||||||
|
function onStakingUpdate (msg, store) { |
||||||
|
$('[data-selector="stakes-top"]').html(msg.top_html) |
||||||
|
} |
||||||
|
@ -0,0 +1,22 @@ |
|||||||
|
defmodule BlockScoutWeb.StakesChannel do |
||||||
|
@moduledoc """ |
||||||
|
Establishes pub/sub channel for staking page live updates. |
||||||
|
""" |
||||||
|
use BlockScoutWeb, :channel |
||||||
|
|
||||||
|
alias BlockScoutWeb.StakesController |
||||||
|
|
||||||
|
intercept(["staking_update"]) |
||||||
|
|
||||||
|
def join("stakes:staking_update", _params, socket) do |
||||||
|
{:ok, %{}, socket} |
||||||
|
end |
||||||
|
|
||||||
|
def handle_out("staking_update", _data, socket) do |
||||||
|
push(socket, "staking_update", %{ |
||||||
|
top_html: StakesController.render_top() |
||||||
|
}) |
||||||
|
|
||||||
|
{:noreply, socket} |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,4 @@ |
|||||||
|
<div class="stakes-top-stats-item"> |
||||||
|
<span class="stakes-top-stats-label"><%= @title %></span> |
||||||
|
<span class="stakes-top-stats-value"><%= @value %></span> |
||||||
|
</div> |
@ -0,0 +1,13 @@ |
|||||||
|
<div class="stakes-top"> |
||||||
|
<div class="container"> |
||||||
|
<div class="stakes-top-stats"> |
||||||
|
<%= render BlockScoutWeb.StakesView, "_stakes_stats_item.html", title: gettext("Epoch number"), value: @epoch_number %> |
||||||
|
<%= render BlockScoutWeb.StakesView, "_stakes_stats_item.html", title: gettext("Block number"), value: @block_number %> |
||||||
|
<%= render BlockScoutWeb.StakesView, "_stakes_stats_item.html", title: gettext("Next epoch in"), value: ngettext("%{blocks} block", "%{blocks} blocks", @epoch_end_in, blocks: @epoch_end_in) %> |
||||||
|
<!-- Buttons --> |
||||||
|
<div class="stakes-top-buttons"> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<%= render BlockScoutWeb.StakesView, "_stakes_modal_become_candidate.html" %> |
@ -0,0 +1,20 @@ |
|||||||
|
defmodule BlockScoutWeb.StakesChannelTest do |
||||||
|
use BlockScoutWeb.ChannelCase |
||||||
|
|
||||||
|
alias BlockScoutWeb.Notifier |
||||||
|
|
||||||
|
test "subscribed user is notified of staking_update event" do |
||||||
|
topic = "stakes:staking_update" |
||||||
|
@endpoint.subscribe(topic) |
||||||
|
|
||||||
|
Notifier.handle_event({:chain_event, :staking_update}) |
||||||
|
|
||||||
|
receive do |
||||||
|
%Phoenix.Socket.Broadcast{topic: ^topic, event: "staking_update", payload: %{epoch_number: _}} -> |
||||||
|
assert true |
||||||
|
after |
||||||
|
:timer.seconds(5) -> |
||||||
|
assert false, "Expected message received nothing." |
||||||
|
end |
||||||
|
end |
||||||
|
end |
Loading…
Reference in new issue