Infinite scroll on uncles and reorgs pages

pull/1058/head
jimmay5469 6 years ago
parent 056f0648fe
commit e5aee95bb9
  1. 2
      apps/block_scout_web/assets/js/app.js
  2. 111
      apps/block_scout_web/assets/js/pages/reorgs.js
  3. 111
      apps/block_scout_web/assets/js/pages/uncles.js
  4. 95
      apps/block_scout_web/lib/block_scout_web/controllers/block_controller.ex

@ -24,8 +24,10 @@ import './pages/address'
import './pages/blocks'
import './pages/chain'
import './pages/pending_transactions'
import './pages/reorgs'
import './pages/transaction'
import './pages/transactions'
import './pages/uncles'
import './lib/clipboard_buttons'
import './lib/currency'

@ -0,0 +1,111 @@
import $ from 'jquery'
import _ from 'lodash'
import humps from 'humps'
import { createStore, connectElements } from '../lib/redux_helpers.js'
import { onScrollBottom } from '../lib/utils'
import listMorph from '../lib/list_morph'
export const initialState = {
reorgs: [],
loadingNextPage: false,
pagingError: false,
nextPageUrl: null
}
function reducer (state = initialState, action) {
switch (action.type) {
case 'ELEMENTS_LOAD': {
return Object.assign({}, state, _.omit(action, 'type'))
}
case 'LOADING_NEXT_PAGE': {
return Object.assign({}, state, {
loadingNextPage: true
})
}
case 'PAGING_ERROR': {
return Object.assign({}, state, {
loadingNextPage: false,
pagingError: true
})
}
case 'RECEIVED_NEXT_PAGE': {
return Object.assign({}, state, {
loadingNextPage: false,
nextPageUrl: action.msg.nextPageUrl,
reorgs: [
...state.reorgs,
..._.map(action.msg.blocks, 'blockHtml')
]
})
}
default:
return state
}
}
const elements = {
'[data-selector="blocks-list"]': {
load ($el) {
return {
reorgs: _.map($el.children().toArray(), 'outerHTML')
}
},
render ($el, state, oldState) {
if (oldState.reorgs === state.reorgs) return
const container = $el[0]
const newElements = state.reorgs.map((html) => $(html)[0])
listMorph(container, newElements, { key: 'dataset.blockNumber' })
}
},
'[data-selector="next-page-button"]': {
load ($el) {
return {
nextPageUrl: `${$el.hide().attr('href')}&type=JSON`
}
}
},
'[data-selector="loading-next-page"]': {
render ($el, state) {
if (state.loadingNextPage) {
$el.show()
} else {
$el.hide()
}
}
},
'[data-selector="paging-error-message"]': {
render ($el, state) {
if (state.pagingError) {
$el.show()
}
}
}
}
const $reorgListPage = $('[data-page="reorg-list"]')
if ($reorgListPage.length) {
const store = createStore(reducer)
connectElements({ store, elements })
onScrollBottom(() => {
const { loadingNextPage, nextPageUrl, pagingError } = store.getState()
if (!loadingNextPage && nextPageUrl && !pagingError) {
store.dispatch({
type: 'LOADING_NEXT_PAGE'
})
$.get(nextPageUrl)
.done(msg => {
store.dispatch({
type: 'RECEIVED_NEXT_PAGE',
msg: humps.camelizeKeys(msg)
})
})
.fail(() => {
store.dispatch({
type: 'PAGING_ERROR'
})
})
}
})
}

@ -0,0 +1,111 @@
import $ from 'jquery'
import _ from 'lodash'
import humps from 'humps'
import { createStore, connectElements } from '../lib/redux_helpers.js'
import { onScrollBottom } from '../lib/utils'
import listMorph from '../lib/list_morph'
export const initialState = {
uncles: [],
loadingNextPage: false,
pagingError: false,
nextPageUrl: null
}
function reducer (state = initialState, action) {
switch (action.type) {
case 'ELEMENTS_LOAD': {
return Object.assign({}, state, _.omit(action, 'type'))
}
case 'LOADING_NEXT_PAGE': {
return Object.assign({}, state, {
loadingNextPage: true
})
}
case 'PAGING_ERROR': {
return Object.assign({}, state, {
loadingNextPage: false,
pagingError: true
})
}
case 'RECEIVED_NEXT_PAGE': {
return Object.assign({}, state, {
loadingNextPage: false,
nextPageUrl: action.msg.nextPageUrl,
uncles: [
...state.uncles,
..._.map(action.msg.blocks, 'blockHtml')
]
})
}
default:
return state
}
}
const elements = {
'[data-selector="blocks-list"]': {
load ($el) {
return {
uncles: _.map($el.children().toArray(), 'outerHTML')
}
},
render ($el, state, oldState) {
if (oldState.uncles === state.uncles) return
const container = $el[0]
const newElements = state.uncles.map((html) => $(html)[0])
listMorph(container, newElements, { key: 'dataset.blockNumber' })
}
},
'[data-selector="next-page-button"]': {
load ($el) {
return {
nextPageUrl: `${$el.hide().attr('href')}&type=JSON`
}
}
},
'[data-selector="loading-next-page"]': {
render ($el, state) {
if (state.loadingNextPage) {
$el.show()
} else {
$el.hide()
}
}
},
'[data-selector="paging-error-message"]': {
render ($el, state) {
if (state.pagingError) {
$el.show()
}
}
}
}
const $uncleListPage = $('[data-page="uncle-list"]')
if ($uncleListPage.length) {
const store = createStore(reducer)
connectElements({ store, elements })
onScrollBottom(() => {
const { loadingNextPage, nextPageUrl, pagingError } = store.getState()
if (!loadingNextPage && nextPageUrl && !pagingError) {
store.dispatch({
type: 'LOADING_NEXT_PAGE'
})
$.get(nextPageUrl)
.done(msg => {
store.dispatch({
type: 'RECEIVED_NEXT_PAGE',
msg: humps.camelizeKeys(msg)
})
})
.fail(() => {
store.dispatch({
type: 'PAGING_ERROR'
})
})
}
})
}

@ -7,17 +7,49 @@ defmodule BlockScoutWeb.BlockController do
alias Explorer.Chain
alias Phoenix.View
def index(conn, %{"type" => "JSON"} = params) do
full_options =
[
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional
}
]
def index(conn, params) do
[
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional
}
]
|> handle_render(conn, params)
end
def show(conn, %{"hash_or_number" => hash_or_number}) do
redirect(conn, to: block_transaction_path(conn, :index, hash_or_number))
end
def reorg(conn, params) do
[
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional
},
block_type: "Reorg"
]
|> handle_render(conn, params)
end
def uncle(conn, params) do
[
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional,
:nephews => :required
},
block_type: "Uncle"
]
|> handle_render(conn, params)
end
defp handle_render(full_options, conn, %{"type" => "JSON"} = params) do
blocks_plus_one =
full_options
|> Keyword.merge(paging_options(params))
|> Chain.list_blocks()
blocks_plus_one = Chain.list_blocks(full_options)
{blocks, next_page} = split_list_by_page(blocks_plus_one)
next_page_url =
@ -56,48 +88,11 @@ defmodule BlockScoutWeb.BlockController do
)
end
def index(conn, params) do
[
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional
}
]
|> Keyword.merge(paging_options(%{}))
|> handle_render(conn, params)
end
def show(conn, %{"hash_or_number" => hash_or_number}) do
redirect(conn, to: block_transaction_path(conn, :index, hash_or_number))
end
def reorg(conn, params) do
[
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional
},
block_type: "Reorg"
]
|> Keyword.merge(paging_options(params))
|> handle_render(conn, params)
end
def uncle(conn, params) do
[
necessity_by_association: %{
:transactions => :optional,
[miner: :names] => :optional,
:nephews => :required
},
block_type: "Uncle"
]
|> Keyword.merge(paging_options(params))
|> handle_render(conn, params)
end
defp handle_render(full_options, conn, params) do
blocks_plus_one = Chain.list_blocks(full_options)
blocks_plus_one =
full_options
|> Keyword.merge(paging_options(%{}))
|> Chain.list_blocks()
{blocks, next_page} = split_list_by_page(blocks_plus_one)

Loading…
Cancel
Save