k9s/internal/ui/select_table.go

185 lines
4.0 KiB
Go

package ui
import (
"context"
"time"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/render"
"github.com/derailed/tview"
"github.com/gdamore/tcell"
)
// Namespaceable represents a namespaceable model.
type Namespaceable interface {
// ClusterWide returns true if the model represents resource in all namespaces.
ClusterWide() bool
// GetNamespace returns the model namespace.
GetNamespace() string
// SetNamespace changes the model namespace.
SetNamespace(string)
// InNamespace check if current namespace matches models.
InNamespace(string) bool
}
// Tabular represents a tabular model.
type Tabular interface {
Namespaceable
// Empty returns true if model has no data.
Empty() bool
// Peek returns current model data.
Peek() render.TableData
// Watch watches a given resource for changes.
Watch(context.Context)
// SetRefreshRate sets the model watch loop rate.
SetRefreshRate(time.Duration)
// AddListener registers a model listener.
AddListener(model.TableListener)
}
// SelectTable represents a table with selections.
type SelectTable struct {
*tview.Table
model Tabular
selectedRow int
selectedFn func(string) string
marks map[string]struct{}
}
// SetModel sets the table model.
func (s *SelectTable) SetModel(m Tabular) {
s.model = m
}
// GetModel returns the current model.
func (s *SelectTable) GetModel() Tabular {
return s.model
}
// ClearSelection reset selected row.
func (s *SelectTable) ClearSelection() {
s.Select(0, 0)
s.ScrollToBeginning()
}
// SelectFirstRow select first data row if any.
func (s *SelectTable) SelectFirstRow() {
if s.GetRowCount() > 0 {
s.Select(1, 0)
}
}
// GetSelectedItems return currently marked or selected items names.
func (s *SelectTable) GetSelectedItems() []string {
if len(s.marks) == 0 {
return []string{s.GetSelectedItem()}
}
var items []string
for item := range s.marks {
items = append(items, item)
}
return items
}
// GetSelectedItem returns the currently selected item name.
func (s *SelectTable) GetSelectedItem() string {
if s.GetSelectedRowIndex() == 0 || s.model.Empty() {
return ""
}
sel, ok := s.GetCell(s.GetSelectedRowIndex(), 0).GetReference().(string)
if !ok {
return ""
}
if s.selectedFn != nil {
return s.selectedFn(sel)
}
return sel
}
// GetSelectedCell returns the content of a cell for the currently selected row.
func (s *SelectTable) GetSelectedCell(col int) string {
return TrimCell(s, s.selectedRow, col)
}
// SetSelectedFn defines a function that cleanse the current selection.
func (s *SelectTable) SetSelectedFn(f func(string) string) {
s.selectedFn = f
}
// GetSelectedRowIndex fetch the currently selected row index.
func (s *SelectTable) GetSelectedRowIndex() int {
return s.selectedRow
}
// SelectRow select a given row by index.
func (s *SelectTable) SelectRow(r int, broadcast bool) {
if !broadcast {
s.SetSelectionChangedFunc(nil)
}
defer s.SetSelectionChangedFunc(s.selectionChanged)
s.Select(r, 0)
}
// UpdateSelection refresh selected row.
func (s *SelectTable) updateSelection(broadcast bool) {
s.SelectRow(s.selectedRow, broadcast)
}
func (s *SelectTable) selectionChanged(r, c int) {
if r <= 0 {
return
}
s.selectedRow = r
cell := s.GetCell(r, c)
s.SetSelectedStyle(tcell.ColorBlack, cell.Color, tcell.AttrBold)
}
// ClearMarks delete all marked items.
func (s *SelectTable) ClearMarks() {
for k := range s.marks {
delete(s.marks, k)
}
}
// DeleteMark delete a marked item.
func (s *SelectTable) DeleteMark(k string) {
delete(s.marks, k)
}
// ToggleMark toggles marked row
func (s *SelectTable) ToggleMark() {
sel := s.GetSelectedItem()
if sel == "" {
return
}
if _, ok := s.marks[sel]; ok {
delete(s.marks, s.GetSelectedItem())
} else {
s.marks[sel] = struct{}{}
}
cell := s.GetCell(s.GetSelectedRowIndex(), 0)
s.SetSelectedStyle(
tcell.ColorBlack,
cell.Color,
tcell.AttrBold,
)
}
// IsMarked returns true if this item was marked.
func (s *Table) IsMarked(item string) bool {
_, ok := s.marks[item]
return ok
}