repositories / bugabinga.net
bugabinga.net
personal infrastructure for bugabinga!
owned by admin
services/toad/internal/api/web/dashboard.html
Raw<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Toad deployment control</title>
<link rel="stylesheet" href="/assets/dashboard.css">
<link rel="stylesheet" href="/assets/theme.css">
<script defer src="/assets/dashboard.js"></script>
</head>
<body>
<main class="shell">
<header class="top">
<div class="identity">
<svg class="mark" viewBox="0 0 52 52" role="img" aria-label="Toad">
<path d="M6 25C6 11 15 4 26 4s20 7 20 21c-5 3-10 4-20 4S11 28 6 25z" fill="var(--nugu-ui-accent)"/>
<circle cx="26" cy="12" r="6" fill="var(--nugu-content-backdrop)"/><circle cx="12" cy="20" r="4" fill="var(--nugu-content-backdrop)"/><circle cx="40" cy="20" r="4" fill="var(--nugu-content-backdrop)"/>
<path d="M15 27c0 13 4 20 11 20s11-7 11-20c-3 1-7 2-11 2s-8-1-11-2z" fill="var(--nugu-content-normal)"/>
<circle cx="22" cy="36" r="2" fill="var(--nugu-content-backdrop)"/><circle cx="30" cy="36" r="2" fill="var(--nugu-content-backdrop)"/>
</svg>
<div class="brand">toad</div>
</div>
{{if .Services}}<div class="fleet {{if eq .Healthy (len .Services)}}healthy{{else}}unhealthy{{end}}"><span class="nf"></span> {{.Healthy}}/{{len .Services}} healthy</div>{{end}}
</header>
{{if .Services}}
<nav class="grid" aria-label="Services">
{{range .Services}}
<a class="card {{if $.Selected}}{{if eq .Service.Name $.Selected.Service.Name}}selected{{end}}{{end}}" href="/?service={{.Service.Name}}">
<span class="title"><strong>{{.Service.Name}}</strong><span class="{{.Health}} nf" title="{{.Health}}"></span></span>
<span class="digest">{{shortDigest .State.Current}}</span>
<span class="meta"><span>generation {{.State.Generation}}</span><span>{{elapsed .State.UpdatedAt}}</span></span>
</a>
{{end}}
</nav>
{{else}}
<section class="empty"><h1>No services enrolled</h1></section>
{{end}}
{{with .Selected}}
<article class="panel">
<header class="panel-head">
<div><h1>{{.Service.Name}}</h1><span class="repository">{{.Service.ImageRepository}}</span></div>
<span class="{{.Health}}"><span class="nf"></span> {{.Health}}</span>
</header>
<nav class="tabs" role="tablist" aria-label="Service detail">
<button class="tab" role="tab" aria-selected="true" aria-controls="overview">Overview</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="configuration">Configuration</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="systemd">Systemd</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="operations">Operations</button>
</nav>
<section id="overview" role="tabpanel">
<div class="facts">
<section class="group"><h2>Deployment</h2>
<div class="fact"><span>Generation</span><code>{{.State.Generation}}</code></div>
<div class="fact"><span>Current</span><code>{{shortDigest .State.Current}}</code></div>
<div class="fact"><span>Rollback</span><code>{{shortDigest .State.Rollback}}</code></div>
</section>
<section class="group"><h2>Container</h2>
<div class="fact"><span>Running</span><code class="{{if .Container.Running}}healthy{{else}}unhealthy{{end}}">{{.Container.Running}}</code></div>
<div class="fact"><span>Digest</span><code>{{shorten .Container.ImageDigest}}</code></div>
<div class="fact"><span>Restarts</span><code>{{.Unit.Restarts}}</code></div>
</section>
<section class="group"><h2>Systemd</h2>
<div class="fact"><span>Unit</span><code>{{.Service.UnitName}}</code></div>
<div class="fact"><span>Active</span><code>{{.Unit.ActiveState}}</code></div>
<div class="fact"><span>Result</span><code>{{.Unit.Result}}</code></div>
</section>
</div>
</section>
<section id="configuration" role="tabpanel" hidden>
<div class="rows">
<div class="row"><span class="label">Image repository</span><code>{{.Service.ImageRepository}}</code><button class="copy nf" data-copy="{{.Service.ImageRepository}}" aria-label="Copy image repository" title="Copy"></button></div>
<div class="row"><span class="label">Container</span><code>{{.Service.ContainerName}}</code><button class="copy nf" data-copy="{{.Service.ContainerName}}" aria-label="Copy container name" title="Copy"></button></div>
<div class="row"><span class="label">Readiness status</span><code class="{{.Health}}">{{.Health}}</code><span></span></div>
<div class="row"><span class="label">Probation</span><code>{{probation .Service}}</code><span></span></div>
</div>
<p class="boundary">Raw Quadlets and environment values are excluded because they may contain secret references or host internals.</p>
</section>
<section id="systemd" role="tabpanel" hidden>
<div class="rows">
<div class="row"><span class="label">Unit</span><code>{{.Service.UnitName}}</code><button class="copy nf" data-copy="{{.Service.UnitName}}" aria-label="Copy unit name" title="Copy"></button></div>
<div class="row"><span class="label">Load state</span><code>{{.Unit.LoadState}}</code><span></span></div>
<div class="row"><span class="label">Active state</span><code>{{.Unit.ActiveState}}</code><span></span></div>
<div class="row"><span class="label">Result</span><code>{{.Unit.Result}}</code><span></span></div>
<div class="row"><span class="label">NRestarts</span><code>{{.Unit.Restarts}}</code><span></span></div>
</div>
<p class="boundary">Toad reads its own user manager over D-Bus. It does not mount or expose the host journal.</p>
</section>
<section id="operations" role="tabpanel" hidden>
{{range .Operations}}
<details class="operation">
<summary><strong class="{{.Operation.Phase}}">{{.Operation.Phase}}</strong><span>generation {{.Operation.Generation}}{{with .Operation.Reason}} · {{.}}{{end}}</span><time>{{elapsed .Operation.UpdatedAt}}</time></summary>
{{if .Log}}<div class="log-tools"><button class="copy nf" data-copy-target="log-{{.Operation.ID}}" aria-label="Copy operation log" title="Copy log"></button></div><pre class="log" id="log-{{.Operation.ID}}">{{.Log}}</pre>{{end}}
</details>
{{else}}<p class="empty">No operations recorded</p>{{end}}
</section>
</article>
{{end}}
</main>
</body>
</html>