From f90a9e0063dbe4ca06c193aec7e7469a32e0b422 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 14 Apr 2026 22:05:08 +0300 Subject: Release 0.4.0: foo.zone HTML styling, uptime-stats section order, dashboard without full Kernel tables. - Link foo.zone stylesheet and mirror header/heading/quote layout for HTML reports. - Default -all stats order matches foo.zone (Host Uptime through Score, then KernelMajor and KernelName; full Kernel last when include-kernel). - Daemon root HTML uses include-kernel=false like the public stats page. - Refresh HTML integration fixtures. Made-with: Cursor --- fixtures/Host.Boots.HTML.expected | 11 +++++++++-- fixtures/Host.Downtime.HTML.expected | 11 +++++++++-- fixtures/Host.Lifespan.HTML.expected | 11 +++++++++-- fixtures/Host.Score.HTML.expected | 11 +++++++++-- fixtures/Host.Uptime.HTML.expected | 11 +++++++++-- fixtures/Kernel.Boots.HTML.expected | 11 +++++++++-- fixtures/Kernel.Score.HTML.expected | 11 +++++++++-- fixtures/Kernel.Uptime.HTML.expected | 11 +++++++++-- fixtures/KernelMajor.Boots.HTML.expected | 11 +++++++++-- fixtures/KernelMajor.Score.HTML.expected | 11 +++++++++-- fixtures/KernelMajor.Uptime.HTML.expected | 11 +++++++++-- fixtures/KernelName.Boots.HTML.expected | 11 +++++++++-- fixtures/KernelName.Score.HTML.expected | 11 +++++++++-- fixtures/KernelName.Uptime.HTML.expected | 11 +++++++++-- internal/daemon/daemon.go | 2 +- internal/goprecords/order.go | 21 +++++++++++++++------ internal/goprecords/order_test.go | 30 ++++++++++++++++++++++++++---- internal/goprecords/report_format.go | 19 +++++++++++++------ internal/version/version.go | 2 +- 19 files changed, 182 insertions(+), 46 deletions(-) diff --git a/fixtures/Host.Boots.HTML.expected b/fixtures/Host.Boots.HTML.expected index e0b78a3..225f751 100644 --- a/fixtures/Host.Boots.HTML.expected +++ b/fixtures/Host.Boots.HTML.expected @@ -2,11 +2,18 @@ + + Top 3 Boots's by Host -

Top 3 Boots's by Host

-

Boots is the total number of host boots over the entire lifespan.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Boots's by Host


+
+Boots is the total number of host boots over the entire lifespan.
+
+-----+----------------+-------+-----------------------------+
 | Pos |           Host | Boots |                 Last Kernel |
 +-----+----------------+-------+-----------------------------+
diff --git a/fixtures/Host.Downtime.HTML.expected b/fixtures/Host.Downtime.HTML.expected
index 72bdd43..fcb1569 100644
--- a/fixtures/Host.Downtime.HTML.expected
+++ b/fixtures/Host.Downtime.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Downtime's by Host
 
 
-

Top 3 Downtime's by Host

-

Downtime is the total downtime of a host over the entire lifespan.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Downtime's by Host


+
+Downtime is the total downtime of a host over the entire lifespan.
+
+-----+----------------+-----------------------------+--------------------------+
 | Pos |           Host |                    Downtime |              Last Kernel |
 +-----+----------------+-----------------------------+--------------------------+
diff --git a/fixtures/Host.Lifespan.HTML.expected b/fixtures/Host.Lifespan.HTML.expected
index 12bfe4d..ea34115 100644
--- a/fixtures/Host.Lifespan.HTML.expected
+++ b/fixtures/Host.Lifespan.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Lifespan's by Host
 
 
-

Top 3 Lifespan's by Host

-

Lifespan is the total uptime + the total downtime of a host.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Lifespan's by Host


+
+Lifespan is the total uptime + the total downtime of a host.
+
+-----+----------------+----------------------------+--------------------------+
 | Pos |           Host |                   Lifespan |              Last Kernel |
 +-----+----------------+----------------------------+--------------------------+
diff --git a/fixtures/Host.Score.HTML.expected b/fixtures/Host.Score.HTML.expected
index e42adf9..61c77d8 100644
--- a/fixtures/Host.Score.HTML.expected
+++ b/fixtures/Host.Score.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Score's by Host
 
 
-

Top 3 Score's by Host

-

Score is calculated by combining all other metrics.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Score's by Host


+
+Score is calculated by combining all other metrics.
+
+-----+---------+-------+-----------------------------------+
 | Pos |    Host | Score |                       Last Kernel |
 +-----+---------+-------+-----------------------------------+
diff --git a/fixtures/Host.Uptime.HTML.expected b/fixtures/Host.Uptime.HTML.expected
index 484aef6..2c38c84 100644
--- a/fixtures/Host.Uptime.HTML.expected
+++ b/fixtures/Host.Uptime.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Uptime's by Host
 
 
-

Top 3 Uptime's by Host

-

Uptime is the total uptime of a host over the entire lifespan.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Uptime's by Host


+
+Uptime is the total uptime of a host over the entire lifespan.
+
+-----+---------+-----------------------------+-----------------------------------+
 | Pos |    Host |                      Uptime |                       Last Kernel |
 +-----+---------+-----------------------------+-----------------------------------+
diff --git a/fixtures/Kernel.Boots.HTML.expected b/fixtures/Kernel.Boots.HTML.expected
index d4e7435..e748baf 100644
--- a/fixtures/Kernel.Boots.HTML.expected
+++ b/fixtures/Kernel.Boots.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Boots's by Kernel
 
 
-

Top 3 Boots's by Kernel

-

Boots is the total number of host boots over the entire lifespan.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Boots's by Kernel


+
+Boots is the total number of host boots over the entire lifespan.
+
+-----+------------------------------+-------+
 | Pos |                       Kernel | Boots |
 +-----+------------------------------+-------+
diff --git a/fixtures/Kernel.Score.HTML.expected b/fixtures/Kernel.Score.HTML.expected
index 2446cfe..0aaa7ee 100644
--- a/fixtures/Kernel.Score.HTML.expected
+++ b/fixtures/Kernel.Score.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Score's by Kernel
 
 
-

Top 3 Score's by Kernel

-

Score is calculated by combining all other metrics.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Score's by Kernel


+
+Score is calculated by combining all other metrics.
+
+-----+------------------------------------+-------+
 | Pos |                             Kernel | Score |
 +-----+------------------------------------+-------+
diff --git a/fixtures/Kernel.Uptime.HTML.expected b/fixtures/Kernel.Uptime.HTML.expected
index d57421a..84b1691 100644
--- a/fixtures/Kernel.Uptime.HTML.expected
+++ b/fixtures/Kernel.Uptime.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Uptime's by Kernel
 
 
-

Top 3 Uptime's by Kernel

-

Uptime is the total uptime of a host over the entire lifespan.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Uptime's by Kernel


+
+Uptime is the total uptime of a host over the entire lifespan.
+
+-----+------------------------------------+-----------------------------+
 | Pos |                             Kernel |                      Uptime |
 +-----+------------------------------------+-----------------------------+
diff --git a/fixtures/KernelMajor.Boots.HTML.expected b/fixtures/KernelMajor.Boots.HTML.expected
index 298f5d0..d639641 100644
--- a/fixtures/KernelMajor.Boots.HTML.expected
+++ b/fixtures/KernelMajor.Boots.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Boots's by KernelMajor
 
 
-

Top 3 Boots's by KernelMajor

-

Boots is the total number of host boots over the entire lifespan.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Boots's by KernelMajor


+
+Boots is the total number of host boots over the entire lifespan.
+
+-----+----------------+-------+
 | Pos |    KernelMajor | Boots |
 +-----+----------------+-------+
diff --git a/fixtures/KernelMajor.Score.HTML.expected b/fixtures/KernelMajor.Score.HTML.expected
index 9aa35d0..fc5362c 100644
--- a/fixtures/KernelMajor.Score.HTML.expected
+++ b/fixtures/KernelMajor.Score.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Score's by KernelMajor
 
 
-

Top 3 Score's by KernelMajor

-

Score is calculated by combining all other metrics.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Score's by KernelMajor


+
+Score is calculated by combining all other metrics.
+
+-----+----------------+-------+
 | Pos |    KernelMajor | Score |
 +-----+----------------+-------+
diff --git a/fixtures/KernelMajor.Uptime.HTML.expected b/fixtures/KernelMajor.Uptime.HTML.expected
index c77248e..6608613 100644
--- a/fixtures/KernelMajor.Uptime.HTML.expected
+++ b/fixtures/KernelMajor.Uptime.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Uptime's by KernelMajor
 
 
-

Top 3 Uptime's by KernelMajor

-

Uptime is the total uptime of a host over the entire lifespan.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Uptime's by KernelMajor


+
+Uptime is the total uptime of a host over the entire lifespan.
+
+-----+----------------+-----------------------------+
 | Pos |    KernelMajor |                      Uptime |
 +-----+----------------+-----------------------------+
diff --git a/fixtures/KernelName.Boots.HTML.expected b/fixtures/KernelName.Boots.HTML.expected
index 298d9b7..37c38a1 100644
--- a/fixtures/KernelName.Boots.HTML.expected
+++ b/fixtures/KernelName.Boots.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Boots's by KernelName
 
 
-

Top 3 Boots's by KernelName

-

Boots is the total number of host boots over the entire lifespan.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Boots's by KernelName


+
+Boots is the total number of host boots over the entire lifespan.
+
+-----+------------+-------+
 | Pos | KernelName | Boots |
 +-----+------------+-------+
diff --git a/fixtures/KernelName.Score.HTML.expected b/fixtures/KernelName.Score.HTML.expected
index 483414a..eae7811 100644
--- a/fixtures/KernelName.Score.HTML.expected
+++ b/fixtures/KernelName.Score.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Score's by KernelName
 
 
-

Top 3 Score's by KernelName

-

Score is calculated by combining all other metrics.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Score's by KernelName


+
+Score is calculated by combining all other metrics.
+
+-----+------------+-------+
 | Pos | KernelName | Score |
 +-----+------------+-------+
diff --git a/fixtures/KernelName.Uptime.HTML.expected b/fixtures/KernelName.Uptime.HTML.expected
index 862be60..2c0bcf4 100644
--- a/fixtures/KernelName.Uptime.HTML.expected
+++ b/fixtures/KernelName.Uptime.HTML.expected
@@ -2,11 +2,18 @@
 
 
 
+
+
 Top 3 Uptime's by KernelName
 
 
-

Top 3 Uptime's by KernelName

-

Uptime is the total uptime of a host over the entire lifespan.

+

+Dashboard | foo.zone | Report API +

+

Top 3 Uptime's by KernelName


+
+Uptime is the total uptime of a host over the entire lifespan.
+
+-----+------------+-----------------------------+
 | Pos | KernelName |                      Uptime |
 +-----+------------+-----------------------------+
diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go
index 63d80d4..e4f07f6 100644
--- a/internal/daemon/daemon.go
+++ b/internal/daemon/daemon.go
@@ -201,7 +201,7 @@ func root(statsDir string) http.HandlerFunc {
 			Limit:         20,
 			OutputFormat:  goprecords.FormatHTML,
 			All:           true,
-			IncludeKernel: true,
+			IncludeKernel: false,
 		}
 		var buf bytes.Buffer
 		if err := goprecords.WriteReports(&buf, aggregates, cfg); err != nil {
diff --git a/internal/goprecords/order.go b/internal/goprecords/order.go
index a20e5f9..6397e06 100644
--- a/internal/goprecords/order.go
+++ b/internal/goprecords/order.go
@@ -83,11 +83,20 @@ func StatsOrderList(statsOrder string) ([]CategoryMetric, error) {
 }
 
 func defaultStatsOrder() []CategoryMetric {
-	var out []CategoryMetric
-	for _, c := range []Category{CategoryHost, CategoryKernel, CategoryKernelMajor, CategoryKernelName} {
-		for _, m := range []Metric{MetricBoots, MetricUptime, MetricScore, MetricDowntime, MetricLifespan} {
-			out = append(out, CategoryMetric{c, m})
-		}
+	return []CategoryMetric{
+		{CategoryHost, MetricUptime},
+		{CategoryHost, MetricLifespan},
+		{CategoryHost, MetricDowntime},
+		{CategoryHost, MetricBoots},
+		{CategoryHost, MetricScore},
+		{CategoryKernelMajor, MetricBoots},
+		{CategoryKernelMajor, MetricUptime},
+		{CategoryKernelMajor, MetricScore},
+		{CategoryKernelName, MetricBoots},
+		{CategoryKernelName, MetricUptime},
+		{CategoryKernelName, MetricScore},
+		{CategoryKernel, MetricBoots},
+		{CategoryKernel, MetricUptime},
+		{CategoryKernel, MetricScore},
 	}
-	return out
 }
diff --git a/internal/goprecords/order_test.go b/internal/goprecords/order_test.go
index c085723..0a7d5cb 100644
--- a/internal/goprecords/order_test.go
+++ b/internal/goprecords/order_test.go
@@ -50,15 +50,34 @@ func TestParseStatsOrder(t *testing.T) {
 }
 
 func TestStatsOrderList(t *testing.T) {
-	// Empty string returns default order (all category×metric pairs).
+	wantDefaultPrefix := []CategoryMetric{
+		{CategoryHost, MetricUptime},
+		{CategoryHost, MetricLifespan},
+		{CategoryHost, MetricDowntime},
+		{CategoryHost, MetricBoots},
+		{CategoryHost, MetricScore},
+		{CategoryKernelMajor, MetricBoots},
+		{CategoryKernelMajor, MetricUptime},
+		{CategoryKernelMajor, MetricScore},
+		{CategoryKernelName, MetricBoots},
+		{CategoryKernelName, MetricUptime},
+		{CategoryKernelName, MetricScore},
+		{CategoryKernel, MetricBoots},
+		{CategoryKernel, MetricUptime},
+		{CategoryKernel, MetricScore},
+	}
 	got, err := StatsOrderList("")
 	if err != nil {
 		t.Fatalf("StatsOrderList(\"\"): %v", err)
 	}
-	if len(got) == 0 {
-		t.Error("StatsOrderList(\"\"): got empty order")
+	if len(got) != len(wantDefaultPrefix) {
+		t.Fatalf("StatsOrderList(\"\"): len=%d want %d", len(got), len(wantDefaultPrefix))
+	}
+	for i := range wantDefaultPrefix {
+		if got[i] != wantDefaultPrefix[i] {
+			t.Errorf("StatsOrderList(\"\")[%d] = %v; want %v", i, got[i], wantDefaultPrefix[i])
+		}
 	}
-	// Custom order: Host:Uptime first, then rest of default.
 	got, err = StatsOrderList("Host:Uptime")
 	if err != nil {
 		t.Fatalf("StatsOrderList(\"Host:Uptime\"): %v", err)
@@ -69,4 +88,7 @@ func TestStatsOrderList(t *testing.T) {
 	if got[0].Category != CategoryHost || got[0].Metric != MetricUptime {
 		t.Errorf("StatsOrderList(\"Host:Uptime\")[0] = %v; want Host:Uptime", got[0])
 	}
+	if got[1] != (CategoryMetric{CategoryHost, MetricLifespan}) {
+		t.Errorf("StatsOrderList(\"Host:Uptime\")[1] = %v; want Host:Lifespan", got[1])
+	}
 }
diff --git a/internal/goprecords/report_format.go b/internal/goprecords/report_format.go
index 0d5e4dd..eb2c49c 100644
--- a/internal/goprecords/report_format.go
+++ b/internal/goprecords/report_format.go
@@ -44,19 +44,26 @@ func (r reportBuilder) formatReportHTML(rows []tableRow, hasLastKernel bool) str
 	desc := MetricDescription(r.metric)
 
 	var b strings.Builder
-	b.WriteString("\n\n\n\n")
+	b.WriteString("<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n")
+	b.WriteString("<link rel=\"shortcut icon\" type=\"image/gif\" href=\"https://foo.zone/favicon.ico\" />\n")
+	b.WriteString("<link rel=\"stylesheet\" href=\"https://foo.zone/style.css\" />\n<title>")
 	b.WriteString(template.HTMLEscapeString(title))
-	b.WriteString("\n\n\n\n\n\n")
+	b.WriteString("

\n") + b.WriteString("Dashboard | foo.zone | ") + b.WriteString("Report API\n

\n") + b.WriteString(" style=\"display: inline\">") b.WriteString(template.HTMLEscapeString(title)) b.WriteString("\n") + b.WriteString(">
\n
\n") if desc != "" { - b.WriteString("

") + b.WriteString("") b.WriteString(template.HTMLEscapeString(desc)) - b.WriteString("

\n") + b.WriteString("
\n
\n") } b.WriteString("
")
 	b.WriteString(template.HTMLEscapeString(ascii))
diff --git a/internal/version/version.go b/internal/version/version.go
index 83b3aa0..371f9d1 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -1,4 +1,4 @@
 package version
 
 // Tag is the application release version.
-const Tag = "0.3.1"
+const Tag = "0.4.0"
-- 
cgit v1.2.3