feat: add storage info to settings page and improve NFS export handling

Backend:
- Add source/used_by/available/error fields to diskUsage in system status
- collectDiskUsage() now reads /proc/mounts, samba shares and NFS exports from DB
- Paths are deduplicated; shared paths list all shares/exports using them
- syscall.Statfs errors surface as available=false with user-facing error
- collectServiceStatus made a method of Server (receiver consistency)

Frontend:
- Settings page now shows two cards: mount points and shared resources
- Each path shows source badge (Sistema/Mount/SMB/NFS), used_by chips, progress bar
- Unavailable paths show amber warning instead of progress bar
- DiskUsage interface updated with new fields
- NFSExport interface updated with structured fields (fsid, async, etc)
- NFS page updated to use new export fields
This commit is contained in:
2026-07-05 22:56:39 -04:00
parent 72a8336087
commit 65cd753818
14 changed files with 696 additions and 100 deletions
+40 -7
View File
@@ -3,6 +3,9 @@ package importer
import (
"bufio"
"bytes"
"crypto/rand"
"encoding/binary"
"encoding/json"
"fmt"
"os"
"regexp"
@@ -58,11 +61,11 @@ func parseExports(data []byte) ([]db.NFSExport, error) {
}
export.Clients = validClients
if export.Options != "" {
if err := system.ValidateNFSOptions(export.Options); err != nil {
continue
}
fsid, err := generateImportFSID()
if err != nil {
continue
}
export.FSID = fsid
exports = append(exports, export)
}
@@ -141,13 +144,43 @@ func parseExportLine(line string) (db.NFSExport, bool) {
options = "rw,sync,no_root_squash"
}
readOnly := strings.Contains(options, "ro")
async := strings.Contains(options, "async")
rootSquash := !strings.Contains(options, "no_root_squash")
subtreeCheck := strings.Contains(options, "subtree_check")
adv := db.NFSAdvanced{
AllSquash: strings.Contains(options, "all_squash"),
Secure: strings.Contains(options, "secure"),
WDelay: strings.Contains(options, "wdelay"),
Hide: strings.Contains(options, "hide"),
Crossmnt: strings.Contains(options, "crossmnt"),
}
advJSON, _ := json.Marshal(adv)
return db.NFSExport{
Path: path,
Clients: clients,
Options: options,
Path: path,
Clients: clients,
ReadOnly: readOnly,
Async: async,
RootSquash: rootSquash,
SubtreeCheck: subtreeCheck,
Advanced: string(advJSON),
}, true
}
func generateImportFSID() (int64, error) {
var b [4]byte
if _, err := rand.Read(b[:]); err != nil {
return 0, err
}
n := binary.BigEndian.Uint32(b[:])
if n == 0 {
n = 1
}
return int64(n), nil
}
func splitExportsClients(s string) []string {
var result []string
var current []byte