P2R-02: UI rewire against the slim-schedule + source-group model #2

Merged
steve merged 16 commits from p2r-02-ui-rebuild into main 2026-05-03 21:34:02 +01:00
2 changed files with 17 additions and 0 deletions
Showing only changes of commit dede74fd3a - Show all commits
+14
View File
@@ -310,6 +310,20 @@ func (s *Server) handleUISourceGroupDelete(w stdhttp.ResponseWriter, r *stdhttp.
return return
} }
// Refuse to delete the host's last source group — every host
// needs at least one to be backup-able. UI disables the button
// in this case; this guards against form-replay / curl.
groups, err := s.deps.Store.ListSourceGroupsByHost(r.Context(), host.ID)
if err != nil {
slog.Error("ui sources: count groups", "err", err)
stdhttp.Error(w, "internal", stdhttp.StatusInternalServerError)
return
}
if len(groups) <= 1 {
stdhttp.Error(w, "this is the host's only source group — create another one first", stdhttp.StatusConflict)
return
}
if err := s.deps.Store.DeleteSourceGroup(r.Context(), host.ID, gid); err != nil { if err := s.deps.Store.DeleteSourceGroup(r.Context(), host.ID, gid); err != nil {
if errors.Is(err, store.ErrNotFound) { if errors.Is(err, store.ErrNotFound) {
stdhttp.NotFound(w, r) stdhttp.NotFound(w, r)
+3
View File
@@ -66,6 +66,9 @@
{{if gt $row.UsedBy 0}} {{if gt $row.UsedBy 0}}
<button class="btn btn-danger" disabled <button class="btn btn-danger" disabled
title="remove this group from {{$row.UsedBy}} schedule{{if ne $row.UsedBy 1}}s{{end}} first">Delete</button> title="remove this group from {{$row.UsedBy}} schedule{{if ne $row.UsedBy 1}}s{{end}} first">Delete</button>
{{else if eq (len $page.Groups) 1}}
<button class="btn btn-danger" disabled
title="this is the host's only source group — create another one first">Delete</button>
{{else}} {{else}}
<form method="post" action="/hosts/{{$host.ID}}/sources/{{$g.ID}}/delete" style="display: inline;" <form method="post" action="/hosts/{{$host.ID}}/sources/{{$g.ID}}/delete" style="display: inline;"
onsubmit="return confirm('Delete source group &quot;{{$g.Name}}&quot;? Existing snapshots are not affected.');"> onsubmit="return confirm('Delete source group &quot;{{$g.Name}}&quot;? Existing snapshots are not affected.');">