feat(ui): asleep state, 24×7 chip, presence toggle for host mode
This commit is contained in:
@@ -70,6 +70,7 @@
|
|||||||
.dot-online { background: var(--ok); box-shadow: 0 0 0 3px color-mix(in oklch, var(--ok), transparent 80%); }
|
.dot-online { background: var(--ok); box-shadow: 0 0 0 3px color-mix(in oklch, var(--ok), transparent 80%); }
|
||||||
.dot-degraded { background: var(--warn); box-shadow: 0 0 0 3px color-mix(in oklch, var(--warn), transparent 80%); }
|
.dot-degraded { background: var(--warn); box-shadow: 0 0 0 3px color-mix(in oklch, var(--warn), transparent 80%); }
|
||||||
.dot-offline { background: var(--off); }
|
.dot-offline { background: var(--off); }
|
||||||
|
.dot-asleep { background: var(--ink-fade); opacity: 0.6; }
|
||||||
.dot-failed { background: var(--bad); box-shadow: 0 0 0 3px color-mix(in oklch, var(--bad), transparent 80%); }
|
.dot-failed { background: var(--bad); box-shadow: 0 0 0 3px color-mix(in oklch, var(--bad), transparent 80%); }
|
||||||
.pulse { animation: rm-pulse 2.4s ease-in-out infinite; }
|
.pulse { animation: rm-pulse 2.4s ease-in-out infinite; }
|
||||||
@keyframes rm-pulse {
|
@keyframes rm-pulse {
|
||||||
|
|||||||
@@ -34,7 +34,11 @@
|
|||||||
{{else if eq $host.Status "degraded"}}
|
{{else if eq $host.Status "degraded"}}
|
||||||
<span class="dot dot-degraded"></span>
|
<span class="dot dot-degraded"></span>
|
||||||
{{else if eq $host.Status "offline"}}
|
{{else if eq $host.Status "offline"}}
|
||||||
|
{{if $host.AlwaysOn}}
|
||||||
<span class="dot dot-offline"></span>
|
<span class="dot dot-offline"></span>
|
||||||
|
{{else}}
|
||||||
|
<span class="dot dot-asleep"></span>
|
||||||
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="dot dot-failed"></span>
|
<span class="dot dot-failed"></span>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -45,6 +49,11 @@
|
|||||||
style="padding: 2px 8px; border: 1px dashed var(--line); border-radius: 3px; cursor: pointer;"
|
style="padding: 2px 8px; border: 1px dashed var(--line); border-radius: 3px; cursor: pointer;"
|
||||||
onclick="document.getElementById('tags-edit-{{$host.ID}}').classList.toggle('hidden')"
|
onclick="document.getElementById('tags-edit-{{$host.ID}}').classList.toggle('hidden')"
|
||||||
title="Edit tags">{{if $host.Tags}}edit tags{{else}}add tags{{end}}</button>
|
title="Edit tags">{{if $host.Tags}}edit tags{{else}}add tags{{end}}</button>
|
||||||
|
{{if $host.AlwaysOn}}<span class="tag" title="Expected online 24×7 — offline raises an alert">24×7</span>{{end}}
|
||||||
|
<button type="button" class="text-ink-fade text-[11px] hover:text-ink-mid whitespace-nowrap"
|
||||||
|
style="padding: 2px 8px; border: 1px dashed var(--line); border-radius: 3px; cursor: pointer;"
|
||||||
|
onclick="document.getElementById('mode-edit-{{$host.ID}}').classList.toggle('hidden')"
|
||||||
|
title="Change presence mode">presence</button>
|
||||||
</div>
|
</div>
|
||||||
{{if gt $page.ScheduleVersion 0}}
|
{{if gt $page.ScheduleVersion 0}}
|
||||||
<span class="mono text-[11px] text-ink-mute ml-2">
|
<span class="mono text-[11px] text-ink-mute ml-2">
|
||||||
@@ -80,6 +89,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="field-help">Comma-separated. Lowercased automatically.</div>
|
<div class="field-help">Comma-separated. Lowercased automatically.</div>
|
||||||
</form>
|
</form>
|
||||||
|
{{/* Presence-mode editor — hidden by default; toggled by the
|
||||||
|
"presence" button. Checkbox present => always-on (24×7);
|
||||||
|
unchecked => intermittent (laptop): no offline alerts, shows
|
||||||
|
"asleep", auto-catches-up a missed backup on reconnect. */}}
|
||||||
|
<form id="mode-edit-{{$host.ID}}" method="post"
|
||||||
|
action="/hosts/{{$host.ID}}/mode"
|
||||||
|
class="hidden mt-3" style="max-width: 640px;">
|
||||||
|
<label class="flex items-center gap-2 text-[12px] text-ink-mid">
|
||||||
|
<input type="checkbox" name="always_on" value="on" {{if $host.AlwaysOn}}checked{{end}} />
|
||||||
|
Always On — expected online 24×7
|
||||||
|
</label>
|
||||||
|
<div class="field-help">
|
||||||
|
Uncheck for an intermittent host (laptop/workstation): it won't
|
||||||
|
raise offline alerts when asleep, shows an "asleep" state, and
|
||||||
|
catches up a missed backup ~1 minute after it reconnects.
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary mt-2 whitespace-nowrap">Save presence</button>
|
||||||
|
</form>
|
||||||
<div class="flex items-center gap-3 mt-3 text-[13px] text-ink-mute">
|
<div class="flex items-center gap-3 mt-3 text-[13px] text-ink-mute">
|
||||||
<span class="mono text-ink-mid">{{$host.OS}}/{{$host.Arch}}</span>
|
<span class="mono text-ink-mid">{{$host.OS}}/{{$host.Arch}}</span>
|
||||||
<span class="text-ink-fade">·</span>
|
<span class="text-ink-fade">·</span>
|
||||||
@@ -88,7 +115,11 @@
|
|||||||
<span>restic <span class="mono text-ink-mid">{{if $host.ResticVersion}}{{$host.ResticVersion}}{{else}}—{{end}}</span></span>
|
<span>restic <span class="mono text-ink-mid">{{if $host.ResticVersion}}{{$host.ResticVersion}}{{else}}—{{end}}</span></span>
|
||||||
<span class="text-ink-fade">·</span>
|
<span class="text-ink-fade">·</span>
|
||||||
{{if eq $host.Status "offline"}}
|
{{if eq $host.Status "offline"}}
|
||||||
|
{{if $host.AlwaysOn}}
|
||||||
<span>last seen <span class="mono text-ink-mid">{{relTime $host.LastSeenAt}}</span></span>
|
<span>last seen <span class="mono text-ink-mid">{{relTime $host.LastSeenAt}}</span></span>
|
||||||
|
{{else}}
|
||||||
|
<span>asleep · last seen <span class="mono text-ink-mid">{{relTime $host.LastSeenAt}}</span> · will catch up on return</span>
|
||||||
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<span>online · last heartbeat <span class="mono text-ink-mid">{{relTime $host.LastSeenAt}}</span></span>
|
<span>online · last heartbeat <span class="mono text-ink-mid">{{relTime $host.LastSeenAt}}</span></span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -8,7 +8,11 @@
|
|||||||
{{- else if eq $h.Status "degraded" -}}
|
{{- else if eq $h.Status "degraded" -}}
|
||||||
<span class="dot dot-degraded"></span>
|
<span class="dot dot-degraded"></span>
|
||||||
{{- else if eq $h.Status "offline" -}}
|
{{- else if eq $h.Status "offline" -}}
|
||||||
|
{{- if $h.AlwaysOn -}}
|
||||||
<span class="dot dot-offline"></span>
|
<span class="dot dot-offline"></span>
|
||||||
|
{{- else -}}
|
||||||
|
<span class="dot dot-asleep"></span>
|
||||||
|
{{- end -}}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
<span class="dot dot-failed"></span>
|
<span class="dot dot-failed"></span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
@@ -26,7 +30,11 @@
|
|||||||
{{- else if eq (deref $h.LastBackupStatus) "cancelled" -}}
|
{{- else if eq (deref $h.LastBackupStatus) "cancelled" -}}
|
||||||
<span class="text-warn">cancelled</span> · <span class="mono">{{relTime $h.LastBackupAt}}</span>
|
<span class="text-warn">cancelled</span> · <span class="mono">{{relTime $h.LastBackupAt}}</span>
|
||||||
{{- else if eq $h.Status "offline" -}}
|
{{- else if eq $h.Status "offline" -}}
|
||||||
|
{{- if $h.AlwaysOn -}}
|
||||||
<span class="text-ink-mute">last seen <span class="mono">{{relTime $h.LastSeenAt}}</span></span>
|
<span class="text-ink-mute">last seen <span class="mono">{{relTime $h.LastSeenAt}}</span></span>
|
||||||
|
{{- else -}}
|
||||||
|
<span class="text-ink-mute">asleep · <span class="mono">{{relTime $h.LastSeenAt}}</span> · will catch up on return</span>
|
||||||
|
{{- end -}}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
<span class="text-ink-fade italic">never run</span>
|
<span class="text-ink-fade italic">never run</span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
@@ -53,7 +61,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="text-right row-action">
|
<div class="text-right row-action">
|
||||||
{{- if eq $h.Status "offline" -}}
|
{{- if eq $h.Status "offline" -}}
|
||||||
<span class="mono text-xs text-ink-fade">offline</span>
|
<span class="mono text-xs text-ink-fade">{{if $h.AlwaysOn}}offline{{else}}asleep{{end}}</span>
|
||||||
{{- else if $h.CurrentJobID -}}
|
{{- else if $h.CurrentJobID -}}
|
||||||
<a href="/jobs/{{deref $h.CurrentJobID}}" class="btn btn-ghost">View job →</a>
|
<a href="/jobs/{{deref $h.CurrentJobID}}" class="btn btn-ghost">View job →</a>
|
||||||
{{- else if .RunAllScheduleID -}}
|
{{- else if .RunAllScheduleID -}}
|
||||||
|
|||||||
Reference in New Issue
Block a user