P2R-02: UI rewire against the slim-schedule + source-group model #2
@@ -301,9 +301,8 @@ func (s *Server) handleUIScheduleRun(w stdhttp.ResponseWriter, r *stdhttp.Reques
|
|||||||
stdhttp.Error(w, "internal", stdhttp.StatusInternalServerError)
|
stdhttp.Error(w, "internal", stdhttp.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !sc.Enabled {
|
if len(sc.SourceGroupIDs) == 0 {
|
||||||
stdhttp.Error(w, "schedule is paused — enable it first or use per-group Run-now from the Sources tab",
|
stdhttp.Error(w, "this schedule has no source groups attached", stdhttp.StatusConflict)
|
||||||
stdhttp.StatusConflict)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.deps.Hub == nil {
|
if s.deps.Hub == nil {
|
||||||
@@ -316,9 +315,24 @@ func (s *Server) handleUIScheduleRun(w stdhttp.ResponseWriter, r *stdhttp.Reques
|
|||||||
stdhttp.StatusConflict)
|
stdhttp.StatusConflict)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manual Run-now ignores Enabled. "Disabled" only suppresses
|
||||||
|
// cron-tick firing; an ad-hoc one-off run is a separate intent
|
||||||
|
// (and the dispatch is audit-logged inside dispatchBackupForGroup).
|
||||||
|
// We dispatch inline rather than calling dispatchScheduledJob,
|
||||||
|
// which short-circuits on !Enabled.
|
||||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
s.dispatchScheduledJob(ctx, host.ID, conn, sid, time.Now().UTC())
|
now := time.Now().UTC()
|
||||||
|
for _, gid := range sc.SourceGroupIDs {
|
||||||
|
g, gerr := s.deps.Store.GetSourceGroup(ctx, host.ID, gid)
|
||||||
|
if gerr != nil {
|
||||||
|
slog.Warn("ui schedule run: load source group",
|
||||||
|
"host_id", host.ID, "schedule_id", sid, "group_id", gid, "err", gerr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.dispatchBackupForGroup(ctx, conn, host.ID, sid, g, now)
|
||||||
|
}
|
||||||
|
|
||||||
if wantsHTML(r) {
|
if wantsHTML(r) {
|
||||||
// HX-Redirect would jump to a single job log, but a multi-group
|
// HX-Redirect would jump to a single job log, but a multi-group
|
||||||
|
|||||||
@@ -53,11 +53,22 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-1.5 justify-end row-action">
|
<div class="flex gap-1.5 justify-end row-action">
|
||||||
{{if and $sc.Enabled (eq $host.Status "online")}}
|
{{if eq $host.Status "online"}}
|
||||||
<button class="btn btn-primary"
|
{{if $sc.Enabled}}
|
||||||
hx-post="/hosts/{{$host.ID}}/schedules/{{$sc.ID}}/run"
|
<button class="btn btn-primary"
|
||||||
hx-swap="none"
|
hx-post="/hosts/{{$host.ID}}/schedules/{{$sc.ID}}/run"
|
||||||
hx-disabled-elt="this">Run now</button>
|
hx-swap="none"
|
||||||
|
hx-disabled-elt="this">Run now</button>
|
||||||
|
{{else}}
|
||||||
|
<button class="btn"
|
||||||
|
hx-post="/hosts/{{$host.ID}}/schedules/{{$sc.ID}}/run"
|
||||||
|
hx-swap="none"
|
||||||
|
hx-disabled-elt="this"
|
||||||
|
hx-confirm="This schedule is paused — running it now won't change that. Fire it once anyway?"
|
||||||
|
title="schedule is paused; click to fire one ad-hoc run anyway">Run now</button>
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
<button class="btn" disabled title="host is offline">Run now</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
<form method="post" action="/hosts/{{$host.ID}}/schedules/{{$sc.ID}}/delete" style="display: inline;"
|
<form method="post" action="/hosts/{{$host.ID}}/schedules/{{$sc.ID}}/delete" style="display: inline;"
|
||||||
onsubmit="return confirm('Delete this schedule? Existing snapshots are not affected.');">
|
onsubmit="return confirm('Delete this schedule? Existing snapshots are not affected.');">
|
||||||
|
|||||||
Reference in New Issue
Block a user