ui: P2R-12 hook editor — source-group form + host-default Repo section

Source-group edit form gains pre/post hook textareas with a service-
user warning banner; bodies AEAD-encrypted on save (per-group AD).
Repo page adds a 'Host-default hooks' panel above the danger zone
with the same shape; saved via POST /hosts/{id}/repo/hooks.
This commit is contained in:
2026-05-04 11:00:28 +01:00
parent 7b1990cf11
commit a5a2cb91d0
6 changed files with 133 additions and 1 deletions
+26
View File
@@ -220,6 +220,32 @@
</div>
</div>
{{/* ---------- Host-default hooks ---------- */}}
<h2 class="text-[11.5px] font-semibold uppercase tracking-[0.08em] text-ink-mute mt-9 mb-3.5">Host-default hooks</h2>
<form method="post" action="/hosts/{{$host.ID}}/repo/hooks" class="panel rounded-[7px] p-5">
<p class="text-[12px] text-ink-mute leading-[1.55] mb-3">
Defaults applied to every backup that doesn't set its own. Per-source-group hooks (on the
<a href="/hosts/{{$host.ID}}/sources" class="text-accent">Sources</a> tab) override these.
</p>
<div class="text-[12px] text-warn leading-[1.55] mb-3"
style="background: color-mix(in oklch, var(--warn), transparent 92%); border: 1px solid color-mix(in oklch, var(--warn), transparent 75%); padding: 8px 10px; border-radius: 5px;">
Hooks run as the agent service user — root on Linux, LocalSystem on Windows.
</div>
<div class="mb-3">
<label class="field-label" for="host_pre_hook">Pre-backup hook (default)</label>
<textarea id="host_pre_hook" name="pre_hook" class="field mono" rows="3" style="resize: vertical;"
placeholder="# default; per-group overrides win">{{$page.HostPreHook}}</textarea>
</div>
<div class="mb-3">
<label class="field-label" for="host_post_hook">Post-backup hook (default)</label>
<textarea id="host_post_hook" name="post_hook" class="field mono" rows="3" style="resize: vertical;"
placeholder="# RM_JOB_STATUS in env">{{$page.HostPostHook}}</textarea>
</div>
<div class="mt-3">
<button type="submit" class="btn btn-primary">Save host-default hooks</button>
</div>
</form>
{{/* ---------- Danger zone ---------- */}}
<h2 class="text-[11.5px] font-semibold uppercase tracking-[0.08em] text-bad mt-9 mb-3.5">Danger zone</h2>
<div class="panel rounded-[7px] p-5"
@@ -95,6 +95,27 @@
Each retry doubles the wait. <strong>Manual run-now ignores this</strong> — it just fails immediately if the agent is offline.
</div>
<h3 class="text-[11.5px] font-semibold uppercase tracking-[0.08em] text-ink-mute mb-3.5 mt-7 pt-4 border-t border-line-soft">
Hooks
<span class="text-ink-fade font-medium normal-case tracking-[0.01em] ml-2">backup jobs only</span>
</h3>
<div class="text-[12px] text-warn leading-[1.55] mb-3"
style="background: color-mix(in oklch, var(--warn), transparent 92%); border: 1px solid color-mix(in oklch, var(--warn), transparent 75%); padding: 8px 10px; border-radius: 5px;">
Hooks run as the agent service user — root on Linux, LocalSystem on Windows. Treat them like any other root cron entry.
</div>
<div class="mb-3">
<label class="field-label" for="pre_hook">Pre-backup hook</label>
<textarea id="pre_hook" name="pre_hook" class="field mono" rows="3" style="resize: vertical;"
placeholder="# e.g. systemctl stop myapp">{{$f.PreHook}}</textarea>
<div class="field-help mt-1">Non-zero exit aborts the backup. Stored AEAD-encrypted.</div>
</div>
<div class="mb-3">
<label class="field-label" for="post_hook">Post-backup hook</label>
<textarea id="post_hook" name="post_hook" class="field mono" rows="3" style="resize: vertical;"
placeholder="# RM_JOB_STATUS={succeeded|failed} is in env">{{$f.PostHook}}</textarea>
<div class="field-help mt-1">Always runs. <span class="mono">RM_JOB_STATUS</span> is set to the backup's outcome. Stored AEAD-encrypted.</div>
</div>
<div class="mt-8 pt-4 border-t border-line-soft flex gap-2">
<button type="submit" class="btn btn-primary btn-lg">{{if $page.IsNew}}Create group{{else}}Save changes{{end}}</button>
<a href="/hosts/{{$host.ID}}/sources" class="btn btn-lg">Cancel</a>