Files
nixos-router/pkgs/router-webui/templates/dashboard.html
T
nilsandClaude Sonnet 5.5 a36cebc827 Add dynamic DNS and show the running kernel on the overview
router.ddns keeps provider records on the uplink's addresses with ddclient,
run by a timer and by a watcher that starts it when an address changes. The
Dynamic DNS page edits it; the secret is a private file on the router. The
overview shows the running kernel and says when the current system boots a
different one. PLAN.md records why the A/B image approach was not pursued.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeFqV9dZrK6nipHkPfyM4F
2026-10-30 13:35:57 +01:00

84 lines
4.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{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>
{{if $sys.Kernel}}<dt>Kernel</dt><dd>{{$sys.Kernel}}{{if $sys.KernelNext}} <span class="bad">reboot to run {{$sys.KernelNext}}</span>{{end}}</dd>{{end}}
<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}}