main.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // Package main provides a TUI (Terminal User Interface) for managing SDM connections.
  2. // It allows users to view, filter, and connect to available SDM resources.
  3. package main
  4. import (
  5. "os"
  6. "github.com/charmbracelet/bubbles/list"
  7. "github.com/charmbracelet/bubbles/spinner"
  8. "github.com/charmbracelet/bubbles/textinput"
  9. tea "github.com/charmbracelet/bubbletea"
  10. "github.com/charmbracelet/lipgloss"
  11. )
  12. // model holds the state of the TUI application.
  13. type model struct {
  14. list list.Model
  15. spinner spinner.Model
  16. loading bool
  17. width int
  18. height int
  19. emailInput textinput.Model
  20. promptingEmail bool
  21. rememberEmail bool
  22. loggingIn bool
  23. err string
  24. }
  25. // initialModel creates and returns the initial model state.
  26. func initialModel() model {
  27. s := spinner.New()
  28. s.Spinner = spinner.Dot
  29. s.Style = lipgloss.NewStyle().Foreground(primaryColor)
  30. ti := textinput.New()
  31. ti.Placeholder = "your.email@example.com"
  32. ti.Focus()
  33. ti.CharLimit = inputCharLimit
  34. ti.Width = inputWidth
  35. ti, rememberEmail := loadEmailIntoInput(ti)
  36. return model{
  37. list: newList(make([]list.Item, 0), 0, 0),
  38. spinner: s,
  39. loading: true,
  40. emailInput: ti,
  41. promptingEmail: false,
  42. rememberEmail: rememberEmail,
  43. }
  44. }
  45. // Init initializes the model and returns the initial batch of commands.
  46. func (m model) Init() tea.Cmd {
  47. return tea.Batch(
  48. tea.WindowSize(),
  49. m.spinner.Tick,
  50. func() tea.Msg {
  51. if err := checkSDMBinary(); err != nil {
  52. return statusMsg{err: err}
  53. }
  54. return fetchStatus()
  55. },
  56. )
  57. }
  58. // Update processes messages and updates the model state accordingly.
  59. func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
  60. switch msg := msg.(type) {
  61. case tea.WindowSizeMsg:
  62. return m.handleWindowSize(msg)
  63. case authRequiredMsg:
  64. return m.handleAuthRequired()
  65. case loginMsg:
  66. return m.handleLogin(msg)
  67. case statusMsg:
  68. return m.handleStatus(msg)
  69. case connectMsg:
  70. return m.handleConnectResult(msg)
  71. case disconnectMsg:
  72. return m.handleDisconnect(msg)
  73. case tea.KeyMsg:
  74. return m.handleKeyInput(msg)
  75. }
  76. if m.loading || m.loggingIn {
  77. var cmd tea.Cmd
  78. m.spinner, cmd = m.spinner.Update(msg)
  79. return m, cmd
  80. }
  81. if !m.promptingEmail {
  82. var cmd tea.Cmd
  83. m.list, cmd = m.list.Update(msg)
  84. return m, cmd
  85. }
  86. return m, nil
  87. }
  88. // View renders the current state of the UI.
  89. func (m model) View() string {
  90. if m.err != "" {
  91. return renderError(m)
  92. }
  93. if m.promptingEmail {
  94. return renderEmailPrompt(m)
  95. }
  96. if m.loading {
  97. return renderLoading(m)
  98. }
  99. return m.list.View()
  100. }
  101. func main() {
  102. p := tea.NewProgram(initialModel())
  103. if _, err := p.Run(); err != nil {
  104. os.Exit(1)
  105. }
  106. }