From a63b480a76ba4233acff26b1b1757e397b9ce1dc Mon Sep 17 00:00:00 2001 From: Kevin Gimbel Date: Wed, 22 Jan 2025 09:46:10 +0100 Subject: [PATCH] feat: add basic for labels in tables #3050 --- internal/config/json/schemas/views.json | 9 ++++++++- internal/config/views.go | 20 ++++++++++++++++++-- internal/model1/header.go | 14 ++++++++------ internal/render/pod.go | 7 +++++++ internal/ui/table.go | 1 + 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/internal/config/json/schemas/views.json b/internal/config/json/schemas/views.json index 6b3971c501..b0591ce912 100644 --- a/internal/config/json/schemas/views.json +++ b/internal/config/json/schemas/views.json @@ -13,7 +13,14 @@ "sortColumn": { "type": "string" }, "columns": { "type": "array", - "items": { "type": "string" } + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { "type": "string"}, + "key": { "type": "string" } + } + } } }, "required": ["columns"] diff --git a/internal/config/views.go b/internal/config/views.go index 41c6b9b5e6..42b17f394d 100644 --- a/internal/config/views.go +++ b/internal/config/views.go @@ -26,10 +26,15 @@ type ViewConfigListener interface { // ViewSetting represents a view configuration. type ViewSetting struct { - Columns []string `yaml:"columns"` + Columns []Column `yaml:"columns"` SortColumn string `yaml:"sortColumn"` } +type Column struct { + Name string `yaml:"name"` + Key string `yaml:"key"` +} + func (v *ViewSetting) HasCols() bool { return len(v.Columns) > 0 } @@ -54,7 +59,18 @@ func (v *ViewSetting) Equals(vs *ViewSetting) bool { if v == nil || vs == nil { return v == nil && vs == nil } - if c := slices.Compare(v.Columns, vs.Columns); c != 0 { + + var vkeys []string + var vskeys []string + + for idx := range v.Columns { + vkeys = append(vkeys, v.Columns[idx].Name) + } + for idx := range vs.Columns { + vskeys = append(vskeys, vs.Columns[idx].Name) + } + + if c := slices.Compare(vkeys, vskeys); c != 0 { return false } return cmp.Compare(v.SortColumn, vs.SortColumn) == 0 diff --git a/internal/model1/header.go b/internal/model1/header.go index d4f6d4c850..eae81fe6a2 100644 --- a/internal/model1/header.go +++ b/internal/model1/header.go @@ -6,6 +6,7 @@ package model1 import ( "reflect" + "github.com/derailed/k9s/internal/config" "github.com/rs/zerolog/log" ) @@ -64,11 +65,11 @@ func (h Header) Labelize(cols []int, labelCol int, rr *RowEvents) Header { } // MapIndices returns a collection of mapped column indices based of the requested columns. -func (h Header) MapIndices(cols []string, wide bool) []int { +func (h Header) MapIndices(cols []config.Column, wide bool) []int { ii := make([]int, 0, len(cols)) cc := make(map[int]struct{}, len(cols)) for _, col := range cols { - idx, ok := h.IndexOf(col, true) + idx, ok := h.IndexOf(col.Name, true) if !ok { log.Warn().Msgf("Column %q not found on resource", col) } @@ -88,22 +89,23 @@ func (h Header) MapIndices(cols []string, wide bool) []int { } // Customize builds a header from custom col definitions. -func (h Header) Customize(cols []string, wide bool) Header { +func (h Header) Customize(cols []config.Column, wide bool) Header { if len(cols) == 0 { return h } cc := make(Header, 0, len(h)) xx := make(map[int]struct{}, len(h)) for _, c := range cols { - idx, ok := h.IndexOf(c, true) + idx, ok := h.IndexOf(c.Name, true) if !ok { - log.Warn().Msgf("Column %s is not available on this resource", c) - cc = append(cc, HeaderColumn{Name: c}) + log.Warn().Msgf("Column %s is not available on this resource", c.Name) + cc = append(cc, HeaderColumn{Name: c.Name}) continue } xx[idx] = struct{}{} col := h[idx].Clone() col.Wide = false + cc = append(cc, col) } diff --git a/internal/render/pod.go b/internal/render/pod.go index a501cad6ce..713b1fdb02 100644 --- a/internal/render/pod.go +++ b/internal/render/pod.go @@ -111,6 +111,7 @@ func (p Pod) Header(ns string) model1.Header { model1.HeaderColumn{Name: "LABELS", Wide: true}, model1.HeaderColumn{Name: "VALID", Wide: true}, model1.HeaderColumn{Name: "AGE", Time: true}, + model1.HeaderColumn{Name: "LABEL"}, } } @@ -166,11 +167,17 @@ func (p Pod) Render(o interface{}, ns string, row *model1.Row) error { mapToStr(po.Labels), AsStatus(p.diagnose(phase, cr, len(cs))), ToAge(po.GetCreationTimestamp()), + ExtractLabel(po), } return nil } +func ExtractLabel(pod v1.Pod) string { + // Need to get the "key" from the views.yaml config here + return pod.Labels["k8s-app"] +} + func (p Pod) diagnose(phase string, cr, ct int) error { if phase == Completed { return nil diff --git a/internal/ui/table.go b/internal/ui/table.go index a1cd7365ef..4305161a93 100644 --- a/internal/ui/table.go +++ b/internal/ui/table.go @@ -360,6 +360,7 @@ func (t *Table) buildRow(r int, re, ore model1.RowEvent, h model1.Header, pads M if h[c].Decorator != nil { field = h[c].Decorator(field) } + if h[c].Align == tview.AlignLeft { field = formatCell(field, pads[c]) }