Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

explorer: update header and blocks pages #1509

Merged
merged 4 commits into from Aug 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions db/dcrpg/internal/blockstmts.go
Expand Up @@ -133,9 +133,9 @@ const (
MIN(time) AS time,
COUNT(*) AS blocks_count
FROM blocks
WHERE height BETWEEN $2 AND $3
GROUP BY window_start
ORDER BY window_start DESC
LIMIT $2 OFFSET $3;`
ORDER BY window_start DESC;`

SelectBlocksTimeListingByLimit = `SELECT date_trunc($1, time) as index_value,
MAX(height),
Expand Down
3 changes: 2 additions & 1 deletion db/dcrpg/pgblockchain.go
Expand Up @@ -1628,7 +1628,8 @@ func (pgb *ChainDB) TicketPoolByDateAndInterval(maturityBlock int64,
func (pgb *ChainDB) PosIntervals(limit, offset uint64) ([]*dbtypes.BlocksGroupedInfo, error) {
ctx, cancel := context.WithTimeout(pgb.ctx, pgb.queryTimeout)
defer cancel()
bgi, err := retrieveWindowBlocks(ctx, pgb.db, pgb.chainParams.StakeDiffWindowSize, limit, offset)
bgi, err := retrieveWindowBlocks(ctx, pgb.db,
pgb.chainParams.StakeDiffWindowSize, pgb.Height(), limit, offset)
return bgi, pgb.replaceCancelError(err)
}

Expand Down
8 changes: 6 additions & 2 deletions db/dcrpg/queries.go
Expand Up @@ -1019,8 +1019,12 @@ func RetrieveAllVotesDbIDsHeightsTicketDbIDs(ctx context.Context, db *sql.DB) (i

// retrieveWindowBlocks fetches chunks of windows using the limit and offset provided
// for a window size of chaincfg.Params.StakeDiffWindowSize.
func retrieveWindowBlocks(ctx context.Context, db *sql.DB, windowSize int64, limit, offset uint64) ([]*dbtypes.BlocksGroupedInfo, error) {
rows, err := db.QueryContext(ctx, internal.SelectWindowsByLimit, windowSize, limit, offset)
func retrieveWindowBlocks(ctx context.Context, db *sql.DB, windowSize, currentHeight int64, limit, offset uint64) ([]*dbtypes.BlocksGroupedInfo, error) {
endWindow := currentHeight/windowSize - int64(offset)
startWindow := endWindow - int64(limit) + 1
startHeight := startWindow * windowSize
endHeight := (endWindow+1)*windowSize - 1
rows, err := db.QueryContext(ctx, internal.SelectWindowsByLimit, windowSize, startHeight, endHeight)
if err != nil {
return nil, fmt.Errorf("retrieveWindowBlocks failed: error: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion explorer/explorer.go
Expand Up @@ -43,7 +43,7 @@ const (
// maxExplorerRows and minExplorerRows are the limits on the number of
// blocks/time-window rows that may be shown on the explorer pages.
maxExplorerRows = 400
minExplorerRows = 20
minExplorerRows = 10

// syncStatusInterval is the frequency with startup synchronization progress
// signals are sent to websocket clients.
Expand Down
146 changes: 139 additions & 7 deletions explorer/explorerroutes.go
Expand Up @@ -374,7 +374,7 @@ func (exp *explorerUI) StakeDiffWindows(w http.ResponseWriter, r *http.Request)
}

rows, err := strconv.ParseUint(r.URL.Query().Get("rows"), 10, 64)
if err != nil || (rows < minExplorerRows && rows == 0) {
if err != nil || rows < 1 {
rows = minExplorerRows
}

Expand All @@ -394,20 +394,26 @@ func (exp *explorerUI) StakeDiffWindows(w http.ResponseWriter, r *http.Request)
return
}

linkTemplate := "/ticketpricewindows?offset=%d&rows=" + strconv.Itoa(int(rows))

str, err := exp.templates.exec("windows", struct {
*CommonPageData
Data []*dbtypes.BlocksGroupedInfo
WindowSize int64
BestWindow int64
OffsetWindow int64
Limit int64
TimeGrouping string
Pages pageNumbers
}{
CommonPageData: exp.commonData(r),
Data: windows,
WindowSize: exp.ChainParams.StakeDiffWindowSize,
BestWindow: int64(bestWindow),
OffsetWindow: int64(offsetWindow),
Limit: int64(rows),
TimeGrouping: "Windows",
Pages: calcPages(int(bestWindow), int(rows), int(offsetWindow), linkTemplate),
})

if err != nil {
Expand Down Expand Up @@ -471,7 +477,7 @@ func (exp *explorerUI) timeBasedBlocksListing(val string, w http.ResponseWriter,
}

rows, err := strconv.ParseUint(r.URL.Query().Get("rows"), 10, 64)
if err != nil || (rows < minExplorerRows && rows == 0) {
if err != nil || rows < 1 {
rows = minExplorerRows
}

Expand All @@ -497,20 +503,24 @@ func (exp *explorerUI) timeBasedBlocksListing(val string, w http.ResponseWriter,
data[0].FormattedStartTime = fmt.Sprintf("%s YTD", time.Now().Format("2006"))
}

linkTemplate := "/" + strings.ToLower(val) + "?offset=%d&rows=" + strconv.Itoa(int(rows))

str, err := exp.templates.exec("timelisting", struct {
*CommonPageData
Data []*dbtypes.BlocksGroupedInfo
TimeGrouping string
Offset int64
Limit int64
BestGrouping int64
Pages pageNumbers
}{
CommonPageData: exp.commonData(r),
Data: data,
TimeGrouping: val,
Offset: int64(offset),
Limit: int64(rows),
BestGrouping: maxOffset,
Pages: calcPages(int(maxOffset), int(rows), int(offset), linkTemplate),
})

if err != nil {
Expand Down Expand Up @@ -540,7 +550,7 @@ func (exp *explorerUI) Blocks(w http.ResponseWriter, r *http.Request) {
}

rows, err := strconv.Atoi(r.URL.Query().Get("rows"))
if err != nil || (rows < minExplorerRows && rows == 0) {
buck54321 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil || rows < 1 {
rows = minExplorerRows
}

Expand Down Expand Up @@ -574,18 +584,24 @@ func (exp *explorerUI) Blocks(w http.ResponseWriter, r *http.Request) {
s.MainChain = blockStatus.IsMainchain
}

linkTemplate := "/blocks?height=%d&rows=" + strconv.Itoa(rows)

str, err := exp.templates.exec("explorer", struct {
*CommonPageData
Data []*types.BlockBasic
BestBlock int64
Rows int64
WindowSize int64
Data []*types.BlockBasic
BestBlock int64
Rows int64
WindowSize int64
TimeGrouping string
Pages pageNumbers
}{
CommonPageData: exp.commonData(r),
Data: summaries,
BestBlock: bestBlockHeight,
Rows: int64(rows),
WindowSize: exp.ChainParams.StakeDiffWindowSize,
TimeGrouping: "Blocks",
Pages: calcPagesDesc(int(bestBlockHeight), rows, height, linkTemplate),
})

if err != nil {
Expand Down Expand Up @@ -2089,3 +2105,119 @@ func (exp *explorerUI) commonData(r *http.Request) *CommonPageData {
RequestURI: r.URL.RequestURI(),
}
}

// A page number has the information necessary to create numbered pagination
// links.
type pageNumber struct {
Active bool
Link string
Str string
}

func makePageNumber(active bool, link, str string) pageNumber {
return pageNumber{
Active: active,
Link: link,
Str: str,
}
}

type pageNumbers []pageNumber

const ellipsisHTML = "…"

// Get a set of pagination numbers, based on a set number of rows that are
// assumed to start from page 1 at the highest row and descend from there.
// For example, if there are 20 pages of 10 rows, 0 - 199, page 1 would start at
// row 199 and go down to row 190. If the offset is between 190 and 199, the
// pagination would return the pageNumbers necessary to create a pagination
// That looks like 1 2 3 4 5 6 7 8 ... 20. The pageNumber includes a link with
// the offset inserted using Sprintf.
func calcPagesDesc(rows, pageSize, offset int, link string) pageNumbers {
nums := make(pageNumbers, 0, 11)
endIdx := rows / pageSize
if endIdx == 0 {
return nums
}
pages := endIdx + 1
currentPageIdx := (rows - offset) / pageSize
if pages > 10 {
nums = append(nums, makePageNumber(currentPageIdx == 0, fmt.Sprintf(link, rows), "1"))
start := currentPageIdx - 3
endMiddle := start + 6
if start <= 1 {
start = 1
endMiddle = 7
} else if endMiddle >= endIdx-1 {
endMiddle = endIdx - 1
start = endMiddle - 6
}
if start > 1 {
nums = append(nums, makePageNumber(false, "", ellipsisHTML))
}
for i := start; i <= endMiddle; i++ {
nums = append(nums, makePageNumber(i == currentPageIdx, fmt.Sprintf(link, rows-i*pageSize), strconv.Itoa(i+1)))
}
if endMiddle < endIdx-1 {
nums = append(nums, makePageNumber(false, "", ellipsisHTML))
}
if pages > 1 {
nums = append(nums, makePageNumber(currentPageIdx == endIdx, fmt.Sprintf(link, rows-endIdx*pageSize), strconv.Itoa(pages)))
}
} else {
for i := 0; i < pages; i++ {
nums = append(nums, makePageNumber(i == currentPageIdx, fmt.Sprintf(link, rows-i*pageSize), strconv.Itoa(i+1)))
}
}

return nums
}

// Get a set of pagination numbers, based on a set number of rows that are
// assumed to start from page 1 at the lowest row and ascend from there.
// For example, if there are 20 pages of 10 rows, 0 - 199, page 1 would start at
// row 0 and go up to row 9. If the offset is between 0 and 9, the
// pagination would return the pageNumbers necessary to create a pagination
// That looks like 1 2 3 4 5 6 7 8 ... 20. The pageNumber includes a link with
// the offset inserted using Sprintf.
func calcPages(rows, pageSize, offset int, link string) pageNumbers {
nums := make(pageNumbers, 0, 11)
endIdx := rows / pageSize
if endIdx == 0 {
return nums
}
pages := endIdx + 1
currentPageIdx := offset / pageSize

if pages > 10 {
nums = append(nums, makePageNumber(currentPageIdx == 0, fmt.Sprintf(link, 0), "1"))
start := currentPageIdx - 3
endMiddle := start + 6
if start <= 1 {
start = 1
endMiddle = 7
} else if endMiddle >= endIdx-1 {
endMiddle = endIdx - 1
start = endMiddle - 6
}
if start > 1 {
nums = append(nums, makePageNumber(false, "", ellipsisHTML))
}

for i := start; i <= endMiddle; i++ {
nums = append(nums, makePageNumber(i == currentPageIdx, fmt.Sprintf(link, i*pageSize), strconv.Itoa(i+1)))
}
if endMiddle < endIdx-1 {
nums = append(nums, makePageNumber(false, "", ellipsisHTML))
}
if pages > 1 {
nums = append(nums, makePageNumber(currentPageIdx == endIdx, fmt.Sprintf(link, endIdx*pageSize), strconv.Itoa(pages)))
}
} else {
for i := 0; i < pages; i++ {
nums = append(nums, makePageNumber(i == currentPageIdx, fmt.Sprintf(link, i*pageSize), strconv.Itoa(i+1)))
}
}

return nums
}