bug fixes + cleanup
parent
56e4dc9ba8
commit
162e3fe7ed
|
|
@ -216,7 +216,7 @@ func newTable() Table {
|
|||
FgColor: "aqua",
|
||||
BgColor: "black",
|
||||
CursorColor: "aqua",
|
||||
MarkColor: "darkgoldenrod",
|
||||
MarkColor: "dodgerblue",
|
||||
Header: newTableHeader(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,11 +121,14 @@ func (s *Stack) Peek() []Component {
|
|||
return s.components
|
||||
}
|
||||
|
||||
// Reset clear out the stack.
|
||||
func (s *Stack) Reset() {
|
||||
// ClearHistory clear out the stack history up to most recent.
|
||||
func (s *Stack) ClearHistory() {
|
||||
s.DumpStack()
|
||||
top := s.Top()
|
||||
for range s.components {
|
||||
s.Pop()
|
||||
}
|
||||
s.Push(top)
|
||||
}
|
||||
|
||||
// Empty returns true if the stack is empty.
|
||||
|
|
|
|||
|
|
@ -57,7 +57,17 @@ func (v *Menu) StackTop(t model.Component) {
|
|||
func (v *Menu) HydrateMenu(hh model.MenuHints) {
|
||||
v.Clear()
|
||||
sort.Sort(hh)
|
||||
t := v.buildMenuTable(hh)
|
||||
|
||||
table := make([]model.MenuHints, maxRows+1)
|
||||
colCount := (len(hh) / maxRows) + 1
|
||||
if v.hasDigits(hh) {
|
||||
colCount++
|
||||
}
|
||||
for row := 0; row < maxRows; row++ {
|
||||
table[row] = make(model.MenuHints, colCount)
|
||||
}
|
||||
t := v.buildMenuTable(hh, table, colCount)
|
||||
|
||||
for row := 0; row < len(t); row++ {
|
||||
for col := 0; col < len(t[row]); col++ {
|
||||
if len(t[row][col]) == 0 {
|
||||
|
|
@ -82,16 +92,7 @@ func (v *Menu) hasDigits(hh model.MenuHints) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (v *Menu) buildMenuTable(hh model.MenuHints) [][]string {
|
||||
table := make([][]string, maxRows+1)
|
||||
colCount := (len(hh) / maxRows) + 1
|
||||
if v.hasDigits(hh) {
|
||||
colCount++
|
||||
}
|
||||
for row := 0; row < maxRows; row++ {
|
||||
table[row] = make([]string, colCount)
|
||||
}
|
||||
|
||||
func (v *Menu) buildMenuTable(hh model.MenuHints, table []model.MenuHints, colCount int) [][]string {
|
||||
var row, col int
|
||||
firstCmd := true
|
||||
maxKeys := make([]int, colCount)
|
||||
|
|
@ -102,21 +103,44 @@ func (v *Menu) buildMenuTable(hh model.MenuHints) [][]string {
|
|||
|
||||
if !menuRX.MatchString(h.Mnemonic) && firstCmd {
|
||||
row, col, firstCmd = 0, col+1, false
|
||||
if table[0][0] == "" {
|
||||
if table[0][0].IsBlank() {
|
||||
col = 0
|
||||
}
|
||||
}
|
||||
if maxKeys[col] < len(h.Mnemonic) {
|
||||
maxKeys[col] = len(h.Mnemonic)
|
||||
}
|
||||
table[row][col] = keyConv(v.formatMenu(h, maxKeys[col]))
|
||||
table[row][col] = h
|
||||
row++
|
||||
if row >= maxRows {
|
||||
row, col = 0, col+1
|
||||
}
|
||||
}
|
||||
|
||||
return table
|
||||
out := make([][]string, len(table))
|
||||
for r := range out {
|
||||
out[r] = make([]string, len(table[r]))
|
||||
}
|
||||
v.layout(table, maxKeys, out)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (v *Menu) layout(table []model.MenuHints, mm []int, out [][]string) {
|
||||
for r := range table {
|
||||
for c := range table[r] {
|
||||
out[r][c] = keyConv(v.formatMenu(table[r][c], mm[c]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Menu) formatMenu(h model.MenuHint, size int) string {
|
||||
i, err := strconv.Atoi(h.Mnemonic)
|
||||
if err == nil {
|
||||
return formatNSMenu(i, h.Description, v.styles.Frame())
|
||||
}
|
||||
|
||||
return formatPlainMenu(h, size, v.styles.Frame())
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -147,15 +171,6 @@ func toMnemonic(s string) string {
|
|||
return "<" + keyConv(strings.ToLower(s)) + ">"
|
||||
}
|
||||
|
||||
func (v *Menu) formatMenu(h model.MenuHint, size int) string {
|
||||
i, err := strconv.Atoi(h.Mnemonic)
|
||||
if err == nil {
|
||||
return formatNSMenu(i, h.Description, v.styles.Frame())
|
||||
}
|
||||
|
||||
return formatPlainMenu(h, size, v.styles.Frame())
|
||||
}
|
||||
|
||||
func formatNSMenu(i int, name string, styles config.Frame) string {
|
||||
fmat := strings.Replace(menuIndexFmt, "[key", "["+styles.Menu.NumKeyColor, 1)
|
||||
fmat = strings.Replace(fmat, ":bg:", ":"+styles.Title.BgColor+":", -1)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,164 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/resource"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Selectable represents a table with selections.
|
||||
type SelectTable struct {
|
||||
*tview.Table
|
||||
|
||||
ActiveNS string
|
||||
selectedItem string
|
||||
selectedRow int
|
||||
selectedFn func(string) string
|
||||
selListeners []SelectedRowFunc
|
||||
marks map[string]bool
|
||||
}
|
||||
|
||||
// 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, marked := range s.marks {
|
||||
if marked {
|
||||
items = append(items, item)
|
||||
}
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
// GetSelectedItem returns the currently selected item name.
|
||||
func (s *SelectTable) GetSelectedItem() string {
|
||||
if s.selectedFn != nil {
|
||||
return s.selectedFn(s.selectedItem)
|
||||
}
|
||||
return s.selectedItem
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// GetSelectedRow fetch the currently selected row index.
|
||||
func (s *SelectTable) GetSelectedRowIndex() int {
|
||||
return s.selectedRow
|
||||
}
|
||||
|
||||
// RowSelected checks if there is an active row selection.
|
||||
func (s *SelectTable) RowSelected() bool {
|
||||
return s.selectedItem != ""
|
||||
}
|
||||
|
||||
// GetRow retrieves the entire selected row.
|
||||
func (s *SelectTable) GetRow() resource.Row {
|
||||
r := make(resource.Row, s.GetColumnCount())
|
||||
for i := 0; i < s.GetColumnCount(); i++ {
|
||||
c := s.GetCell(s.selectedRow, i)
|
||||
r[i] = strings.TrimSpace(c.Text)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *SelectTable) updateSelectedItem(r int) {
|
||||
if r == 0 || s.GetCell(r, 0) == nil {
|
||||
s.selectedItem = ""
|
||||
return
|
||||
}
|
||||
|
||||
col0 := TrimCell(s, r, 0)
|
||||
switch s.ActiveNS {
|
||||
case resource.NotNamespaced:
|
||||
s.selectedItem = col0
|
||||
case resource.AllNamespace, resource.AllNamespaces:
|
||||
s.selectedItem = path.Join(col0, TrimCell(s, r, 1))
|
||||
default:
|
||||
s.selectedItem = path.Join(s.ActiveNS, col0)
|
||||
}
|
||||
}
|
||||
|
||||
// SelectRow select a given row by index.
|
||||
func (s *SelectTable) SelectRow(r int, broadcast bool) {
|
||||
if !broadcast {
|
||||
s.SetSelectionChangedFunc(nil)
|
||||
}
|
||||
defer s.SetSelectionChangedFunc(s.selChanged)
|
||||
s.Select(r, 0)
|
||||
s.updateSelectedItem(r)
|
||||
}
|
||||
|
||||
// UpdateSelection refresh selected row.
|
||||
func (s *SelectTable) updateSelection(broadcast bool) {
|
||||
s.SelectRow(s.selectedRow, broadcast)
|
||||
}
|
||||
|
||||
func (s *SelectTable) selChanged(r, c int) {
|
||||
s.selectedRow = r
|
||||
s.updateSelectedItem(r)
|
||||
if r == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if s.marks[s.GetSelectedItem()] {
|
||||
s.SetSelectedStyle(tcell.ColorBlack, tcell.ColorCadetBlue, tcell.AttrBold)
|
||||
} else {
|
||||
cell := s.GetCell(r, c)
|
||||
s.SetSelectedStyle(tcell.ColorBlack, cell.Color, tcell.AttrBold)
|
||||
}
|
||||
|
||||
for _, f := range s.selListeners {
|
||||
f(r, c)
|
||||
}
|
||||
}
|
||||
|
||||
// ToggleMark toggles marked row
|
||||
func (s *SelectTable) ToggleMark() {
|
||||
s.marks[s.GetSelectedItem()] = !s.marks[s.GetSelectedItem()]
|
||||
if !s.marks[s.GetSelectedItem()] {
|
||||
return
|
||||
}
|
||||
log.Debug().Msgf("YO!!!!")
|
||||
s.SetSelectedStyle(
|
||||
tcell.ColorBlack,
|
||||
tcell.ColorViolet,
|
||||
tcell.AttrBold,
|
||||
)
|
||||
}
|
||||
|
||||
func (s *Table) IsMarked(item string) bool {
|
||||
return s.marks[item]
|
||||
}
|
||||
|
||||
// AddSelectedRowListener add a new selected row listener.
|
||||
func (s *SelectTable) AddSelectedRowListener(f SelectedRowFunc) {
|
||||
s.selListeners = append(s.selListeners, f)
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -29,44 +28,32 @@ type (
|
|||
|
||||
// Table represents tabular data.
|
||||
type Table struct {
|
||||
*tview.Table
|
||||
*SelectTable
|
||||
|
||||
baseTitle string
|
||||
data resource.TableData
|
||||
actions KeyActions
|
||||
cmdBuff *CmdBuff
|
||||
styles *config.Styles
|
||||
activeNS string
|
||||
sortCol SortColumn
|
||||
sortFn SortFn
|
||||
colorerFn ColorerFunc
|
||||
selectedItem string
|
||||
selectedRow int
|
||||
selectedFn func(string) string
|
||||
selListeners []SelectedRowFunc
|
||||
marks map[string]bool
|
||||
baseTitle string
|
||||
Data resource.TableData
|
||||
actions KeyActions
|
||||
cmdBuff *CmdBuff
|
||||
styles *config.Styles
|
||||
colorerFn ColorerFunc
|
||||
sortCol SortColumn
|
||||
sortFn SortFn
|
||||
}
|
||||
|
||||
// NewTable returns a new table view.
|
||||
func NewTable(title string) *Table {
|
||||
return &Table{
|
||||
Table: tview.NewTable(),
|
||||
SelectTable: &SelectTable{
|
||||
Table: tview.NewTable(),
|
||||
marks: make(map[string]bool),
|
||||
},
|
||||
actions: make(KeyActions),
|
||||
cmdBuff: NewCmdBuff('/', FilterBuff),
|
||||
baseTitle: title,
|
||||
sortCol: SortColumn{0, 0, true},
|
||||
marks: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func mustExtractSyles(ctx context.Context) *config.Styles {
|
||||
styles, ok := ctx.Value(KeyStyles).(*config.Styles)
|
||||
if !ok {
|
||||
log.Fatal().Msg("Expecting valid styles")
|
||||
}
|
||||
return styles
|
||||
}
|
||||
|
||||
func (t *Table) Init(ctx context.Context) {
|
||||
t.styles = mustExtractSyles(ctx)
|
||||
|
||||
|
|
@ -93,114 +80,6 @@ func (t *Table) SendKey(evt *tcell.EventKey) {
|
|||
t.keyboard(evt)
|
||||
}
|
||||
|
||||
// GetRow retrieves the entire selected row.
|
||||
func (t *Table) GetRow() resource.Row {
|
||||
r := make(resource.Row, t.GetColumnCount())
|
||||
for i := 0; i < t.GetColumnCount(); i++ {
|
||||
c := t.GetCell(t.selectedRow, i)
|
||||
r[i] = strings.TrimSpace(c.Text)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// AddSelectedRowListener add a new selected row listener.
|
||||
func (t *Table) AddSelectedRowListener(f SelectedRowFunc) {
|
||||
t.selListeners = append(t.selListeners, f)
|
||||
}
|
||||
|
||||
func (t *Table) selChanged(r, c int) {
|
||||
t.selectedRow = r
|
||||
t.updateSelectedItem(r)
|
||||
if r == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
cell := t.GetCell(r, c)
|
||||
t.SetSelectedStyle(
|
||||
tcell.ColorBlack,
|
||||
cell.Color,
|
||||
tcell.AttrBold,
|
||||
)
|
||||
|
||||
for _, f := range t.selListeners {
|
||||
f(r, c)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateSelection refresh selected row.
|
||||
func (t *Table) updateSelection(broadcast bool) {
|
||||
t.SelectRow(t.selectedRow, broadcast)
|
||||
}
|
||||
|
||||
// SelectRow select a given row by index.
|
||||
func (t *Table) SelectRow(r int, broadcast bool) {
|
||||
if !broadcast {
|
||||
t.SetSelectionChangedFunc(nil)
|
||||
}
|
||||
defer t.SetSelectionChangedFunc(t.selChanged)
|
||||
t.Select(r, 0)
|
||||
t.updateSelectedItem(r)
|
||||
}
|
||||
|
||||
func (t *Table) updateSelectedItem(r int) {
|
||||
if r == 0 || t.GetCell(r, 0) == nil {
|
||||
t.selectedItem = ""
|
||||
return
|
||||
}
|
||||
|
||||
col0 := TrimCell(t, r, 0)
|
||||
switch t.activeNS {
|
||||
case resource.NotNamespaced:
|
||||
t.selectedItem = col0
|
||||
case resource.AllNamespace, resource.AllNamespaces:
|
||||
t.selectedItem = path.Join(col0, TrimCell(t, r, 1))
|
||||
default:
|
||||
t.selectedItem = path.Join(t.activeNS, col0)
|
||||
}
|
||||
}
|
||||
|
||||
// SetSelectedFn defines a function that cleanse the current selection.
|
||||
func (t *Table) SetSelectedFn(f func(string) string) {
|
||||
t.selectedFn = f
|
||||
}
|
||||
|
||||
// RowSelected checks if there is an active row selection.
|
||||
func (t *Table) RowSelected() bool {
|
||||
return t.selectedItem != ""
|
||||
}
|
||||
|
||||
// GetSelectedCell returns the content of a cell for the currently selected row.
|
||||
func (t *Table) GetSelectedCell(col int) string {
|
||||
return TrimCell(t, t.selectedRow, col)
|
||||
}
|
||||
|
||||
// GetSelectedRow fetch the currently selected row index.
|
||||
func (t *Table) GetSelectedRowIndex() int {
|
||||
return t.selectedRow
|
||||
}
|
||||
|
||||
// GetSelectedItem returns the currently selected item name.
|
||||
func (t *Table) GetSelectedItem() string {
|
||||
if t.selectedFn != nil {
|
||||
return t.selectedFn(t.selectedItem)
|
||||
}
|
||||
return t.selectedItem
|
||||
}
|
||||
|
||||
// GetSelectedItems return currently marked or selected items names.
|
||||
func (t *Table) GetSelectedItems() []string {
|
||||
if len(t.marks) > 0 {
|
||||
var items []string
|
||||
for item, marked := range t.marks {
|
||||
if marked {
|
||||
items = append(items, item)
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
return []string{t.GetSelectedItem()}
|
||||
}
|
||||
|
||||
func (t *Table) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
||||
key := evt.Key()
|
||||
if key == tcell.KeyRune {
|
||||
|
|
@ -222,11 +101,6 @@ func (t *Table) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return evt
|
||||
}
|
||||
|
||||
// GetData fetch tabular data.
|
||||
func (t *Table) GetData() resource.TableData {
|
||||
return t.data
|
||||
}
|
||||
|
||||
// GetFilteredData fetch filtered tabular data.
|
||||
func (t *Table) GetFilteredData() resource.TableData {
|
||||
return t.filtered()
|
||||
|
|
@ -247,16 +121,6 @@ func (t *Table) SetColorerFn(f ColorerFunc) {
|
|||
t.colorerFn = f
|
||||
}
|
||||
|
||||
// ActiveNS get the resource namespace.
|
||||
func (t *Table) ActiveNS() string {
|
||||
return t.activeNS
|
||||
}
|
||||
|
||||
// SetActiveNS set the resource namespace.
|
||||
func (t *Table) SetActiveNS(ns string) {
|
||||
t.activeNS = ns
|
||||
}
|
||||
|
||||
// SetSortCol sets in sort column index and order.
|
||||
func (t *Table) SetSortCol(index, count int, asc bool) {
|
||||
t.sortCol.index, t.sortCol.colCount, t.sortCol.asc = index, count, asc
|
||||
|
|
@ -264,9 +128,9 @@ func (t *Table) SetSortCol(index, count int, asc bool) {
|
|||
|
||||
// Update table content.
|
||||
func (t *Table) Update(data resource.TableData) {
|
||||
t.data = data
|
||||
t.Data = data
|
||||
if t.cmdBuff.Empty() {
|
||||
t.doUpdate(t.data)
|
||||
t.doUpdate(t.Data)
|
||||
} else {
|
||||
t.doUpdate(t.filtered())
|
||||
}
|
||||
|
|
@ -275,8 +139,8 @@ func (t *Table) Update(data resource.TableData) {
|
|||
}
|
||||
|
||||
func (t *Table) doUpdate(data resource.TableData) {
|
||||
t.activeNS = data.Namespace
|
||||
if t.activeNS == resource.AllNamespaces && t.activeNS != "*" {
|
||||
t.ActiveNS = data.Namespace
|
||||
if t.ActiveNS == resource.AllNamespaces && t.ActiveNS != "*" {
|
||||
t.actions[KeyShiftP] = NewKeyAction("Sort Namespace", t.SortColCmd(-2), false)
|
||||
} else {
|
||||
delete(t.actions, KeyShiftP)
|
||||
|
|
@ -348,6 +212,13 @@ func (t *Table) sort(data resource.TableData, row int) {
|
|||
row++
|
||||
}
|
||||
}
|
||||
|
||||
// check marks if a row is deleted make sure we blow the mark too.
|
||||
for k := range t.marks {
|
||||
if _, ok := t.Data.Rows[k]; !ok {
|
||||
delete(t.marks, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table) buildRow(row int, data resource.TableData, sk string, pads MaxyPad) {
|
||||
|
|
@ -355,7 +226,7 @@ func (t *Table) buildRow(row int, data resource.TableData, sk string, pads MaxyP
|
|||
if t.colorerFn != nil {
|
||||
f = t.colorerFn
|
||||
}
|
||||
m := t.isMarked(sk)
|
||||
m := t.IsMarked(sk)
|
||||
for col, field := range data.Rows[sk].Fields {
|
||||
header := data.Header[col]
|
||||
cell, align := t.formatCell(data.NumCols[header], header, field+Deltas(data.Rows[sk].Deltas[col], field), pads[col])
|
||||
|
|
@ -392,15 +263,20 @@ func (t *Table) formatCell(numerical bool, header, field string, padding int) (s
|
|||
return field, align
|
||||
}
|
||||
|
||||
func (t *Table) ClearMarks() {
|
||||
t.marks = map[string]bool{}
|
||||
t.Refresh()
|
||||
}
|
||||
|
||||
// Refresh update the table data.
|
||||
func (t *Table) Refresh() {
|
||||
t.Update(t.data)
|
||||
t.Update(t.Data)
|
||||
}
|
||||
|
||||
// NameColIndex returns the index of the resource name column.
|
||||
func (t *Table) NameColIndex() int {
|
||||
col := 0
|
||||
if t.activeNS == resource.AllNamespaces {
|
||||
if t.ActiveNS == resource.AllNamespaces {
|
||||
col++
|
||||
}
|
||||
return col
|
||||
|
|
@ -418,7 +294,7 @@ func (t *Table) AddHeaderCell(numerical bool, col int, name string) {
|
|||
|
||||
func (t *Table) filtered() resource.TableData {
|
||||
if t.cmdBuff.Empty() || IsLabelSelector(t.cmdBuff.String()) {
|
||||
return t.data
|
||||
return t.Data
|
||||
}
|
||||
|
||||
q := t.cmdBuff.String()
|
||||
|
|
@ -434,15 +310,15 @@ func (t *Table) rxFilter() resource.TableData {
|
|||
if err != nil {
|
||||
log.Error().Err(errors.New("Invalid filter expression")).Msg("Regexp")
|
||||
t.cmdBuff.Clear()
|
||||
return t.data
|
||||
return t.Data
|
||||
}
|
||||
|
||||
filtered := resource.TableData{
|
||||
Header: t.data.Header,
|
||||
Header: t.Data.Header,
|
||||
Rows: resource.RowEvents{},
|
||||
Namespace: t.data.Namespace,
|
||||
Namespace: t.Data.Namespace,
|
||||
}
|
||||
for k, row := range t.data.Rows {
|
||||
for k, row := range t.Data.Rows {
|
||||
f := strings.Join(row.Fields, " ")
|
||||
if rx.MatchString(f) {
|
||||
filtered.Rows[k] = row
|
||||
|
|
@ -454,19 +330,19 @@ func (t *Table) rxFilter() resource.TableData {
|
|||
|
||||
func (t *Table) fuzzyFilter(q string) resource.TableData {
|
||||
var ss, kk []string
|
||||
for k, row := range t.data.Rows {
|
||||
for k, row := range t.Data.Rows {
|
||||
ss = append(ss, row.Fields[t.NameColIndex()])
|
||||
kk = append(kk, k)
|
||||
}
|
||||
|
||||
filtered := resource.TableData{
|
||||
Header: t.data.Header,
|
||||
Header: t.Data.Header,
|
||||
Rows: resource.RowEvents{},
|
||||
Namespace: t.data.Namespace,
|
||||
Namespace: t.Data.Namespace,
|
||||
}
|
||||
mm := fuzzy.Find(q, ss)
|
||||
for _, m := range mm {
|
||||
filtered.Rows[kk[m.Index]] = t.data.Rows[kk[m.Index]]
|
||||
filtered.Rows[kk[m.Index]] = t.Data.Rows[kk[m.Index]]
|
||||
}
|
||||
|
||||
return filtered
|
||||
|
|
@ -482,19 +358,6 @@ func (t *Table) SearchBuff() *CmdBuff {
|
|||
return t.cmdBuff
|
||||
}
|
||||
|
||||
// ClearSelection reset selected row.
|
||||
func (t *Table) ClearSelection() {
|
||||
t.Select(0, 0)
|
||||
t.ScrollToBeginning()
|
||||
}
|
||||
|
||||
// SelectFirstRow select first data row if any.
|
||||
func (t *Table) SelectFirstRow() {
|
||||
if t.GetRowCount() > 0 {
|
||||
t.Select(1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// ShowDeleted marks row as deleted.
|
||||
func (t *Table) ShowDeleted() {
|
||||
r, _ := t.GetSelection()
|
||||
|
|
@ -535,11 +398,11 @@ func (t *Table) UpdateTitle() {
|
|||
if rc > 0 {
|
||||
rc--
|
||||
}
|
||||
switch t.activeNS {
|
||||
switch t.ActiveNS {
|
||||
case resource.NotNamespaced, "*":
|
||||
title = skinTitle(fmt.Sprintf(titleFmt, t.baseTitle, rc), t.styles.Frame())
|
||||
default:
|
||||
ns := t.activeNS
|
||||
ns := t.ActiveNS
|
||||
if ns == resource.AllNamespaces {
|
||||
ns = resource.AllNamespace
|
||||
}
|
||||
|
|
@ -563,12 +426,3 @@ func (t *Table) SortInvertCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToggleMark toggles marked row
|
||||
func (t *Table) ToggleMark() {
|
||||
t.marks[t.GetSelectedItem()] = !t.marks[t.GetSelectedItem()]
|
||||
}
|
||||
|
||||
func (t *Table) isMarked(item string) bool {
|
||||
return t.marks[item]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
|
|
@ -37,8 +38,16 @@ var (
|
|||
fuzzyCmd = regexp.MustCompile(`\A\-f`)
|
||||
)
|
||||
|
||||
func mustExtractSyles(ctx context.Context) *config.Styles {
|
||||
styles, ok := ctx.Value(KeyStyles).(*config.Styles)
|
||||
if !ok {
|
||||
log.Fatal().Msg("Expecting valid styles")
|
||||
}
|
||||
return styles
|
||||
}
|
||||
|
||||
// TrimCell removes superfluous padding.
|
||||
func TrimCell(tv *Table, row, col int) string {
|
||||
func TrimCell(tv *SelectTable, row, col int) string {
|
||||
c := tv.GetCell(row, col)
|
||||
if c == nil {
|
||||
log.Error().Err(fmt.Errorf("No cell at location [%d:%d]", row, col)).Msg("Trim cell failed!")
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func (a *Alias) Init(ctx context.Context) {
|
|||
a.SetBorderFocusColor(tcell.ColorMediumSpringGreen)
|
||||
a.SetSelectedStyle(tcell.ColorWhite, tcell.ColorMediumSpringGreen, tcell.AttrNone)
|
||||
a.SetColorerFn(aliasColorer)
|
||||
a.SetActiveNS("")
|
||||
a.ActiveNS = resource.AllNamespaces
|
||||
a.registerActions()
|
||||
|
||||
a.Update(a.hydrate())
|
||||
|
|
@ -53,6 +53,8 @@ func (a *Alias) registerActions() {
|
|||
a.RmAction(ui.KeyShiftA)
|
||||
a.RmAction(ui.KeyShiftN)
|
||||
a.RmAction(tcell.KeyCtrlS)
|
||||
a.RmAction(tcell.KeyCtrlSpace)
|
||||
a.RmAction(ui.KeySpace)
|
||||
|
||||
a.AddActions(ui.KeyActions{
|
||||
tcell.KeyEnter: ui.NewKeyAction("Goto Resource", a.gotoCmd, true),
|
||||
|
|
@ -76,7 +78,7 @@ func (a *Alias) resetCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
func (a *Alias) gotoCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
r, _ := a.GetSelection()
|
||||
if r != 0 {
|
||||
s := ui.TrimCell(a.Table.Table, r, 1)
|
||||
s := ui.TrimCell(a.Table.SelectTable, r, 1)
|
||||
tokens := strings.Split(s, ",")
|
||||
a.app.Content.Pop()
|
||||
if !a.app.gotoResource(tokens[0]) {
|
||||
|
|
|
|||
|
|
@ -399,9 +399,8 @@ func (a *App) toggleHeaderCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
func (a *App) gotoCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if a.CmdBuff().IsActive() && !a.CmdBuff().Empty() {
|
||||
a.Content.Stack.Reset()
|
||||
if !a.gotoResource(a.GetCmd()) {
|
||||
a.Flash().Errf("Goto %s failed!", a.GetCmd())
|
||||
if a.gotoResource(a.GetCmd()) {
|
||||
a.Content.Stack.ClearHistory()
|
||||
}
|
||||
a.ResetCmd()
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ func (b *Bench) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
func (b *Bench) benchFile() string {
|
||||
r := b.masterPage().GetSelectedRowIndex()
|
||||
return ui.TrimCell(b.masterPage().Table, r, 7)
|
||||
return ui.TrimCell(b.masterPage().SelectTable, r, 7)
|
||||
}
|
||||
|
||||
func (b *Bench) hydrate() resource.TableData {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ func (c *Container) Name() string { return "containers" }
|
|||
|
||||
func (c *Container) extraActions(aa ui.KeyActions) {
|
||||
c.LogResource.extraActions(aa)
|
||||
c.masterPage().RmAction(tcell.KeyCtrlSpace)
|
||||
c.masterPage().RmAction(ui.KeySpace)
|
||||
|
||||
aa[ui.KeyShiftF] = ui.NewKeyAction("PortForward", c.portFwdCmd, true)
|
||||
aa[ui.KeyShiftL] = ui.NewKeyAction("Logs Previous", c.prevLogsCmd, true)
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ func TestContainerNew(t *testing.T) {
|
|||
po.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "containers", po.Name())
|
||||
assert.Equal(t, 22, len(po.Hints()))
|
||||
assert.Equal(t, 21, len(po.Hints()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/derailed/k9s/internal/resource"
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
// Context presents a context viewer.
|
||||
|
|
@ -31,6 +32,8 @@ func (c *Context) Init(ctx context.Context) {
|
|||
|
||||
func (c *Context) extraActions(aa ui.KeyActions) {
|
||||
c.masterPage().RmAction(ui.KeyShiftA)
|
||||
c.masterPage().RmAction(tcell.KeyCtrlSpace)
|
||||
c.masterPage().RmAction(ui.KeySpace)
|
||||
}
|
||||
|
||||
func (c *Context) useCtx(app *App, _, res, sel string) {
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ func TestContext(t *testing.T) {
|
|||
ctx.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "ctx", ctx.Name())
|
||||
assert.Equal(t, 13, len(ctx.Hints()))
|
||||
assert.Equal(t, 12, len(ctx.Hints()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ func TestDeploy(t *testing.T) {
|
|||
v.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "deploy", v.Name())
|
||||
assert.Equal(t, 24, len(v.Hints()))
|
||||
assert.Equal(t, 25, len(v.Hints()))
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ func TestDaemonSet(t *testing.T) {
|
|||
v.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "ds", v.Name())
|
||||
assert.Equal(t, 23, len(v.Hints()))
|
||||
assert.Equal(t, 24, len(v.Hints()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ func (v *Help) Hints() model.MenuHints {
|
|||
}
|
||||
|
||||
func (v *Help) bindKeys() {
|
||||
v.RmAction(tcell.KeyCtrlSpace)
|
||||
v.RmAction(ui.KeySpace)
|
||||
|
||||
v.actions = ui.KeyActions{
|
||||
tcell.KeyEsc: ui.NewKeyAction("Back", v.backCmd, true),
|
||||
tcell.KeyEnter: ui.NewKeyAction("Back", v.backCmd, false),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func TestHelpNew(t *testing.T) {
|
|||
v := view.NewHelp()
|
||||
v.Init(ctx)
|
||||
|
||||
assert.Equal(t, 32, v.GetRowCount())
|
||||
assert.Equal(t, 33, v.GetRowCount())
|
||||
assert.Equal(t, 10, v.GetColumnCount())
|
||||
assert.Equal(t, "<esc>", v.GetCell(1, 0).Text)
|
||||
assert.Equal(t, "Back", v.GetCell(1, 1).Text)
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ func TestNSCleanser(t *testing.T) {
|
|||
ns.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "ns", ns.Name())
|
||||
assert.Equal(t, 20, len(ns.Hints()))
|
||||
assert.Equal(t, 21, len(ns.Hints()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ func TestPodNew(t *testing.T) {
|
|||
po.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "pods", po.Name())
|
||||
assert.Equal(t, 31, len(po.Hints()))
|
||||
assert.Equal(t, 32, len(po.Hints()))
|
||||
}
|
||||
|
||||
// Helpers...
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@ func (p *Policy) Init(ctx context.Context) {
|
|||
p.bindKeys()
|
||||
|
||||
p.SetSortCol(1, len(rbacHeader), false)
|
||||
p.Start()
|
||||
p.refresh()
|
||||
p.SelectRow(1, true)
|
||||
p.Start()
|
||||
}
|
||||
|
||||
func (p *Policy) Name() string {
|
||||
|
|
@ -65,6 +65,7 @@ func (p *Policy) Name() string {
|
|||
}
|
||||
|
||||
func (p *Policy) Start() {
|
||||
p.Stop()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
p.cancel = cancel
|
||||
go func(ctx context.Context) {
|
||||
|
|
@ -74,7 +75,6 @@ func (p *Policy) Start() {
|
|||
return
|
||||
case <-time.After(time.Duration(p.app.Config.K9s.GetRefreshRate()) * time.Second):
|
||||
p.refresh()
|
||||
p.app.Draw()
|
||||
}
|
||||
}
|
||||
}(ctx)
|
||||
|
|
@ -88,6 +88,8 @@ func (p *Policy) Stop() {
|
|||
|
||||
func (p *Policy) bindKeys() {
|
||||
p.RmAction(ui.KeyShiftA)
|
||||
p.RmAction(tcell.KeyCtrlSpace)
|
||||
p.RmAction(ui.KeySpace)
|
||||
|
||||
p.AddActions(ui.KeyActions{
|
||||
tcell.KeyEscape: ui.NewKeyAction("Back", p.resetCmd, false),
|
||||
|
|
@ -109,7 +111,9 @@ func (p *Policy) refresh() {
|
|||
log.Error().Err(err).Msgf("Refresh for %s:%s", p.subjectKind, p.subjectName)
|
||||
p.app.Flash().Err(err)
|
||||
}
|
||||
p.Update(data)
|
||||
p.app.QueueUpdateDraw(func() {
|
||||
p.Update(data)
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Policy) resetCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ func (p *PortForward) Init(ctx context.Context) {
|
|||
tv.SetBorderFocusColor(tcell.ColorDodgerBlue)
|
||||
tv.SetSelectedStyle(tcell.ColorWhite, tcell.ColorDodgerBlue, tcell.AttrNone)
|
||||
tv.SetColorerFn(forwardColorer)
|
||||
tv.SetActiveNS("")
|
||||
tv.ActiveNS = resource.AllNamespaces
|
||||
tv.SetSortCol(tv.NameColIndex()+6, 0, true)
|
||||
tv.Select(1, 0)
|
||||
|
||||
|
|
@ -136,13 +136,13 @@ func (p *PortForward) benchCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
tv := p.masterPage()
|
||||
r, _ := tv.GetSelection()
|
||||
cfg, co := defaultConfig(), ui.TrimCell(tv.Table, r, 2)
|
||||
cfg, co := defaultConfig(), ui.TrimCell(tv.SelectTable, r, 2)
|
||||
if b, ok := p.app.Bench.Benchmarks.Containers[containerID(sel, co)]; ok {
|
||||
cfg = b
|
||||
}
|
||||
cfg.Name = sel
|
||||
|
||||
base := ui.TrimCell(tv.Table, r, 4)
|
||||
base := ui.TrimCell(tv.SelectTable, r, 4)
|
||||
var err error
|
||||
if p.bench, err = perf.NewBenchmark(base, cfg); err != nil {
|
||||
p.app.Flash().Errf("Bench failed %v", err)
|
||||
|
|
@ -183,8 +183,8 @@ func (p *PortForward) getSelectedItem() string {
|
|||
return ""
|
||||
}
|
||||
return fwFQN(
|
||||
fqn(ui.TrimCell(tv.Table, r, 0), ui.TrimCell(tv.Table, r, 1)),
|
||||
ui.TrimCell(tv.Table, r, 2),
|
||||
fqn(ui.TrimCell(tv.SelectTable, r, 0), ui.TrimCell(tv.SelectTable, r, 1)),
|
||||
ui.TrimCell(tv.SelectTable, r, 2),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,5 +12,5 @@ func TestPortForwardNew(t *testing.T) {
|
|||
po.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "PortForwards", po.Name())
|
||||
assert.Equal(t, 15, len(po.Hints()))
|
||||
assert.Equal(t, 17, len(po.Hints()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ func NewRbac(app *App, ns, name string, kind roleKind) *Rbac {
|
|||
|
||||
// Init initializes the view.
|
||||
func (r *Rbac) Init(ctx context.Context) {
|
||||
r.SetActiveNS(r.app.Config.ActiveNamespace())
|
||||
r.ActiveNS = r.app.Config.ActiveNamespace()
|
||||
r.SetColorerFn(rbacColorer)
|
||||
r.Table.Init(ctx)
|
||||
r.bindKeys()
|
||||
|
|
@ -131,6 +131,8 @@ func (r *Rbac) Name() string {
|
|||
|
||||
func (r *Rbac) bindKeys() {
|
||||
r.RmAction(ui.KeyShiftA)
|
||||
r.RmAction(tcell.KeyCtrlSpace)
|
||||
r.RmAction(ui.KeySpace)
|
||||
|
||||
r.AddActions(ui.KeyActions{
|
||||
tcell.KeyEscape: ui.NewKeyAction("Reset", r.resetCmd, false),
|
||||
|
|
@ -156,7 +158,6 @@ func (r *Rbac) refresh() {
|
|||
}
|
||||
|
||||
func (r *Rbac) resetCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
log.Debug().Msgf("!!!YO!!!!")
|
||||
if !r.SearchBuff().Empty() {
|
||||
r.SearchBuff().Reset()
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -169,14 +169,14 @@ func (r *Resource) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
sel := r.masterPage().GetSelectedItems()
|
||||
var msg string
|
||||
if len(sel) > 1 {
|
||||
msg = fmt.Sprintf("Delete %d selected %s?", len(sel), r.list.GetName())
|
||||
msg = fmt.Sprintf("Delete %d marked %s?", len(sel), r.list.GetName())
|
||||
} else {
|
||||
msg = fmt.Sprintf("Delete %s %s?", r.list.GetName(), sel[0])
|
||||
}
|
||||
dialog.ShowDelete(r.Pages, msg, func(cascade, force bool) {
|
||||
r.masterPage().ShowDeleted()
|
||||
if len(sel) > 1 {
|
||||
r.app.Flash().Infof("Delete %d selected %s", len(sel), r.list.GetName())
|
||||
r.app.Flash().Infof("Delete %d marked %s", len(sel), r.list.GetName())
|
||||
} else {
|
||||
r.app.Flash().Infof("Delete resource %s %s", r.list.GetName(), sel[0])
|
||||
}
|
||||
|
|
@ -192,17 +192,6 @@ func (r *Resource) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *Resource) markCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !r.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
r.masterPage().ToggleMark()
|
||||
r.refresh()
|
||||
r.app.Draw()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deletePortForward(ff map[string]forwarder, sel string) {
|
||||
for k, f := range ff {
|
||||
tokens := strings.Split(k, ":")
|
||||
|
|
@ -373,7 +362,6 @@ func (r *Resource) refreshActions() {
|
|||
tcell.KeyEnter: ui.NewKeyAction("Enter", r.enterCmd, false),
|
||||
tcell.KeyCtrlR: ui.NewKeyAction("Refresh", r.refreshCmd, false),
|
||||
}
|
||||
aa[ui.KeySpace] = ui.NewKeyAction("Mark", r.markCmd, true)
|
||||
r.namespaceActions(aa)
|
||||
r.defaultActions(aa)
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ func (s *ScreenDump) Init(ctx context.Context) {
|
|||
table.SetBorderFocusColor(tcell.ColorSteelBlue)
|
||||
table.SetSelectedStyle(tcell.ColorWhite, tcell.ColorRoyalBlue, tcell.AttrNone)
|
||||
table.SetColorerFn(dumpColorer)
|
||||
table.SetActiveNS(resource.AllNamespaces)
|
||||
table.ActiveNS = resource.AllNamespaces
|
||||
table.SetSortCol(table.NameColIndex(), 0, true)
|
||||
table.SelectRow(1, true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,5 +12,5 @@ func TestScreenDumpNew(t *testing.T) {
|
|||
po.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "Screen Dumps", po.Name())
|
||||
assert.Equal(t, 11, len(po.Hints()))
|
||||
assert.Equal(t, 13, len(po.Hints()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ func TestSecretNew(t *testing.T) {
|
|||
s.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "secrets", s.Name())
|
||||
assert.Equal(t, 19, len(s.Hints()))
|
||||
assert.Equal(t, 20, len(s.Hints()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ func TestStatefulSetNew(t *testing.T) {
|
|||
s.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "sts", s.Name())
|
||||
assert.Equal(t, 24, len(s.Hints()))
|
||||
assert.Equal(t, 25, len(s.Hints()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package view
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/resource"
|
||||
|
|
@ -42,7 +42,7 @@ func NewSubject(title, gvr string, list resource.List) ResourceViewer {
|
|||
|
||||
// Init initializes the view.
|
||||
func (s *Subject) Init(ctx context.Context) {
|
||||
s.SetActiveNS("*")
|
||||
s.ActiveNS = "*"
|
||||
s.SetColorerFn(rbacColorer)
|
||||
s.Table.Init(ctx)
|
||||
s.bindKeys()
|
||||
|
|
@ -66,8 +66,9 @@ func (s *Subject) Start() {
|
|||
log.Debug().Msgf("Subject:%s Watch bailing out!", s.subjectKind)
|
||||
return
|
||||
case <-time.After(time.Duration(s.app.Config.K9s.GetRefreshRate()) * time.Second):
|
||||
s.refresh()
|
||||
s.app.Draw()
|
||||
s.app.QueueUpdateDraw(func() {
|
||||
s.refresh()
|
||||
})
|
||||
}
|
||||
}
|
||||
}(ctx)
|
||||
|
|
@ -88,9 +89,10 @@ func (s *Subject) masterPage() *Table {
|
|||
}
|
||||
|
||||
func (s *Subject) bindKeys() {
|
||||
// No time data or ns
|
||||
s.RmAction(ui.KeyShiftA)
|
||||
s.RmAction(ui.KeyShiftP)
|
||||
s.RmAction(tcell.KeyCtrlSpace)
|
||||
s.RmAction(ui.KeySpace)
|
||||
|
||||
s.AddActions(ui.KeyActions{
|
||||
tcell.KeyEnter: ui.NewKeyAction("Policies", s.policyCmd, true),
|
||||
|
|
@ -119,7 +121,6 @@ func (s *Subject) refresh() {
|
|||
}
|
||||
|
||||
func (s *Subject) policyCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
log.Debug().Msg("YO!!")
|
||||
if !s.RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
|
@ -296,12 +297,14 @@ func mapCmdSubject(subject string) string {
|
|||
}
|
||||
|
||||
func mapFuSubject(subject string) string {
|
||||
switch strings.ToLower(subject) {
|
||||
switch subject {
|
||||
case group:
|
||||
return "g"
|
||||
case sa:
|
||||
return "s"
|
||||
default:
|
||||
case user:
|
||||
return "u"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown FU subject %q", subject))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ func TestServiceNew(t *testing.T) {
|
|||
s.Init(makeCtx())
|
||||
|
||||
assert.Equal(t, "svc", s.Name())
|
||||
assert.Equal(t, 22, len(s.Hints()))
|
||||
assert.Equal(t, 23, len(s.Hints()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ func NewTable(title string) *Table {
|
|||
|
||||
func (t *Table) Init(ctx context.Context) {
|
||||
t.app = mustExtractApp(ctx)
|
||||
|
||||
ctx = context.WithValue(ctx, ui.KeyStyles, t.app.Styles)
|
||||
t.Table.Init(ctx)
|
||||
|
||||
|
|
@ -65,6 +64,8 @@ func (t *Table) setFilterFn(fn func(string)) {
|
|||
|
||||
func (t *Table) bindKeys() {
|
||||
t.AddActions(ui.KeyActions{
|
||||
ui.KeySpace: ui.NewKeyAction("Mark", t.markCmd, true),
|
||||
tcell.KeyCtrlSpace: ui.NewKeyAction("Marks Clear", t.clearMarksCmd, true),
|
||||
tcell.KeyCtrlS: ui.NewKeyAction("Save", t.saveCmd, true),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter Mode", t.activateCmd, false),
|
||||
tcell.KeyEscape: ui.NewKeyAction("Filter Reset", t.resetCmd, false),
|
||||
|
|
@ -78,6 +79,25 @@ func (t *Table) bindKeys() {
|
|||
})
|
||||
}
|
||||
|
||||
func (t *Table) markCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !t.RowSelected() {
|
||||
return evt
|
||||
}
|
||||
t.ToggleMark()
|
||||
t.Refresh()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Table) clearMarksCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !t.RowSelected() {
|
||||
return evt
|
||||
}
|
||||
t.ClearMarks()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Table) filterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !t.SearchBuff().IsActive() {
|
||||
return evt
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import (
|
|||
)
|
||||
|
||||
func trimCellRelative(t *Table, row, col int) string {
|
||||
return ui.TrimCell(t.Table, row, t.NameColIndex()+col)
|
||||
return ui.TrimCell(t.SelectTable, row, t.NameColIndex()+col)
|
||||
}
|
||||
|
||||
func saveTable(cluster, name string, data resource.TableData) (string, error) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue