summaryrefslogtreecommitdiff
path: root/internal/tui
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-05 22:18:08 +0200
committerPaul Buetow <paul@buetow.org>2026-03-05 22:18:08 +0200
commit043bbbb884560a0f91f5e12d0b7851ad60121d5a (patch)
treeb3345068b594945c777991a03876e2826175c089 /internal/tui
parent98e46348ca59de2033451b844a4f592f1f9e5433 (diff)
task 350: add TabFlame tab infrastructure
Diffstat (limited to 'internal/tui')
-rw-r--r--internal/tui/common/keys.go5
-rw-r--r--internal/tui/common/keys_test.go24
-rw-r--r--internal/tui/dashboard/model.go4
-rw-r--r--internal/tui/dashboard/model_test.go4
-rw-r--r--internal/tui/dashboard/tabs.go7
-rw-r--r--internal/tui/dashboard/tabs_test.go15
-rw-r--r--internal/tui/tui_test.go4
7 files changed, 50 insertions, 13 deletions
diff --git a/internal/tui/common/keys.go b/internal/tui/common/keys.go
index 31fdf64..6b0ae27 100644
--- a/internal/tui/common/keys.go
+++ b/internal/tui/common/keys.go
@@ -44,7 +44,7 @@ func DefaultKeyMap() KeyMap {
Four: key.NewBinding(key.WithKeys("4"), key.WithHelp("4", "processes")),
Five: key.NewBinding(key.WithKeys("5"), key.WithHelp("5", "lat+gaps")),
Six: key.NewBinding(key.WithKeys("6"), key.WithHelp("6", "stream")),
- Seven: key.NewBinding(key.WithKeys("7"), key.WithHelp("7", "stream")),
+ Seven: key.NewBinding(key.WithKeys("7"), key.WithHelp("7", "flame")),
DirGroup: key.NewBinding(key.WithKeys("d"), key.WithHelp("d", "dir group")),
SelectPID: key.NewBinding(key.WithKeys("p"), key.WithHelp("p", "select pid")),
SelectTID: key.NewBinding(key.WithKeys("t"), key.WithHelp("t", "select tid")),
@@ -83,6 +83,7 @@ func (k KeyMap) DashboardStatusHelpSections() []HelpSection {
k.Four,
k.Five,
k.Six,
+ k.Seven,
k.SelectPID,
k.SelectTID,
k.Probes,
@@ -126,7 +127,7 @@ func (k KeyMap) DashboardFullHelp() [][]key.Binding {
controls = append(controls, k.DirGroup, k.SelectPID, k.SelectTID, k.Probes, k.Refresh, k.Quit)
return [][]key.Binding{
- {k.One, k.Two, k.Three, k.Four, k.Five, k.Six},
+ {k.One, k.Two, k.Three, k.Four, k.Five, k.Six, k.Seven},
controls,
{
helpTextBinding("space", "stream pause"),
diff --git a/internal/tui/common/keys_test.go b/internal/tui/common/keys_test.go
index 42e47ab..e043f9e 100644
--- a/internal/tui/common/keys_test.go
+++ b/internal/tui/common/keys_test.go
@@ -23,6 +23,11 @@ func TestDefaultKeyMapIncludesDirGroupBinding(t *testing.T) {
if selectTIDHelp.Key != "t" || selectTIDHelp.Desc != "select tid" {
t.Fatalf("unexpected select tid binding help: key=%q desc=%q", selectTIDHelp.Key, selectTIDHelp.Desc)
}
+
+ flameHelp := keys.Seven.Help()
+ if flameHelp.Key != "7" || flameHelp.Desc != "flame" {
+ t.Fatalf("unexpected flame binding help: key=%q desc=%q", flameHelp.Key, flameHelp.Desc)
+ }
}
func TestDashboardFullHelpIncludesDirGroupBinding(t *testing.T) {
@@ -33,6 +38,7 @@ func TestDashboardFullHelpIncludesDirGroupBinding(t *testing.T) {
}
found := false
+ foundSeven := false
for _, binding := range groups[1] {
help := binding.Help()
if help.Key == "d" && help.Desc == "dir group" {
@@ -44,6 +50,17 @@ func TestDashboardFullHelpIncludesDirGroupBinding(t *testing.T) {
t.Fatalf("expected dir group binding in dashboard full help controls")
}
+ for _, binding := range groups[0] {
+ help := binding.Help()
+ if help.Key == "7" && help.Desc == "flame" {
+ foundSeven = true
+ break
+ }
+ }
+ if !foundSeven {
+ t.Fatalf("expected flame tab binding in dashboard full help tabs")
+ }
+
found = false
for _, binding := range groups[1] {
help := binding.Help()
@@ -86,6 +103,7 @@ func TestDashboardStatusHelpIncludesProbesBinding(t *testing.T) {
short := keys.DashboardStatusHelp()
found := false
foundSelectTID := false
+ foundSeven := false
for _, binding := range short {
help := binding.Help()
if help.Key == "o" && help.Desc == "probes" {
@@ -94,6 +112,9 @@ func TestDashboardStatusHelpIncludesProbesBinding(t *testing.T) {
if help.Key == "t" && help.Desc == "select tid" {
foundSelectTID = true
}
+ if help.Key == "7" && help.Desc == "flame" {
+ foundSeven = true
+ }
}
if !found {
t.Fatalf("expected probes binding in dashboard short help")
@@ -101,4 +122,7 @@ func TestDashboardStatusHelpIncludesProbesBinding(t *testing.T) {
if !foundSelectTID {
t.Fatalf("expected select tid binding in dashboard short help")
}
+ if !foundSeven {
+ t.Fatalf("expected flame tab binding in dashboard short help")
+ }
}
diff --git a/internal/tui/dashboard/model.go b/internal/tui/dashboard/model.go
index f097da7..0a9915b 100644
--- a/internal/tui/dashboard/model.go
+++ b/internal/tui/dashboard/model.go
@@ -166,7 +166,7 @@ func (m Model) handleKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
m.activeTab = TabStream
handled = true
case key.Matches(msg, m.keys.Seven):
- m.activeTab = TabStream
+ m.activeTab = TabFlame
handled = true
case key.Matches(msg, m.keys.Refresh):
snap := m.snapshot()
@@ -378,6 +378,8 @@ func renderActiveTab(tab Tab, snap *statsengine.Snapshot, streamModel *eventstre
return renderProcessesWithOffset(snap, width, height, processesOffset, pidFilter)
case TabLatency:
return renderLatencyGapsTab(snap, width, height)
+ case TabFlame:
+ return common.PanelStyle.Render("Flame: waiting for model...")
default:
return common.PanelStyle.Render("Unknown tab")
}
diff --git a/internal/tui/dashboard/model_test.go b/internal/tui/dashboard/model_test.go
index 642c702..c9a1cb9 100644
--- a/internal/tui/dashboard/model_test.go
+++ b/internal/tui/dashboard/model_test.go
@@ -48,8 +48,8 @@ func TestKeySwitchingChangesActiveTab(t *testing.T) {
next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'7'}[0], Text: string([]rune{'7'})})
model = next.(Model)
- if model.activeTab != TabStream {
- t.Fatalf("expected stream tab on key 7, got %v", model.activeTab)
+ if model.activeTab != TabFlame {
+ t.Fatalf("expected flame tab on key 7, got %v", model.activeTab)
}
next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'6'}[0], Text: string([]rune{'6'})})
diff --git a/internal/tui/dashboard/tabs.go b/internal/tui/dashboard/tabs.go
index 62c7762..731e21f 100644
--- a/internal/tui/dashboard/tabs.go
+++ b/internal/tui/dashboard/tabs.go
@@ -25,6 +25,8 @@ const (
TabLatency
// TabStream is the live event stream tab.
TabStream
+ // TabFlame is the live flamegraph tab.
+ TabFlame
)
var allTabs = []Tab{
@@ -34,6 +36,7 @@ var allTabs = []Tab{
TabProcesses,
TabLatency,
TabStream,
+ TabFlame,
}
func (t Tab) String() string {
@@ -50,6 +53,8 @@ func (t Tab) String() string {
return "Latency+Gaps"
case TabStream:
return "Stream"
+ case TabFlame:
+ return "Flame"
default:
return "Unknown"
}
@@ -192,6 +197,8 @@ func tabLabel(tab Tab, short bool) string {
return "Lat"
case TabStream:
return "Str"
+ case TabFlame:
+ return "Flm"
default:
return "Unk"
}
diff --git a/internal/tui/dashboard/tabs_test.go b/internal/tui/dashboard/tabs_test.go
index 1148103..16f8b76 100644
--- a/internal/tui/dashboard/tabs_test.go
+++ b/internal/tui/dashboard/tabs_test.go
@@ -11,17 +11,20 @@ func TestTabNavigationWraps(t *testing.T) {
if got := nextTab(TabLatency); got != TabStream {
t.Fatalf("expected next after latency+gaps to be stream, got %v", got)
}
- if got := nextTab(TabStream); got != TabOverview {
- t.Fatalf("expected wrap to overview from stream, got %v", got)
+ if got := nextTab(TabStream); got != TabFlame {
+ t.Fatalf("expected next after stream to be flame, got %v", got)
}
- if got := prevTab(TabOverview); got != TabStream {
- t.Fatalf("expected wrap to stream, got %v", got)
+ if got := nextTab(TabFlame); got != TabOverview {
+ t.Fatalf("expected wrap to overview from flame, got %v", got)
+ }
+ if got := prevTab(TabOverview); got != TabFlame {
+ t.Fatalf("expected wrap to flame, got %v", got)
}
}
func TestRenderTabBarContainsLabels(t *testing.T) {
out := renderTabBar(TabOverview, 100)
- for _, label := range []string{"Overview", "Syscalls", "Files", "Processes", "Latency+Gaps", "Stream"} {
+ for _, label := range []string{"Overview", "Syscalls", "Files", "Processes", "Latency+Gaps", "Stream", "Flame"} {
if !strings.Contains(out, label) {
t.Fatalf("expected tab label %q in tab bar", label)
}
@@ -34,7 +37,7 @@ func TestRenderTabBarSmallWidthUsesSingleLine(t *testing.T) {
if len(lines) != 1 {
t.Fatalf("expected single-line tab bar at width 70, got %d lines", len(lines))
}
- if strings.Contains(out, "6:Strea") {
+ if strings.Contains(out, "7:Flam") {
t.Fatalf("tab label should not be wrapped/split in small width output")
}
}
diff --git a/internal/tui/tui_test.go b/internal/tui/tui_test.go
index 68bfca0..610461d 100644
--- a/internal/tui/tui_test.go
+++ b/internal/tui/tui_test.go
@@ -255,7 +255,7 @@ func TestTracingStartedRebindsEventStreamSource(t *testing.T) {
next, _ = m.Update(tea.WindowSizeMsg{Width: 120, Height: 30})
m = next.(Model)
- next, _ = m.Update(tea.KeyPressMsg{Code: []rune{'7'}[0], Text: string([]rune{'7'})})
+ next, _ = m.Update(tea.KeyPressMsg{Code: []rune{'6'}[0], Text: string([]rune{'6'})})
m = next.(Model)
next, _ = m.Update(messages.StatsTickMsg{})
m = next.(Model)
@@ -429,7 +429,7 @@ func TestStreamFilterModalConsumesEKeyInsteadOfOpeningExport(t *testing.T) {
m.width = 120
m.height = 30
- next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'7'}[0], Text: string([]rune{'7'})})
+ next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'6'}[0], Text: string([]rune{'6'})})
m = next.(Model)
next, _ = m.Update(tea.KeyPressMsg{Code: []rune{'f'}[0], Text: string([]rune{'f'})})
m = next.(Model)