diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-26 23:33:55 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-26 23:33:55 +0200 |
| commit | 4ca34f040203c8e31603bbb39fd38632b68067d8 (patch) | |
| tree | eed81b39e169eb6d0cd7d2eca6b338c7c0914ba4 /internal/tui/dashboard | |
| parent | e5cb5db2292ae84680935767d455a777125e0fe9 (diff) | |
tui: add paused stream CSV export and foreground editor open
Diffstat (limited to 'internal/tui/dashboard')
| -rw-r--r-- | internal/tui/dashboard/model.go | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/internal/tui/dashboard/model.go b/internal/tui/dashboard/model.go index fae6a1b..0e485d5 100644 --- a/internal/tui/dashboard/model.go +++ b/internal/tui/dashboard/model.go @@ -23,6 +23,9 @@ type SnapshotSource interface { type refreshTickMsg struct{} type streamTickMsg struct{} +type streamEditorDoneMsg struct { + err error +} // Model is the dashboard tab framework model. type Model struct { @@ -99,6 +102,11 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case tea.KeyMsg: return m.handleKey(msg) + case streamEditorDoneMsg: + if msg.err != nil { + m.streamModel.SetStatusMessage("Open failed: " + msg.err.Error()) + } + return m, nil } return m, nil } @@ -107,7 +115,10 @@ func (m Model) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { prevActiveTab := m.activeTab var cmd tea.Cmd keyStr := msg.String() - handled := m.handleScrollKey(msg) + handled, scrollCmd := m.handleScrollKey(msg) + if scrollCmd != nil { + cmd = scrollCmd + } if handled && m.activeTab == TabStream && (keyStr == " " || keyStr == "space") && !m.streamModel.Paused() { cmd = streamTickCmd() } @@ -164,24 +175,35 @@ func (m Model) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { return m, cmd } -func (m *Model) handleScrollKey(msg tea.KeyMsg) bool { +func (m *Model) handleScrollKey(msg tea.KeyMsg) (bool, tea.Cmd) { keyStr := msg.String() switch m.activeTab { case TabSyscalls: - return scrollOffset(keyStr, &m.syscallsOffset, m.maxSyscallsRows()) + return scrollOffset(keyStr, &m.syscallsOffset, m.maxSyscallsRows()), nil case TabFiles: if m.filesDirGrouped { - return scrollOffset(keyStr, &m.filesDirOffset, m.maxFilesDirRows()) + return scrollOffset(keyStr, &m.filesDirOffset, m.maxFilesDirRows()), nil } - return scrollOffset(keyStr, &m.filesOffset, m.maxFilesRows()) + return scrollOffset(keyStr, &m.filesOffset, m.maxFilesRows()), nil case TabProcesses: - return scrollOffset(keyStr, &m.processesOffset, m.maxProcessesRows()) + return scrollOffset(keyStr, &m.processesOffset, m.maxProcessesRows()), nil case TabStream: streamWidth, streamHeight := streamViewport(m.width, m.height) m.streamModel.SetViewport(streamWidth, streamHeight) - return m.streamModel.HandleTeaKey(msg) + handled := m.streamModel.HandleTeaKey(msg) + if path, ok := m.streamModel.ConsumeOpenEditorRequest(); ok { + editorCmd, err := eventstream.EditorCommandForPath(path) + if err != nil { + m.streamModel.SetStatusMessage("Open failed: " + err.Error()) + return true, nil + } + return true, tea.ExecProcess(editorCmd, func(err error) tea.Msg { + return streamEditorDoneMsg{err: err} + }) + } + return handled, nil default: - return false + return false, nil } } @@ -245,7 +267,7 @@ func (m Model) LatestSnapshot() *statsengine.Snapshot { // BlocksGlobalShortcuts reports whether modal UI in the active tab should // suppress top-level shortcuts (for example global export key handling). func (m Model) BlocksGlobalShortcuts() bool { - return m.activeTab == TabStream && m.streamModel.FilterModalVisible() + return m.activeTab == TabStream && (m.streamModel.FilterModalVisible() || m.streamModel.ExportModalVisible()) } // SetStreamSource updates the live stream source used by the stream tab. |
