Most of the new models have been reimplemented
This commit is contained in:
parent
7a5584cf9a
commit
aa828df3ae
|
@ -22,7 +22,6 @@ import (
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/modal"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/modal"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/statusandprompt"
|
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/tableselect"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/tableselect"
|
||||||
"github.com/lmika/gopkgs/cli"
|
"github.com/lmika/gopkgs/cli"
|
||||||
)
|
)
|
||||||
|
@ -157,7 +156,8 @@ func newTestModel(descr string) tea.Model {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
tableselect.ShowTableSelect(func(n string) tea.Cmd {
|
tableselect.ShowTableSelect(func(n string) tea.Cmd {
|
||||||
return statusandprompt.SetStatus("New table = " + n)
|
// return statusandprompt.SetStatus("New table = " + n)
|
||||||
|
return nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,9 +23,9 @@ func NewCommandController(commands map[string]uimodels.Operation) *CommandContro
|
||||||
func (c *CommandController) Prompt() uimodels.Operation {
|
func (c *CommandController) Prompt() uimodels.Operation {
|
||||||
return uimodels.OperationFn(func(ctx context.Context) error {
|
return uimodels.OperationFn(func(ctx context.Context) error {
|
||||||
uiCtx := uimodels.Ctx(ctx)
|
uiCtx := uimodels.Ctx(ctx)
|
||||||
uiCtx.Send(events.PromptForInput{
|
uiCtx.Send(events.PromptForInputMsg{
|
||||||
Prompt: ":",
|
Prompt: ":",
|
||||||
OnDone: c.Execute(),
|
// OnDone: c.Execute(),
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package dispatcher
|
package dispatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/lmika/awstools/internal/common/ui/events"
|
|
||||||
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,20 +10,20 @@ type DispatcherContext struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc DispatcherContext) Messagef(format string, args ...interface{}) {
|
func (dc DispatcherContext) Messagef(format string, args ...interface{}) {
|
||||||
dc.Publisher.Send(events.Message(fmt.Sprintf(format, args...)))
|
// dc.Publisher.Send(events.Message(fmt.Sprintf(format, args...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc DispatcherContext) Send(teaMessage tea.Msg) {
|
func (dc DispatcherContext) Send(teaMessage tea.Msg) {
|
||||||
dc.Publisher.Send(teaMessage)
|
// dc.Publisher.Send(teaMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc DispatcherContext) Message(msg string) {
|
func (dc DispatcherContext) Message(msg string) {
|
||||||
dc.Publisher.Send(events.Message(msg))
|
// dc.Publisher.Send(events.Message(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc DispatcherContext) Input(prompt string, onDone uimodels.Operation) {
|
func (dc DispatcherContext) Input(prompt string, onDone uimodels.Operation) {
|
||||||
dc.Publisher.Send(events.PromptForInput{
|
// dc.Publisher.Send(events.PromptForInput{
|
||||||
Prompt: prompt,
|
// Prompt: prompt,
|
||||||
OnDone: onDone,
|
// OnDone: onDone,
|
||||||
})
|
// })
|
||||||
}
|
}
|
||||||
|
|
26
internal/common/ui/events/commands.go
Normal file
26
internal/common/ui/events/commands.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package events
|
||||||
|
|
||||||
|
import tea "github.com/charmbracelet/bubbletea"
|
||||||
|
|
||||||
|
func Error(err error) tea.Msg {
|
||||||
|
return ErrorMsg(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetStatus(msg string) tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
return StatusMsg(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PromptForInput(prompt string, onDone func(value string) tea.Cmd) tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
return PromptForInputMsg{
|
||||||
|
Prompt: prompt,
|
||||||
|
OnDone: onDone,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageWithStatus interface {
|
||||||
|
StatusMessage() string
|
||||||
|
}
|
|
@ -1,17 +1,17 @@
|
||||||
package events
|
package events
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error indicates that an error occurred
|
// Error indicates that an error occurred
|
||||||
type Error error
|
type ErrorMsg error
|
||||||
|
|
||||||
// Message indicates that a message should be shown to the user
|
// Message indicates that a message should be shown to the user
|
||||||
type Message string
|
type StatusMsg string
|
||||||
|
|
||||||
// PromptForInput indicates that the context is requesting a line of input
|
// PromptForInput indicates that the context is requesting a line of input
|
||||||
type PromptForInput struct {
|
type PromptForInputMsg struct {
|
||||||
Prompt string
|
Prompt string
|
||||||
OnDone uimodels.Operation
|
OnDone func(value string) tea.Cmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,25 @@
|
||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import "github.com/lmika/awstools/internal/dynamo-browse/models"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/lmika/awstools/internal/dynamo-browse/models"
|
||||||
|
)
|
||||||
|
|
||||||
type NewResultSet struct {
|
type NewResultSet struct {
|
||||||
ResultSet *models.ResultSet
|
ResultSet *models.ResultSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rs NewResultSet) StatusMessage() string {
|
||||||
|
return fmt.Sprintf("%d items returned", len(rs.ResultSet.Items))
|
||||||
|
}
|
||||||
|
|
||||||
type SetReadWrite struct {
|
type SetReadWrite struct {
|
||||||
NewValue bool
|
NewValue bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PromptForTableMsg struct {
|
||||||
|
Tables []string
|
||||||
|
OnSelected func(tableName string) tea.Cmd
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/lmika/awstools/internal/common/ui/events"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/models"
|
"github.com/lmika/awstools/internal/dynamo-browse/models"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
|
"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -22,22 +23,62 @@ func NewTableReadController(tableService *tables.Service, tableName string) *Tab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TableReadController) Scan() tea.Cmd {
|
// Init does an initial scan of the table. If no table is specified, it prompts for a table, then does a scan.
|
||||||
|
func (c *TableReadController) Init() tea.Cmd {
|
||||||
|
if c.tableName == "" {
|
||||||
|
return c.listTables()
|
||||||
|
} else {
|
||||||
|
return c.scanTable(c.tableName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TableReadController) listTables() tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
tables, err := c.tableService.ListTables(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return events.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return PromptForTableMsg{
|
||||||
|
Tables: tables,
|
||||||
|
OnSelected: func(tableName string) tea.Cmd {
|
||||||
|
return c.scanTable(tableName)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TableReadController) scanTable(name string) tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
log.Println("Fetching table info")
|
log.Println("Fetching table info")
|
||||||
tableInfo, err := c.tableInfo(ctx)
|
tableInfo, err := c.tableService.Describe(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error: ", err)
|
return events.Error(errors.Wrapf(err, "cannot describe %v", c.tableName))
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Scanning")
|
log.Println("Scanning")
|
||||||
resultSet, err := c.tableService.Scan(ctx, tableInfo)
|
resultSet, err := c.tableService.Scan(ctx, tableInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error: ", err)
|
log.Println("error: ", err)
|
||||||
return err
|
return events.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Scan done")
|
||||||
|
return NewResultSet{resultSet}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TableReadController) Rescan(resultSet *models.ResultSet) tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
log.Println("Scanning")
|
||||||
|
resultSet, err := c.tableService.Scan(ctx, resultSet.TableInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("error: ", err)
|
||||||
|
return events.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Scan done")
|
log.Println("Scan done")
|
||||||
|
@ -79,16 +120,16 @@ func (c *TableReadController) doScan(ctx context.Context, quiet bool) (err error
|
||||||
|
|
||||||
// tableInfo returns the table info from the state if a result set exists. If not, it fetches the
|
// tableInfo returns the table info from the state if a result set exists. If not, it fetches the
|
||||||
// table information from the service.
|
// table information from the service.
|
||||||
func (c *TableReadController) tableInfo(ctx context.Context) (*models.TableInfo, error) {
|
// func (c *TableReadController) tableInfo(ctx context.Context) (*models.TableInfo, error) {
|
||||||
/*
|
// /*
|
||||||
if existingResultSet := CurrentState(ctx).ResultSet; existingResultSet != nil {
|
// if existingResultSet := CurrentState(ctx).ResultSet; existingResultSet != nil {
|
||||||
return existingResultSet.TableInfo, nil
|
// return existingResultSet.TableInfo, nil
|
||||||
}
|
// }
|
||||||
*/
|
// */
|
||||||
|
|
||||||
tableInfo, err := c.tableService.Describe(ctx, c.tableName)
|
// tableInfo, err := c.tableService.Describe(ctx, c.tableName)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return nil, errors.Wrapf(err, "cannot describe %v", c.tableName)
|
// return nil, errors.Wrapf(err, "cannot describe %v", c.tableName)
|
||||||
}
|
// }
|
||||||
return tableInfo, nil
|
// return tableInfo, nil
|
||||||
}
|
// }
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/models/modexpr"
|
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
|
"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
@ -41,56 +40,59 @@ func (c *TableWriteController) ToggleReadWrite() uimodels.Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TableWriteController) Duplicate() uimodels.Operation {
|
func (c *TableWriteController) Duplicate() uimodels.Operation {
|
||||||
return uimodels.OperationFn(func(ctx context.Context) error {
|
return nil
|
||||||
uiCtx := uimodels.Ctx(ctx)
|
/*
|
||||||
state := CurrentState(ctx)
|
return uimodels.OperationFn(func(ctx context.Context) error {
|
||||||
|
|
||||||
if state.SelectedItem == nil {
|
|
||||||
return errors.New("no selected item")
|
|
||||||
} else if !state.InReadWriteMode {
|
|
||||||
return errors.New("not in read/write mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
uiCtx.Input("Dup: ", uimodels.OperationFn(func(ctx context.Context) error {
|
|
||||||
modExpr, err := modexpr.Parse(uimodels.PromptValue(ctx))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newItem, err := modExpr.Patch(state.SelectedItem)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: preview new item
|
|
||||||
|
|
||||||
uiCtx := uimodels.Ctx(ctx)
|
uiCtx := uimodels.Ctx(ctx)
|
||||||
uiCtx.Input("Put item? ", uimodels.OperationFn(func(ctx context.Context) error {
|
state := CurrentState(ctx)
|
||||||
if uimodels.PromptValue(ctx) != "y" {
|
|
||||||
return errors.New("operation aborted")
|
|
||||||
}
|
|
||||||
|
|
||||||
tableInfo, err := c.tableReadControllers.tableInfo(ctx)
|
if state.SelectedItem == nil {
|
||||||
|
return errors.New("no selected item")
|
||||||
|
} else if !state.InReadWriteMode {
|
||||||
|
return errors.New("not in read/write mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
uiCtx.Input("Dup: ", uimodels.OperationFn(func(ctx context.Context) error {
|
||||||
|
modExpr, err := modexpr.Parse(uimodels.PromptValue(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the item
|
newItem, err := modExpr.Patch(state.SelectedItem)
|
||||||
if err := c.tableService.Put(ctx, tableInfo, newItem); err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rescan to get updated items
|
// TODO: preview new item
|
||||||
// if err := c.tableReadControllers.doScan(ctx, true); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
uiCtx := uimodels.Ctx(ctx)
|
||||||
|
uiCtx.Input("Put item? ", uimodels.OperationFn(func(ctx context.Context) error {
|
||||||
|
if uimodels.PromptValue(ctx) != "y" {
|
||||||
|
return errors.New("operation aborted")
|
||||||
|
}
|
||||||
|
|
||||||
|
tableInfo, err := c.tableReadControllers.tableInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the item
|
||||||
|
if err := c.tableService.Put(ctx, tableInfo, newItem); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rescan to get updated items
|
||||||
|
// if err := c.tableReadControllers.doScan(ctx, true); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
return nil
|
return nil
|
||||||
}))
|
})
|
||||||
return nil
|
*/
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TableWriteController) Delete() uimodels.Operation {
|
func (c *TableWriteController) Delete() uimodels.Operation {
|
||||||
|
@ -111,15 +113,17 @@ func (c *TableWriteController) Delete() uimodels.Operation {
|
||||||
return errors.New("operation aborted")
|
return errors.New("operation aborted")
|
||||||
}
|
}
|
||||||
|
|
||||||
tableInfo, err := c.tableReadControllers.tableInfo(ctx)
|
/*
|
||||||
if err != nil {
|
tableInfo, err := c.tableReadControllers.tableInfo(ctx)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Delete the item
|
// Delete the item
|
||||||
if err := c.tableService.Delete(ctx, tableInfo, state.SelectedItem); err != nil {
|
if err := c.tableService.Delete(ctx, tableInfo, state.SelectedItem); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Rescan to get updated items
|
// Rescan to get updated items
|
||||||
// if err := c.tableReadControllers.doScan(ctx, true); err != nil {
|
// if err := c.tableReadControllers.doScan(ctx, true); err != nil {
|
||||||
|
|
|
@ -14,6 +14,15 @@ type Provider struct {
|
||||||
client *dynamodb.Client
|
client *dynamodb.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) ListTables(ctx context.Context) ([]string, error) {
|
||||||
|
out, err := p.client.ListTables(ctx, &dynamodb.ListTablesInput{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "cannot list tables")
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.TableNames, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Provider) DescribeTable(ctx context.Context, tableName string) (*models.TableInfo, error) {
|
func (p *Provider) DescribeTable(ctx context.Context, tableName string) (*models.TableInfo, error) {
|
||||||
out, err := p.client.DescribeTable(ctx, &dynamodb.DescribeTableInput{
|
out, err := p.client.DescribeTable(ctx, &dynamodb.DescribeTableInput{
|
||||||
TableName: aws.String(tableName),
|
TableName: aws.String(tableName),
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type TableProvider interface {
|
type TableProvider interface {
|
||||||
|
ListTables(ctx context.Context) ([]string, error)
|
||||||
DescribeTable(ctx context.Context, tableName string) (*models.TableInfo, error)
|
DescribeTable(ctx context.Context, tableName string) (*models.TableInfo, error)
|
||||||
ScanItems(ctx context.Context, tableName string) ([]models.Item, error)
|
ScanItems(ctx context.Context, tableName string) ([]models.Item, error)
|
||||||
DeleteItem(ctx context.Context, tableName string, key map[string]types.AttributeValue) error
|
DeleteItem(ctx context.Context, tableName string, key map[string]types.AttributeValue) error
|
||||||
|
|
|
@ -18,6 +18,10 @@ func NewService(provider TableProvider) *Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) ListTables(ctx context.Context) ([]string, error) {
|
||||||
|
return s.provider.ListTables(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) Describe(ctx context.Context, table string) (*models.TableInfo, error) {
|
func (s *Service) Describe(ctx context.Context, table string) (*models.TableInfo, error) {
|
||||||
return s.provider.DescribeTable(ctx, table)
|
return s.provider.DescribeTable(ctx, table)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ func NewModel(rc *controllers.TableReadController) Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Model) Init() tea.Cmd {
|
func (m Model) Init() tea.Cmd {
|
||||||
return m.tableReadController.Scan()
|
return m.tableReadController.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/lmika/awstools/internal/common/ui/commandctrl"
|
"github.com/lmika/awstools/internal/common/ui/commandctrl"
|
||||||
"github.com/lmika/awstools/internal/common/ui/dispatcher"
|
"github.com/lmika/awstools/internal/common/ui/dispatcher"
|
||||||
"github.com/lmika/awstools/internal/common/ui/events"
|
|
||||||
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/controllers"
|
"github.com/lmika/awstools/internal/dynamo-browse/controllers"
|
||||||
)
|
)
|
||||||
|
@ -40,8 +39,8 @@ type uiModel struct {
|
||||||
state controllers.State
|
state controllers.State
|
||||||
message string
|
message string
|
||||||
|
|
||||||
pendingInput *events.PromptForInput
|
// pendingInput *events.PromptForInput
|
||||||
textInput textinput.Model
|
textInput textinput.Model
|
||||||
|
|
||||||
dispatcher *dispatcher.Dispatcher
|
dispatcher *dispatcher.Dispatcher
|
||||||
commandController *commandctrl.CommandController
|
commandController *commandctrl.CommandController
|
||||||
|
@ -152,15 +151,15 @@ func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
m.state.InReadWriteMode = msg.NewValue
|
m.state.InReadWriteMode = msg.NewValue
|
||||||
|
|
||||||
// Shared events
|
// Shared events
|
||||||
case events.Error:
|
// case events.Error:
|
||||||
m.message = "Error: " + msg.Error()
|
// m.message = "Error: " + msg.Error()
|
||||||
case events.Message:
|
// case events.Message:
|
||||||
m.message = string(msg)
|
// m.message = string(msg)
|
||||||
case events.PromptForInput:
|
// case events.PromptForInput:
|
||||||
m.textInput.Prompt = msg.Prompt
|
// m.textInput.Prompt = msg.Prompt
|
||||||
m.textInput.Focus()
|
// m.textInput.Focus()
|
||||||
m.textInput.SetValue("")
|
// m.textInput.SetValue("")
|
||||||
m.pendingInput = &msg
|
// m.pendingInput = &msg
|
||||||
|
|
||||||
// Tea events
|
// Tea events
|
||||||
case tea.WindowSizeMsg:
|
case tea.WindowSizeMsg:
|
||||||
|
@ -186,18 +185,18 @@ func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
|
|
||||||
// If text input in focus, allow that to accept input messages
|
// If text input in focus, allow that to accept input messages
|
||||||
if m.pendingInput != nil {
|
// if m.pendingInput != nil {
|
||||||
switch msg.String() {
|
// switch msg.String() {
|
||||||
case "ctrl+c", "esc":
|
// case "ctrl+c", "esc":
|
||||||
m.pendingInput = nil
|
// m.pendingInput = nil
|
||||||
case "enter":
|
// case "enter":
|
||||||
m.invokeOperation(uimodels.WithPromptValue(context.Background(), m.textInput.Value()), m.pendingInput.OnDone)
|
// m.invokeOperation(uimodels.WithPromptValue(context.Background(), m.textInput.Value()), m.pendingInput.OnDone)
|
||||||
m.pendingInput = nil
|
// m.pendingInput = nil
|
||||||
default:
|
// default:
|
||||||
m.textInput, textInputCommands = m.textInput.Update(msg)
|
// m.textInput, textInputCommands = m.textInput.Update(msg)
|
||||||
}
|
// }
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
|
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
case "ctrl+c", "q":
|
||||||
|
|
|
@ -57,7 +57,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
|
||||||
// TEMP
|
// TEMP
|
||||||
case "s":
|
case "s":
|
||||||
return m, m.tableReadControllers.Scan()
|
return m, m.tableReadControllers.Rescan(m.resultSet)
|
||||||
case "ctrl+c", "esc":
|
case "ctrl+c", "esc":
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
package statusandprompt
|
|
||||||
|
|
||||||
import tea "github.com/charmbracelet/bubbletea"
|
|
||||||
|
|
||||||
type setStatusMsg string
|
|
||||||
|
|
||||||
type startPromptMsg struct {
|
|
||||||
prompt string
|
|
||||||
onDone func(val string) tea.Cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetStatus(newStatus string) tea.Cmd {
|
|
||||||
return func() tea.Msg {
|
|
||||||
return setStatusMsg(newStatus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Prompt(prompt string, onDone func(val string) tea.Cmd) tea.Cmd {
|
|
||||||
return func() tea.Msg {
|
|
||||||
return startPromptMsg{
|
|
||||||
prompt: prompt,
|
|
||||||
onDone: onDone,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/charmbracelet/bubbles/textinput"
|
"github.com/charmbracelet/bubbles/textinput"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
"github.com/lmika/awstools/internal/common/ui/events"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/utils"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/utils"
|
||||||
)
|
)
|
||||||
|
@ -13,7 +14,7 @@ import (
|
||||||
type StatusAndPrompt struct {
|
type StatusAndPrompt struct {
|
||||||
model layout.ResizingModel
|
model layout.ResizingModel
|
||||||
statusMessage string
|
statusMessage string
|
||||||
pendingInput *startPromptMsg
|
pendingInput *events.PromptForInputMsg
|
||||||
textInput textinput.Model
|
textInput textinput.Model
|
||||||
width int
|
width int
|
||||||
}
|
}
|
||||||
|
@ -29,15 +30,19 @@ func (s StatusAndPrompt) Init() tea.Cmd {
|
||||||
|
|
||||||
func (s StatusAndPrompt) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (s StatusAndPrompt) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case setStatusMsg:
|
case events.ErrorMsg:
|
||||||
s.statusMessage = string(msg)
|
s.statusMessage = "Error: " + msg.Error()
|
||||||
case startPromptMsg:
|
case events.StatusMsg:
|
||||||
|
s.statusMessage = string(s.statusMessage)
|
||||||
|
case events.MessageWithStatus:
|
||||||
|
s.statusMessage = msg.StatusMessage()
|
||||||
|
case events.PromptForInputMsg:
|
||||||
if s.pendingInput != nil {
|
if s.pendingInput != nil {
|
||||||
// ignore, already in an input
|
// ignore, already in an input
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
s.textInput.Prompt = msg.prompt
|
s.textInput.Prompt = msg.Prompt
|
||||||
s.textInput.Focus()
|
s.textInput.Focus()
|
||||||
s.textInput.SetValue("")
|
s.textInput.SetValue("")
|
||||||
s.pendingInput = &msg
|
s.pendingInput = &msg
|
||||||
|
@ -51,7 +56,7 @@ func (s StatusAndPrompt) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
pendingInput := s.pendingInput
|
pendingInput := s.pendingInput
|
||||||
s.pendingInput = nil
|
s.pendingInput = nil
|
||||||
|
|
||||||
return s, pendingInput.onDone(s.textInput.Value())
|
return s, pendingInput.OnDone(s.textInput.Value())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,13 @@ func (ti tableItem) Title() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ti tableItem) Description() string {
|
func (ti tableItem) Description() string {
|
||||||
return "abc"
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func toListItems[T list.Item](xs []T) []list.Item {
|
func toListItems(xs []string) []list.Item {
|
||||||
ls := make([]list.Item, len(xs))
|
ls := make([]list.Item, len(xs))
|
||||||
for i, x := range xs {
|
for i, x := range xs {
|
||||||
ls[i] = x
|
ls[i] = tableItem{name: x}
|
||||||
}
|
}
|
||||||
return ls
|
return ls
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,8 @@ type listController struct {
|
||||||
list list.Model
|
list list.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
func newListController(w, h int) listController {
|
func newListController(tableNames []string, w, h int) listController {
|
||||||
tableItems := []tableItem{
|
items := toListItems(tableNames)
|
||||||
{name: "alpha"},
|
|
||||||
{name: "beta"},
|
|
||||||
{name: "gamma"},
|
|
||||||
}
|
|
||||||
|
|
||||||
items := toListItems(tableItems)
|
|
||||||
|
|
||||||
delegate := list.NewDefaultDelegate()
|
delegate := list.NewDefaultDelegate()
|
||||||
delegate.ShowDescription = false
|
delegate.ShowDescription = false
|
||||||
|
|
|
@ -2,13 +2,14 @@ package tableselect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/lmika/awstools/internal/dynamo-browse/controllers"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/utils"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
submodel tea.Model
|
submodel tea.Model
|
||||||
pendingSelection *showTableSelectMsg
|
pendingSelection *controllers.PromptForTableMsg
|
||||||
listController listController
|
listController listController
|
||||||
isLoading bool
|
isLoading bool
|
||||||
w, h int
|
w, h int
|
||||||
|
@ -25,10 +26,10 @@ func (m Model) Init() tea.Cmd {
|
||||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
var cc utils.CmdCollector
|
var cc utils.CmdCollector
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case showTableSelectMsg:
|
case controllers.PromptForTableMsg:
|
||||||
m.isLoading = false
|
m.isLoading = false
|
||||||
m.pendingSelection = &msg
|
m.pendingSelection = &msg
|
||||||
m.listController = newListController(m.w, m.h)
|
m.listController = newListController(msg.Tables, m.w, m.h)
|
||||||
return m, nil
|
return m, nil
|
||||||
case indicateLoadingTablesMsg:
|
case indicateLoadingTablesMsg:
|
||||||
m.isLoading = true
|
m.isLoading = true
|
||||||
|
@ -37,10 +38,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
if m.pendingSelection != nil {
|
if m.pendingSelection != nil {
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "enter":
|
case "enter":
|
||||||
var sel showTableSelectMsg
|
var sel controllers.PromptForTableMsg
|
||||||
sel, m.pendingSelection = *m.pendingSelection, nil
|
sel, m.pendingSelection = *m.pendingSelection, nil
|
||||||
|
|
||||||
return m, sel.onSelected(m.listController.list.SelectedItem().(tableItem).name)
|
return m, sel.OnSelected(m.listController.list.SelectedItem().(tableItem).name)
|
||||||
default:
|
default:
|
||||||
m.listController = cc.Collect(m.listController.Update(msg)).(listController)
|
m.listController = cc.Collect(m.listController.Update(msg)).(listController)
|
||||||
return m, cc.Cmd()
|
return m, cc.Cmd()
|
||||||
|
|
Loading…
Reference in a new issue