diff options
Diffstat (limited to 'internal/tui/eventstream')
| -rw-r--r-- | internal/tui/eventstream/doc.go | 2 | ||||
| -rw-r--r-- | internal/tui/eventstream/exportmodal.go | 17 | ||||
| -rw-r--r-- | internal/tui/eventstream/filtermodal.go | 19 | ||||
| -rw-r--r-- | internal/tui/eventstream/filtermodal_test.go | 50 | ||||
| -rw-r--r-- | internal/tui/eventstream/model.go | 164 | ||||
| -rw-r--r-- | internal/tui/eventstream/render.go | 5 | ||||
| -rw-r--r-- | internal/tui/eventstream/render_test.go | 2 | ||||
| -rw-r--r-- | internal/tui/eventstream/searchmodal.go | 17 | ||||
| -rw-r--r-- | internal/tui/eventstream/streamevent.go | 3 | ||||
| -rw-r--r-- | internal/tui/eventstream/streamevent_test.go | 3 |
10 files changed, 188 insertions, 94 deletions
diff --git a/internal/tui/eventstream/doc.go b/internal/tui/eventstream/doc.go new file mode 100644 index 0000000..38bc854 --- /dev/null +++ b/internal/tui/eventstream/doc.go @@ -0,0 +1,2 @@ +// Package eventstream renders live event rows and interactive filtering controls. +package eventstream diff --git a/internal/tui/eventstream/exportmodal.go b/internal/tui/eventstream/exportmodal.go index cf020f7..3c0e2cd 100644 --- a/internal/tui/eventstream/exportmodal.go +++ b/internal/tui/eventstream/exportmodal.go @@ -3,9 +3,9 @@ package eventstream import ( "strings" - "github.com/charmbracelet/bubbles/textinput" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/textinput" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) type ExportModal struct { @@ -18,7 +18,8 @@ func NewExportModal() ExportModal { input := textinput.New() input.Prompt = "" input.CharLimit = 0 - input.Width = 44 + input.SetWidth(44) + input.SetStyles(textinput.DefaultStyles(true)) return ExportModal{textInput: input} } @@ -26,6 +27,12 @@ func (m ExportModal) Visible() bool { return m.visible } +// SetDarkMode updates export modal text input styles. +func (m ExportModal) SetDarkMode(isDark bool) ExportModal { + m.textInput.SetStyles(textinput.DefaultStyles(isDark)) + return m +} + func (m ExportModal) Open(defaultName string) ExportModal { m.visible = true m.err = "" @@ -47,7 +54,7 @@ func (m ExportModal) Update(msg tea.Msg) (ExportModal, string, bool) { if !m.visible { return m, "", false } - if keyMsg, ok := msg.(tea.KeyMsg); ok { + if keyMsg, ok := msg.(tea.KeyPressMsg); ok { switch keyMsg.String() { case "esc": return m.Close(), "", false diff --git a/internal/tui/eventstream/filtermodal.go b/internal/tui/eventstream/filtermodal.go index f98db7f..bd20a03 100644 --- a/internal/tui/eventstream/filtermodal.go +++ b/internal/tui/eventstream/filtermodal.go @@ -5,9 +5,9 @@ import ( "strconv" "strings" - "github.com/charmbracelet/bubbles/textinput" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/textinput" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) type fieldKey int @@ -48,7 +48,8 @@ func NewFilterModal() FilterModal { input := textinput.New() input.Prompt = "" input.CharLimit = 0 - input.Width = 24 + input.SetWidth(24) + input.SetStyles(textinput.DefaultStyles(true)) m := FilterModal{textInput: input} m.fields = defaultFilterFields() @@ -63,6 +64,12 @@ func (m FilterModal) Filter() Filter { return m.filter } +// SetDarkMode updates filter modal text input styles. +func (m FilterModal) SetDarkMode(isDark bool) FilterModal { + m.textInput.SetStyles(textinput.DefaultStyles(isDark)) + return m +} + func (m FilterModal) Open(initial Filter) FilterModal { m.visible = true m.activeField = 0 @@ -86,7 +93,7 @@ func (m FilterModal) Update(msg tea.Msg) FilterModal { return m } - if keyMsg, ok := msg.(tea.KeyMsg); ok { + if keyMsg, ok := msg.(tea.KeyPressMsg); ok { switch keyMsg.String() { case "esc": if m.editing { @@ -112,7 +119,7 @@ func (m FilterModal) Update(msg tea.Msg) FilterModal { m.fields[m.activeField].opIndex = (m.fields[m.activeField].opIndex + 1) % len(compareOps) } return m - case " ": + case " ", "space": if !m.editing && m.fields[m.activeField].fieldKey == fieldErrorsOnly { if strings.TrimSpace(m.fields[m.activeField].value) == "true" { m.fields[m.activeField].value = "false" diff --git a/internal/tui/eventstream/filtermodal_test.go b/internal/tui/eventstream/filtermodal_test.go index ee53c82..a33cbb1 100644 --- a/internal/tui/eventstream/filtermodal_test.go +++ b/internal/tui/eventstream/filtermodal_test.go @@ -3,7 +3,7 @@ package eventstream import ( "testing" - tea "github.com/charmbracelet/bubbletea" + tea "charm.land/bubbletea/v2" ) func TestFilterModalOpenClose(t *testing.T) { @@ -17,7 +17,7 @@ func TestFilterModalOpenClose(t *testing.T) { t.Fatalf("modal should be visible after open") } - m = m.Update(tea.KeyMsg{Type: tea.KeyEsc}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeyEsc}) if m.Visible() { t.Fatalf("modal should close on esc") } @@ -29,11 +29,11 @@ func TestFilterModalNavigateFields(t *testing.T) { t.Fatalf("activeField=%d, want 0", m.activeField) } - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("j")}) + m = m.Update(tea.KeyPressMsg{Code: []rune("j")[0], Text: string([]rune("j"))}) if m.activeField != 1 { t.Fatalf("activeField=%d, want 1", m.activeField) } - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("k")}) + m = m.Update(tea.KeyPressMsg{Code: []rune("k")[0], Text: string([]rune("k"))}) if m.activeField != 0 { t.Fatalf("activeField=%d, want 0", m.activeField) } @@ -43,34 +43,34 @@ func TestFilterModalEditAndBuildFilter(t *testing.T) { m := NewFilterModal().Open(Filter{}) // Syscall = read - m = m.Update(tea.KeyMsg{Type: tea.KeyEnter}) - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("read")}) - m = m.Update(tea.KeyMsg{Type: tea.KeyEnter}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeyEnter}) + m = m.Update(tea.KeyPressMsg{Code: []rune("read")[0], Text: string([]rune("read"))}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeyEnter}) // PID >= 123 - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("j")}) - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("j")}) - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("j")}) - m = m.Update(tea.KeyMsg{Type: tea.KeyTab}) // '=' -> '>' - m = m.Update(tea.KeyMsg{Type: tea.KeyEnter}) - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("123")}) - m = m.Update(tea.KeyMsg{Type: tea.KeyEnter}) + m = m.Update(tea.KeyPressMsg{Code: []rune("j")[0], Text: string([]rune("j"))}) + m = m.Update(tea.KeyPressMsg{Code: []rune("j")[0], Text: string([]rune("j"))}) + m = m.Update(tea.KeyPressMsg{Code: []rune("j")[0], Text: string([]rune("j"))}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeyTab}) // '=' -> '>' + m = m.Update(tea.KeyPressMsg{Code: tea.KeyEnter}) + m = m.Update(tea.KeyPressMsg{Code: []rune("123")[0], Text: string([]rune("123"))}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeyEnter}) // Latency >= 1ms - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("j")}) - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("j")}) - m = m.Update(tea.KeyMsg{Type: tea.KeyTab}) // '=' -> '>=' - m = m.Update(tea.KeyMsg{Type: tea.KeyEnter}) - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("1ms")}) - m = m.Update(tea.KeyMsg{Type: tea.KeyEnter}) + m = m.Update(tea.KeyPressMsg{Code: []rune("j")[0], Text: string([]rune("j"))}) + m = m.Update(tea.KeyPressMsg{Code: []rune("j")[0], Text: string([]rune("j"))}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeyTab}) // '=' -> '>=' + m = m.Update(tea.KeyPressMsg{Code: tea.KeyEnter}) + m = m.Update(tea.KeyPressMsg{Code: []rune("1ms")[0], Text: string([]rune("1ms"))}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeyEnter}) // ErrorsOnly = true for m.activeField < len(m.fields)-1 { - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("j")}) + m = m.Update(tea.KeyPressMsg{Code: []rune("j")[0], Text: string([]rune("j"))}) } - m = m.Update(tea.KeyMsg{Type: tea.KeySpace}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeySpace}) - m = m.Update(tea.KeyMsg{Type: tea.KeyEsc}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeyEsc}) if m.Visible() { t.Fatalf("modal should close on esc") } @@ -98,8 +98,8 @@ func TestFilterModalClearAll(t *testing.T) { } m := NewFilterModal().Open(initial) - m = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("c")}) - m = m.Update(tea.KeyMsg{Type: tea.KeyEsc}) + m = m.Update(tea.KeyPressMsg{Code: []rune("c")[0], Text: string([]rune("c"))}) + m = m.Update(tea.KeyPressMsg{Code: tea.KeyEsc}) f := m.Filter() if f.IsActive() { diff --git a/internal/tui/eventstream/model.go b/internal/tui/eventstream/model.go index d9c4ee3..12aff4d 100644 --- a/internal/tui/eventstream/model.go +++ b/internal/tui/eventstream/model.go @@ -6,7 +6,8 @@ import ( "strconv" "strings" - tea "github.com/charmbracelet/bubbletea" + "charm.land/bubbles/v2/viewport" + tea "charm.land/bubbletea/v2" ) const ( @@ -23,8 +24,14 @@ const ( streamColumnCount ) +// Source is the minimal stream buffer contract needed by the stream model. +type Source interface { + Len() int + Snapshot() []StreamEvent +} + type Model struct { - source *RingBuffer + source Source allEvents []StreamEvent filtered []StreamEvent @@ -53,11 +60,13 @@ type Model struct { pendingOpenPath string statusMessage string exportDir string + isDark bool width int height int showFooter bool + viewport viewport.Model } type fdTraceViewState struct { @@ -68,8 +77,8 @@ type fdTraceViewState struct { offset int } -func NewModel(source *RingBuffer) Model { - return Model{ +func NewModel(source Source) Model { + m := Model{ source: source, filterModal: NewFilterModal(), exportModal: NewExportModal(), @@ -79,7 +88,25 @@ func NewModel(source *RingBuffer) Model { selectedCol: 0, exportDir: ".", showFooter: true, + isDark: true, + viewport: newStreamViewport(), } + m.SetDarkMode(true) + return m +} + +func newStreamViewport() viewport.Model { + vp := viewport.New() + keyMap := viewport.DefaultKeyMap() + keyMap.Down.SetKeys("down", "j") + keyMap.Up.SetKeys("up", "k") + keyMap.Left.SetKeys("left", "h") + keyMap.Right.SetKeys("right", "l") + keyMap.PageDown.SetKeys("pgdown", "pgdn", "pagedown") + keyMap.PageUp.SetKeys("pgup", "pageup") + vp.KeyMap = keyMap + vp.SoftWrap = true + return vp } // SetViewport updates the render/scroll viewport dimensions used for @@ -87,9 +114,11 @@ func NewModel(source *RingBuffer) Model { func (m *Model) SetViewport(width, height int) { if width > 0 { m.width = width + m.viewport.SetWidth(width) } if height > 0 { m.height = height + m.viewport.SetHeight(m.visibleRows()) } } @@ -99,11 +128,19 @@ func (m *Model) SetFooterVisible(visible bool) { } // SetSource updates the backing ring buffer and refreshes visible rows. -func (m *Model) SetSource(source *RingBuffer) { +func (m *Model) SetSource(source Source) { m.source = source m.Refresh() } +// SetDarkMode updates stream modal text input styles for the active theme. +func (m *Model) SetDarkMode(isDark bool) { + m.isDark = isDark + m.filterModal = m.filterModal.SetDarkMode(isDark) + m.exportModal = m.exportModal.SetDarkMode(isDark) + m.searchModal = m.searchModal.SetDarkMode(isDark) +} + // FilterModalVisible reports whether the filter modal is currently open. func (m Model) FilterModalVisible() bool { return m.filterModal.Visible() @@ -284,7 +321,8 @@ func (m *Model) HandleKey(keyStr string) bool { m.moveSelectionTo(len(m.filtered) - 1) } else { m.autoScroll = true - m.scrollOffset = m.maxScrollOffset() + m.viewport.GotoBottom() + m.scrollOffset = clamp(m.viewport.YOffset(), 0, m.maxScrollOffset()) } return true case "g": @@ -292,6 +330,7 @@ func (m *Model) HandleKey(keyStr string) bool { m.moveSelectionTo(0) } else { m.autoScroll = false + m.viewport.GotoTop() m.scrollOffset = 0 } return true @@ -305,14 +344,14 @@ func (m *Model) HandleKey(keyStr string) bool { if m.paused { m.moveSelectionBy(1) } else { - m.scrollByLines(1) + m.handleViewportUpdate(keyMsgFromString("down")) } return true case "k", "up": if m.paused { m.moveSelectionBy(-1) } else { - m.scrollByLines(-1) + m.handleViewportUpdate(keyMsgFromString("up")) } return true case "left", "h": @@ -320,25 +359,25 @@ func (m *Model) HandleKey(keyStr string) bool { m.moveSelectedColBy(-1) return true } - return false + return m.handleViewportUpdate(keyMsgFromString("left")) case "right", "l": if m.paused { m.moveSelectedColBy(1) return true } - return false + return m.handleViewportUpdate(keyMsgFromString("right")) case "pgdown", "pgdn", "pagedown": if m.paused { m.moveSelectionBy(m.pageStep()) } else { - m.scrollByLines(m.pageStep()) + m.handleViewportUpdate(keyMsgFromString("pgdown")) } return true case "pgup", "pageup": if m.paused { m.moveSelectionBy(-m.pageStep()) } else { - m.scrollByLines(-m.pageStep()) + m.handleViewportUpdate(keyMsgFromString("pgup")) } return true case "esc": @@ -353,8 +392,12 @@ func (m *Model) HandleKey(keyStr string) bool { // HandleTeaKey handles stream keys based on Bubble Tea key message types first, // then falls back to string matching for rune-driven shortcuts. -func (m *Model) HandleTeaKey(msg tea.KeyMsg) bool { - switch msg.Type { +func (m *Model) HandleTeaKey(msg tea.KeyPressMsg) bool { + if m.handleViewportUpdate(msg) { + return true + } + + switch msg.Code { case tea.KeyLeft: return m.HandleKey("left") case tea.KeyRight: @@ -373,14 +416,45 @@ func (m *Model) HandleTeaKey(msg tea.KeyMsg) bool { return m.HandleKey("esc") case tea.KeyEnter: return m.HandleKey("enter") - case tea.KeyRunes: - if len(msg.Runes) == 1 { - return m.HandleKey(string(msg.Runes[0])) + default: + if msg.Text != "" { + runes := []rune(msg.Text) + if len(runes) == 1 { + return m.HandleKey(msg.Text) + } } } return m.HandleKey(msg.String()) } +func (m *Model) handleViewportUpdate(msg tea.KeyPressMsg) bool { + if m.paused || m.fdTraceView.visible || m.filterModal.Visible() || m.exportModal.Visible() || m.searchModal.Visible() { + return false + } + + switch msg.String() { + case "down", "j", "up", "k", "left", "h", "right", "l", "pgup", "pageup", "pgdown", "pgdn", "pagedown": + default: + return false + } + + switch msg.String() { + case "pgup", "pageup": + m.viewport.ScrollUp(m.pageStep()) + case "pgdown", "pgdn", "pagedown": + m.viewport.ScrollDown(m.pageStep()) + default: + vp, cmd := m.viewport.Update(msg) + _ = cmd + m.viewport = vp + } + m.scrollOffset = clamp(m.viewport.YOffset(), 0, m.maxScrollOffset()) + if m.scrollOffset < m.maxScrollOffset() { + m.autoScroll = false + } + return true +} + func (m *Model) View(width, height int) string { if width <= 0 { width = 100 @@ -390,13 +464,16 @@ func (m *Model) View(width, height int) string { } m.width = width m.height = height + m.viewport.SetWidth(width) + m.viewport.SetHeight(m.visibleRows()) if m.fdTraceView.visible { return m.viewFDTrace(width) } rows := m.visibleRows() - start := clamp(m.scrollOffset, 0, m.maxScrollOffset()) + start := clamp(m.viewport.YOffset(), 0, m.maxScrollOffset()) + m.scrollOffset = start end := start + rows if end > len(m.filtered) { end = len(m.filtered) @@ -464,6 +541,8 @@ func (m *Model) Refresh() { m.allEvents = []StreamEvent{} m.filtered = []StreamEvent{} m.scrollOffset = 0 + m.viewport.SetContentLines(nil) + m.viewport.SetYOffset(0) return } @@ -476,6 +555,8 @@ func (m *Model) applyFilter() { m.filtered = []StreamEvent{} m.scrollOffset = 0 m.selectedIdx = -1 + m.viewport.SetContentLines(nil) + m.viewport.SetYOffset(0) return } @@ -487,12 +568,18 @@ func (m *Model) applyFilter() { } } m.filtered = filtered + m.viewport.SetWidth(m.width) + m.viewport.SetHeight(m.visibleRows()) + lines := make([]string, len(m.filtered)) + m.viewport.SetContentLines(lines) max := m.maxScrollOffset() if m.autoScroll { - m.scrollOffset = max + m.viewport.GotoBottom() + m.scrollOffset = clamp(m.viewport.YOffset(), 0, max) } else { m.scrollOffset = clamp(m.scrollOffset, 0, max) + m.viewport.SetYOffset(m.scrollOffset) } m.clampSelection() if m.paused { @@ -529,26 +616,6 @@ func (m *Model) pageStep() int { return rows - 1 } -func (m *Model) scrollByLines(delta int) { - if delta == 0 { - return - } - max := m.maxScrollOffset() - next := m.scrollOffset + delta - if next < 0 { - next = 0 - } - if next > max { - next = max - } - if next != m.scrollOffset { - m.scrollOffset = next - } - if m.scrollOffset < max { - m.autoScroll = false - } -} - func (m *Model) openFDTraceView() bool { if m.fdTraceView.visible || m.selectedIdx < 0 || m.selectedIdx >= len(m.filtered) { return false @@ -646,6 +713,7 @@ func (m *Model) centerSelection() { mid := m.visibleRows() / 2 target := m.selectedIdx - mid m.scrollOffset = clamp(target, 0, m.maxScrollOffset()) + m.viewport.SetYOffset(m.scrollOffset) } func (m *Model) ensureSelection() { @@ -807,26 +875,26 @@ func (m *Model) clampSelection() { m.selectedIdx = clamp(m.selectedIdx, 0, len(m.filtered)-1) } -func keyMsgFromString(keyStr string) tea.KeyMsg { +func keyMsgFromString(keyStr string) tea.KeyPressMsg { switch keyStr { case "esc": - return tea.KeyMsg{Type: tea.KeyEsc} + return tea.KeyPressMsg{Code: tea.KeyEsc} case "enter": - return tea.KeyMsg{Type: tea.KeyEnter} + return tea.KeyPressMsg{Code: tea.KeyEnter} case "tab": - return tea.KeyMsg{Type: tea.KeyTab} + return tea.KeyPressMsg{Code: tea.KeyTab} case "up": - return tea.KeyMsg{Type: tea.KeyUp} + return tea.KeyPressMsg{Code: tea.KeyUp} case "down": - return tea.KeyMsg{Type: tea.KeyDown} + return tea.KeyPressMsg{Code: tea.KeyDown} case " ", "space": - return tea.KeyMsg{Type: tea.KeySpace} + return tea.KeyPressMsg{Code: tea.KeySpace, Text: " "} } if keyStr == "" { - return tea.KeyMsg{} + return tea.KeyPressMsg{} } runes := []rune(keyStr) - return tea.KeyMsg{Type: tea.KeyRunes, Runes: runes} + return tea.KeyPressMsg{Code: runes[0], Text: keyStr} } func rowNumber(start, total int) int { diff --git a/internal/tui/eventstream/render.go b/internal/tui/eventstream/render.go index 1f539c6..3ec4d65 100644 --- a/internal/tui/eventstream/render.go +++ b/internal/tui/eventstream/render.go @@ -2,11 +2,12 @@ package eventstream import ( "fmt" - "ior/internal/tui/common" "strconv" "strings" - "github.com/charmbracelet/lipgloss" + "ior/internal/tui/common" + + "charm.land/lipgloss/v2" ) type columnLayout struct { diff --git a/internal/tui/eventstream/render_test.go b/internal/tui/eventstream/render_test.go index b020edf..6240c69 100644 --- a/internal/tui/eventstream/render_test.go +++ b/internal/tui/eventstream/render_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/charmbracelet/lipgloss" + "charm.land/lipgloss/v2" ) func TestRenderStatusAndFilterLines(t *testing.T) { diff --git a/internal/tui/eventstream/searchmodal.go b/internal/tui/eventstream/searchmodal.go index f744d00..c09542b 100644 --- a/internal/tui/eventstream/searchmodal.go +++ b/internal/tui/eventstream/searchmodal.go @@ -3,9 +3,9 @@ package eventstream import ( "strings" - "github.com/charmbracelet/bubbles/textinput" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/textinput" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) type SearchDirection int @@ -26,7 +26,8 @@ func NewSearchModal() SearchModal { input := textinput.New() input.Prompt = "" input.CharLimit = 0 - input.Width = 44 + input.SetWidth(44) + input.SetStyles(textinput.DefaultStyles(true)) return SearchModal{textInput: input, direction: SearchForward} } @@ -38,6 +39,12 @@ func (m SearchModal) Direction() SearchDirection { return m.direction } +// SetDarkMode updates search modal text input styles. +func (m SearchModal) SetDarkMode(isDark bool) SearchModal { + m.textInput.SetStyles(textinput.DefaultStyles(isDark)) + return m +} + func (m SearchModal) Open(direction SearchDirection, defaultTerm string) SearchModal { m.visible = true m.err = "" @@ -60,7 +67,7 @@ func (m SearchModal) Update(msg tea.Msg) (SearchModal, string, bool) { if !m.visible { return m, "", false } - if keyMsg, ok := msg.(tea.KeyMsg); ok { + if keyMsg, ok := msg.(tea.KeyPressMsg); ok { switch keyMsg.String() { case "esc": return m.Close(), "", false diff --git a/internal/tui/eventstream/streamevent.go b/internal/tui/eventstream/streamevent.go index dbe04dd..5f1e27f 100644 --- a/internal/tui/eventstream/streamevent.go +++ b/internal/tui/eventstream/streamevent.go @@ -1,9 +1,10 @@ package eventstream import ( + "time" + "ior/internal/event" "ior/internal/types" - "time" ) type StreamEvent struct { diff --git a/internal/tui/eventstream/streamevent_test.go b/internal/tui/eventstream/streamevent_test.go index 6131fed..dd65dd1 100644 --- a/internal/tui/eventstream/streamevent_test.go +++ b/internal/tui/eventstream/streamevent_test.go @@ -1,10 +1,11 @@ package eventstream import ( + "testing" + "ior/internal/event" "ior/internal/file" "ior/internal/types" - "testing" ) func TestNewStreamEventPopulatesFields(t *testing.T) { |
