initial commit

This commit is contained in:
2026-08-16 21:18:45 -05:00
commit 1e05a01bcf
122 changed files with 29178 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
{{define "content"}}
{{$c := .Data.Stats}}{{$csrf := .CSRF}}
<div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-4">
<div>
<h1 class="page-title">Cache</h1>
<p class="text-body-secondary mb-0">Responses held in memory to answer repeat queries instantly.</p>
</div>
<div class="d-flex flex-wrap gap-2">
<a href="/settings/cache" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-gear me-1"></i>Cache settings
</a>
{{template "confirmform" dict
"Action" "/cache/flush" "CSRF" $csrf
"Label" "Flush entire cache" "Icon" "bi-trash"
"Class" "btn btn-sm btn-danger"
"Message" "Flush every cached response? Queries will go back upstream until the cache refills."}}
</div>
</div>
{{if not $c.Enabled}}
<div class="alert alert-secondary d-flex align-items-center gap-2">
<i class="bi bi-info-circle"></i>
<div>The cache is turned off. Every recursive query is forwarded upstream.</div>
</div>
{{end}}
<div class="row g-3 mb-4">
{{template "stat" dict "Label" "Entries" "Value" (num $c.Entries) "Icon" "bi-database"
"Sub" (printf "limit %s" (num $c.MaxEntries))}}
{{template "stat" dict "Label" "Hit rate" "Value" (pct $c.HitRate) "Icon" "bi-lightning-charge" "Tone" "success"}}
{{template "stat" dict "Label" "Hits" "Value" (num $c.Hits) "Icon" "bi-check-circle" "Tone" "success"
"Sub" (printf "%s served stale" (num $c.StaleHits))}}
{{template "stat" dict "Label" "Misses" "Value" (num $c.Misses) "Icon" "bi-x-circle"}}
{{template "stat" dict "Label" "Memory estimate" "Value" (bytes $c.Bytes) "Icon" "bi-memory"}}
{{template "stat" dict "Label" "Insertions" "Value" (num $c.Insertions) "Icon" "bi-box-arrow-in-down"}}
{{template "stat" dict "Label" "Evictions" "Value" (num $c.Evictions) "Icon" "bi-box-arrow-up"
"Sub" "least recently used first"}}
{{template "stat" dict "Label" "Expirations" "Value" (num $c.Expirations) "Icon" "bi-hourglass-bottom"}}
</div>
<div class="card">
<div class="card-header d-flex flex-wrap justify-content-between align-items-center gap-2">
<span>Cached entries</span>
<span class="small text-body-secondary">
TTL clamped to {{$c.MinTTL}}{{$c.MaxTTL}}s · negative {{$c.NegativeTTL}}s
{{if $c.ServeStale}}· serves stale for {{$c.StaleTTL}}s{{end}}
{{if $c.Prefetch}}· prefetch on{{end}}
</span>
</div>
<div class="card-body">
<form method="get" data-autosubmit class="row g-2 align-items-center mb-3">
<div class="col-12 col-md-6 col-lg-4">
<div class="input-group input-group-sm">
<span class="input-group-text"><i class="bi bi-search"></i></span>
<input type="search" class="form-control" name="q" value="{{.Data.Search}}"
placeholder="Search cached names..." aria-label="Search cached entries">
</div>
</div>
<div class="col-auto">
<noscript><button class="btn btn-sm btn-outline-secondary" type="submit">Search</button></noscript>
</div>
</form>
{{if .Data.Entries}}
<div class="table-responsive">
<table class="table table-hover align-middle table-compact">
<thead>
<tr>
<th>Name</th><th>Type</th><th>Result</th>
<th class="text-end">Answers</th><th class="text-end">TTL left</th>
<th class="text-end">Size</th><th>Cached</th><th class="row-actions">Actions</th>
</tr>
</thead>
<tbody>
{{range .Data.Entries}}
<tr {{if .Stale}}class="is-disabled"{{end}}>
<td class="mono truncate-cell" title="{{.Name}}">{{trimDot .Name}}</td>
<td>
<span class="type-chip {{typeBadge .Type}}">{{.Type}}</span>
{{if .DO}}<span class="badge text-bg-light text-dark ms-1" title="DNSSEC answer">+do</span>{{end}}
</td>
<td>
<span class="badge {{rcodeBadge .Rcode}}">{{.Rcode}}</span>
{{if .Negative}}<span class="badge text-bg-light text-dark ms-1">negative</span>{{end}}
</td>
<td class="text-end">{{.Answers}}</td>
<td class="text-end">
{{if .Stale}}<span class="text-warning">stale</span>{{else}}{{.TTL}}s{{end}}
</td>
<td class="text-end small text-body-secondary">{{bytes .Size}}</td>
<td class="small text-body-secondary">{{timeAgo .Stored}}</td>
<td class="row-actions">
{{template "confirmform" dict
"Action" "/cache/delete" "CSRF" $csrf
"Icon" "bi-trash" "Title" "Remove this entry"
"Fields" (dict "name" .Name "type" .Type "dnssec" (boolstr .DO))
"Message" (printf "Remove the cached %s answer for %s?" .Type (trimDot .Name))}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{template "pagination" dict "P" .Data.Pagination "Q" .Query}}
{{else if .Data.Search}}
{{template "empty" dict "Icon" "bi-search" "Title" "Nothing cached matches that name"
"Message" "The entry may have expired, or the name may never have been queried."}}
{{else}}
{{template "empty" dict "Icon" "bi-lightning-charge" "Title" "The cache is empty"
"Message" "Recursive answers are cached here as clients query them."}}
{{end}}
</div>
</div>
{{end}}