diff --git a/internal/ssm-browse/controllers/events.go b/internal/ssm-browse/controllers/events.go index 30f125b..0160f0d 100644 --- a/internal/ssm-browse/controllers/events.go +++ b/internal/ssm-browse/controllers/events.go @@ -1,8 +1,15 @@ package controllers -import "github.com/lmika/awstools/internal/ssm-browse/models" +import ( + "fmt" + "github.com/lmika/awstools/internal/ssm-browse/models" +) type NewParameterListMsg struct { Prefix string Parameters *models.SSMParameters } + +func (rs NewParameterListMsg) StatusMessage() string { + return fmt.Sprintf("%d items returned", len(rs.Parameters.Items)) +} \ No newline at end of file diff --git a/internal/ssm-browse/models/models.go b/internal/ssm-browse/models/models.go index 524eeba..777e6c8 100644 --- a/internal/ssm-browse/models/models.go +++ b/internal/ssm-browse/models/models.go @@ -2,7 +2,6 @@ package models type SSMParameters struct { Items []SSMParameter - NextToken string } type SSMParameter struct { diff --git a/internal/ssm-browse/providers/awsssm/provider.go b/internal/ssm-browse/providers/awsssm/provider.go index 049b5d9..07786de 100644 --- a/internal/ssm-browse/providers/awsssm/provider.go +++ b/internal/ssm-browse/providers/awsssm/provider.go @@ -19,33 +19,32 @@ func NewProvider(client *ssm.Client) *Provider { } } -func (p *Provider) List(ctx context.Context, prefix string, nextToken string) (*models.SSMParameters, error) { +func (p *Provider) List(ctx context.Context, prefix string, maxCount int) (*models.SSMParameters, error) { log.Printf("new prefix: %v", prefix) - var nextTokenStr *string = nil - if nextToken != "" { - nextTokenStr = aws.String(nextToken) - } - pars, err := p.client.GetParametersByPath(ctx, &ssm.GetParametersByPathInput{ + pager := ssm.NewGetParametersByPathPaginator(p.client, &ssm.GetParametersByPathInput{ Path: aws.String(prefix), - NextToken: nextTokenStr, - MaxResults: 10, Recursive: true, + WithDecryption: true, }) - if err != nil { - return nil, errors.Wrap(err, "cannot get parameters from path") - } - res := &models.SSMParameters{ - Items: make([]models.SSMParameter, len(pars.Parameters)), - NextToken: aws.ToString(pars.NextToken), - } - for i, p := range pars.Parameters { - res.Items[i] = models.SSMParameter{ - Name: aws.ToString(p.Name), - Value: aws.ToString(p.Value), + items := make([]models.SSMParameter, 0) + outer: for pager.HasMorePages() { + out, err := pager.NextPage(ctx) + if err != nil { + return nil, errors.Wrap(err, "cannot get parameters from path") + } + + for _, p := range out.Parameters { + items = append(items, models.SSMParameter{ + Name: aws.ToString(p.Name), + Value: aws.ToString(p.Value), + }) + if len(items) >= maxCount { + break outer + } } } - return res, nil + return &models.SSMParameters{Items: items}, nil } diff --git a/internal/ssm-browse/services/ssmparameters/iface.go b/internal/ssm-browse/services/ssmparameters/iface.go index f873f72..cc23f54 100644 --- a/internal/ssm-browse/services/ssmparameters/iface.go +++ b/internal/ssm-browse/services/ssmparameters/iface.go @@ -6,5 +6,5 @@ import ( ) type SSMProvider interface { - List(ctx context.Context, prefix string, nextToken string) (*models.SSMParameters, error) + List(ctx context.Context, prefix string, maxCount int) (*models.SSMParameters, error) } diff --git a/internal/ssm-browse/services/ssmparameters/service.go b/internal/ssm-browse/services/ssmparameters/service.go index 521490b..7706801 100644 --- a/internal/ssm-browse/services/ssmparameters/service.go +++ b/internal/ssm-browse/services/ssmparameters/service.go @@ -16,21 +16,5 @@ func NewService(provider SSMProvider) *Service { } func (s *Service) List(ctx context.Context, prefix string) (*models.SSMParameters, error) { - var items []models.SSMParameter - var nextToken string - - for { - page, err := s.provider.List(ctx, prefix, nextToken) - if err != nil { - return nil, err - } - - items = append(items, page.Items...) - nextToken = page.NextToken - if len(items) >= 50 || nextToken == "" { - break - } - } - - return &models.SSMParameters{Items: items, NextToken: nextToken}, nil + return s.provider.List(ctx, prefix, 100) } \ No newline at end of file diff --git a/internal/ssm-browse/ui/model.go b/internal/ssm-browse/ui/model.go index 4de9dea..ae625e9 100644 --- a/internal/ssm-browse/ui/model.go +++ b/internal/ssm-browse/ui/model.go @@ -6,6 +6,7 @@ import ( "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout" "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/statusandprompt" "github.com/lmika/awstools/internal/ssm-browse/controllers" + "github.com/lmika/awstools/internal/ssm-browse/ui/ssmdetails" "github.com/lmika/awstools/internal/ssm-browse/ui/ssmlist" ) @@ -14,13 +15,17 @@ type Model struct { controller *controllers.SSMController statusAndPrompt *statusandprompt.StatusAndPrompt - root tea.Model - ssmList *ssmlist.Model + root tea.Model + ssmList *ssmlist.Model + ssmDetails *ssmdetails.Model } func NewModel(controller *controllers.SSMController, cmdController *commandctrl.CommandController) Model { ssmList := ssmlist.New() - statusAndPrompt := statusandprompt.New(ssmList, "Hello SSM") + ssmdDetails := ssmdetails.New() + statusAndPrompt := statusandprompt.New( + layout.NewVBox(layout.LastChildFixedAt(17), ssmList, ssmdDetails), + "") root := layout.FullScreen(statusAndPrompt) @@ -30,6 +35,7 @@ func NewModel(controller *controllers.SSMController, cmdController *commandctrl. root: root, statusAndPrompt: statusAndPrompt, ssmList: ssmList, + ssmDetails: ssmdDetails, } } @@ -42,6 +48,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case controllers.NewParameterListMsg: m.ssmList.SetPrefix(msg.Prefix) m.ssmList.SetParameters(msg.Parameters) + case ssmlist.NewSSMParameterSelected: + m.ssmDetails.SetSelectedItem(msg) case tea.KeyMsg: if !m.statusAndPrompt.InPrompt() { switch msg.String() { diff --git a/internal/ssm-browse/ui/ssmdetails/model.go b/internal/ssm-browse/ui/ssmdetails/model.go new file mode 100644 index 0000000..c3ea5ca --- /dev/null +++ b/internal/ssm-browse/ui/ssmdetails/model.go @@ -0,0 +1,66 @@ +package ssmdetails + +import ( + "fmt" + "github.com/charmbracelet/bubbles/viewport" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/frame" + "github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout" + "github.com/lmika/awstools/internal/ssm-browse/models" + "strings" +) + +type Model struct { + frameTitle frame.FrameTitle + viewport viewport.Model + w, h int + + // model state + hasSelectedItem bool + selectedItem *models.SSMParameter +} + +func New() *Model { + viewport := viewport.New(0, 0) + viewport.SetContent("") + return &Model{ + frameTitle: frame.NewFrameTitle("Item", false), + viewport: viewport, + } +} + +func (*Model) Init() tea.Cmd { + return nil +} + +func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + return m, nil +} + +func (m *Model) SetSelectedItem(item *models.SSMParameter) { + m.selectedItem = item + + if m.selectedItem != nil { + var viewportContents strings.Builder + fmt.Fprintf(&viewportContents, "Name: %v\n\n", item.Name) + fmt.Fprintf(&viewportContents, "Type: TODO\n\n") + fmt.Fprintf(&viewportContents, "%v\n", item.Value) + + m.viewport.SetContent(viewportContents.String()) + } else { + m.viewport.SetContent("(no parameter selected)") + } +} + +func (m *Model) View() string { + return lipgloss.JoinVertical(lipgloss.Top, m.frameTitle.View(), m.viewport.View()) +} + +func (m *Model) Resize(w, h int) layout.ResizingModel { + m.w, m.h = w, h + m.frameTitle.Resize(w, h) + m.viewport.Width = w + m.viewport.Height = h - m.frameTitle.HeaderHeight() + return m +} diff --git a/internal/ssm-browse/ui/ssmlist/events.go b/internal/ssm-browse/ui/ssmlist/events.go new file mode 100644 index 0000000..13ec0d8 --- /dev/null +++ b/internal/ssm-browse/ui/ssmlist/events.go @@ -0,0 +1,5 @@ +package ssmlist + +import "github.com/lmika/awstools/internal/ssm-browse/models" + +type NewSSMParameterSelected *models.SSMParameter diff --git a/internal/ssm-browse/ui/ssmlist/ssmlist.go b/internal/ssm-browse/ui/ssmlist/ssmlist.go index ca563a3..b909bde 100644 --- a/internal/ssm-browse/ui/ssmlist/ssmlist.go +++ b/internal/ssm-browse/ui/ssmlist/ssmlist.go @@ -51,15 +51,33 @@ func (m *Model) Init() tea.Cmd { } func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - var cmd tea.Cmd + //var cmd tea.Cmd switch msg := msg.(type) { case tea.KeyMsg: - m.table, cmd = m.table.Update(msg) - return m, cmd + switch msg.String() { + case "i", "up": + m.table.GoUp() + return m, m.emitNewSelectedParameter() + case "k", "down": + m.table.GoDown() + return m, m.emitNewSelectedParameter() + } + //m.table, cmd = m.table.Update(msg) + //return m, cmd } return m, nil } +func (m *Model) emitNewSelectedParameter() tea.Cmd { + return func() tea.Msg { + if row, ok := m.table.SelectedRow().(itemTableRow); ok { + return NewSSMParameterSelected(&(row.item)) + } + + return nil + } +} + func (m *Model) View() string { return lipgloss.JoinVertical(lipgloss.Top, m.frameTitle.View(), m.table.View()) }