diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-25 09:45:53 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-25 09:45:53 +0200 |
| commit | 0136c4528316d62810382d38bb007496cba97c24 (patch) | |
| tree | 705e1e697d6f0e2d553f58905b3ad6b6427566e3 /internal/tui | |
| parent | 72ff234e97b16485553a79a876690a359058b110 (diff) | |
Refine overview layout and right-align sparkline history
Diffstat (limited to 'internal/tui')
| -rw-r--r-- | internal/tui/dashboard/overview.go | 25 | ||||
| -rw-r--r-- | internal/tui/dashboard/sparkline.go | 24 | ||||
| -rw-r--r-- | internal/tui/dashboard/sparkline_test.go | 13 |
3 files changed, 44 insertions, 18 deletions
diff --git a/internal/tui/dashboard/overview.go b/internal/tui/dashboard/overview.go index 7cbc7fe..f4ec5bc 100644 --- a/internal/tui/dashboard/overview.go +++ b/internal/tui/dashboard/overview.go @@ -15,6 +15,9 @@ func renderOverview(snap *statsengine.Snapshot, width, height int) string { if snap == nil { return common.PanelStyle.Render("Overview: waiting for stats...") } + if width <= 0 { + width = 80 + } boxWidth := summaryBoxWidth(width) box1 := renderSyscallBox(snap, boxWidth) @@ -38,18 +41,18 @@ func renderOverview(snap *statsengine.Snapshot, width, height int) string { latencyHist := "Latency buckets: " + summarizeHistogramBrief(snap.LatencyHistogram) gapHist := "Gap buckets: " + summarizeHistogramBrief(snap.GapHistogram) + panel := common.PanelStyle.Width(width) + sparkPanel := panel.Render(strings.Join([]string{latencySpark, "", gapSpark, "", throughputSpark}, "\n")) + topPanel := panel.Render(strings.Join([]string{topSyscalls, topFiles, topProcesses}, "\n")) + histPanel := panel.Render(strings.Join([]string{latencyHist, gapHist}, "\n")) + return strings.Join( []string{ row, common.HighlightStyle.Render(trends), - common.PanelStyle.Render(latencySpark), - common.PanelStyle.Render(gapSpark), - common.PanelStyle.Render(throughputSpark), - common.PanelStyle.Render(topSyscalls), - common.PanelStyle.Render(topFiles), - common.PanelStyle.Render(topProcesses), - common.PanelStyle.Render(latencyHist), - common.PanelStyle.Render(gapHist), + sparkPanel, + topPanel, + histPanel, }, "\n", ) @@ -67,7 +70,7 @@ func renderSyscallBox(snap *statsengine.Snapshot, width int) string { snap.SyscallRatePerSec, generatedAt, ) - return common.PanelStyle.Width(width).Render(content) + return common.PanelStyle.Width(width).Height(5).Render(content) } func renderBytesBox(snap *statsengine.Snapshot, width int) string { @@ -77,7 +80,7 @@ func renderBytesBox(snap *statsengine.Snapshot, width int) string { formatBytes(snap.WriteBytesPerSec), formatBytes(float64(snap.TotalBytes)), ) - return common.PanelStyle.Width(width).Render(content) + return common.PanelStyle.Width(width).Height(5).Render(content) } func renderErrorBox(snap *statsengine.Snapshot, width int) string { @@ -93,7 +96,7 @@ func renderErrorBox(snap *statsengine.Snapshot, width int) string { snap.LatencyMeanNs, snap.GapMeanNs, ) - return common.PanelStyle.Width(width).Render(content) + return common.PanelStyle.Width(width).Height(5).Render(content) } func trendWithArrow(trend statsengine.Trend) string { diff --git a/internal/tui/dashboard/sparkline.go b/internal/tui/dashboard/sparkline.go index b94d84f..fad86e2 100644 --- a/internal/tui/dashboard/sparkline.go +++ b/internal/tui/dashboard/sparkline.go @@ -11,15 +11,23 @@ func renderSparkline(data []float64, width int) string { } samples := sampleForWidth(data, width) + leftPad := 0 + if len(samples) < width { + leftPad = width - len(samples) + } min, max := minMax(samples) if min == max { - top := repeatRune(' ', len(samples)) - bottom := repeatRune('ā', len(samples)) + top := repeatRune(' ', width) + bottom := repeatRune(' ', leftPad) + repeatRune('ā', len(samples)) return top + "\n" + bottom } - top := make([]rune, len(samples)) - bottom := make([]rune, len(samples)) + top := make([]rune, width) + bottom := make([]rune, width) + for i := 0; i < leftPad; i++ { + top[i] = ' ' + bottom[i] = ' ' + } scale := 16.0 denom := max - min for i, value := range samples { @@ -39,9 +47,13 @@ func renderSparkline(data []float64, width int) string { if bottomLevel > 8 { bottomLevel = 8 } + if bottomLevel == 0 { + bottomLevel = 1 + } - top[i] = sparkRowChars[topLevel] - bottom[i] = sparkRowChars[bottomLevel] + col := leftPad + i + top[col] = sparkRowChars[topLevel] + bottom[col] = sparkRowChars[bottomLevel] } return string(top) + "\n" + string(bottom) } diff --git a/internal/tui/dashboard/sparkline_test.go b/internal/tui/dashboard/sparkline_test.go index 97dac03..e1fb316 100644 --- a/internal/tui/dashboard/sparkline_test.go +++ b/internal/tui/dashboard/sparkline_test.go @@ -16,7 +16,7 @@ func TestRenderSparklineEmptyOrInvalidWidth(t *testing.T) { func TestRenderSparklineSingleValue(t *testing.T) { got := renderSparkline([]float64{10}, 8) - if got != " \nā" { + if got != " \n ā" { t.Fatalf("expected two-line constant sparkline, got %q", got) } } @@ -28,6 +28,17 @@ func TestRenderSparklineAllEqualValues(t *testing.T) { } } +func TestRenderSparklineRightAlignsShortHistory(t *testing.T) { + got := renderSparkline([]float64{1, 2, 3}, 6) + lines := strings.Split(got, "\n") + if len(lines) != 2 { + t.Fatalf("expected 2 lines, got %q", got) + } + if !strings.HasPrefix(lines[1], " ") { + t.Fatalf("expected left padding for short history, got %q", lines[1]) + } +} + func TestRenderSparklineRespectsWidthTruncation(t *testing.T) { got := renderSparkline([]float64{1, 2, 3, 4, 5, 6, 7, 8}, 4) lines := strings.Split(got, "\n") |
