ssm-browse: added mark and delete in dynamo-browse
This commit is contained in:
parent
b3d0fbfe29
commit
c49f3913a8
|
@ -44,24 +44,10 @@ func main() {
|
||||||
tableService := tables.NewService(dynamoProvider)
|
tableService := tables.NewService(dynamoProvider)
|
||||||
|
|
||||||
tableReadController := controllers.NewTableReadController(tableService, *flagTable)
|
tableReadController := controllers.NewTableReadController(tableService, *flagTable)
|
||||||
tableWriteController := controllers.NewTableWriteController(tableService, tableReadController, *flagTable)
|
tableWriteController := controllers.NewTableWriteController(tableService, tableReadController)
|
||||||
_ = tableWriteController
|
|
||||||
|
|
||||||
commandController := commandctrl.NewCommandController()
|
commandController := commandctrl.NewCommandController()
|
||||||
commandController.AddCommands(&commandctrl.CommandContext{
|
model := ui.NewModel(tableReadController, tableWriteController, commandController)
|
||||||
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)
|
|
||||||
|
|
||||||
// Pre-determine if layout has dark background. This prevents calls for creating a list to hang.
|
// Pre-determine if layout has dark background. This prevents calls for creating a list to hang.
|
||||||
lipgloss.HasDarkBackground()
|
lipgloss.HasDarkBackground()
|
||||||
|
|
|
@ -23,3 +23,5 @@ type PromptForTableMsg struct {
|
||||||
Tables []string
|
Tables []string
|
||||||
OnSelected func(tableName string) tea.Cmd
|
OnSelected func(tableName string) tea.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ResultSetUpdated struct{}
|
||||||
|
|
|
@ -72,17 +72,26 @@ func (c *TableReadController) ScanTable(name string) tea.Cmd {
|
||||||
|
|
||||||
func (c *TableReadController) Rescan() tea.Cmd {
|
func (c *TableReadController) Rescan() tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
ctx := context.Background()
|
return c.doScan(context.Background(), c.resultSet)
|
||||||
|
|
||||||
resultSet, err := c.tableService.Scan(ctx, c.resultSet.TableInfo)
|
|
||||||
if err != nil {
|
|
||||||
return events.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.setResultSet(resultSet)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *TableReadController) doScan(ctx context.Context, resultSet *models.ResultSet) tea.Msg {
|
||||||
|
newResultSet, err := c.tableService.Scan(ctx, resultSet.TableInfo)
|
||||||
|
if err != nil {
|
||||||
|
return events.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.setResultSet(newResultSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TableReadController) ResultSet() *models.ResultSet {
|
||||||
|
c.mutex.Lock()
|
||||||
|
defer c.mutex.Unlock()
|
||||||
|
|
||||||
|
return c.resultSet
|
||||||
|
}
|
||||||
|
|
||||||
func (c *TableReadController) setResultSet(resultSet *models.ResultSet) tea.Msg {
|
func (c *TableReadController) setResultSet(resultSet *models.ResultSet) tea.Msg {
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
|
@ -90,51 +99,3 @@ func (c *TableReadController) setResultSet(resultSet *models.ResultSet) tea.Msg
|
||||||
c.resultSet = resultSet
|
c.resultSet = resultSet
|
||||||
return NewResultSet{resultSet}
|
return NewResultSet{resultSet}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func (c *TableReadController) Scan() uimodels.Operation {
|
|
||||||
return uimodels.OperationFn(func(ctx context.Context) error {
|
|
||||||
return c.doScan(ctx, false)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TableReadController) doScan(ctx context.Context, quiet bool) (err error) {
|
|
||||||
uiCtx := uimodels.Ctx(ctx)
|
|
||||||
|
|
||||||
if !quiet {
|
|
||||||
uiCtx.Message("Scanning...")
|
|
||||||
}
|
|
||||||
|
|
||||||
tableInfo, err := c.tableInfo(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resultSet, err := c.tableService.Scan(ctx, tableInfo)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !quiet {
|
|
||||||
uiCtx.Messagef("Found %d items", len(resultSet.Items))
|
|
||||||
}
|
|
||||||
uiCtx.Send(NewResultSet{resultSet})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// tableInfo returns the table info from the state if a result set exists. If not, it fetches the
|
|
||||||
// table information from the service.
|
|
||||||
// func (c *TableReadController) tableInfo(ctx context.Context) (*models.TableInfo, error) {
|
|
||||||
// /*
|
|
||||||
// if existingResultSet := CurrentState(ctx).ResultSet; existingResultSet != nil {
|
|
||||||
// return existingResultSet.TableInfo, nil
|
|
||||||
// }
|
|
||||||
// */
|
|
||||||
|
|
||||||
// tableInfo, err := c.tableService.Describe(ctx, c.tableName)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, errors.Wrapf(err, "cannot describe %v", c.tableName)
|
|
||||||
// }
|
|
||||||
// return tableInfo, nil
|
|
||||||
// }
|
|
||||||
|
|
|
@ -2,137 +2,58 @@ package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"github.com/lmika/awstools/internal/common/ui/uimodels"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/lmika/awstools/internal/common/ui/events"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
|
"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TableWriteController struct {
|
type TableWriteController struct {
|
||||||
tableService *tables.Service
|
tableService *tables.Service
|
||||||
tableReadControllers *TableReadController
|
tableReadControllers *TableReadController
|
||||||
tableName string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTableWriteController(tableService *tables.Service, tableReadControllers *TableReadController, tableName string) *TableWriteController {
|
func NewTableWriteController(tableService *tables.Service, tableReadControllers *TableReadController) *TableWriteController {
|
||||||
return &TableWriteController{
|
return &TableWriteController{
|
||||||
tableService: tableService,
|
tableService: tableService,
|
||||||
tableReadControllers: tableReadControllers,
|
tableReadControllers: tableReadControllers,
|
||||||
tableName: tableName,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TableWriteController) ToggleReadWrite() uimodels.Operation {
|
func (twc *TableWriteController) ToggleMark(idx int) tea.Cmd {
|
||||||
return uimodels.OperationFn(func(ctx context.Context) error {
|
return func() tea.Msg {
|
||||||
uiCtx := uimodels.Ctx(ctx)
|
resultSet := twc.tableReadControllers.ResultSet()
|
||||||
state := CurrentState(ctx)
|
resultSet.SetMark(idx, !resultSet.Marked(idx))
|
||||||
|
|
||||||
if state.InReadWriteMode {
|
return ResultSetUpdated{}
|
||||||
uiCtx.Send(SetReadWrite{NewValue: false})
|
}
|
||||||
uiCtx.Message("read/write mode disabled")
|
}
|
||||||
} else {
|
|
||||||
uiCtx.Send(SetReadWrite{NewValue: true})
|
func (twc *TableWriteController) DeleteMarked() tea.Cmd {
|
||||||
uiCtx.Message("read/write mode enabled")
|
return func() tea.Msg {
|
||||||
|
resultSet := twc.tableReadControllers.ResultSet()
|
||||||
|
markedItems := resultSet.MarkedItems()
|
||||||
|
|
||||||
|
if len(markedItems) == 0 {
|
||||||
|
return events.StatusMsg("no marked items")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return events.PromptForInputMsg{
|
||||||
})
|
Prompt: fmt.Sprintf("delete %d items? ", len(markedItems)),
|
||||||
}
|
OnDone: func(value string) tea.Cmd {
|
||||||
|
if value != "y" {
|
||||||
func (c *TableWriteController) Duplicate() uimodels.Operation {
|
return events.SetStatus("operation aborted")
|
||||||
return nil
|
|
||||||
/*
|
|
||||||
return uimodels.OperationFn(func(ctx context.Context) error {
|
|
||||||
uiCtx := uimodels.Ctx(ctx)
|
|
||||||
state := CurrentState(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 {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newItem, err := modExpr.Patch(state.SelectedItem)
|
return func() tea.Msg {
|
||||||
if err != nil {
|
ctx := context.Background()
|
||||||
return err
|
if err := twc.tableService.Delete(ctx, resultSet.TableInfo, markedItems); err != nil {
|
||||||
|
return events.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return twc.tableReadControllers.doScan(ctx, resultSet)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
// TODO: preview new item
|
|
||||||
|
|
||||||
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
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TableWriteController) Delete() uimodels.Operation {
|
|
||||||
return uimodels.OperationFn(func(ctx context.Context) error {
|
|
||||||
uiCtx := uimodels.Ctx(ctx)
|
|
||||||
state := CurrentState(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("Delete item? ", uimodels.OperationFn(func(ctx context.Context) error {
|
|
||||||
uiCtx := uimodels.Ctx(ctx)
|
|
||||||
|
|
||||||
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.Delete(ctx, tableInfo, state.SelectedItem); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Rescan to get updated items
|
|
||||||
// if err := c.tableReadControllers.doScan(ctx, true); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
uiCtx.Message("Item deleted")
|
|
||||||
return nil
|
|
||||||
}))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ type ResultSet struct {
|
||||||
TableInfo *TableInfo
|
TableInfo *TableInfo
|
||||||
Columns []string
|
Columns []string
|
||||||
Items []Item
|
Items []Item
|
||||||
|
Marks map[int]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Item map[string]types.AttributeValue
|
type Item map[string]types.AttributeValue
|
||||||
|
@ -30,3 +31,28 @@ func (i Item) KeyValue(info *TableInfo) map[string]types.AttributeValue {
|
||||||
}
|
}
|
||||||
return itemKey
|
return itemKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rs *ResultSet) SetMark(idx int, marked bool) {
|
||||||
|
if marked {
|
||||||
|
if rs.Marks == nil {
|
||||||
|
rs.Marks = make(map[int]bool)
|
||||||
|
}
|
||||||
|
rs.Marks[idx] = true
|
||||||
|
} else {
|
||||||
|
delete(rs.Marks, idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *ResultSet) Marked(idx int) bool {
|
||||||
|
return rs.Marks[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *ResultSet) MarkedItems() []Item {
|
||||||
|
items := make([]Item, 0)
|
||||||
|
for i, marked := range rs.Marks {
|
||||||
|
if marked {
|
||||||
|
items = append(items, rs.Items[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
|
@ -78,6 +78,11 @@ func (s *Service) Put(ctx context.Context, tableInfo *models.TableInfo, item mod
|
||||||
return s.provider.PutItem(ctx, tableInfo.Name, item)
|
return s.provider.PutItem(ctx, tableInfo.Name, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Delete(ctx context.Context, tableInfo *models.TableInfo, item models.Item) error {
|
func (s *Service) Delete(ctx context.Context, tableInfo *models.TableInfo, items []models.Item) error {
|
||||||
return s.provider.DeleteItem(ctx, tableInfo.Name, item.KeyValue(tableInfo))
|
for _, item := range items {
|
||||||
|
if err := s.provider.DeleteItem(ctx, tableInfo.Name, item.KeyValue(tableInfo)); err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot delete item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,28 +12,46 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
tableReadController *controllers.TableReadController
|
tableReadController *controllers.TableReadController
|
||||||
commandController *commandctrl.CommandController
|
tableWriteController *controllers.TableWriteController
|
||||||
statusAndPrompt *statusandprompt.StatusAndPrompt
|
commandController *commandctrl.CommandController
|
||||||
tableSelect *tableselect.Model
|
statusAndPrompt *statusandprompt.StatusAndPrompt
|
||||||
|
tableSelect *tableselect.Model
|
||||||
|
|
||||||
root tea.Model
|
root tea.Model
|
||||||
|
tableView *dynamotableview.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewModel(rc *controllers.TableReadController, cc *commandctrl.CommandController) Model {
|
func NewModel(rc *controllers.TableReadController, wc *controllers.TableWriteController, cc *commandctrl.CommandController) Model {
|
||||||
dtv := dynamotableview.New()
|
dtv := dynamotableview.New()
|
||||||
div := dynamoitemview.New()
|
div := dynamoitemview.New()
|
||||||
statusAndPrompt := statusandprompt.New(layout.NewVBox(layout.LastChildFixedAt(17), dtv, div), "")
|
statusAndPrompt := statusandprompt.New(layout.NewVBox(layout.LastChildFixedAt(17), dtv, div), "")
|
||||||
tableSelect := tableselect.New(statusAndPrompt)
|
tableSelect := tableselect.New(statusAndPrompt)
|
||||||
|
|
||||||
|
cc.AddCommands(&commandctrl.CommandContext{
|
||||||
|
Commands: map[string]commandctrl.Command{
|
||||||
|
"q": commandctrl.NoArgCommand(tea.Quit),
|
||||||
|
"table": func(args []string) tea.Cmd {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return rc.ListTables()
|
||||||
|
} else {
|
||||||
|
return rc.ScanTable(args[0])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": commandctrl.NoArgCommand(wc.DeleteMarked()),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
root := layout.FullScreen(tableSelect)
|
root := layout.FullScreen(tableSelect)
|
||||||
|
|
||||||
return Model{
|
return Model{
|
||||||
tableReadController: rc,
|
tableReadController: rc,
|
||||||
commandController: cc,
|
tableWriteController: wc,
|
||||||
statusAndPrompt: statusAndPrompt,
|
commandController: cc,
|
||||||
tableSelect: tableSelect,
|
statusAndPrompt: statusAndPrompt,
|
||||||
root: root,
|
tableSelect: tableSelect,
|
||||||
|
root: root,
|
||||||
|
tableView: dtv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,9 +61,13 @@ 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) {
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
|
case controllers.ResultSetUpdated:
|
||||||
|
m.tableView.Refresh()
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
if !m.statusAndPrompt.InPrompt() && !m.tableSelect.Visible() {
|
if !m.statusAndPrompt.InPrompt() && !m.tableSelect.Visible() {
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
|
case "m":
|
||||||
|
return m, m.tableWriteController.ToggleMark(m.tableView.SelectedItemIndex())
|
||||||
case "s":
|
case "s":
|
||||||
return m, m.tableReadController.Rescan()
|
return m, m.tableReadController.Rescan()
|
||||||
case ":":
|
case ":":
|
||||||
|
|
|
@ -28,8 +28,8 @@ func New() *Model {
|
||||||
frameTitle := frame.NewFrameTitle("No table", true)
|
frameTitle := frame.NewFrameTitle("No table", true)
|
||||||
|
|
||||||
return &Model{
|
return &Model{
|
||||||
frameTitle: frameTitle,
|
frameTitle: frameTitle,
|
||||||
table: tbl,
|
table: tbl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +85,10 @@ func (m *Model) updateTable() {
|
||||||
m.table = newTbl
|
m.table = newTbl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Model) SelectedItemIndex() int {
|
||||||
|
return m.table.Cursor()
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Model) selectedItem() (itemTableRow, bool) {
|
func (m *Model) selectedItem() (itemTableRow, bool) {
|
||||||
resultSet := m.resultSet
|
resultSet := m.resultSet
|
||||||
if resultSet != nil && len(resultSet.Items) > 0 {
|
if resultSet != nil && len(resultSet.Items) > 0 {
|
||||||
|
@ -105,3 +109,8 @@ func (m *Model) postSelectedItemChanged() tea.Msg {
|
||||||
|
|
||||||
return dynamoitemview.NewItemSelected{ResultSet: item.resultSet, Item: item.item}
|
return dynamoitemview.NewItemSelected{ResultSet: item.resultSet, Item: item.item}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Model) Refresh() {
|
||||||
|
m.table.GoDown()
|
||||||
|
m.table.GoUp()
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package dynamotableview
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/charmbracelet/lipgloss"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -10,12 +11,19 @@ import (
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/models"
|
"github.com/lmika/awstools/internal/dynamo-browse/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
markedRowStyle = lipgloss.NewStyle().
|
||||||
|
Background(lipgloss.Color("#e1e1e1"))
|
||||||
|
)
|
||||||
|
|
||||||
type itemTableRow struct {
|
type itemTableRow struct {
|
||||||
resultSet *models.ResultSet
|
resultSet *models.ResultSet
|
||||||
item models.Item
|
item models.Item
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mtr itemTableRow) Render(w io.Writer, model table.Model, index int) {
|
func (mtr itemTableRow) Render(w io.Writer, model table.Model, index int) {
|
||||||
|
isMarked := mtr.resultSet.Marked(index)
|
||||||
|
|
||||||
sb := strings.Builder{}
|
sb := strings.Builder{}
|
||||||
for i, colName := range mtr.resultSet.Columns {
|
for i, colName := range mtr.resultSet.Columns {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
@ -34,7 +42,13 @@ func (mtr itemTableRow) Render(w io.Writer, model table.Model, index int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if index == model.Cursor() {
|
if index == model.Cursor() {
|
||||||
fmt.Fprintln(w, model.Styles.SelectedRow.Render(sb.String()))
|
style := model.Styles.SelectedRow
|
||||||
|
if isMarked {
|
||||||
|
style = style.Copy().Inherit(markedRowStyle)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, style.Render(sb.String()))
|
||||||
|
} else if isMarked {
|
||||||
|
fmt.Fprintln(w, markedRowStyle.Render(sb.String()))
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(w, sb.String())
|
fmt.Fprintln(w, sb.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/lmika/awstools/internal/common/ui/events"
|
"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"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StatusAndPrompt is a resizing model which displays a submodel and a status bar. When the start prompt
|
// StatusAndPrompt is a resizing model which displays a submodel and a status bar. When the start prompt
|
||||||
|
@ -33,7 +34,7 @@ func (s *StatusAndPrompt) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
case events.ErrorMsg:
|
case events.ErrorMsg:
|
||||||
s.statusMessage = "Error: " + msg.Error()
|
s.statusMessage = "Error: " + msg.Error()
|
||||||
case events.StatusMsg:
|
case events.StatusMsg:
|
||||||
s.statusMessage = string(s.statusMessage)
|
s.statusMessage = string(msg)
|
||||||
case events.MessageWithStatus:
|
case events.MessageWithStatus:
|
||||||
s.statusMessage = msg.StatusMessage()
|
s.statusMessage = msg.StatusMessage()
|
||||||
case events.PromptForInputMsg:
|
case events.PromptForInputMsg:
|
||||||
|
@ -46,15 +47,18 @@ func (s *StatusAndPrompt) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
s.textInput.Focus()
|
s.textInput.Focus()
|
||||||
s.textInput.SetValue("")
|
s.textInput.SetValue("")
|
||||||
s.pendingInput = &msg
|
s.pendingInput = &msg
|
||||||
|
log.Println("pending input == ", s.pendingInput)
|
||||||
return s, nil
|
return s, nil
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
if s.pendingInput != nil {
|
if s.pendingInput != nil {
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "esc":
|
case "ctrl+c", "esc":
|
||||||
s.pendingInput = nil
|
s.pendingInput = nil
|
||||||
|
log.Println("pending input == ", s.pendingInput)
|
||||||
case "enter":
|
case "enter":
|
||||||
pendingInput := s.pendingInput
|
pendingInput := s.pendingInput
|
||||||
s.pendingInput = nil
|
s.pendingInput = nil
|
||||||
|
log.Println("pending input == ", s.pendingInput)
|
||||||
|
|
||||||
return s, pendingInput.OnDone(s.textInput.Value())
|
return s, pendingInput.OnDone(s.textInput.Value())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue