table-select: cleanup
This commit is contained in:
parent
6f323fa4cf
commit
9709e6aed1
|
@ -4,25 +4,18 @@ import (
|
|||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/lmika/awstools/internal/common/ui/commandctrl"
|
||||
"github.com/lmika/awstools/internal/common/ui/dispatcher"
|
||||
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
||||
"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"
|
||||
"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/modal"
|
||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/tableselect"
|
||||
"github.com/lmika/gopkgs/cli"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -32,10 +25,7 @@ func main() {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
// TEMP
|
||||
cfg, err := config.LoadDefaultConfig(ctx)
|
||||
|
||||
// END TEMP
|
||||
if err != nil {
|
||||
cli.Fatalf("cannot load AWS config: %v", err)
|
||||
}
|
||||
|
@ -52,70 +42,22 @@ func main() {
|
|||
|
||||
tableService := tables.NewService(dynamoProvider)
|
||||
|
||||
loopback := &msgLoopback{}
|
||||
uiDispatcher := dispatcher.NewDispatcher(loopback)
|
||||
|
||||
tableReadController := controllers.NewTableReadController(tableService, *flagTable)
|
||||
tableWriteController := controllers.NewTableWriteController(tableService, tableReadController, *flagTable)
|
||||
_ = tableWriteController
|
||||
|
||||
commandController := commandctrl.NewCommandController(map[string]uimodels.Operation{
|
||||
// "scan": tableReadController.Scan(),
|
||||
"rw": tableWriteController.ToggleReadWrite(),
|
||||
"dup": tableWriteController.Duplicate(),
|
||||
commandController := commandctrl.NewCommandController(map[string]commandctrl.Command{
|
||||
"q": commandctrl.NoArgCommand(tea.Quit),
|
||||
//"rw": tableWriteController.ToggleReadWrite(),
|
||||
//"dup": tableWriteController.Duplicate(),
|
||||
})
|
||||
|
||||
_ = uiDispatcher
|
||||
_ = commandController
|
||||
|
||||
// uiModel := ui.NewModel(uiDispatcher, commandController, tableReadController, tableWriteController)
|
||||
|
||||
// TEMP
|
||||
// _ = uiModel
|
||||
// END TEMP
|
||||
|
||||
/*
|
||||
var model tea.Model = statusandprompt.New(
|
||||
layout.NewVBox(
|
||||
layout.LastChildFixedAt(11),
|
||||
dynamotableview.New(tableReadController),
|
||||
dynamoitemview.New(),
|
||||
),
|
||||
"Hello world",
|
||||
)
|
||||
model = layout.FullScreen(tableselect.New(model))
|
||||
*/
|
||||
model := ui.NewModel(tableReadController)
|
||||
model := ui.NewModel(tableReadController, commandController)
|
||||
|
||||
// Pre-determine if layout has dark background. This prevents calls for creating a list to hang.
|
||||
lipgloss.HasDarkBackground()
|
||||
|
||||
//frameSet := frameset.New([]frameset.Frame{
|
||||
// {
|
||||
// Header: "Frame 1",
|
||||
// Model: newTestModel("this is model 1"),
|
||||
// },
|
||||
// {
|
||||
// Header: "Frame 2",
|
||||
// Model: newTestModel("this is model 2"),
|
||||
// },
|
||||
//})
|
||||
//
|
||||
//modal := modal.New(frameSet)
|
||||
|
||||
p := tea.NewProgram(model, tea.WithAltScreen())
|
||||
//loopback.program = p
|
||||
|
||||
// TEMP -- profiling
|
||||
//cf, err := os.Create("trace.out")
|
||||
//if err != nil {
|
||||
// log.Fatal("could not create CPU profile: ", err)
|
||||
//}
|
||||
//defer cf.Close() // error handling omitted for example
|
||||
//if err := trace.Start(cf); err != nil {
|
||||
// log.Fatal("could not start CPU profile: ", err)
|
||||
//}
|
||||
//defer trace.Stop()
|
||||
// END TEMP
|
||||
|
||||
f, err := tea.LogToFile("debug.log", "debug")
|
||||
if err != nil {
|
||||
|
@ -131,37 +73,11 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
type msgLoopback struct {
|
||||
program *tea.Program
|
||||
}
|
||||
|
||||
func (m *msgLoopback) Send(msg tea.Msg) {
|
||||
m.program.Send(msg)
|
||||
}
|
||||
|
||||
func newTestModel(descr string) tea.Model {
|
||||
return teamodels.TestModel{
|
||||
Message: descr,
|
||||
OnKeyPressed: func(k string) tea.Cmd {
|
||||
log.Println("got key press: " + k)
|
||||
if k == "enter" {
|
||||
return tea.Batch(
|
||||
tableselect.IndicateLoadingTables(),
|
||||
tea.Sequentially(
|
||||
func() tea.Msg {
|
||||
<-time.After(2 * time.Second)
|
||||
return nil
|
||||
},
|
||||
tableselect.ShowTableSelect(func(n string) tea.Cmd {
|
||||
// return statusandprompt.SetStatus("New table = " + n)
|
||||
return nil
|
||||
}),
|
||||
),
|
||||
)
|
||||
} else if k == "k" {
|
||||
return modal.PopMode
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
//
|
||||
//type msgLoopback struct {
|
||||
// program *tea.Program
|
||||
//}
|
||||
//
|
||||
//func (m *msgLoopback) Send(msg tea.Msg) {
|
||||
// m.program.Send(msg)
|
||||
//}
|
||||
|
|
|
@ -1,49 +1,45 @@
|
|||
package commandctrl
|
||||
|
||||
import (
|
||||
"context"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"strings"
|
||||
|
||||
"github.com/lmika/awstools/internal/common/ui/events"
|
||||
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
||||
"github.com/lmika/shellwords"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type CommandController struct {
|
||||
commands map[string]uimodels.Operation
|
||||
commands map[string]Command
|
||||
}
|
||||
|
||||
func NewCommandController(commands map[string]uimodels.Operation) *CommandController {
|
||||
func NewCommandController(commands map[string]Command) *CommandController {
|
||||
return &CommandController{
|
||||
commands: commands,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CommandController) Prompt() uimodels.Operation {
|
||||
return uimodels.OperationFn(func(ctx context.Context) error {
|
||||
uiCtx := uimodels.Ctx(ctx)
|
||||
uiCtx.Send(events.PromptForInputMsg{
|
||||
func (c *CommandController) Prompt() tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
return events.PromptForInputMsg{
|
||||
Prompt: ":",
|
||||
// OnDone: c.Execute(),
|
||||
})
|
||||
OnDone: func(value string) tea.Cmd {
|
||||
return c.Execute(value)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CommandController) Execute(commandInput string) tea.Cmd {
|
||||
input := strings.TrimSpace(commandInput)
|
||||
if input == "" {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CommandController) Execute() uimodels.Operation {
|
||||
return uimodels.OperationFn(func(ctx context.Context) error {
|
||||
input := strings.TrimSpace(uimodels.PromptValue(ctx))
|
||||
if input == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokens := shellwords.Split(input)
|
||||
command, ok := c.commands[tokens[0]]
|
||||
if !ok {
|
||||
return errors.New("no such command: " + tokens[0])
|
||||
}
|
||||
|
||||
return command.Execute(WithCommandArgs(ctx, tokens[1:]))
|
||||
})
|
||||
}
|
||||
|
||||
tokens := shellwords.Split(input)
|
||||
command, ok := c.commands[tokens[0]]
|
||||
if !ok {
|
||||
return events.SetStatus("no such command: " + tokens[0])
|
||||
}
|
||||
|
||||
return command(tokens)
|
||||
}
|
||||
|
|
11
internal/common/ui/commandctrl/types.go
Normal file
11
internal/common/ui/commandctrl/types.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package commandctrl
|
||||
|
||||
import tea "github.com/charmbracelet/bubbletea"
|
||||
|
||||
type Command func(args []string) tea.Cmd
|
||||
|
||||
func NoArgCommand(cmd tea.Cmd) Command {
|
||||
return func(args []string) tea.Cmd {
|
||||
return cmd
|
||||
}
|
||||
}
|
|
@ -2,8 +2,6 @@ package controllers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/lmika/awstools/internal/common/ui/events"
|
||||
"github.com/lmika/awstools/internal/dynamo-browse/models"
|
||||
|
@ -52,20 +50,16 @@ func (c *TableReadController) scanTable(name string) tea.Cmd {
|
|||
return func() tea.Msg {
|
||||
ctx := context.Background()
|
||||
|
||||
log.Println("Fetching table info")
|
||||
tableInfo, err := c.tableService.Describe(ctx, name)
|
||||
if err != nil {
|
||||
return events.Error(errors.Wrapf(err, "cannot describe %v", c.tableName))
|
||||
}
|
||||
|
||||
log.Println("Scanning")
|
||||
resultSet, err := c.tableService.Scan(ctx, tableInfo)
|
||||
if err != nil {
|
||||
log.Println("error: ", err)
|
||||
return events.Error(err)
|
||||
}
|
||||
|
||||
log.Println("Scan done")
|
||||
return NewResultSet{resultSet}
|
||||
}
|
||||
}
|
||||
|
@ -74,14 +68,11 @@ 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")
|
||||
return NewResultSet{resultSet}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package ui
|
||||
|
||||
import tea "github.com/charmbracelet/bubbletea"
|
||||
|
||||
type MessagePublisher interface {
|
||||
Send(msg tea.Msg)
|
||||
}
|
|
@ -2,6 +2,7 @@ package ui
|
|||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/lmika/awstools/internal/common/ui/commandctrl"
|
||||
"github.com/lmika/awstools/internal/dynamo-browse/controllers"
|
||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/dynamoitemview"
|
||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/dynamotableview"
|
||||
|
@ -12,12 +13,13 @@ import (
|
|||
|
||||
type Model struct {
|
||||
tableReadController *controllers.TableReadController
|
||||
commandController *commandctrl.CommandController
|
||||
|
||||
root tea.Model
|
||||
}
|
||||
|
||||
func NewModel(rc *controllers.TableReadController) Model {
|
||||
dtv := dynamotableview.New(rc)
|
||||
func NewModel(rc *controllers.TableReadController, cc *commandctrl.CommandController) Model {
|
||||
dtv := dynamotableview.New(rc, cc)
|
||||
div := dynamoitemview.New()
|
||||
|
||||
m := statusandprompt.New(
|
||||
|
@ -28,6 +30,7 @@ func NewModel(rc *controllers.TableReadController) Model {
|
|||
|
||||
return Model{
|
||||
tableReadController: rc,
|
||||
commandController: cc,
|
||||
root: root,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,303 +0,0 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
table "github.com/calyptia/go-bubble-table"
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
"github.com/charmbracelet/bubbles/viewport"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/lmika/awstools/internal/common/ui/commandctrl"
|
||||
"github.com/lmika/awstools/internal/common/ui/dispatcher"
|
||||
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
||||
"github.com/lmika/awstools/internal/dynamo-browse/controllers"
|
||||
)
|
||||
|
||||
var (
|
||||
activeHeaderStyle = lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("#ffffff")).
|
||||
Background(lipgloss.Color("#4479ff"))
|
||||
|
||||
inactiveHeaderStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#000000")).
|
||||
Background(lipgloss.Color("#d1d1d1"))
|
||||
)
|
||||
|
||||
type uiModel struct {
|
||||
table table.Model
|
||||
viewport viewport.Model
|
||||
|
||||
// TEMP
|
||||
tableSelect tea.Model
|
||||
|
||||
tableWidth, tableHeight int
|
||||
|
||||
ready bool
|
||||
state controllers.State
|
||||
message string
|
||||
|
||||
// pendingInput *events.PromptForInput
|
||||
textInput textinput.Model
|
||||
|
||||
dispatcher *dispatcher.Dispatcher
|
||||
commandController *commandctrl.CommandController
|
||||
tableReadController *controllers.TableReadController
|
||||
tableWriteController *controllers.TableWriteController
|
||||
}
|
||||
|
||||
func NewModelOld(dispatcher *dispatcher.Dispatcher, commandController *commandctrl.CommandController, tableReadController *controllers.TableReadController, tableWriteController *controllers.TableWriteController) tea.Model {
|
||||
tbl := table.New([]string{"pk", "sk"}, 100, 20)
|
||||
rows := make([]table.Row, 0)
|
||||
tbl.SetRows(rows)
|
||||
|
||||
textInput := textinput.New()
|
||||
|
||||
model := uiModel{
|
||||
table: tbl,
|
||||
message: "Press s to scan",
|
||||
textInput: textInput,
|
||||
|
||||
// TEMP
|
||||
tableSelect: newSizeWaitModel(func(w, h int) tea.Model {
|
||||
return newTableSelectModel(w, h)
|
||||
}),
|
||||
|
||||
dispatcher: dispatcher,
|
||||
commandController: commandController,
|
||||
tableReadController: tableReadController,
|
||||
tableWriteController: tableWriteController,
|
||||
}
|
||||
|
||||
return model
|
||||
}
|
||||
|
||||
func (m uiModel) Init() tea.Cmd {
|
||||
//m.invokeOperation(context.Background(), m.tableReadController.Scan())
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (m *uiModel) updateTable() {
|
||||
if !m.ready {
|
||||
return
|
||||
}
|
||||
|
||||
resultSet := m.state.ResultSet
|
||||
newTbl := table.New(resultSet.Columns, m.tableWidth, m.tableHeight)
|
||||
newRows := make([]table.Row, len(resultSet.Items))
|
||||
for i, r := range resultSet.Items {
|
||||
newRows[i] = itemTableRow{resultSet, r}
|
||||
}
|
||||
newTbl.SetRows(newRows)
|
||||
|
||||
m.table = newTbl
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (m *uiModel) selectedItem() (itemTableRow, bool) {
|
||||
resultSet := m.state.ResultSet
|
||||
if m.ready && resultSet != nil && len(resultSet.Items) > 0 {
|
||||
selectedItem, ok := m.table.SelectedRow().(itemTableRow)
|
||||
if ok {
|
||||
return selectedItem, true
|
||||
}
|
||||
}
|
||||
|
||||
return itemTableRow{}, false
|
||||
}
|
||||
|
||||
func (m *uiModel) 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())
|
||||
}
|
||||
*/
|
||||
|
||||
func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var textInputCommands tea.Cmd
|
||||
|
||||
switch msg := msg.(type) {
|
||||
|
||||
// Local events
|
||||
case controllers.NewResultSet:
|
||||
m.state.ResultSet = msg.ResultSet
|
||||
// m.updateTable()
|
||||
// m.updateViewportToSelectedMessage()
|
||||
case controllers.SetReadWrite:
|
||||
m.state.InReadWriteMode = msg.NewValue
|
||||
|
||||
// Shared events
|
||||
// case events.Error:
|
||||
// m.message = "Error: " + msg.Error()
|
||||
// case events.Message:
|
||||
// m.message = string(msg)
|
||||
// case events.PromptForInput:
|
||||
// m.textInput.Prompt = msg.Prompt
|
||||
// m.textInput.Focus()
|
||||
// m.textInput.SetValue("")
|
||||
// m.pendingInput = &msg
|
||||
|
||||
// Tea events
|
||||
case tea.WindowSizeMsg:
|
||||
fixedViewsHeight := lipgloss.Height(m.headerView()) + lipgloss.Height(m.splitterView()) + lipgloss.Height(m.footerView())
|
||||
viewportHeight := msg.Height / 2 // TODO: make this dynamic
|
||||
if viewportHeight > 15 {
|
||||
viewportHeight = 15
|
||||
}
|
||||
tableHeight := msg.Height - fixedViewsHeight - viewportHeight
|
||||
|
||||
if !m.ready {
|
||||
m.viewport = viewport.New(msg.Width, viewportHeight)
|
||||
m.viewport.SetContent("(no message selected)")
|
||||
m.ready = true
|
||||
} else {
|
||||
m.viewport.Width = msg.Width
|
||||
m.viewport.Height = msg.Height - tableHeight - fixedViewsHeight
|
||||
}
|
||||
|
||||
m.tableWidth, m.tableHeight = msg.Width, tableHeight
|
||||
m.table.SetSize(m.tableWidth, m.tableHeight)
|
||||
|
||||
case tea.KeyMsg:
|
||||
|
||||
// If text input in focus, allow that to accept input messages
|
||||
// if m.pendingInput != nil {
|
||||
// switch msg.String() {
|
||||
// case "ctrl+c", "esc":
|
||||
// m.pendingInput = nil
|
||||
// case "enter":
|
||||
// m.invokeOperation(uimodels.WithPromptValue(context.Background(), m.textInput.Value()), m.pendingInput.OnDone)
|
||||
// m.pendingInput = nil
|
||||
// default:
|
||||
// m.textInput, textInputCommands = m.textInput.Update(msg)
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "q":
|
||||
return m, tea.Quit
|
||||
case "up", "i":
|
||||
m.table.GoUp()
|
||||
// m.updateViewportToSelectedMessage()
|
||||
case "down", "k":
|
||||
m.table.GoDown()
|
||||
// m.updateViewportToSelectedMessage()
|
||||
|
||||
// TODO: these should be moved somewhere else
|
||||
case ":":
|
||||
m.invokeOperation(context.Background(), m.commandController.Prompt())
|
||||
// case "s":
|
||||
// m.invokeOperation(context.Background(), m.tableReadController.Scan())
|
||||
case "D":
|
||||
m.invokeOperation(context.Background(), m.tableWriteController.Delete())
|
||||
}
|
||||
default:
|
||||
m.textInput, textInputCommands = m.textInput.Update(msg)
|
||||
}
|
||||
|
||||
updatedTable, tableMsgs := m.table.Update(msg)
|
||||
updatedViewport, viewportMsgs := m.viewport.Update(msg)
|
||||
updatedTableSelectModel, tableSelectMsgs := m.tableSelect.Update(msg)
|
||||
|
||||
m.table = updatedTable
|
||||
m.viewport = updatedViewport
|
||||
m.tableSelect = updatedTableSelectModel
|
||||
|
||||
return m, tea.Batch(textInputCommands, tableMsgs, viewportMsgs, tableSelectMsgs)
|
||||
}
|
||||
|
||||
func (m uiModel) invokeOperation(ctx context.Context, op uimodels.Operation) {
|
||||
state := m.state
|
||||
// if selectedItem, ok := m.selectedItem(); ok {
|
||||
// state.SelectedItem = selectedItem.item
|
||||
// }
|
||||
|
||||
ctx = controllers.ContextWithState(ctx, state)
|
||||
m.dispatcher.Start(ctx, op)
|
||||
}
|
||||
|
||||
func (m uiModel) View() string {
|
||||
// TEMP
|
||||
return m.tableSelect.View()
|
||||
|
||||
/*
|
||||
if !m.ready {
|
||||
return "Initializing"
|
||||
}
|
||||
|
||||
if m.pendingInput != nil {
|
||||
return lipgloss.JoinVertical(lipgloss.Top,
|
||||
m.headerView(),
|
||||
m.table.View(),
|
||||
m.splitterView(),
|
||||
m.viewport.View(),
|
||||
m.textInput.View(),
|
||||
)
|
||||
}
|
||||
|
||||
return lipgloss.JoinVertical(lipgloss.Top,
|
||||
m.headerView(),
|
||||
m.table.View(),
|
||||
m.splitterView(),
|
||||
m.viewport.View(),
|
||||
m.footerView(),
|
||||
)
|
||||
*/
|
||||
}
|
||||
|
||||
func (m uiModel) headerView() string {
|
||||
var titleText string
|
||||
if m.state.ResultSet != nil {
|
||||
titleText = "Table: " + m.state.ResultSet.TableInfo.Name
|
||||
} else {
|
||||
titleText = "No table"
|
||||
}
|
||||
|
||||
title := activeHeaderStyle.Render(titleText)
|
||||
line := activeHeaderStyle.Render(strings.Repeat(" ", max(0, m.viewport.Width-lipgloss.Width(title))))
|
||||
return lipgloss.JoinHorizontal(lipgloss.Left, title, line)
|
||||
}
|
||||
|
||||
func (m uiModel) splitterView() string {
|
||||
title := inactiveHeaderStyle.Render("Item")
|
||||
line := inactiveHeaderStyle.Render(strings.Repeat(" ", max(0, m.viewport.Width-lipgloss.Width(title))))
|
||||
return lipgloss.JoinHorizontal(lipgloss.Left, title, line)
|
||||
}
|
||||
|
||||
func (m uiModel) footerView() string {
|
||||
title := m.message
|
||||
line := strings.Repeat(" ", max(0, m.viewport.Width-lipgloss.Width(title)))
|
||||
return lipgloss.JoinHorizontal(lipgloss.Left, title, line)
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"log"
|
||||
)
|
||||
|
||||
// sizeWaitModel is a model which waits until the first screen size message comes through. It then creates the
|
||||
// submodel and delegates calls to that model
|
||||
type sizeWaitModel struct {
|
||||
constr func(width, height int) tea.Model
|
||||
model tea.Model
|
||||
}
|
||||
|
||||
func newSizeWaitModel(constr func(width, height int) tea.Model) tea.Model {
|
||||
return sizeWaitModel{constr: constr}
|
||||
}
|
||||
|
||||
func (s sizeWaitModel) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s sizeWaitModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch m := msg.(type) {
|
||||
case tea.WindowSizeMsg:
|
||||
log.Println("got window size message")
|
||||
if s.model == nil {
|
||||
log.Println("creating model")
|
||||
s.model = s.constr(m.Width, m.Height)
|
||||
s.model.Init()
|
||||
}
|
||||
}
|
||||
|
||||
var submodelCmds tea.Cmd
|
||||
if s.model != nil {
|
||||
log.Println("starting update")
|
||||
s.model, submodelCmds = s.model.Update(msg)
|
||||
log.Println("ending update")
|
||||
}
|
||||
return s, submodelCmds
|
||||
}
|
||||
|
||||
func (s sizeWaitModel) View() string {
|
||||
if s.model == nil {
|
||||
return ""
|
||||
}
|
||||
return s.model.View()
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
var (
|
||||
titleStyle = lipgloss.NewStyle().MarginLeft(2)
|
||||
itemStyle = lipgloss.NewStyle().PaddingLeft(4)
|
||||
selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170"))
|
||||
paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
|
||||
helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
|
||||
quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4)
|
||||
)
|
||||
|
||||
type tableSelectModel struct {
|
||||
list list.Model
|
||||
}
|
||||
|
||||
func (t tableSelectModel) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t tableSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.WindowSizeMsg:
|
||||
t.list.SetHeight(msg.Height)
|
||||
t.list.SetWidth(msg.Width)
|
||||
return t, nil
|
||||
|
||||
case tea.KeyMsg:
|
||||
switch keypress := msg.String(); keypress {
|
||||
case "ctrl+c":
|
||||
return t, tea.Quit
|
||||
|
||||
case "enter":
|
||||
//i, ok := m.list.SelectedItem().(item)
|
||||
//if ok {
|
||||
// m.choice = string(i)
|
||||
//}
|
||||
return t, tea.Quit
|
||||
}
|
||||
}
|
||||
|
||||
var cmd tea.Cmd
|
||||
t.list, cmd = t.list.Update(msg)
|
||||
return t, cmd
|
||||
}
|
||||
|
||||
func (t tableSelectModel) View() string {
|
||||
return t.list.View()
|
||||
}
|
||||
|
||||
func newTableSelectModel(w, h int) tableSelectModel {
|
||||
tableItems := []tableItem{
|
||||
{name: "alpha"},
|
||||
{name: "beta"},
|
||||
{name: "gamma"},
|
||||
}
|
||||
|
||||
items := toListItems(tableItems)
|
||||
|
||||
delegate := list.NewDefaultDelegate()
|
||||
delegate.ShowDescription = false
|
||||
|
||||
return tableSelectModel{
|
||||
list: list.New(items, delegate, w, h),
|
||||
}
|
||||
}
|
||||
|
||||
type tableItem struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (ti tableItem) FilterValue() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ti tableItem) Title() string {
|
||||
return ti.name
|
||||
}
|
||||
|
||||
func (ti tableItem) Description() string {
|
||||
return "abc"
|
||||
}
|
||||
|
||||
func toListItems[T list.Item](xs []T) []list.Item {
|
||||
ls := make([]list.Item, len(xs))
|
||||
for i, x := range xs {
|
||||
ls[i] = x
|
||||
}
|
||||
return ls
|
||||
}
|
|
@ -4,6 +4,7 @@ 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,15 +14,17 @@ import (
|
|||
|
||||
type Model struct {
|
||||
tableReadControllers *controllers.TableReadController
|
||||
frameTitle frame.FrameTitle
|
||||
table table.Model
|
||||
w, h int
|
||||
commandCtrl *commandctrl.CommandController
|
||||
|
||||
frameTitle frame.FrameTitle
|
||||
table table.Model
|
||||
w, h int
|
||||
|
||||
// model state
|
||||
resultSet *models.ResultSet
|
||||
}
|
||||
|
||||
func New(tableReadControllers *controllers.TableReadController) Model {
|
||||
func New(tableReadControllers *controllers.TableReadController, commandCtrl *commandctrl.CommandController) Model {
|
||||
tbl := table.New([]string{"pk", "sk"}, 100, 100)
|
||||
rows := make([]table.Row, 0)
|
||||
tbl.SetRows(rows)
|
||||
|
@ -30,6 +33,7 @@ func New(tableReadControllers *controllers.TableReadController) Model {
|
|||
|
||||
return Model{
|
||||
tableReadControllers: tableReadControllers,
|
||||
commandCtrl: commandCtrl,
|
||||
frameTitle: frameTitle,
|
||||
table: tbl,
|
||||
}
|
||||
|
@ -58,6 +62,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
// 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
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
package teamodels
|
||||
|
||||
import tea "github.com/charmbracelet/bubbletea"
|
||||
|
||||
// NewModePushed pushes a new mode on the modal stack
|
||||
type NewModePushed tea.Model
|
||||
|
||||
// ModePopped pops a mode from the modal stack
|
||||
type ModePopped struct{}
|
|
@ -1,33 +0,0 @@
|
|||
package teamodels
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
// TestModel is a model used for testing
|
||||
type TestModel struct {
|
||||
Message string
|
||||
OnKeyPressed func(k string) tea.Cmd
|
||||
}
|
||||
|
||||
func (t TestModel) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t TestModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "esc":
|
||||
return t, tea.Quit
|
||||
default:
|
||||
return t, t.OnKeyPressed(msg.String())
|
||||
}
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (t TestModel) View() string {
|
||||
return t.Message
|
||||
}
|
Loading…
Reference in a new issue