diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-05 19:20:18 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-05 19:20:18 +0200 |
| commit | bab716a6a5931c211fad2f17ee2f67e8d182a7fc (patch) | |
| tree | 89b16ed3bf85198dd63751d2e1e54537c9340a1b /internal/tui/dashboard | |
| parent | 96225fb6159212a8851043a08d781aba721b4e78 (diff) | |
feat(tui): migrate Bubble Tea stack to charm.land v2
Diffstat (limited to 'internal/tui/dashboard')
| -rw-r--r-- | internal/tui/dashboard/files.go | 2 | ||||
| -rw-r--r-- | internal/tui/dashboard/histogram_test.go | 2 | ||||
| -rw-r--r-- | internal/tui/dashboard/model.go | 8 | ||||
| -rw-r--r-- | internal/tui/dashboard/model_test.go | 78 | ||||
| -rw-r--r-- | internal/tui/dashboard/overview.go | 2 | ||||
| -rw-r--r-- | internal/tui/dashboard/overview_test.go | 2 | ||||
| -rw-r--r-- | internal/tui/dashboard/processes.go | 2 | ||||
| -rw-r--r-- | internal/tui/dashboard/syscalls.go | 2 | ||||
| -rw-r--r-- | internal/tui/dashboard/tabs.go | 2 |
9 files changed, 50 insertions, 50 deletions
diff --git a/internal/tui/dashboard/files.go b/internal/tui/dashboard/files.go index 80e3037..0393553 100644 --- a/internal/tui/dashboard/files.go +++ b/internal/tui/dashboard/files.go @@ -7,7 +7,7 @@ import ( "sort" "strconv" - "github.com/charmbracelet/bubbles/table" + "charm.land/bubbles/v2/table" ) type DirSnapshot struct { diff --git a/internal/tui/dashboard/histogram_test.go b/internal/tui/dashboard/histogram_test.go index 7790394..48297a2 100644 --- a/internal/tui/dashboard/histogram_test.go +++ b/internal/tui/dashboard/histogram_test.go @@ -6,7 +6,7 @@ import ( "ior/internal/statsengine" - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) func TestRenderHistogramNoBuckets(t *testing.T) { diff --git a/internal/tui/dashboard/model.go b/internal/tui/dashboard/model.go index fc9caf6..39150e8 100644 --- a/internal/tui/dashboard/model.go +++ b/internal/tui/dashboard/model.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" + "charm.land/bubbles/v2/key" + tea "charm.land/bubbletea/v2" ) const defaultRefreshMs = 1000 @@ -288,7 +288,7 @@ func (m *Model) SetPidFilter(pid int) { } // View renders the tab bar, active tab scaffold, and help bar. -func (m Model) View() string { +func (m Model) View() tea.View { width, height := common.EffectiveViewport(m.width, m.height) activeHeight := height streamModel := m.streamModel @@ -319,7 +319,7 @@ func (m Model) View() string { } else { b.WriteString(renderHelpHint(width)) } - return common.ScreenStyle.Render(b.String()) + return tea.NewView(common.ScreenStyle.Render(b.String())) } func tickCmd(d time.Duration) tea.Cmd { diff --git a/internal/tui/dashboard/model_test.go b/internal/tui/dashboard/model_test.go index 87b60e3..642c702 100644 --- a/internal/tui/dashboard/model_test.go +++ b/internal/tui/dashboard/model_test.go @@ -12,7 +12,7 @@ import ( "ior/internal/tui/eventstream" "ior/internal/tui/messages" - tea "github.com/charmbracelet/bubbletea" + tea "charm.land/bubbletea/v2" ) type fakeSnapshotSource struct { @@ -28,31 +28,31 @@ func (f *fakeSnapshotSource) Snapshot() *statsengine.Snapshot { func TestKeySwitchingChangesActiveTab(t *testing.T) { m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap()) - next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'2'}}) + next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'2'}[0], Text: string([]rune{'2'})}) model := next.(Model) if model.activeTab != TabSyscalls { t.Fatalf("expected syscalls tab, got %v", model.activeTab) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyTab}) + next, _ = model.Update(tea.KeyPressMsg{Code: tea.KeyTab}) model = next.(Model) if model.activeTab != TabFiles { t.Fatalf("expected next tab to be files, got %v", model.activeTab) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyShiftTab}) + next, _ = model.Update(tea.KeyPressMsg{Code: tea.KeyTab, Mod: tea.ModShift}) model = next.(Model) if model.activeTab != TabSyscalls { t.Fatalf("expected previous tab to be syscalls, got %v", model.activeTab) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'7'}}) + 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) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'6'}}) + next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'6'}[0], Text: string([]rune{'6'})}) model = next.(Model) if model.activeTab != TabStream { t.Fatalf("expected stream tab on key 6, got %v", model.activeTab) @@ -62,25 +62,25 @@ func TestKeySwitchingChangesActiveTab(t *testing.T) { func TestArrowAndViKeysDoNotCycleTabs(t *testing.T) { m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap()) - next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRight}) + next, _ := m.Update(tea.KeyPressMsg{Code: tea.KeyRight}) model := next.(Model) if model.activeTab != TabOverview { t.Fatalf("expected right arrow not to change tabs, got %v", model.activeTab) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'l'}}) + next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'l'}[0], Text: string([]rune{'l'})}) model = next.(Model) if model.activeTab != TabOverview { t.Fatalf("expected l not to change tabs, got %v", model.activeTab) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyLeft}) + next, _ = model.Update(tea.KeyPressMsg{Code: tea.KeyLeft}) model = next.(Model) if model.activeTab != TabOverview { t.Fatalf("expected left arrow not to change tabs, got %v", model.activeTab) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'h'}}) + next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'h'}[0], Text: string([]rune{'h'})}) model = next.(Model) if model.activeTab != TabOverview { t.Fatalf("expected h not to change tabs, got %v", model.activeTab) @@ -93,13 +93,13 @@ func TestSyscallsTabScrollsWithJK(t *testing.T) { snap := statsengine.NewSnapshot(nil, nil, nil, []statsengine.SyscallSnapshot{{Name: "read", Count: 1}, {Name: "write", Count: 1}}, nil, nil, statsengine.HistogramSnapshot{}, statsengine.HistogramSnapshot{}) m.latest = &snap - next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'j'}}) + next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'j'}[0], Text: string([]rune{'j'})}) model := next.(Model) if model.syscallsOffset != 1 { t.Fatalf("expected offset 1 after j, got %d", model.syscallsOffset) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'k'}}) + next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'k'}[0], Text: string([]rune{'k'})}) model = next.(Model) if model.syscallsOffset != 0 { t.Fatalf("expected offset 0 after k, got %d", model.syscallsOffset) @@ -112,13 +112,13 @@ func TestProcessesTabScrollsWithJK(t *testing.T) { snap := statsengine.NewSnapshot(nil, nil, nil, nil, nil, []statsengine.ProcessSnapshot{{PID: 1}, {PID: 2}}, statsengine.HistogramSnapshot{}, statsengine.HistogramSnapshot{}) m.latest = &snap - next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'j'}}) + next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'j'}[0], Text: string([]rune{'j'})}) model := next.(Model) if model.processesOffset != 1 { t.Fatalf("expected processes offset 1 after j, got %d", model.processesOffset) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'k'}}) + next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'k'}[0], Text: string([]rune{'k'})}) model = next.(Model) if model.processesOffset != 0 { t.Fatalf("expected processes offset 0 after k, got %d", model.processesOffset) @@ -131,13 +131,13 @@ func TestFilesTabScrollsWithJK(t *testing.T) { snap := statsengine.NewSnapshot(nil, nil, nil, nil, []statsengine.FileSnapshot{{Path: "/a"}, {Path: "/b"}}, nil, statsengine.HistogramSnapshot{}, statsengine.HistogramSnapshot{}) m.latest = &snap - next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'j'}}) + next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'j'}[0], Text: string([]rune{'j'})}) model := next.(Model) if model.filesOffset != 1 { t.Fatalf("expected files offset 1 after j, got %d", model.filesOffset) } - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'k'}}) + next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'k'}[0], Text: string([]rune{'k'})}) model = next.(Model) if model.filesOffset != 0 { t.Fatalf("expected files offset 0 after k, got %d", model.filesOffset) @@ -155,7 +155,7 @@ func TestFilesTabGroupedScrollUsesDirectoryOffset(t *testing.T) { }, nil, statsengine.HistogramSnapshot{}, statsengine.HistogramSnapshot{}) m.latest = &snap - next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'j'}}) + next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'j'}[0], Text: string([]rune{'j'})}) model := next.(Model) if model.filesDirOffset != 1 { t.Fatalf("expected grouped dir offset 1 after j, got %d", model.filesDirOffset) @@ -171,7 +171,7 @@ func TestStreamSpaceUnpauseSchedulesStreamTick(t *testing.T) { m.activeTab = TabStream m.streamModel.HandleKey("space") // pause - next, cmd := m.Update(tea.KeyMsg{Type: tea.KeySpace}) + next, cmd := m.Update(tea.KeyPressMsg{Code: tea.KeySpace}) _ = next if cmd == nil { t.Fatalf("expected stream tick command when unpausing stream") @@ -200,34 +200,34 @@ func TestStreamPausedSupportsJKArrowsAndPageKeys(t *testing.T) { m.streamModel.Refresh() _ = m.View() - next, _ = m.Update(tea.KeyMsg{Type: tea.KeySpace}) // pause + next, _ = m.Update(tea.KeyPressMsg{Code: tea.KeySpace}) // pause m = next.(Model) - before := rowFromStreamView(t, m.View()) + before := rowFromStreamView(t, m.View().Content) - next, _ = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'k'}}) + next, _ = m.Update(tea.KeyPressMsg{Code: []rune{'k'}[0], Text: string([]rune{'k'})}) m = next.(Model) - afterK := rowFromStreamView(t, m.View()) + afterK := rowFromStreamView(t, m.View().Content) if afterK >= before { t.Fatalf("expected k to scroll up while paused: before=%d afterK=%d", before, afterK) } - next, _ = m.Update(tea.KeyMsg{Type: tea.KeyDown}) + next, _ = m.Update(tea.KeyPressMsg{Code: tea.KeyDown}) m = next.(Model) - afterDown := rowFromStreamView(t, m.View()) + afterDown := rowFromStreamView(t, m.View().Content) if afterDown <= afterK { t.Fatalf("expected down arrow to scroll down while paused: afterK=%d afterDown=%d", afterK, afterDown) } - next, _ = m.Update(tea.KeyMsg{Type: tea.KeyPgUp}) + next, _ = m.Update(tea.KeyPressMsg{Code: tea.KeyPgUp}) m = next.(Model) - afterPgUp := rowFromStreamView(t, m.View()) + afterPgUp := rowFromStreamView(t, m.View().Content) if afterPgUp >= afterDown { t.Fatalf("expected pgup to scroll up while paused: afterDown=%d afterPgUp=%d", afterDown, afterPgUp) } - next, _ = m.Update(tea.KeyMsg{Type: tea.KeyPgDown}) + next, _ = m.Update(tea.KeyPressMsg{Code: tea.KeyPgDown}) m = next.(Model) - afterPgDown := rowFromStreamView(t, m.View()) + afterPgDown := rowFromStreamView(t, m.View().Content) if afterPgDown <= afterPgUp { t.Fatalf("expected pgdown to scroll down while paused: afterPgUp=%d afterPgDown=%d", afterPgUp, afterPgDown) } @@ -251,14 +251,14 @@ func TestDirGroupKeyTogglesOnlyOnFilesTab(t *testing.T) { m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap()) m.activeTab = TabFiles - next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'d'}}) + next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'d'}[0], Text: string([]rune{'d'})}) model := next.(Model) if !model.filesDirGrouped { t.Fatalf("expected filesDirGrouped to toggle on files tab") } model.activeTab = TabOverview - next, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'d'}}) + next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'d'}[0], Text: string([]rune{'d'})}) model = next.(Model) if !model.filesDirGrouped { t.Fatalf("expected filesDirGrouped unchanged outside files tab") @@ -272,7 +272,7 @@ func TestScrollOffsetDoesNotGrowUnbounded(t *testing.T) { m.latest = &snap for i := 0; i < 50; i++ { - next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'j'}}) + next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'j'}[0], Text: string([]rune{'j'})}) m = next.(Model) } if m.syscallsOffset != 1 { @@ -284,7 +284,7 @@ func TestRefreshKeyEmitsRefreshTick(t *testing.T) { snap := &statsengine.Snapshot{TotalSyscalls: 13} engine := &fakeSnapshotSource{snap: snap} m := NewModelWithConfig(engine, nil, 250, common.DefaultKeyMap()) - next, cmd := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'r'}}) + next, cmd := m.Update(tea.KeyPressMsg{Code: []rune{'r'}[0], Text: string([]rune{'r'})}) _ = next if cmd == nil { t.Fatalf("expected refresh command") @@ -366,7 +366,7 @@ func TestStatsTickClampsGroupedFilesOffset(t *testing.T) { func TestViewRendersTabBarAndHelp(t *testing.T) { m := NewModelWithConfig(nil, nil, 1000, common.DefaultKeyMap()) - out := m.View() + out := m.View().Content if !strings.Contains(out, "Overview") { t.Fatalf("expected overview label in view") } @@ -405,7 +405,7 @@ func TestStreamTabViewKeepsTabAndHelpChromeVisible(t *testing.T) { m.streamModel.SetSource(rb) m.streamModel.Refresh() - out := m.View() + out := m.View().Content if !strings.Contains(out, "1:Overview") { t.Fatalf("expected tab bar to remain visible in stream view") } @@ -416,21 +416,21 @@ func TestStreamTabViewKeepsTabAndHelpChromeVisible(t *testing.T) { func TestHelpToggleWithH(t *testing.T) { m := NewModelWithConfig(nil, nil, 1000, common.DefaultKeyMap()) - out := m.View() + out := m.View().Content if !strings.Contains(out, "press H for help") { t.Fatalf("expected default help hint") } - next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'H'}}) + next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'H'}[0], Text: string([]rune{'H'})}) m = next.(Model) - out = m.View() + out = m.View().Content if !strings.Contains(out, "tab next tab") { t.Fatalf("expected expanded help after pressing h") } - next, _ = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'H'}}) + next, _ = m.Update(tea.KeyPressMsg{Code: []rune{'H'}[0], Text: string([]rune{'H'})}) m = next.(Model) - out = m.View() + out = m.View().Content if !strings.Contains(out, "press H for help") { t.Fatalf("expected help hint after pressing h again") } diff --git a/internal/tui/dashboard/overview.go b/internal/tui/dashboard/overview.go index 5b8fab8..3ddeaf6 100644 --- a/internal/tui/dashboard/overview.go +++ b/internal/tui/dashboard/overview.go @@ -8,7 +8,7 @@ import ( "time" "unicode/utf8" - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) func renderOverview(snap *statsengine.Snapshot, width, height int) string { diff --git a/internal/tui/dashboard/overview_test.go b/internal/tui/dashboard/overview_test.go index 9895490..7de411c 100644 --- a/internal/tui/dashboard/overview_test.go +++ b/internal/tui/dashboard/overview_test.go @@ -7,7 +7,7 @@ import ( "ior/internal/statsengine" - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) func TestRenderOverviewIncludesCoreMetrics(t *testing.T) { diff --git a/internal/tui/dashboard/processes.go b/internal/tui/dashboard/processes.go index 281a86a..a9de382 100644 --- a/internal/tui/dashboard/processes.go +++ b/internal/tui/dashboard/processes.go @@ -6,7 +6,7 @@ import ( "strconv" "strings" - "github.com/charmbracelet/bubbles/table" + "charm.land/bubbles/v2/table" ) func renderProcesses(snap *statsengine.Snapshot, width, height int) string { diff --git a/internal/tui/dashboard/syscalls.go b/internal/tui/dashboard/syscalls.go index 23fe37c..31f719e 100644 --- a/internal/tui/dashboard/syscalls.go +++ b/internal/tui/dashboard/syscalls.go @@ -6,7 +6,7 @@ import ( "strconv" "time" - "github.com/charmbracelet/bubbles/table" + "charm.land/bubbles/v2/table" ) func renderSyscalls(snap *statsengine.Snapshot, width, height int) string { diff --git a/internal/tui/dashboard/tabs.go b/internal/tui/dashboard/tabs.go index df8f03e..62c7762 100644 --- a/internal/tui/dashboard/tabs.go +++ b/internal/tui/dashboard/tabs.go @@ -6,7 +6,7 @@ import ( "strings" "unicode/utf8" - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) // Tab is a dashboard tab identifier. |
