ssm-browse: fixed the views of dynamo-browse

This commit is contained in:
Leon Mika 2022-03-29 15:46:18 +11:00
parent f6f06eb22d
commit d3f6475070
6 changed files with 79 additions and 96 deletions

View file

@ -9,6 +9,7 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/lmika/awstools/internal/common/ui/commandctrl"
"github.com/lmika/awstools/internal/common/ui/logging"
"github.com/lmika/awstools/internal/dynamo-browse/controllers"
"github.com/lmika/awstools/internal/dynamo-browse/providers/dynamo"
"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
@ -46,10 +47,18 @@ func main() {
tableWriteController := controllers.NewTableWriteController(tableService, tableReadController, *flagTable)
_ = tableWriteController
commandController := commandctrl.NewCommandController(map[string]commandctrl.Command{
"q": commandctrl.NoArgCommand(tea.Quit),
//"rw": tableWriteController.ToggleReadWrite(),
//"dup": tableWriteController.Duplicate(),
commandController := commandctrl.NewCommandController()
commandController.AddCommands(&commandctrl.CommandContext{
Commands: map[string]commandctrl.Command{
"q": commandctrl.NoArgCommand(tea.Quit),
"table": func(args []string) tea.Cmd {
if len(args) == 0 {
return tableReadController.ListTables()
} else {
return tableReadController.ScanTable(args[0])
}
},
},
})
model := ui.NewModel(tableReadController, commandController)
@ -59,12 +68,8 @@ func main() {
p := tea.NewProgram(model, tea.WithAltScreen())
f, err := tea.LogToFile("debug.log", "debug")
if err != nil {
fmt.Println("fatal:", err)
os.Exit(1)
}
defer f.Close()
closeFn := logging.EnableLogging()
defer closeFn()
log.Println("launching")
if err := p.Start(); err != nil {
@ -72,12 +77,3 @@ func main() {
os.Exit(1)
}
}
//
//type msgLoopback struct {
// program *tea.Program
//}
//
//func (m *msgLoopback) Send(msg tea.Msg) {
// m.program.Send(msg)
//}

View file

@ -7,30 +7,36 @@ import (
"github.com/lmika/awstools/internal/dynamo-browse/models"
"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
"github.com/pkg/errors"
"sync"
)
type TableReadController struct {
tableService *tables.Service
tableName string
// state
mutex *sync.Mutex
resultSet *models.ResultSet
}
func NewTableReadController(tableService *tables.Service, tableName string) *TableReadController {
return &TableReadController{
tableService: tableService,
tableName: tableName,
mutex: new(sync.Mutex),
}
}
// 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()
return c.ListTables()
} else {
return c.scanTable(c.tableName)
return c.ScanTable(c.tableName)
}
}
func (c *TableReadController) listTables() tea.Cmd {
func (c *TableReadController) ListTables() tea.Cmd {
return func() tea.Msg {
tables, err := c.tableService.ListTables(context.Background())
if err != nil {
@ -40,13 +46,13 @@ func (c *TableReadController) listTables() tea.Cmd {
return PromptForTableMsg{
Tables: tables,
OnSelected: func(tableName string) tea.Cmd {
return c.scanTable(tableName)
return c.ScanTable(tableName)
},
}
}
}
func (c *TableReadController) scanTable(name string) tea.Cmd {
func (c *TableReadController) ScanTable(name string) tea.Cmd {
return func() tea.Msg {
ctx := context.Background()
@ -60,23 +66,31 @@ func (c *TableReadController) scanTable(name string) tea.Cmd {
return events.Error(err)
}
return NewResultSet{resultSet}
return c.setResultSet(resultSet)
}
}
func (c *TableReadController) Rescan(resultSet *models.ResultSet) tea.Cmd {
func (c *TableReadController) Rescan() tea.Cmd {
return func() tea.Msg {
ctx := context.Background()
resultSet, err := c.tableService.Scan(ctx, resultSet.TableInfo)
resultSet, err := c.tableService.Scan(ctx, c.resultSet.TableInfo)
if err != nil {
return events.Error(err)
}
return NewResultSet{resultSet}
return c.setResultSet(resultSet)
}
}
func (c *TableReadController) setResultSet(resultSet *models.ResultSet) tea.Msg {
c.mutex.Lock()
defer c.mutex.Unlock()
c.resultSet = resultSet
return NewResultSet{resultSet}
}
/*
func (c *TableReadController) Scan() uimodels.Operation {
return uimodels.OperationFn(func(ctx context.Context) error {

View file

@ -14,23 +14,25 @@ import (
type Model struct {
tableReadController *controllers.TableReadController
commandController *commandctrl.CommandController
statusAndPrompt *statusandprompt.StatusAndPrompt
tableSelect *tableselect.Model
root tea.Model
}
func NewModel(rc *controllers.TableReadController, cc *commandctrl.CommandController) Model {
dtv := dynamotableview.New(rc, cc)
dtv := dynamotableview.New()
div := dynamoitemview.New()
statusAndPrompt := statusandprompt.New(layout.NewVBox(layout.LastChildFixedAt(17), dtv, div), "")
tableSelect := tableselect.New(statusAndPrompt)
m := statusandprompt.New(
layout.NewVBox(layout.LastChildFixedAt(17), dtv, div),
"Hello world",
)
root := layout.FullScreen(tableselect.New(m))
root := layout.FullScreen(tableSelect)
return Model{
tableReadController: rc,
commandController: cc,
statusAndPrompt: statusAndPrompt,
tableSelect: tableSelect,
root: root,
}
}
@ -40,6 +42,20 @@ func (m Model) Init() tea.Cmd {
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
if !m.statusAndPrompt.InPrompt() && !m.tableSelect.Visible() {
switch msg.String() {
case "s":
return m, m.tableReadController.Rescan()
case ":":
return m, m.commandController.Prompt()
case "ctrl+c", "esc":
return m, tea.Quit
}
}
}
var cmd tea.Cmd
m.root, cmd = m.root.Update(msg)
return m, cmd

View file

@ -25,18 +25,18 @@ type Model struct {
selectedItem models.Item
}
func New() Model {
return Model{
func New() *Model {
return &Model{
frameTitle: frame.NewFrameTitle("Item", false),
viewport: viewport.New(100, 100),
}
}
func (Model) Init() tea.Cmd {
func (*Model) Init() tea.Cmd {
return nil
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case NewItemSelected:
m.currentResultSet = msg.ResultSet
@ -47,14 +47,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
func (m Model) View() string {
func (m *Model) View() string {
if !m.ready {
return ""
}
return lipgloss.JoinVertical(lipgloss.Top, m.frameTitle.View(), m.viewport.View())
}
func (m Model) Resize(w, h int) layout.ResizingModel {
func (m *Model) Resize(w, h int) layout.ResizingModel {
m.w, m.h = w, h
if !m.ready {
m.viewport = viewport.New(w, h-m.frameTitle.HeaderHeight())

View file

@ -4,7 +4,6 @@ import (
table "github.com/calyptia/go-bubble-table"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/lmika/awstools/internal/common/ui/commandctrl"
"github.com/lmika/awstools/internal/dynamo-browse/controllers"
"github.com/lmika/awstools/internal/dynamo-browse/models"
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/dynamoitemview"
@ -13,9 +12,6 @@ import (
)
type Model struct {
tableReadControllers *controllers.TableReadController
commandCtrl *commandctrl.CommandController
frameTitle frame.FrameTitle
table table.Model
w, h int
@ -24,26 +20,24 @@ type Model struct {
resultSet *models.ResultSet
}
func New(tableReadControllers *controllers.TableReadController, commandCtrl *commandctrl.CommandController) Model {
func New() *Model {
tbl := table.New([]string{"pk", "sk"}, 100, 100)
rows := make([]table.Row, 0)
tbl.SetRows(rows)
frameTitle := frame.NewFrameTitle("No table", true)
return Model{
tableReadControllers: tableReadControllers,
commandCtrl: commandCtrl,
return &Model{
frameTitle: frameTitle,
table: tbl,
}
}
func (m Model) Init() tea.Cmd {
func (m *Model) Init() tea.Cmd {
return nil
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case controllers.NewResultSet:
m.resultSet = msg.ResultSet
@ -58,26 +52,17 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case "k", "down":
m.table.GoDown()
return m, m.postSelectedItemChanged
// TEMP
case "s":
return m, m.tableReadControllers.Rescan(m.resultSet)
case ":":
return m, m.commandCtrl.Prompt()
// END TEMP
case "ctrl+c", "esc":
return m, tea.Quit
}
}
return m, nil
}
func (m Model) View() string {
func (m *Model) View() string {
return lipgloss.JoinVertical(lipgloss.Top, m.frameTitle.View(), m.table.View())
}
func (m Model) Resize(w, h int) layout.ResizingModel {
func (m *Model) Resize(w, h int) layout.ResizingModel {
m.w, m.h = w, h
tblHeight := h - m.frameTitle.HeaderHeight()
m.table.SetSize(w, tblHeight)
@ -120,31 +105,3 @@ func (m *Model) postSelectedItemChanged() tea.Msg {
return dynamoitemview.NewItemSelected{ResultSet: item.resultSet, Item: item.item}
}
/*
func (m *Model) updateViewportToSelectedMessage() {
selectedItem, ok := m.selectedItem()
if !ok {
m.viewport.SetContent("(no row selected)")
return
}
viewportContent := &strings.Builder{}
tabWriter := tabwriter.NewWriter(viewportContent, 0, 1, 1, ' ', 0)
for _, colName := range selectedItem.resultSet.Columns {
switch colVal := selectedItem.item[colName].(type) {
case nil:
break
case *types.AttributeValueMemberS:
fmt.Fprintf(tabWriter, "%v\tS\t%s\n", colName, colVal.Value)
case *types.AttributeValueMemberN:
fmt.Fprintf(tabWriter, "%v\tN\t%s\n", colName, colVal.Value)
default:
fmt.Fprintf(tabWriter, "%v\t?\t%s\n", colName, "(other)")
}
}
tabWriter.Flush()
m.viewport.SetContent(viewportContent.String())
}
*/

View file

@ -19,16 +19,16 @@ type Model struct {
w, h int
}
func New(submodel tea.Model) Model {
func New(submodel tea.Model) *Model {
frameTitle := frame.NewFrameTitle("Select table", false)
return Model{frameTitle: frameTitle, submodel: submodel}
return &Model{frameTitle: frameTitle, submodel: submodel}
}
func (m Model) Init() tea.Cmd {
func (m *Model) Init() tea.Cmd {
return m.submodel.Init()
}
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
switch msg := msg.(type) {
case controllers.PromptForTableMsg:
@ -60,7 +60,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, cc.Cmd()
}
func (m Model) View() string {
func (m *Model) View() string {
if m.pendingSelection != nil {
return lipgloss.JoinVertical(lipgloss.Top, m.frameTitle.View(), m.listController.View())
} else if m.isLoading {
@ -70,11 +70,11 @@ func (m Model) View() string {
return m.submodel.View()
}
func (m Model) shouldShow() bool {
func (m *Model) Visible() bool {
return m.pendingSelection != nil || m.isLoading
}
func (m Model) Resize(w, h int) layout.ResizingModel {
func (m *Model) Resize(w, h int) layout.ResizingModel {
m.w, m.h = w, h
m.submodel = layout.Resize(m.submodel, w, h)