v0.15.1: Backup page Részletek overhaul with per-drive tier sections
Replace Tároló section with collapsible Részletek containing 3 tiers: - Tier 1: per-drive restic repo stats with storage labels - Tier 2: cross-drive items grouped by destination, split by method - Tier 3: remote backup placeholder Restore UI now shows tier + drive labels in snapshot dropdown. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -525,33 +525,59 @@ func (s *Server) backupsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data["ResticPassword"] = pw
|
||||
}
|
||||
|
||||
// Tároló section: DB dump total size
|
||||
// Részletek section: DB dump total size
|
||||
var dbDumpTotalBytes int64
|
||||
for _, f := range fullStatus.DumpFiles {
|
||||
dbDumpTotalBytes += f.Size
|
||||
}
|
||||
data["DBDumpTotalBytes"] = dbDumpTotalBytes
|
||||
|
||||
// Tároló section: deduplicated Tier 2 destination list
|
||||
tier2DestMap := make(map[string]map[string]string)
|
||||
// Részletek section: enrich per-drive repo stats with storage labels
|
||||
for i := range fullStatus.PerDriveRepoStats {
|
||||
for _, sp := range storagePaths {
|
||||
if strings.HasPrefix(fullStatus.PerDriveRepoStats[i].DrivePath, sp.Path) ||
|
||||
fullStatus.PerDriveRepoStats[i].DrivePath == sp.Path {
|
||||
fullStatus.PerDriveRepoStats[i].DriveLabel = sp.Label
|
||||
break
|
||||
}
|
||||
}
|
||||
if fullStatus.PerDriveRepoStats[i].DriveLabel == "" {
|
||||
fullStatus.PerDriveRepoStats[i].DriveLabel = filepath.Base(fullStatus.PerDriveRepoStats[i].DrivePath)
|
||||
}
|
||||
}
|
||||
data["PerDriveRepoStats"] = fullStatus.PerDriveRepoStats
|
||||
|
||||
// Részletek section: group Tier 2 items by destination drive
|
||||
tier2GroupMap := make(map[string]*Tier2DriveGroup)
|
||||
for _, item := range fullStatus.CrossDriveSummary {
|
||||
if item.DestPath == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := tier2DestMap[item.DestPath]; !exists {
|
||||
tier2DestMap[item.DestPath] = map[string]string{
|
||||
"Path": item.DestPath,
|
||||
"Label": item.DestLabel,
|
||||
"Method": item.MethodLabel,
|
||||
"SizeHuman": item.SizeHuman,
|
||||
grp, exists := tier2GroupMap[item.DestPath]
|
||||
if !exists {
|
||||
grp = &Tier2DriveGroup{
|
||||
DestPath: item.DestPath,
|
||||
DestLabel: item.DestLabel,
|
||||
}
|
||||
if grp.DestLabel == "" {
|
||||
grp.DestLabel = filepath.Base(item.DestPath)
|
||||
}
|
||||
tier2GroupMap[item.DestPath] = grp
|
||||
}
|
||||
switch item.Method {
|
||||
case "restic":
|
||||
grp.ResticItems = append(grp.ResticItems, item)
|
||||
case "rsync":
|
||||
grp.RsyncItems = append(grp.RsyncItems, item)
|
||||
default:
|
||||
grp.RsyncItems = append(grp.RsyncItems, item)
|
||||
}
|
||||
}
|
||||
var tier2DestList []map[string]string
|
||||
for _, d := range tier2DestMap {
|
||||
tier2DestList = append(tier2DestList, d)
|
||||
var tier2Groups []Tier2DriveGroup
|
||||
for _, grp := range tier2GroupMap {
|
||||
tier2Groups = append(tier2Groups, *grp)
|
||||
}
|
||||
data["Tier2Dests"] = tier2DestList
|
||||
data["Tier2DriveGroups"] = tier2Groups
|
||||
} else {
|
||||
data["Backup"] = nil
|
||||
}
|
||||
@@ -559,6 +585,14 @@ func (s *Server) backupsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.render(w, "backups", data)
|
||||
}
|
||||
|
||||
// Tier2DriveGroup holds grouped Tier 2 cross-drive backup items for one destination drive.
|
||||
type Tier2DriveGroup struct {
|
||||
DestPath string
|
||||
DestLabel string
|
||||
ResticItems []backup.CrossDriveSummaryItem
|
||||
RsyncItems []backup.CrossDriveSummaryItem
|
||||
}
|
||||
|
||||
// AppBackupRow holds per-tier backup information for one app on the backup page.
|
||||
type AppBackupRow struct {
|
||||
StackName string
|
||||
|
||||
Reference in New Issue
Block a user