Add a dashboard and backup download to the web UI
Metric history (5s to 1h tiers, persisted), uplink status, ping targets, DHCP leases, and a tar.gz backup of the state directory. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeFqV9dZrK6nipHkPfyM4F
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
{{define "dashboard"}}
|
||||
{{$d := .Data.Dashboard}}{{$u := $d.Snap.Uplink}}{{$sys := $d.Snap.System}}
|
||||
<div class="ranges" role="group" aria-label="Time range">
|
||||
{{range $d.Ranges}}<a href="/?range={{.}}" data-range="{{.}}"{{if eq . $d.Range}} class="active" aria-current="true"{{end}}>{{.}}</a>{{end}}
|
||||
</div>
|
||||
|
||||
<div class="cards">
|
||||
{{if $d.Snap.Time.IsZero}}
|
||||
<section class="card"><h2>Internet</h2><p class="state">Collecting…</p></section>
|
||||
{{else}}
|
||||
<section class="card {{if and $u.Connected (or $u.Reachable (not $u.Checked))}}up{{else if $u.Connected}}degraded{{else}}down{{end}}">
|
||||
<h2>Internet</h2>
|
||||
<p class="state">
|
||||
{{if and $u.Connected (or $u.Reachable (not $u.Checked))}}Connected
|
||||
{{else if $u.Connected}}Connected, but no answer from the internet
|
||||
{{else if not $u.Exists}}{{if eq $u.Type "pppoe"}}Not connected: no PPPoE session{{else}}Not connected: {{$u.Device}} is missing{{end}}
|
||||
{{else}}Not connected{{end}}
|
||||
{{if not $u.Since.IsZero}}<span class="muted">for {{ago $u.Since}}</span>{{end}}
|
||||
</p>
|
||||
<dl>
|
||||
<dt>Uplink</dt><dd>{{$u.Device}} ({{if eq $u.Type "pppoe"}}PPPoE{{else}}DHCP{{end}})</dd>
|
||||
{{if $u.IPv4}}<dt>IPv4</dt><dd>{{join $u.IPv4 ", "}}</dd>{{end}}
|
||||
{{if $u.IPv6}}<dt>IPv6</dt><dd>{{join $u.IPv6 ", "}}</dd>{{end}}
|
||||
{{if $u.Gateway}}<dt>Gateway</dt><dd>{{$u.Gateway}}</dd>{{end}}
|
||||
{{range $d.Snap.Pings}}
|
||||
<dt>Ping {{.Target}}</dt><dd>{{if .OK}}{{ms .RTT}}{{else if .Address}}<span class="bad">no answer</span>{{else}}<span class="muted">no address</span>{{end}}{{if and .Address (ne .Address .Target)}} <span class="muted">{{.Address}}</span>{{end}}</dd>
|
||||
{{end}}
|
||||
</dl>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
<section class="card">
|
||||
<h2>System</h2>
|
||||
<dl>
|
||||
<dt>Uptime</dt><dd>{{age $sys.Uptime}}</dd>
|
||||
<dt>Load</dt><dd>{{$sys.Load}}</dd>
|
||||
<dt>CPU</dt><dd>{{value $sys.CPU "%"}}</dd>
|
||||
{{if $sys.MemTotal}}<dt>Memory</dt><dd>{{bytes $sys.MemUsed}} of {{bytes $sys.MemTotal}}</dd>{{end}}
|
||||
{{if not (isNaN $sys.Temperature)}}<dt>Temperature</dt><dd>{{value $sys.Temperature "°C"}}</dd>{{end}}
|
||||
{{if $sys.DiskTotal}}<dt>Disk</dt><dd>{{bytes $sys.DiskUsed}} of {{bytes $sys.DiskTotal}}</dd>{{end}}
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
{{if $d.Events}}
|
||||
<section class="card">
|
||||
<h2>Connection log</h2>
|
||||
<ul class="events">
|
||||
{{range $d.Events}}<li><span class="{{if .Connected}}ok{{else}}bad{{end}}">{{if .Connected}}up{{else}}down{{end}}</span> {{.Time.Local.Format "Jan 2 15:04:05"}}{{if .Detail}} <span class="muted">{{.Detail}}</span>{{end}}</li>{{end}}
|
||||
</ul>
|
||||
</section>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<section>
|
||||
<h2>DHCP clients</h2>
|
||||
{{if $d.Leases}}
|
||||
<div class="scroll">
|
||||
<table class="leases">
|
||||
<tr><th>Name</th><th>Address</th><th>MAC</th><th>LAN</th><th>Lease ends in</th></tr>
|
||||
{{range $d.Leases}}<tr><td>{{or .Hostname "–"}}</td><td>{{.Address}}</td><td><code>{{.MAC}}</code></td><td>{{.LAN}}</td><td>{{until .Expires}}</td></tr>{{end}}
|
||||
</table>
|
||||
</div>
|
||||
{{else}}<p class="muted">No active leases.</p>{{end}}
|
||||
</section>
|
||||
|
||||
<div class="charts">
|
||||
{{range $d.Charts}}
|
||||
<figure class="chart">
|
||||
<figcaption><strong>{{.Title}}</strong>
|
||||
<span class="legend">{{range .Lines}}<span class="key {{.Class}}">{{.Label}} <b>{{.Now}}</b></span>{{end}}</span>
|
||||
</figcaption>
|
||||
<svg viewBox="-64 -8 690 150" role="img" aria-label="{{.Title}}">
|
||||
{{range .YTicks}}<line class="grid" x1="0" x2="{{chartW}}" y1="{{.Pos}}" y2="{{.Pos}}"/><text class="lab" x="-6" y="{{.Pos}}" text-anchor="end" dominant-baseline="middle">{{.Label}}</text>{{end}}
|
||||
{{range .XTicks}}<text class="lab" x="{{.Pos}}" y="138" text-anchor="middle">{{.Label}}</text>{{end}}
|
||||
{{range .Lines}}<path class="line {{.Class}}" d="{{.Path}}"/>{{end}}
|
||||
{{if .Empty}}<text class="lab" x="300" y="64" text-anchor="middle">no data yet</text>{{end}}
|
||||
{{range .Cols}}<rect class="hover" x="{{.X}}" y="0" width="{{.W}}" height="{{chartH}}"><title>{{.Tip}}</title></rect>{{end}}
|
||||
</svg>
|
||||
</figure>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user