Files
telephony-inspector/internal/tui/ssh_config.go

181 lines
4.1 KiB
Go
Raw Normal View History

package tui
import (
"strings"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
// SSHConfigModel handles SSH connection input
type SSHConfigModel struct {
inputs []textinput.Model
focusIndex int
submitted bool
cancelled bool
// Parsed values
Host string
Port string
User string
Password string
}
const (
inputHost = iota
inputPort
inputUser
inputPassword
)
// NewSSHConfigModel creates a new SSH config input model
func NewSSHConfigModel() SSHConfigModel {
inputs := make([]textinput.Model, 4)
// Host input
inputs[inputHost] = textinput.New()
inputs[inputHost].Placeholder = "192.168.1.100"
inputs[inputHost].Focus()
inputs[inputHost].CharLimit = 256
inputs[inputHost].Width = 30
inputs[inputHost].Prompt = "Host: "
// Port input
inputs[inputPort] = textinput.New()
inputs[inputPort].Placeholder = "22"
inputs[inputPort].CharLimit = 5
inputs[inputPort].Width = 10
inputs[inputPort].Prompt = "Port: "
inputs[inputPort].SetValue("22")
// User input
inputs[inputUser] = textinput.New()
inputs[inputUser].Placeholder = "root"
inputs[inputUser].CharLimit = 64
inputs[inputUser].Width = 20
inputs[inputUser].Prompt = "User: "
// Password input
inputs[inputPassword] = textinput.New()
inputs[inputPassword].Placeholder = "password"
inputs[inputPassword].CharLimit = 128
inputs[inputPassword].Width = 30
inputs[inputPassword].Prompt = "Password: "
inputs[inputPassword].EchoMode = textinput.EchoPassword
inputs[inputPassword].EchoCharacter = '•'
return SSHConfigModel{
inputs: inputs,
focusIndex: 0,
}
}
// Init initializes the model
func (m SSHConfigModel) Init() tea.Cmd {
return textinput.Blink
}
// Update handles messages
func (m SSHConfigModel) Update(msg tea.Msg) (SSHConfigModel, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "esc":
m.cancelled = true
return m, nil
case "tab", "down":
m.focusIndex++
if m.focusIndex >= len(m.inputs) {
m.focusIndex = 0
}
return m, m.updateFocus()
case "shift+tab", "up":
m.focusIndex--
if m.focusIndex < 0 {
m.focusIndex = len(m.inputs) - 1
}
return m, m.updateFocus()
case "enter":
if m.focusIndex == len(m.inputs)-1 {
// Submit on last field
m.submitted = true
m.Host = m.inputs[inputHost].Value()
m.Port = m.inputs[inputPort].Value()
m.User = m.inputs[inputUser].Value()
m.Password = m.inputs[inputPassword].Value()
return m, nil
}
// Move to next field
m.focusIndex++
return m, m.updateFocus()
}
}
// Update focused input
cmd := m.updateInputs(msg)
return m, cmd
}
func (m *SSHConfigModel) updateFocus() tea.Cmd {
cmds := make([]tea.Cmd, len(m.inputs))
for i := range m.inputs {
if i == m.focusIndex {
cmds[i] = m.inputs[i].Focus()
} else {
m.inputs[i].Blur()
}
}
return tea.Batch(cmds...)
}
func (m *SSHConfigModel) updateInputs(msg tea.Msg) tea.Cmd {
cmds := make([]tea.Cmd, len(m.inputs))
for i := range m.inputs {
m.inputs[i], cmds[i] = m.inputs[i].Update(msg)
}
return tea.Batch(cmds...)
}
// View renders the SSH config form
func (m SSHConfigModel) View() string {
var b strings.Builder
titleStyle := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#7D56F4")).
MarginBottom(1)
b.WriteString(titleStyle.Render("🔌 SSH Connection"))
b.WriteString("\n\n")
for i := range m.inputs {
b.WriteString(m.inputs[i].View())
b.WriteString("\n")
}
helpStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#626262"))
b.WriteString("\n")
b.WriteString(helpStyle.Render("Tab/↑↓ navigate • Enter submit • Esc cancel"))
return b.String()
}
// IsSubmitted returns true if the form was submitted
func (m SSHConfigModel) IsSubmitted() bool {
return m.submitted
}
// IsCancelled returns true if the form was cancelled
func (m SSHConfigModel) IsCancelled() bool {
return m.cancelled
}
// GetConfig returns the SSH config values
func (m SSHConfigModel) GetConfig() (host, port, user, password string) {
return m.Host, m.Port, m.User, m.Password
}