P6-01 + P6-02: agent self-update + fleet update #19

Merged
steve merged 12 commits from p6-agent-self-update into main 2026-05-07 17:49:25 +01:00
2 changed files with 28 additions and 0 deletions
Showing only changes of commit ccaccd840a - Show all commits
@@ -11,6 +11,7 @@ import (
"time"
"gitea.dcglab.co.uk/steve/restic-manager/internal/store"
"gitea.dcglab.co.uk/steve/restic-manager/internal/version"
)
func makeFilterHosts() []store.Host {
@@ -98,6 +99,23 @@ func TestSortDashboardHostsColumns(t *testing.T) {
}
}
// TestFilterAndSortDashboardUpdatesBehind: ?updates=behind narrows
// to hosts whose agent_version is non-empty AND != server's version.
func TestFilterAndSortDashboardUpdatesBehind(t *testing.T) {
t.Parallel()
hosts := []store.Host{
{ID: "01a", Name: "alpha", AgentVersion: "v0.0.1", Status: "online"},
{ID: "01b", Name: "bravo", AgentVersion: version.Version, Status: "online"},
{ID: "01c", Name: "charlie", AgentVersion: "", Status: "online"}, // never seen
{ID: "01d", Name: "delta", AgentVersion: "v0.0.1", Status: "offline"},
}
got := filterAndSortDashboardHosts(hosts, dashboardFilter{Updates: "behind", Sort: "name", Dir: "asc"})
// alpha + delta both behind; bravo (current) and charlie (empty) excluded.
if len(got) != 2 || got[0].Name != "alpha" || got[1].Name != "delta" {
t.Errorf("updates=behind: got %v", namesOf(got))
}
}
// TestParseDashboardFilterDefaults: empty query gives sort=name asc.
func TestParseDashboardFilterDefaults(t *testing.T) {
t.Parallel()
+10
View File
@@ -66,6 +66,16 @@
</div>
</div>
{{/* ---------- Hosts-behind hero tile (P6-18) ---------- */}}
{{if gt $page.UpdatesBehind 0}}
<div class="pt-4">
<a href="?updates=behind" class="hero-tile hero-tile--amber" style="display:inline-flex;">
<span class="hero-num">{{$page.UpdatesBehind}}</span>
<span class="hero-label">{{if eq $page.UpdatesBehind 1}}host behind{{else}}hosts behind{{end}} · review →</span>
</a>
</div>
{{end}}
{{/* ---------- Pending hosts (announce-and-approve queue) ---------- */}}
{{if gt (len $page.PendingHosts) 0}}
<div class="pt-6">