Skip to content

Commit

Permalink
add pagination to storageGC page (#376)
Browse files Browse the repository at this point in the history
* add pagination to storageGC page

* add search

* fix row count
  • Loading branch information
LexLuthr authored Jan 24, 2025
1 parent 04e7578 commit 2347010
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 34 deletions.
13 changes: 8 additions & 5 deletions deps/apiinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math/rand"
"net/http"
"reflect"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -71,11 +72,13 @@ func GetFullNodeAPIV1Curio(ctx *cli.Context, ainfoCfg []string) (api.Chain, json
}

// Compare with binary's network using BuildTypeString()
if string(networkName) != build.BuildTypeString()[1:] {
clog.Warnf("Network mismatch for node %s: binary built for %s but node is on %s",
head.addr, build.BuildTypeString()[1:], networkName)
closer()
continue
if !(strings.HasPrefix(string(networkName), "test") || strings.HasPrefix(string(networkName), "local")) {
if string(networkName) != build.BuildTypeString()[1:] {
clog.Warnf("Network mismatch for node %s: binary built for %s but node is on %s",
head.addr, build.BuildTypeString()[1:], networkName)
closer()
continue
}
}

fullNodes = append(fullNodes, v1api)
Expand Down
86 changes: 74 additions & 12 deletions web/api/webrpc/storage_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/samber/lo"
"github.com/snadrus/must"
"golang.org/x/xerrors"

"github.com/filecoin-project/go-address"

Expand Down Expand Up @@ -80,7 +81,7 @@ func (a *WebRPC) StorageUseStats(ctx context.Context) ([]StorageUseStats, error)
return stats, nil
}

type StorageGCMarks struct {
type StorageGCMark struct {
Actor int64 `db:"sp_id"`
SectorNum int64 `db:"sector_num"`
FileType int64 `db:"sector_filetype"`
Expand All @@ -102,16 +103,70 @@ type StorageGCMarks struct {
Miner string
}

func (a *WebRPC) StorageGCMarks(ctx context.Context) ([]*StorageGCMarks, error) {
var marks []*StorageGCMarks
err := a.deps.DB.Select(ctx, &marks, `
SELECT m.sp_id, m.sector_num, m.sector_filetype, m.storage_id, m.created_at, m.approved, m.approved_at, sl.can_seal, sl.can_store, sl.urls
FROM storage_removal_marks m LEFT JOIN storage_path sl ON m.storage_id = sl.storage_id
ORDER BY created_at DESC`)
type StorageGCMarks struct {
Marks []*StorageGCMark
Total int
}

func (a *WebRPC) StorageGCMarks(ctx context.Context, miner *string, sectorNum *int64, limit int, offset int) (*StorageGCMarks, error) {
var spID *int64
if miner != nil {
maddr, err := address.NewFromString(*miner)
if err != nil {
return nil, err
}
sp_id, err := address.IDFromAddress(maddr)
if err != nil {
return nil, err
}
tspid := int64(sp_id)
spID = &tspid
}

if sectorNum != nil && *sectorNum < 0 {
return nil, xerrors.Errorf("invalid sector_num: %d", *sectorNum)
}

var marks []*StorageGCMark
var total int

// Get the total count of rows
err := a.deps.DB.QueryRow(ctx, `SELECT
COUNT(*)
FROM storage_removal_marks
WHERE
($1::BIGINT IS NULL OR sp_id = $1)
AND ($2::BIGINT IS NULL OR sector_num = $2)`, spID, sectorNum).Scan(&total)
if err != nil {
return nil, err
return nil, xerrors.Errorf("querying storage removal marks: %w", err)
}

err = a.deps.DB.Select(ctx, &marks, `
SELECT
m.sp_id,
m.sector_num,
m.sector_filetype,
m.storage_id,
m.created_at,
m.approved,
m.approved_at,
sl.can_seal,
sl.can_store,
sl.urls
FROM storage_removal_marks m
LEFT JOIN storage_path sl ON m.storage_id = sl.storage_id
WHERE
($1::BIGINT IS NULL OR m.sp_id = $1)
AND ($2::BIGINT IS NULL OR m.sector_num = $2)
ORDER BY created_at
DESC LIMIT $3
OFFSET $4`, spID, sectorNum, limit, offset)
if err != nil {
return nil, xerrors.Errorf("querying storage removal marks: %w", err)
}

minerMap := make(map[int64]address.Address)

for i, m := range marks {
marks[i].TypeName = storiface.SectorFileType(m.FileType).String()

Expand All @@ -129,14 +184,21 @@ func (a *WebRPC) StorageGCMarks(ctx context.Context) ([]*StorageGCMarks, error)
return must.One(url.Parse(u)).Host
})
marks[i].Urls = strings.Join(us, ", ")
maddr, err := address.NewIDAddress(uint64(marks[i].Actor))
if err != nil {
return nil, err
maddr, ok := minerMap[marks[i].Actor]
if !ok {
maddr, err = address.NewIDAddress(uint64(marks[i].Actor))
if err != nil {
return nil, err
}
minerMap[marks[i].Actor] = maddr
}
marks[i].Miner = maddr.String()
}

return marks, nil
return &StorageGCMarks{
Marks: marks,
Total: total,
}, nil
}

func (a *WebRPC) StorageGCApprove(ctx context.Context, actor int64, sectorNum int64, fileType int64, storageID string) error {
Expand Down
118 changes: 101 additions & 17 deletions web/static/gc/gc-marks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,117 @@ import RPCCall from '/lib/jsonrpc.mjs';

class StorageGCStats extends LitElement {
static properties = {
data: { type: Array }
data: { type: Array },
pageSize: { type: Number },
currentPage: { type: Number },
totalPages: { type: Number },
totalCount: { type: Number },
miner: { type: String },
sectorNum: { type: Number },
};

constructor() {
super();
this.data = [];
this.loadData();
this.pageSize = 50; // Default number of rows per page
this.currentPage = 1;
this.totalPages = 0;
this.totalCount = 0;
this.miner = null; // Default: No Miner filter
this.sectorNum = null; // Default: No Sector Number filter
this.loadData(); // Load initial data for page 1
}

async loadData() {
this.data = await RPCCall('StorageGCMarks');
async loadData(page = 1) {
const offset = (page - 1) * this.pageSize;

// Fetch data from the backend with limit, offset, and optional filters
const response = await RPCCall('StorageGCMarks', [
this.miner, // Include Miner filter if set
this.sectorNum, // Include Sector Number filter if set
this.pageSize,
offset,
]);

this.data = response.Marks || []; // Data for the current page
this.totalCount = response.Total || 0; // Total rows matching the filters
this.totalPages = Math.ceil(this.totalCount / this.pageSize); // Calculate total pages
this.currentPage = page; // Update the current page
this.requestUpdate();
}

async approveEntry(entry) {
await RPCCall('StorageGCApprove', [entry.Actor, entry.SectorNum, entry.FileType, entry.StorageID]);
this.loadData(this.currentPage); // Reload current page
}

updateFilters(event) {
const { name, value } = event.target;
if (name === 'miner') {
this.miner = value ? value.trim() : null; // Trim spaces for miner ID
} else if (name === 'sectorNum') {
this.sectorNum = value ? Number(value) : null; // Convert sectorNum to a number
}
}

applyFilters() {
this.currentPage = 1; // Reset to page 1 when filters are applied
this.loadData();
}

renderFilters() {
return html`
<div class="filter-container mb-3">
<label for="miner">Miner:</label>
<input
id="miner"
name="miner"
type="text"
@input="${this.updateFilters}"
placeholder="Enter Miner ID"
>
<label for="sectorNum">Sector Number:</label>
<input
id="sectorNum"
name="sectorNum"
type="number"
@input="${this.updateFilters}"
placeholder="Enter Sector Number"
>
<p></p>
<button @click="${this.applyFilters}" class="btn btn-primary">Apply Filters</button>
</div>
`;
}

renderPagination() {
return html`
<nav>
<ul class="pagination">
<li class="page-item ${this.currentPage === 1 ? 'disabled' : ''}">
<button class="page-link" @click="${() => this.loadData(this.currentPage - 1)}">Previous</button>
</li>
<li class="page-item disabled">
<span class="page-link">
Page ${this.currentPage} of ${this.totalPages}
</span>
</li>
<li class="page-item ${this.currentPage === this.totalPages ? 'disabled' : ''}">
<button class="page-link" @click="${() => this.loadData(this.currentPage + 1)}">Next</button>
</li>
</ul>
</nav>
`;
}

render() {
return html`
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="/ux/main.css" onload="document.body.style.visibility = 'initial'">
<p></p>
${this.renderFilters()}
<p></p>
<table class="table table-dark">
<thead>
<tr>
Expand All @@ -44,26 +132,22 @@ class StorageGCStats extends LitElement {
<td>${entry.Miner}</td>
<td>${entry.SectorNum}</td>
<td>
<div>
${entry.StorageID}
</div>
<div>
${entry.Urls}
</div>
<div>${entry.StorageID}</div>
<div>${entry.Urls}</div>
</td>
<td>${entry.PathType}</td>
<td>${entry.TypeName}</td>
<td>${entry.CreatedAt}</td>
<td>
${entry.Approved ?
"Yes " + entry.ApprovedAt :
html`No <button @click="${() => this.approveEntry(entry)}" class="btn btn-primary btn-sm">Approve</button>`
}
${entry.Approved
? `Yes ${entry.ApprovedAt}`
: html`No <button @click="${() => this.approveEntry(entry)}" class="btn btn-primary btn-sm">Approve</button>`}
</td>
</tr>
`)}
`)}
</tbody>
</table>
${this.renderPagination()}
`;
}
}
Expand All @@ -76,7 +160,7 @@ class ApproveAllButton extends LitElement {

constructor() {
super();
this.unapprove = false; // default is false, meaning "Approve All"
this.unapprove = false; // Default is "Approve All"
}

async handleClick() {
Expand All @@ -98,4 +182,4 @@ class ApproveAllButton extends LitElement {
`;
}
}
customElements.define('approve-all-button', ApproveAllButton);
customElements.define('approve-all-button', ApproveAllButton);
1 change: 1 addition & 0 deletions web/static/pages/pipeline_porep/pipeline-porep-sectors.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ export function renderSectorState(name, rowspan, sector, task, after, started) {
// 1) "waiting for precommit"
if (
name === 'PComm Msg' &&
sector.AfterSynthetic &&
sector.PreCommitReadyAt &&
!sector.AfterPrecommitMsg &&
!sector.TaskPrecommitMsg
Expand Down

0 comments on commit 2347010

Please sign in to comment.