diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a84a03..bd2e424 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,12 @@ - Auto-refresh destination pane after transfer completes - Success message shown for 1 second before clearing +### SFTP Auto-Refresh Fix +- Added `program *tea.Program` field to SFTPBrowserTab and Model +- `SetProgram()` method allows goroutines to send messages to Bubble Tea +- After transfer: `t.program.Send(sftpRefreshMsg{})` triggers re-render +- Model stores program reference, passes it to SFTP tab on creation + ## v1.0.0 (2025-01-30) ### Added diff --git a/cmd/hostkeeper/tui.go b/cmd/hostkeeper/tui.go index 4ddc2d2..47824cc 100644 --- a/cmd/hostkeeper/tui.go +++ b/cmd/hostkeeper/tui.go @@ -50,6 +50,7 @@ func runTUI(cmd *cobra.Command, args []string) error { model.LoadHosts(hosts) p := tea.NewProgram(model) + model.SetProgram(p) if _, err := p.Run(); err != nil { return fmt.Errorf("failed to run TUI: %w", err) } diff --git a/pkg/tui/sftp_browser_tab.go b/pkg/tui/sftp_browser_tab.go index d2a945c..2521cda 100644 --- a/pkg/tui/sftp_browser_tab.go +++ b/pkg/tui/sftp_browser_tab.go @@ -69,6 +69,8 @@ type SFTPBrowserTab struct { transferring bool transferMsg string + program *tea.Program + mu sync.Mutex closeOnce sync.Once } @@ -98,6 +100,10 @@ func NewSFTPBrowserTab(host *models.Host, dataDir string) *SFTPBrowserTab { func (t *SFTPBrowserTab) Name() string { return "SFTP: " + t.host.Name } +func (t *SFTPBrowserTab) SetProgram(p *tea.Program) { + t.program = p +} + func (t *SFTPBrowserTab) Init() tea.Cmd { go t.connect() go t.refreshLocal() @@ -497,11 +503,21 @@ func (t *SFTPBrowserTab) copyFile(srcType, dstType paneType, srcPath, dstPath, n t.refreshLocal() } + // Trigger re-render in Bubble Tea + if t.program != nil { + t.program.Send(sftpRefreshMsg{}) + } + // Clear success message after brief delay time.Sleep(1 * time.Second) t.mu.Lock() t.transferMsg = "" t.mu.Unlock() + + // Trigger re-render again after clearing message + if t.program != nil { + t.program.Send(sftpRefreshMsg{}) + } } func downloadFile(client *sftp.Client, remotePath, localPath string, progressFn func(int64)) error { diff --git a/pkg/tui/tui.go b/pkg/tui/tui.go index 9e17b45..7f51dc5 100644 --- a/pkg/tui/tui.go +++ b/pkg/tui/tui.go @@ -27,6 +27,7 @@ type Model struct { Error error Quit bool dataDir string + program *tea.Program } // New creates a new TUI model @@ -47,6 +48,11 @@ func (m *Model) Init() tea.Cmd { return m.tabs.Init() } +// SetProgram stores a reference to the tea.Program for sending messages from goroutines +func (m *Model) SetProgram(p *tea.Program) { + m.program = p +} + // Update handles messages and updates the model func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { @@ -82,6 +88,9 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case openSFTPMsg: tab := NewSFTPBrowserTab(msg.host, m.dataDir) + if m.program != nil { + tab.SetProgram(m.program) + } cmd := m.tabs.Add(tab) return m, cmd