Fixed a glaring error where the user cannot close the column selector
Some checks failed
ci / build (push) Has been cancelled

Cause of this was that the close event type was also being used by the related overlay, and the event was being caught by that even though the overlay was hidden.

Also started working on changing the sort order within the column selector by pressing S.
This commit is contained in:
Leon Mika 2024-04-02 23:00:19 +11:00
parent f5bf31a903
commit e37b8099a3
20 changed files with 213 additions and 67 deletions

View file

@ -123,7 +123,7 @@ func main() {
*flagTable, *flagTable,
) )
tableWriteController := controllers.NewTableWriteController(state, tableService, jobsController, tableReadController, settingStore) tableWriteController := controllers.NewTableWriteController(state, tableService, jobsController, tableReadController, settingStore)
columnsController := controllers.NewColumnsController(eventBus) columnsController := controllers.NewColumnsController(tableReadController, eventBus)
exportController := controllers.NewExportController(state, tableService, jobsController, columnsController, pasteboardProvider) exportController := controllers.NewExportController(state, tableService, jobsController, columnsController, pasteboardProvider)
settingsController := controllers.NewSettingsController(settingStore, eventBus) settingsController := controllers.NewSettingsController(settingStore, eventBus)
keyBindings := keybindings.Default() keyBindings := keybindings.Default()

View file

@ -5,19 +5,22 @@ import (
"github.com/lmika/dynamo-browse/internal/common/ui/events" "github.com/lmika/dynamo-browse/internal/common/ui/events"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models" "github.com/lmika/dynamo-browse/internal/dynamo-browse/models"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models/columns" "github.com/lmika/dynamo-browse/internal/dynamo-browse/models/columns"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models/evaluators"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models/queryexpr" "github.com/lmika/dynamo-browse/internal/dynamo-browse/models/queryexpr"
bus "github.com/lmika/events" bus "github.com/lmika/events"
"strings" "strings"
) )
type ColumnsController struct { type ColumnsController struct {
tr *TableReadController
// State // State
colModel *columns.Columns colModel *columns.Columns
resultSet *models.ResultSet resultSet *models.ResultSet
} }
func NewColumnsController(eventBus *bus.Bus) *ColumnsController { func NewColumnsController(tr *TableReadController, eventBus *bus.Bus) *ColumnsController {
cc := &ColumnsController{} cc := &ColumnsController{tr: tr}
eventBus.On(newResultSetEvent, cc.onNewResultSet) eventBus.On(newResultSetEvent, cc.onNewResultSet)
return cc return cc
@ -80,7 +83,7 @@ func (cc *ColumnsController) AddColumn(afterIndex int) tea.Msg {
newCol := columns.Column{ newCol := columns.Column{
Name: colExpr.String(), Name: colExpr.String(),
Evaluator: columns.ExprFieldValueEvaluator{Expr: colExpr}, Evaluator: queryexpr.ExprFieldValueEvaluator{Expr: colExpr},
} }
if afterIndex >= len(cc.colModel.Columns)-1 { if afterIndex >= len(cc.colModel.Columns)-1 {
@ -117,6 +120,25 @@ func (cc *ColumnsController) DeleteColumn(afterIndex int) tea.Msg {
return ColumnsUpdated{} return ColumnsUpdated{}
} }
func (cc *ColumnsController) SortByColumn(index int) tea.Msg {
if index >= len(cc.colModel.Columns) {
return nil
}
column := cc.colModel.Columns[index]
newCriteria := models.SortCriteria{
Fields: []models.SortField{
{Field: column.Evaluator, Asc: true},
},
}
if ff := cc.SortCriteria().FirstField(); evaluators.Equals(ff.Field, column.Evaluator) {
newCriteria.Fields[0].Asc = !ff.Asc
}
cc.SetSortCriteria(newCriteria)
return ColumnsUpdated{}
}
func (c *ColumnsController) AttributesWithPrefix(prefix string) []string { func (c *ColumnsController) AttributesWithPrefix(prefix string) []string {
options := make([]string, 0) options := make([]string, 0)
for _, col := range c.resultSet.Columns() { for _, col := range c.resultSet.Columns() {
@ -126,3 +148,15 @@ func (c *ColumnsController) AttributesWithPrefix(prefix string) []string {
} }
return options return options
} }
func (cc *ColumnsController) SortCriteria() models.SortCriteria {
if cc.resultSet == nil {
return models.SortCriteria{}
}
return cc.resultSet.SortCriteria()
}
func (cc *ColumnsController) SetSortCriteria(criteria models.SortCriteria) {
cc.tr.SortResultSet(criteria)
}

View file

@ -35,6 +35,7 @@ const (
resultSetUpdateTouch resultSetUpdateTouch
resultSetUpdateNextPage resultSetUpdateNextPage
resultSetUpdateScript resultSetUpdateScript
resultSetUpdateResort
) )
type MarkOp int type MarkOp int
@ -150,6 +151,13 @@ func (c *TableReadController) ScanTable(name string) tea.Msg {
}).OnEither(c.handleResultSetFromJobResult(c.state.Filter(), true, false, resultSetUpdateInit)).Submit() }).OnEither(c.handleResultSetFromJobResult(c.state.Filter(), true, false, resultSetUpdateInit)).Submit()
} }
func (c *TableReadController) SortResultSet(newCriteria models.SortCriteria) {
c.state.withResultSet(func(rs *models.ResultSet) {
rs.Sort(newCriteria.Append(models.PKSKSortFilter(rs.TableInfo)))
})
c.eventBus.Fire(newResultSetEvent, c.state.resultSet, resultSetUpdateResort)
}
func (c *TableReadController) PromptForQuery() tea.Msg { func (c *TableReadController) PromptForQuery() tea.Msg {
return events.PromptForInputMsg{ return events.PromptForInputMsg{
Prompt: "query: ", Prompt: "query: ",

View file

@ -632,7 +632,7 @@ func newService(t *testing.T, cfg serviceConfig) *services {
) )
writeController := controllers.NewTableWriteController(state, service, jobsController, readController, settingStore) writeController := controllers.NewTableWriteController(state, service, jobsController, readController, settingStore)
settingsController := controllers.NewSettingsController(settingStore, eventBus) settingsController := controllers.NewSettingsController(settingStore, eventBus)
columnsController := controllers.NewColumnsController(eventBus) columnsController := controllers.NewColumnsController(readController, eventBus)
exportController := controllers.NewExportController(state, service, jobsController, columnsController, pasteboardprovider.NilProvider{}) exportController := controllers.NewExportController(state, service, jobsController, columnsController, pasteboardprovider.NilProvider{})
scriptController := controllers.NewScriptController(scriptService, readController, jobsController, settingsController, eventBus) scriptController := controllers.NewScriptController(scriptService, readController, jobsController, settingsController, eventBus)

View file

@ -1,9 +1,7 @@
package columns package columns
import ( import (
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models" "github.com/lmika/dynamo-browse/internal/dynamo-browse/models"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models/queryexpr"
) )
type Columns struct { type Columns struct {
@ -19,7 +17,7 @@ func NewColumnsFromResultSet(rs *models.ResultSet) *Columns {
for i, c := range rsCols { for i, c := range rsCols {
cols[i] = Column{ cols[i] = Column{
Name: c, Name: c,
Evaluator: SimpleFieldValueEvaluator(c), Evaluator: models.SimpleFieldValueEvaluator(c),
} }
} }
@ -44,7 +42,7 @@ func (cols *Columns) AddMissingColumns(rs *models.ResultSet) {
if _, hasCol := existingColumns[c]; !hasCol { if _, hasCol := existingColumns[c]; !hasCol {
newCols = append(newCols, Column{ newCols = append(newCols, Column{
Name: c, Name: c,
Evaluator: SimpleFieldValueEvaluator(c), Evaluator: models.SimpleFieldValueEvaluator(c),
}) })
} }
} }
@ -56,7 +54,7 @@ func (cols *Columns) AddMissingColumns(rs *models.ResultSet) {
} else { } else {
newCols[i] = Column{ newCols[i] = Column{
Name: c, Name: c,
Evaluator: SimpleFieldValueEvaluator(c), Evaluator: models.SimpleFieldValueEvaluator(c),
} }
} }
} }
@ -82,25 +80,6 @@ func (cols *Columns) VisibleColumns() []Column {
type Column struct { type Column struct {
Name string Name string
Evaluator FieldValueEvaluator Evaluator models.FieldValueEvaluator
Hidden bool Hidden bool
} }
type FieldValueEvaluator interface {
EvaluateForItem(item models.Item) types.AttributeValue
}
type SimpleFieldValueEvaluator string
func (sfve SimpleFieldValueEvaluator) EvaluateForItem(item models.Item) types.AttributeValue {
return item[string(sfve)]
}
type ExprFieldValueEvaluator struct {
Expr *queryexpr.QueryExpr
}
func (sfve ExprFieldValueEvaluator) EvaluateForItem(item models.Item) types.AttributeValue {
val, _ := sfve.Expr.EvalItem(item)
return val
}

View file

@ -0,0 +1,15 @@
package models
import (
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
type FieldValueEvaluator interface {
EvaluateForItem(item Item) types.AttributeValue
}
type SimpleFieldValueEvaluator string
func (sfve SimpleFieldValueEvaluator) EvaluateForItem(item Item) types.AttributeValue {
return item[string(sfve)]
}

View file

@ -0,0 +1,25 @@
package evaluators
import (
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models/queryexpr"
)
func Equals(x, y models.FieldValueEvaluator) bool {
if x == nil {
return y == nil
}
switch xt := x.(type) {
case models.SimpleFieldValueEvaluator:
if yt, ok := y.(models.SimpleFieldValueEvaluator); ok {
return xt == yt
}
case queryexpr.ExprFieldValueEvaluator:
if yt, ok := y.(queryexpr.ExprFieldValueEvaluator); ok {
return xt.Expr.Equal(yt.Expr)
}
}
return false
}

View file

@ -19,6 +19,7 @@ type ResultSet struct {
attributes []ItemAttribute attributes []ItemAttribute
columns []string columns []string
sortCriteria SortCriteria
} }
type Queryable interface { type Queryable interface {
@ -48,6 +49,10 @@ func (rs *ResultSet) SetItems(items []Item) {
rs.attributes = make([]ItemAttribute, len(items)) rs.attributes = make([]ItemAttribute, len(items))
} }
func (rs *ResultSet) SortCriteria() SortCriteria {
return rs.sortCriteria
}
func (rs *ResultSet) AddNewItem(item Item, attrs ItemAttribute) { func (rs *ResultSet) AddNewItem(item Item, attrs ItemAttribute) {
rs.items = append(rs.items, item) rs.items = append(rs.items, item)
rs.attributes = append(rs.attributes, attrs) rs.attributes = append(rs.attributes, attrs)
@ -141,3 +146,8 @@ func (rs *ResultSet) RefreshColumns() {
func (rs *ResultSet) HasNextPage() bool { func (rs *ResultSet) HasNextPage() bool {
return rs.LastEvaluatedKey != nil return rs.LastEvaluatedKey != nil
} }
func (rs *ResultSet) Sort(criteria SortCriteria) {
rs.sortCriteria = criteria
Sort(rs.items, criteria)
}

View file

@ -53,6 +53,11 @@ func TestModExpr_Query(t *testing.T) {
`#0 = :0`, `#0 = :0`,
exprNameIsString(0, 0, "pk", "prefix"), exprNameIsString(0, 0, "pk", "prefix"),
), ),
//scanCase("when request pk is fixed (reverse)",
// `prefix="pk"`,
// `#0 = :0`,
// exprNameIsString(0, 0, "pk", "prefix"),
//),
scanCase("when request pk is fixed in parens #1", scanCase("when request pk is fixed in parens #1",
`(pk="prefix")`, `(pk="prefix")`,
`#0 = :0`, `#0 = :0`,
@ -513,6 +518,7 @@ func TestQueryExpr_EvalItem(t *testing.T) {
{expr: "three <= 2", expected: &types.AttributeValueMemberBOOL{Value: false}}, {expr: "three <= 2", expected: &types.AttributeValueMemberBOOL{Value: false}},
// Between // Between
{expr: "3 between 1 and 5", expected: &types.AttributeValueMemberBOOL{Value: true}},
{expr: "three between 1 and 5", expected: &types.AttributeValueMemberBOOL{Value: true}}, {expr: "three between 1 and 5", expected: &types.AttributeValueMemberBOOL{Value: true}},
{expr: "three between one and five", expected: &types.AttributeValueMemberBOOL{Value: true}}, {expr: "three between one and five", expected: &types.AttributeValueMemberBOOL{Value: true}},
{expr: "three between 10 and 15", expected: &types.AttributeValueMemberBOOL{Value: false}}, {expr: "three between 10 and 15", expected: &types.AttributeValueMemberBOOL{Value: false}},

View file

@ -0,0 +1,15 @@
package queryexpr
import (
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models"
)
type ExprFieldValueEvaluator struct {
Expr *QueryExpr
}
func (sfve ExprFieldValueEvaluator) EvaluateForItem(item models.Item) types.AttributeValue {
val, _ := sfve.Expr.EvalItem(item)
return val
}

View file

@ -8,13 +8,60 @@ import (
// sortedItems is a collection of items that is sorted. // sortedItems is a collection of items that is sorted.
// Items are sorted based on the PK, and SK in ascending order // Items are sorted based on the PK, and SK in ascending order
type sortedItems struct { type sortedItems struct {
tableInfo *TableInfo criteria SortCriteria
items []Item items []Item
} }
type SortField struct {
Field FieldValueEvaluator
Asc bool
}
type SortCriteria struct {
Fields []SortField
}
func (sc SortCriteria) FirstField() SortField {
if len(sc.Fields) == 0 {
return SortField{}
}
return sc.Fields[0]
}
func (sc SortCriteria) Equals(osc SortCriteria) bool {
if len(sc.Fields) != len(osc.Fields) {
return false
}
for i := range osc.Fields {
if sc.Fields[i].Field != osc.Fields[i].Field ||
sc.Fields[i].Asc != osc.Fields[i].Asc {
return false
}
}
return true
}
func (sc SortCriteria) Append(osc SortCriteria) SortCriteria {
newItems := make([]SortField, 0, len(osc.Fields))
newItems = append(newItems, sc.Fields...)
newItems = append(newItems, osc.Fields...)
return SortCriteria{Fields: newItems}
}
func PKSKSortFilter(ti *TableInfo) SortCriteria {
return SortCriteria{
Fields: []SortField{
{Field: SimpleFieldValueEvaluator(ti.Keys.PartitionKey), Asc: true},
{Field: SimpleFieldValueEvaluator(ti.Keys.SortKey), Asc: true},
},
}
}
// Sort sorts the items in place // Sort sorts the items in place
func Sort(items []Item, tableInfo *TableInfo) { func Sort(items []Item, criteria SortCriteria) {
si := sortedItems{items: items, tableInfo: tableInfo} si := sortedItems{items: items, criteria: criteria}
sort.Sort(&si) sort.Sort(&si)
} }
@ -23,32 +70,23 @@ func (si *sortedItems) Len() int {
} }
func (si *sortedItems) Less(i, j int) bool { func (si *sortedItems) Less(i, j int) bool {
for _, field := range si.criteria.Fields {
// Compare primary keys // Compare primary keys
pv1, pv2 := si.items[i][si.tableInfo.Keys.PartitionKey], si.items[j][si.tableInfo.Keys.PartitionKey] pv1, pv2 := field.Field.EvaluateForItem(si.items[i]), field.Field.EvaluateForItem(si.items[j])
pc, ok := attrutils.CompareScalarAttributes(pv1, pv2) pc, ok := attrutils.CompareScalarAttributes(pv1, pv2)
if !ok { if !ok {
return i < j return i < j
} }
if !field.Asc {
pc = -pc
}
if pc < 0 { if pc < 0 {
return true return true
} else if pc > 0 { } else if pc > 0 {
return false return false
} }
// Partition keys are equal, compare sort key
if sortKey := si.tableInfo.Keys.SortKey; sortKey != "" {
sv1, sv2 := si.items[i][sortKey], si.items[j][sortKey]
sc, ok := attrutils.CompareScalarAttributes(sv1, sv2)
if !ok {
return i < j
}
if sc < 0 {
return true
} else if sc > 0 {
return false
}
} }
// This should never happen, but just in case // This should never happen, but just in case

View file

@ -15,7 +15,7 @@ func TestSort(t *testing.T) {
items := make([]models.Item, len(testStringData)) items := make([]models.Item, len(testStringData))
copy(items, testStringData) copy(items, testStringData)
models.Sort(items, tableInfo) models.Sort(items, models.PKSKSortFilter(tableInfo))
assert.Equal(t, items[0], testStringData[1]) assert.Equal(t, items[0], testStringData[1])
assert.Equal(t, items[1], testStringData[2]) assert.Equal(t, items[1], testStringData[2])
@ -28,7 +28,7 @@ func TestSort(t *testing.T) {
items := make([]models.Item, len(testNumberData)) items := make([]models.Item, len(testNumberData))
copy(items, testNumberData) copy(items, testNumberData)
models.Sort(items, tableInfo) models.Sort(items, models.PKSKSortFilter(tableInfo))
assert.Equal(t, items[0], testNumberData[2]) assert.Equal(t, items[0], testNumberData[2])
assert.Equal(t, items[1], testNumberData[1]) assert.Equal(t, items[1], testNumberData[1])
@ -41,7 +41,7 @@ func TestSort(t *testing.T) {
items := make([]models.Item, len(testBoolData)) items := make([]models.Item, len(testBoolData))
copy(items, testBoolData) copy(items, testBoolData)
models.Sort(items, tableInfo) models.Sort(items, models.PKSKSortFilter(tableInfo))
assert.Equal(t, items[0], testBoolData[2]) assert.Equal(t, items[0], testBoolData[2])
assert.Equal(t, items[1], testBoolData[1]) assert.Equal(t, items[1], testBoolData[1])

View file

@ -86,8 +86,6 @@ func (s *Service) doScan(
}, errors.Wrapf(err, "unable to scan table %v", tableInfo.Name) }, errors.Wrapf(err, "unable to scan table %v", tableInfo.Name)
} }
models.Sort(results, tableInfo)
resultSet := &models.ResultSet{ resultSet := &models.ResultSet{
TableInfo: tableInfo, TableInfo: tableInfo,
Created: time.Now(), Created: time.Now(),
@ -97,6 +95,7 @@ func (s *Service) doScan(
} }
resultSet.SetItems(results) resultSet.SetItems(results)
resultSet.RefreshColumns() resultSet.RefreshColumns()
resultSet.Sort(models.PKSKSortFilter(tableInfo))
return resultSet, err return resultSet, err
} }

View file

@ -12,6 +12,7 @@ func Default() *KeyBindings {
ResetColumns: key.NewBinding(key.WithKeys("R", "reset columns")), ResetColumns: key.NewBinding(key.WithKeys("R", "reset columns")),
AddColumn: key.NewBinding(key.WithKeys("a", "add new column")), AddColumn: key.NewBinding(key.WithKeys("a", "add new column")),
DeleteColumn: key.NewBinding(key.WithKeys("d", "delete column")), DeleteColumn: key.NewBinding(key.WithKeys("d", "delete column")),
SortByColumn: key.NewBinding(key.WithKeys("s", "sort by column")),
}, },
TableView: &TableKeyBinding{ TableView: &TableKeyBinding{
MoveUp: key.NewBinding(key.WithKeys("i", "up")), MoveUp: key.NewBinding(key.WithKeys("i", "up")),

View file

@ -16,6 +16,7 @@ type FieldsPopupBinding struct {
ResetColumns key.Binding `keymap:"reset-columns"` ResetColumns key.Binding `keymap:"reset-columns"`
AddColumn key.Binding `keymap:"add-column"` AddColumn key.Binding `keymap:"add-column"`
DeleteColumn key.Binding `keymap:"delete-column"` DeleteColumn key.Binding `keymap:"delete-column"`
SortByColumn key.Binding `keymap:"sort-by-column"`
} }
type TableKeyBinding struct { type TableKeyBinding struct {

View file

@ -6,6 +6,7 @@ import (
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/lmika/dynamo-browse/internal/common/ui/events" "github.com/lmika/dynamo-browse/internal/common/ui/events"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/controllers" "github.com/lmika/dynamo-browse/internal/dynamo-browse/controllers"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models/columns" "github.com/lmika/dynamo-browse/internal/dynamo-browse/models/columns"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/ui/keybindings" "github.com/lmika/dynamo-browse/internal/dynamo-browse/ui/keybindings"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/ui/teamodels/layout" "github.com/lmika/dynamo-browse/internal/dynamo-browse/ui/teamodels/layout"
@ -27,6 +28,7 @@ type colListModel struct {
rows []table.Row rows []table.Row
table table.Model table table.Model
sortCriteria models.SortCriteria
} }
func newColListModel(keyBinding *keybindings.KeyBindings, colController *controllers.ColumnsController) *colListModel { func newColListModel(keyBinding *keybindings.KeyBindings, colController *controllers.ColumnsController) *colListModel {
@ -68,6 +70,8 @@ func (m *colListModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, events.SetTeaMessage(m.colController.AddColumn(m.table.Cursor())) return m, events.SetTeaMessage(m.colController.AddColumn(m.table.Cursor()))
case key.Matches(msg, m.keyBinding.ColumnPopup.DeleteColumn): case key.Matches(msg, m.keyBinding.ColumnPopup.DeleteColumn):
return m, events.SetTeaMessage(m.colController.DeleteColumn(m.table.Cursor())) return m, events.SetTeaMessage(m.colController.DeleteColumn(m.table.Cursor()))
case key.Matches(msg, m.keyBinding.ColumnPopup.SortByColumn):
return m, events.SetTeaMessage(m.colController.SortByColumn(m.table.Cursor()))
// Main table nav // Main table nav
case key.Matches(msg, m.keyBinding.TableView.ColLeft): case key.Matches(msg, m.keyBinding.TableView.ColLeft):
@ -122,6 +126,7 @@ func (c *colListModel) Resize(w, h int) layout.ResizingModel {
func (c *colListModel) refreshTable() { func (c *colListModel) refreshTable() {
colsFromController := c.colController.Columns() colsFromController := c.colController.Columns()
c.sortCriteria = c.colController.SortCriteria()
if len(c.rows) != len(colsFromController.Columns) { if len(c.rows) != len(colsFromController.Columns) {
c.setColumnsFromModel(colsFromController) c.setColumnsFromModel(colsFromController)
} }

View file

@ -42,6 +42,7 @@ 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 controllers.ShowColumnOverlay: case controllers.ShowColumnOverlay:
m.colListModel.sortCriteria = m.columnsController.SortCriteria()
m.colListModel.setColumnsFromModel(m.columnsController.Columns()) m.colListModel.setColumnsFromModel(m.columnsController.Columns())
m.compositor.SetOverlay(m.colListModel, m.w/2-overlayWidth/2, m.h/2-overlayHeight/2, overlayWidth, overlayHeight) m.compositor.SetOverlay(m.colListModel, m.w/2-overlayWidth/2, m.h/2-overlayHeight/2, overlayWidth, overlayHeight)
case controllers.HideColumnOverlay: case controllers.HideColumnOverlay:

View file

@ -3,6 +3,7 @@ package colselector
import ( import (
"fmt" "fmt"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models/evaluators"
table "github.com/lmika/go-bubble-table" table "github.com/lmika/go-bubble-table"
"io" "io"
) )
@ -23,9 +24,17 @@ func (clr colListRowModel) Render(w io.Writer, model table.Model, index int) {
} }
col := clr.m.colController.Columns().Columns[index] col := clr.m.colController.Columns().Columns[index]
if !col.Hidden { ff := clr.m.sortCriteria.FirstField()
fmt.Fprintln(w, style.Render(fmt.Sprintf("⋅\t%v", col.Name))) switch {
} else { case col.Hidden:
fmt.Fprintln(w, style.Render(fmt.Sprintf("✕\t%v", col.Name))) fmt.Fprintln(w, style.Render(fmt.Sprintf("✕\t%v", col.Name)))
case evaluators.Equals(ff.Field, col.Evaluator):
if ff.Asc {
fmt.Fprintln(w, style.Render(fmt.Sprintf("v\t%v", col.Name)))
} else {
fmt.Fprintln(w, style.Render(fmt.Sprintf("^\t%v", col.Name)))
}
default:
fmt.Fprintln(w, style.Render(fmt.Sprintf("⋅\t%v", col.Name)))
} }
} }

View file

@ -90,9 +90,9 @@ func (m *listModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if onSel := m.event.OnSelected; onSel != nil { if onSel := m.event.OnSelected; onSel != nil {
cc.Add(events.SetTeaMessage(onSel(m.event.Items[m.list.Index()]))) cc.Add(events.SetTeaMessage(onSel(m.event.Items[m.list.Index()])))
} }
return m, events.SetTeaMessage(controllers.HideColumnOverlay{}) return m, events.SetTeaMessage(controllers.HideRelatedItemsOverlay{})
case key.Matches(msg, keyEsc): case key.Matches(msg, keyEsc):
return m, events.SetTeaMessage(controllers.HideColumnOverlay{}) return m, events.SetTeaMessage(controllers.HideRelatedItemsOverlay{})
default: default:
m.list = cc.Collect(m.list.Update(msg)).(list.Model) m.list = cc.Collect(m.list.Update(msg)).(list.Model)
} }

View file

@ -45,7 +45,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.listModel.setItems(msg, newHeight) m.listModel.setItems(msg, newHeight)
m.compositor.SetOverlay(m.listModel, m.w/2-overlayWidth/2, m.h/2-newHeight/2, overlayWidth, newHeight) m.compositor.SetOverlay(m.listModel, m.w/2-overlayWidth/2, m.h/2-newHeight/2, overlayWidth, newHeight)
case controllers.HideColumnOverlay: case controllers.HideRelatedItemsOverlay:
m.compositor.ClearOverlay() m.compositor.ClearOverlay()
case tea.KeyMsg: case tea.KeyMsg:
m.compositor = cc.Collect(m.compositor.Update(msg)).(*layout.Compositor) m.compositor = cc.Collect(m.compositor.Update(msg)).(*layout.Compositor)