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