allow to mark multiple resources to act upon

mine
Bruno Meneguello 2019-10-11 14:11:06 -03:00
parent 23f61320cb
commit 42e5793438
No known key found for this signature in database
GPG Key ID: 1ECBE47F41FA3A4B
8 changed files with 89 additions and 15 deletions

View File

@ -99,6 +99,7 @@ type (
FgColor string `yaml:"fgColor"`
BgColor string `yaml:"bgColor"`
CursorColor string `yaml:"cursorColor"`
MarkColor string `yaml:"markColor"`
Header TableHeader `yaml:"header"`
}
@ -215,6 +216,7 @@ func newTable() Table {
FgColor: "aqua",
BgColor: "black",
CursorColor: "aqua",
MarkColor: "darkgoldenrod",
Header: newTableHeader(),
}
}

View File

@ -66,6 +66,7 @@ type (
Rows RowEvents
NumCols map[string]bool
Namespace string
Marks []string
}
// List protocol to display and update a collection of resources
@ -84,6 +85,7 @@ type (
SetFieldSelector(string)
SetLabelSelector(string)
HasSelectors() bool
ToggleMark(sk string)
}
// Columnar tracks resources that can be diplayed in a tabular fashion.
@ -127,9 +129,20 @@ type (
verbs int
resource Resource
cache RowEvents
marks []string
}
)
// IsMarked checks if key is marked.
func (t *TableData) IsMarked(sk string) bool {
for _, mark := range t.Marks {
if mark == sk {
return true
}
}
return false
}
func newRowEvent(a watch.EventType, f, d Row) *RowEvent {
return &RowEvent{Action: a, Fields: f, Deltas: d}
}
@ -232,6 +245,7 @@ func (l *list) Data() TableData {
Rows: l.cache,
NumCols: l.resource.NumCols(l.namespace),
Namespace: l.namespace,
Marks: l.marks,
}
}
@ -343,10 +357,29 @@ func (l *list) ensureDeletes(kk []string) {
}
if !found {
delete(l.cache, k)
l.removeMark(k)
}
}
}
func (l *list) removeMark(sk string) {
for index, mark := range l.marks {
if mark == sk {
l.marks = append(l.marks[:index], l.marks[index+1:]...)
}
}
}
func (l *list) ToggleMark(sk string) {
for index, mark := range l.marks {
if mark == sk {
l.marks = append(l.marks[:index], l.marks[index+1:]...)
return
}
}
l.marks = append(l.marks, sk)
}
// Helpers...
func computeDeltas(evt *RowEvent, newRow, deltas Row) watch.EventType {

View File

@ -169,6 +169,16 @@ func (v *Table) GetSelectedItem() string {
return v.selectedItem
}
// GetSelectedItems return currently marked or selected items names.
func (v *Table) GetSelectedItems() []string {
if len(v.data.Marks) > 0 {
items := make([]string, len(v.data.Marks))
copy(items, v.data.Marks)
return items
}
return []string{v.GetSelectedItem()}
}
func (v *Table) keyboard(evt *tcell.EventKey) *tcell.EventKey {
key := evt.Key()
if key == tcell.KeyRune {
@ -318,6 +328,7 @@ func (v *Table) buildRow(row int, data resource.TableData, sk string, pads MaxyP
if v.colorerFn != nil {
f = v.colorerFn
}
m := data.IsMarked(sk)
for col, field := range data.Rows[sk].Fields {
header := data.Header[col]
field, align := v.formatCell(data.NumCols[header], header, field+Deltas(data.Rows[sk].Deltas[col], field), pads[col])
@ -326,6 +337,9 @@ func (v *Table) buildRow(row int, data resource.TableData, sk string, pads MaxyP
c.SetExpansion(1)
c.SetAlign(align)
c.SetTextColor(f(data.Namespace, data.Rows[sk]))
if m {
c.SetBackgroundColor(config.AsColor(v.styles.Table().MarkColor))
}
}
v.SetCell(row, col, c)
}

View File

@ -115,15 +115,17 @@ func (v *podView) killCmd(evt *tcell.EventKey) *tcell.EventKey {
return evt
}
sel := v.masterPage().GetSelectedItem()
sel := v.masterPage().GetSelectedItems()
v.masterPage().ShowDeleted()
v.app.Flash().Infof("Delete resource %s %s", v.list.GetName(), sel)
if err := v.list.Resource().Delete(sel, true, false); err != nil {
v.app.Flash().Errf("Delete failed with %s", err)
} else {
deletePortForward(v.app.forwarders, sel)
v.refresh()
for _, res := range sel {
v.app.Flash().Infof("Delete resource %s %s", v.list.GetName(), res)
if err := v.list.Resource().Delete(res, true, false); err != nil {
v.app.Flash().Errf("Delete failed with %s", err)
} else {
deletePortForward(v.app.forwarders, res)
}
}
v.refresh()
return nil
}

View File

@ -192,23 +192,42 @@ func (v *resourceView) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
return evt
}
sel := v.masterPage().GetSelectedItem()
msg := fmt.Sprintf("Delete %s %s?", v.list.GetName(), sel)
sel := v.masterPage().GetSelectedItems()
var msg string
if len(sel) > 1 {
msg = fmt.Sprintf("Delete %d selected %s?", len(sel), v.list.GetName())
} else {
msg = fmt.Sprintf("Delete %s %s?", v.list.GetName(), sel)
}
dialog.ShowDelete(v.Pages, msg, func(cascade, force bool) {
v.masterPage().ShowDeleted()
v.app.Flash().Infof("Delete resource %s %s", v.list.GetName(), sel)
if err := v.list.Resource().Delete(sel, cascade, force); err != nil {
v.app.Flash().Errf("Delete failed with %s", err)
} else {
deletePortForward(v.app.forwarders, sel)
v.refresh()
for _, res := range sel {
v.app.Flash().Infof("Delete resource %s %s", v.list.GetName(), res)
if err := v.list.Resource().Delete(res, cascade, force); err != nil {
v.app.Flash().Errf("Delete failed with %s", err)
} else {
deletePortForward(v.app.forwarders, res)
}
}
v.refresh()
}, func() {
v.switchPage("master")
})
return nil
}
func (v *resourceView) markCmd(evt *tcell.EventKey) *tcell.EventKey {
if !v.masterPage().RowSelected() {
return evt
}
sel := v.masterPage().GetSelectedItem()
v.list.ToggleMark(sel)
v.refresh()
v.app.Draw()
return nil
}
func deletePortForward(ff map[string]forwarder, sel string) {
for k, v := range ff {
tokens := strings.Split(k, ":")
@ -371,6 +390,7 @@ func (v *resourceView) refreshActions() {
tcell.KeyEnter: ui.NewKeyAction("Enter", v.enterCmd, false),
tcell.KeyCtrlR: ui.NewKeyAction("Refresh", v.refreshCmd, false),
}
aa[tcell.KeyCtrlSpace] = ui.NewKeyAction("Mark", v.markCmd, true)
v.namespaceActions(aa)
v.defaultActions(aa)

View File

@ -35,6 +35,7 @@ k9s:
fgColor: white
bgColor: black
cursorColor: white
markColor: darkgoldenrod
header:
fgColor: darkgray
bgColor: black

View File

@ -37,6 +37,7 @@ k9s:
fgColor: blue
bgColor: darkblue
cursorColor: aqua
markColor: mediumslateblue
header:
fgColor: white
bgColor: darkblue

View File

@ -35,6 +35,7 @@ k9s:
fgColor: blue
bgColor: black
cursorColor: aqua
markColor: darkgoldenrod
header:
fgColor: white
bgColor: black