feat(storage): paginate operations history with prev/next controls
Backend:
- ListStorageJobs(limit, offset) adds OFFSET for pagination
- CountStorageJobs() returns total row count for UI
- handler returns { jobs, total, limit, offset }
- JobManager.List(limit, offset) updated signature
Frontend:
- loadJobs(offset) with default 0
- Pagination UI: 'Mostrando X-Y de Z' + Anterior/Siguiente buttons
- After job start/end, reloads from offset 0
- listStorageJobs(limit, offset) API updated
Tests: fix List/ListStorageJobs calls to include offset=0
This commit is contained in:
@@ -159,13 +159,13 @@ func (d *DB) TrimJobOutput(id int64, maxLines int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DB) ListStorageJobs(limit int) ([]StorageJob, error) {
|
||||
func (d *DB) ListStorageJobs(limit, offset int) ([]StorageJob, error) {
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
limit = 20
|
||||
}
|
||||
rows, err := d.conn.Query(`
|
||||
SELECT id, kind, status, args_json, pid, started_at, finished_at, exit_code, output, error, created_at
|
||||
FROM storage_jobs ORDER BY created_at DESC LIMIT ?`, limit)
|
||||
FROM storage_jobs ORDER BY created_at DESC LIMIT ? OFFSET ?`, limit, offset)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list storage jobs: %w", err)
|
||||
}
|
||||
@@ -182,6 +182,15 @@ func (d *DB) ListStorageJobs(limit int) ([]StorageJob, error) {
|
||||
return jobs, rows.Err()
|
||||
}
|
||||
|
||||
func (d *DB) CountStorageJobs() (int, error) {
|
||||
var count int
|
||||
err := d.conn.QueryRow(`SELECT COUNT(1) FROM storage_jobs`).Scan(&count)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("count storage jobs: %w", err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (d *DB) GetRunningJob() (*StorageJob, error) {
|
||||
row := d.conn.QueryRow(`
|
||||
SELECT id, kind, status, args_json, pid, started_at, finished_at, exit_code, output, error, created_at
|
||||
|
||||
@@ -14,7 +14,7 @@ func TestListStorageJobsEmptyReturnsSlice(t *testing.T) {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
|
||||
jobs, err := d.ListStorageJobs(50)
|
||||
jobs, err := d.ListStorageJobs(50, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("ListStorageJobs: %v", err)
|
||||
}
|
||||
|
||||
@@ -285,8 +285,8 @@ func (jm *JobManager) Get(id int64) (db.StorageJob, error) {
|
||||
return jm.db.GetStorageJob(id)
|
||||
}
|
||||
|
||||
func (jm *JobManager) List(limit int) ([]db.StorageJob, error) {
|
||||
return jm.db.ListStorageJobs(limit)
|
||||
func (jm *JobManager) List(limit, offset int) ([]db.StorageJob, error) {
|
||||
return jm.db.ListStorageJobs(limit, offset)
|
||||
}
|
||||
|
||||
func (jm *JobManager) Cancel(id int64) error {
|
||||
|
||||
@@ -54,7 +54,7 @@ func TestJobManagerListEmpty(t *testing.T) {
|
||||
defer d.Close()
|
||||
|
||||
jm := NewJobManager(d, false)
|
||||
jobs, err := jm.List(10)
|
||||
jobs, err := jm.List(10, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("List: %v", err)
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func TestJobManagerResetOrphans(t *testing.T) {
|
||||
t.Fatalf("ResetOrphans: %v", err)
|
||||
}
|
||||
|
||||
jobs, _ := jm.List(10)
|
||||
jobs, _ := jm.List(10, 0)
|
||||
runningCount := 0
|
||||
queuedCount := 0
|
||||
for _, j := range jobs {
|
||||
|
||||
@@ -111,14 +111,23 @@ func (s *Server) handleStorageUpdateConfig(w http.ResponseWriter, r *http.Reques
|
||||
func (s *Server) handleStorageListJobs(w http.ResponseWriter, r *http.Request) {
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
limit = 20
|
||||
}
|
||||
jobs, err := s.JM.List(limit)
|
||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
jobs, err := s.JM.List(limit, offset)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"jobs": jobs})
|
||||
total, err := s.DB.CountStorageJobs()
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"jobs": jobs, "total": total, "limit": limit, "offset": offset})
|
||||
}
|
||||
|
||||
func (s *Server) handleStorageGetJob(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user