package tui import ( "fmt" "strings" tea "github.com/charmbracelet/bubbletea" "git.tukangketik.id/swanadiva/hostkeeper/internal/models" ) // HostListTab is the host list tab type HostListTab struct { hosts []*models.Host selectedIndex int err error width int height int } // NewHostListTab creates a new host list tab func NewHostListTab() *HostListTab { return &HostListTab{ selectedIndex: 0, } } // Init initializes the tab func (t *HostListTab) Init() tea.Cmd { return nil } // Name returns the tab name func (t *HostListTab) Name() string { return "Hosts" } // Update handles messages for the host list func (t *HostListTab) Update(msg tea.Msg) (Tab, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: t.width = msg.Width t.height = msg.Height case tea.KeyMsg: switch msg.String() { case "up", "k": if t.selectedIndex > 0 { t.selectedIndex-- } case "down", "j": if t.selectedIndex < len(t.hosts)-1 { t.selectedIndex++ } case "enter", " ": if len(t.hosts) > 0 { return t, tea.Quit } } } return t, nil } // View renders the host list func (t *HostListTab) View() string { var b strings.Builder b.WriteString(AppTitleStyle.Render("HOSTKEEPER - SSH Manager")) b.WriteString("\n\n") if len(t.hosts) == 0 { b.WriteString(SubtitleStyle.Render("No hosts found. Add your first host with: hostkeeper add")) b.WriteString("\n\n") return b.String() } for i, host := range t.hosts { if i == t.selectedIndex { b.WriteString(renderSelectedHost(host)) } else { b.WriteString(renderHost(host)) } b.WriteString("\n") } return b.String() } // SetHosts sets the host list func (t *HostListTab) SetHosts(hosts []*models.Host) { t.hosts = hosts if len(hosts) > 0 && t.selectedIndex >= len(hosts) { t.selectedIndex = len(hosts) - 1 } } // Hosts returns the host list func (t *HostListTab) Hosts() []*models.Host { return t.hosts } // SelectedIndex returns the selected index func (t *HostListTab) SelectedIndex() int { return t.selectedIndex } // FindHostListTab finds the first HostListTab in a list of tabs func FindHostListTab(tabs []Tab) *HostListTab { for _, tab := range tabs { if ht, ok := tab.(*HostListTab); ok { return ht } } return nil } // renderHost renders a single host func renderHost(host *models.Host) string { var b strings.Builder b.WriteString(HostNameStyle.Render(host.Name)) b.WriteString("\n") details := fmt.Sprintf(" %s@%s:%d", host.Username, host.Hostname, host.Port) b.WriteString(HostDetailStyle.Render(details)) if len(host.Tags) > 0 { tags := formatTagsForTUI(host.Tags) b.WriteString(" " + TagStyle.Render(tags)) } return b.String() } // renderSelectedHost renders the selected host with highlight func renderSelectedHost(host *models.Host) string { hostText := renderHost(host) return SelectedStyle.Render(hostText) } // formatTagsForTUI formats tags for TUI display func formatTagsForTUI(tags []string) string { if len(tags) == 0 { return "" } var formatted []string for _, tag := range tags { formatted = append(formatted, "["+tag+"]") } return strings.Join(formatted, " ") }