feat: TUI Host Forms (add/edit) - Task 17

- HostFormTab with textinput fields for all host fields
- Add (Ctrl+N) and Edit (Ctrl+E) from host list
- Save to JSON storage, auto-reload on save
- Esc to cancel, navigable form with keyboard
This commit is contained in:
swanadiva
2026-06-23 15:05:08 +07:00
parent 809ac1d2e8
commit 3dc482e353
6 changed files with 440 additions and 11 deletions
+49 -3
View File
@@ -1,14 +1,20 @@
package tui
import "git.tukangketik.id/swanadiva/hostkeeper/internal/models"
import (
"context"
tea "github.com/charmbracelet/bubbletea"
"git.tukangketik.id/swanadiva/hostkeeper/internal/models"
"git.tukangketik.id/swanadiva/hostkeeper/pkg/storage"
)
// quitMsg signals the TUI to exit
type quitMsg struct{}
// openSessionMsg signals the TUI to open a new SSH session tab
type openSessionMsg struct {
host *models.Host
dataDir string
host *models.Host
}
// sessionOutputMsg carries SSH output to the TUI renderer
@@ -18,3 +24,43 @@ type sessionOutputMsg string
type sessionDoneMsg struct {
err error
}
// openHostFormMsg signals the TUI to open a host form tab
type openHostFormMsg struct {
editing *models.Host // nil for add mode
}
// closeFormMsg signals the TUI to close the active form tab
type closeFormMsg struct{}
// saveHostMsg is produced when the form needs to save a host
type saveHostMsg struct {
host *models.Host
dataDir string
}
// saveHostResultMsg is produced after a save attempt
type saveHostResultMsg struct {
host *models.Host
err error
}
// loadedHostsMsg is produced after reloading hosts from storage
type loadedHostsMsg struct {
hosts []*models.Host
}
// saveHostCmd creates a command that saves a host to storage
func saveHostCmd(host *models.Host, dataDir string) tea.Cmd {
return func() tea.Msg {
store, err := storage.NewJSONStorage(dataDir)
if err != nil {
return saveHostResultMsg{err: err}
}
ctx := context.Background()
if err := store.SaveHost(ctx, host); err != nil {
return saveHostResultMsg{err: err}
}
return saveHostResultMsg{host: host}
}
}