feat: show disk usage of mover source with configurable warning threshold

GET /api/storage/disk-usage returns source path stats (total/used/free bytes, %).
Polls every 30s while Storage page is open.

Backend:
- migration 0009: adds mover_warning_threshold (1-99, default 80) to storage_config
- StatPath moved to internal/storage package for testability
- handleStorageDiskUsage returns {source: PathStat}

Frontend:
- DiskUsageBar component in Mergerfs Mover card: usage bar with color
  green < threshold, amber >= threshold, red >= 95%
- Warning message when threshold reached or exceeded
- New input in config form: Umbral de aviso (%)
- storageDiskUsage() API method

Tests: StatPath unit tests (empty/nonexistent/valid paths)

Version: 0.7.3
This commit is contained in:
2026-07-07 00:30:32 -04:00
parent e5b9b233b8
commit 428056e1be
9 changed files with 169 additions and 38 deletions
+32
View File
@@ -3,6 +3,7 @@ package storage
import (
"context"
"os/exec"
"syscall"
"github.com/darroyo/nasctl/internal/db"
"github.com/darroyo/nasctl/internal/system"
@@ -30,6 +31,37 @@ func Probe(ctx context.Context) (Capabilities, error) {
}, nil
}
type PathStat struct {
Path string `json:"path"`
Available bool `json:"available"`
TotalBytes uint64 `json:"total_bytes"`
UsedBytes uint64 `json:"used_bytes"`
FreeBytes uint64 `json:"free_bytes"`
UsedPercent float64 `json:"used_percent"`
Error string `json:"error,omitempty"`
}
func StatPath(p string) PathStat {
out := PathStat{Path: p, Available: false}
if p == "" {
out.Error = "path no configurado"
return out
}
var st syscall.Statfs_t
if err := syscall.Statfs(p, &st); err != nil {
out.Error = err.Error()
return out
}
out.Available = true
out.TotalBytes = st.Blocks * uint64(st.Bsize)
out.FreeBytes = st.Bavail * uint64(st.Bsize)
out.UsedBytes = out.TotalBytes - out.FreeBytes
if out.TotalBytes > 0 {
out.UsedPercent = float64(out.UsedBytes) / float64(out.TotalBytes) * 100
}
return out
}
func ValidatePaths(cfg db.StorageConfig) error {
return nil
}