8d993ac77c
Schedules list: status (enabled/paused) + cron + source-group tags + actions (Run-now when enabled+online, Edit, Delete). Run-now reuses dispatchScheduledJob — same path real cron fires take, so each referenced source group runs as its own backup with its own tag. Falls back to a 409 if the agent is offline. Schedule new/edit form: cron input with five preset chips (quick-pick @hourly / nightly / 6h / weekly / monthly), source-group multi-pick rendered as styled checkbox cards (visual state tracks the underlying box via a tiny inline script), enabled toggle. No paths/excludes/retention/kind on the schedule itself — those live on source groups now. Server-side validation re-renders with the operator's input + ticked groups intact. Every successful mutation calls pushScheduleSetAsync. Adds .schd-row, .preset-chip, .picker styles.
74 lines
3.3 KiB
HTML
74 lines
3.3 KiB
HTML
{{define "title"}}{{.Title}}{{end}}
|
|
|
|
{{define "content"}}
|
|
{{template "host_chrome" .}}
|
|
{{$page := .Page}}
|
|
{{$host := $page.Host}}
|
|
{{$groupNames := $page.GroupNames}}
|
|
<div class="max-w-[1280px] mx-auto px-8 pb-14 pt-6">
|
|
|
|
<div class="flex items-center justify-between mb-4">
|
|
<p class="text-pretty text-[12.5px] text-ink-mute leading-[1.6] max-w-[760px]">
|
|
A schedule is a cron expression pointing at one or more source groups. When it fires, the agent runs a separate
|
|
<span class="mono text-ink-mid">restic backup</span> per chosen group — independent jobs, independent snapshots,
|
|
independent retention. Failure of one group doesn't fail the others.
|
|
</p>
|
|
<a href="/hosts/{{$host.ID}}/schedules/new" class="btn btn-primary whitespace-nowrap">+ New schedule</a>
|
|
</div>
|
|
|
|
{{if eq (len $page.Schedules) 0}}
|
|
<div class="panel rounded-[7px] empty-state" style="border-radius: 7px;">
|
|
<h3 class="text-base font-medium tracking-[-0.005em]">No schedules yet.</h3>
|
|
<p class="text-pretty text-ink-mute text-[13px] mt-2 mx-auto max-w-[480px] leading-[1.65]">
|
|
Add one and the agent will start running backups on whatever cron expression you give it.
|
|
Until then, Run-now from the Sources tab is the only way to trigger a backup.
|
|
</p>
|
|
<div class="mt-5">
|
|
<a href="/hosts/{{$host.ID}}/schedules/new" class="btn btn-primary">+ New schedule</a>
|
|
</div>
|
|
</div>
|
|
{{else}}
|
|
<div class="panel rounded-[7px] overflow-hidden">
|
|
<div class="schd-row head hairline">
|
|
<div>Status</div>
|
|
<div>Cron</div>
|
|
<div>Sources</div>
|
|
<div></div>
|
|
</div>
|
|
{{range $i, $sc := $page.Schedules}}
|
|
<div class="schd-row {{if not (eq $i 0)}}hairline{{end}}">
|
|
<div>
|
|
{{if $sc.Enabled}}
|
|
<span class="mono text-[11px] text-ok">enabled</span>
|
|
{{else}}
|
|
<span class="mono text-[11px] text-ink-fade">paused</span>
|
|
{{end}}
|
|
</div>
|
|
<div class="mono {{if $sc.Enabled}}text-ink{{else}}text-ink-mute{{end}}">{{$sc.CronExpr}}</div>
|
|
<div class="flex gap-1.5 flex-wrap">
|
|
{{range $sc.SourceGroupIDs}}
|
|
{{$name := index $groupNames .}}
|
|
<span class="tag" style="border-color: color-mix(in oklch, var(--accent), transparent 60%); color: var(--accent); {{if not $sc.Enabled}}opacity: 0.6;{{end}}">{{if $name}}{{$name}}{{else}}<span class="text-ink-fade">unknown</span>{{end}}</span>
|
|
{{end}}
|
|
</div>
|
|
<div class="flex gap-1.5 justify-end">
|
|
{{if and $sc.Enabled (eq $host.Status "online")}}
|
|
<button class="btn btn-primary"
|
|
hx-post="/hosts/{{$host.ID}}/schedules/{{$sc.ID}}/run"
|
|
hx-swap="none"
|
|
hx-disabled-elt="this">Run now</button>
|
|
{{end}}
|
|
<a href="/hosts/{{$host.ID}}/schedules/{{$sc.ID}}/edit" class="btn">Edit</a>
|
|
<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.');">
|
|
<button type="submit" class="btn btn-danger">Delete</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
</div>
|
|
{{end}}
|