// Package main provides a TUI (Terminal User Interface) for managing SDM connections. // It allows users to view, filter, and connect to available SDM resources. package main import ( "os" "github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/bubbles/spinner" "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) // model holds the state of the TUI application. type model struct { list list.Model spinner spinner.Model loading bool width int height int emailInput textinput.Model promptingEmail bool rememberEmail bool loggingIn bool err string } // initialModel creates and returns the initial model state. func initialModel() model { s := spinner.New() s.Spinner = spinner.Dot s.Style = lipgloss.NewStyle().Foreground(primaryColor) ti := textinput.New() ti.Placeholder = "your.email@example.com" ti.Focus() ti.CharLimit = inputCharLimit ti.Width = inputWidth ti, rememberEmail := loadEmailIntoInput(ti) return model{ list: newList(make([]list.Item, 0), 0, 0), spinner: s, loading: true, emailInput: ti, promptingEmail: false, rememberEmail: rememberEmail, } } // Init initializes the model and returns the initial batch of commands. func (m model) Init() tea.Cmd { return tea.Batch( tea.WindowSize(), m.spinner.Tick, func() tea.Msg { if err := checkSDMBinary(); err != nil { return statusMsg{err: err} } return fetchStatus() }, ) } // Update processes messages and updates the model state accordingly. func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: return m.handleWindowSize(msg) case authRequiredMsg: return m.handleAuthRequired() case loginMsg: return m.handleLogin(msg) case statusMsg: return m.handleStatus(msg) case connectMsg: return m.handleConnectResult(msg) case disconnectMsg: return m.handleDisconnect(msg) case tea.KeyMsg: return m.handleKeyInput(msg) } if m.loading || m.loggingIn { var cmd tea.Cmd m.spinner, cmd = m.spinner.Update(msg) return m, cmd } if !m.promptingEmail { var cmd tea.Cmd m.list, cmd = m.list.Update(msg) return m, cmd } return m, nil } // View renders the current state of the UI. func (m model) View() string { if m.err != "" { return renderError(m) } if m.promptingEmail { return renderEmailPrompt(m) } if m.loading { return renderLoading(m) } return m.list.View() } func main() { p := tea.NewProgram(initialModel()) if _, err := p.Run(); err != nil { os.Exit(1) } }