dynamo-browse/internal/dynamo-browse/ui/model.go

238 lines
6.9 KiB
Go

package ui
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/lmika/audax/internal/common/ui/commandctrl"
"github.com/lmika/audax/internal/common/ui/events"
"github.com/lmika/audax/internal/dynamo-browse/controllers"
"github.com/lmika/audax/internal/dynamo-browse/models"
"github.com/lmika/audax/internal/dynamo-browse/services/itemrenderer"
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dialogprompt"
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dynamoitemedit"
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dynamoitemview"
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/dynamotableview"
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/layout"
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/statusandprompt"
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/styles"
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/tableselect"
"github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/utils"
"github.com/pkg/errors"
"log"
"strings"
)
const (
ViewModeTablePrimary = 0
ViewModeTableItemEqual = 1
ViewModeItemPrimary = 2
ViewModeItemOnly = 3
ViewModeTableOnly = 4
ViewModeCount = 5
)
type Model struct {
tableReadController *controllers.TableReadController
tableWriteController *controllers.TableWriteController
commandController *commandctrl.CommandController
itemEdit *dynamoitemedit.Model
statusAndPrompt *statusandprompt.StatusAndPrompt
tableSelect *tableselect.Model
mainViewIndex int
root tea.Model
tableView *dynamotableview.Model
itemView *dynamoitemview.Model
mainView tea.Model
}
func NewModel(
rc *controllers.TableReadController,
wc *controllers.TableWriteController,
itemRendererService *itemrenderer.Service,
cc *commandctrl.CommandController,
) Model {
uiStyles := styles.DefaultStyles
dtv := dynamotableview.New(uiStyles)
div := dynamoitemview.New(itemRendererService, uiStyles)
mainView := layout.NewVBox(layout.LastChildFixedAt(14), dtv, div)
itemEdit := dynamoitemedit.NewModel(mainView)
statusAndPrompt := statusandprompt.New(itemEdit, "", uiStyles.StatusAndPrompt)
dialogPrompt := dialogprompt.New(statusAndPrompt)
tableSelect := tableselect.New(dialogPrompt, uiStyles)
cc.AddCommands(&commandctrl.CommandContext{
Commands: map[string]commandctrl.Command{
"quit": commandctrl.NoArgCommand(tea.Quit),
"table": func(args []string) tea.Msg {
if len(args) == 0 {
return rc.ListTables()
} else {
return rc.ScanTable(args[0])
}
},
"export": func(args []string) tea.Msg {
if len(args) == 0 {
return events.Error(errors.New("expected filename"))
}
return rc.ExportCSV(args[0])
},
"unmark": commandctrl.NoArgCommand(rc.Unmark),
"delete": commandctrl.NoArgCommand(wc.DeleteMarked),
// TEMP
"new-item": commandctrl.NoArgCommand(wc.NewItem),
"set-attr": func(args []string) tea.Msg {
if len(args) == 0 {
return events.Error(errors.New("expected field"))
}
var itemType = models.UnsetItemType
if len(args) == 2 {
switch strings.ToUpper(args[0]) {
case "-S":
itemType = models.StringItemType
case "-N":
itemType = models.NumberItemType
case "-BOOL":
itemType = models.BoolItemType
case "-NULL":
itemType = models.NullItemType
default:
return events.Error(errors.New("unrecognised item type"))
}
args = args[1:]
}
return wc.SetAttributeValue(dtv.SelectedItemIndex(), itemType, args[0])
},
"del-attr": func(args []string) tea.Msg {
if len(args) == 0 {
return events.Error(errors.New("expected field"))
}
return wc.DeleteAttribute(dtv.SelectedItemIndex(), args[0])
},
"put": func(args []string) tea.Msg {
return wc.PutItems()
},
"touch": func(args []string) tea.Msg {
return wc.TouchItem(dtv.SelectedItemIndex())
},
"noisy-touch": func(args []string) tea.Msg {
return wc.NoisyTouchItem(dtv.SelectedItemIndex())
},
// Aliases
"sa": cc.Alias("set-attr"),
"da": cc.Alias("del-attr"),
"w": cc.Alias("put"),
"q": cc.Alias("quit"),
},
})
root := layout.FullScreen(tableSelect)
return Model{
tableReadController: rc,
tableWriteController: wc,
commandController: cc,
itemEdit: itemEdit,
statusAndPrompt: statusAndPrompt,
tableSelect: tableSelect,
root: root,
tableView: dtv,
itemView: div,
mainView: mainView,
}
}
func (m Model) Init() tea.Cmd {
return m.tableReadController.Init
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case controllers.SetTableItemView:
cmd := m.setMainViewIndex(msg.ViewIndex)
return m, cmd
case controllers.ResultSetUpdated:
return m, m.tableView.Refresh()
case tea.KeyMsg:
if !m.statusAndPrompt.InPrompt() && !m.tableSelect.Visible() {
log.Printf("key = %+v", msg)
switch msg.String() {
case "m":
if idx := m.tableView.SelectedItemIndex(); idx >= 0 {
return m, func() tea.Msg { return m.tableWriteController.ToggleMark(idx) }
}
case "c":
if idx := m.tableView.SelectedItemIndex(); idx >= 0 {
return m, func() tea.Msg { return m.tableReadController.CopyItemToClipboard(idx) }
}
case "R":
return m, m.tableReadController.Rescan
case "?":
return m, m.tableReadController.PromptForQuery
case "/":
return m, m.tableReadController.Filter
case "backspace":
return m, m.tableReadController.ViewBack
case "\\":
return m, m.tableReadController.ViewForward
case "w":
return m, func() tea.Msg {
return controllers.SetTableItemView{ViewIndex: utils.Cycle(m.mainViewIndex, 1, ViewModeCount)}
}
case "W":
return m, func() tea.Msg {
return controllers.SetTableItemView{ViewIndex: utils.Cycle(m.mainViewIndex, -1, ViewModeCount)}
}
//case "e":
// m.itemEdit.Visible()
// return m, nil
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
}
func (m Model) View() string {
return m.root.View()
}
func (m *Model) setMainViewIndex(viewIndex int) tea.Cmd {
log.Printf("setting view index = %v", viewIndex)
var newMainView tea.Model
switch viewIndex {
case ViewModeTablePrimary:
newMainView = layout.NewVBox(layout.LastChildFixedAt(14), m.tableView, m.itemView)
case ViewModeTableItemEqual:
newMainView = layout.NewVBox(layout.EqualSize(), m.tableView, m.itemView)
case ViewModeItemPrimary:
newMainView = layout.NewVBox(layout.FirstChildFixedAt(7), m.tableView, m.itemView)
case ViewModeItemOnly:
newMainView = layout.NewZStack(m.itemView, m.tableView)
case ViewModeTableOnly:
newMainView = layout.NewZStack(m.tableView, m.tableView)
default:
newMainView = m.mainView
}
m.mainViewIndex = viewIndex
m.mainView = newMainView
m.itemEdit.SetSubmodel(m.mainView)
return m.tableView.Refresh()
}