parent
f0ae348b02
commit
43d62f9528
2
go.mod
2
go.mod
|
|
@ -2,6 +2,8 @@ module github.com/derailed/k9s
|
|||
|
||||
go 1.13
|
||||
|
||||
replace github.com/derailed/tview => /Users/fernand/go_wk/derailed/src/github.com/derailed/tview
|
||||
|
||||
replace (
|
||||
github.com/docker/docker => github.com/docker/docker v1.4.2-0.20181221150755-2cb26cfe9cbf
|
||||
k8s.io/api => k8s.io/api v0.0.0-20190918155943-95b840bb6a1f
|
||||
|
|
|
|||
|
|
@ -112,6 +112,11 @@ func join(a []string, sep string) string {
|
|||
return buff.String()
|
||||
}
|
||||
|
||||
// ToPerc prints a number as percentage.
|
||||
func ToPerc(f float64) string {
|
||||
return AsPerc(f) + "%"
|
||||
}
|
||||
|
||||
// AsPerc prints a number as a percentage.
|
||||
func AsPerc(f float64) string {
|
||||
return strconv.Itoa(int(f))
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -61,9 +60,7 @@ func (c *Component) InputHandler() func(event *tcell.EventKey, setFocus func(p t
|
|||
return c.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
|
||||
switch key := event.Key(); key {
|
||||
case tcell.KeyEnter:
|
||||
log.Debug().Msgf("YO %s ENTER!!", c.id)
|
||||
case tcell.KeyBacktab, tcell.KeyTab:
|
||||
log.Debug().Msgf("YO %s TAB!!", c.id)
|
||||
if c.blur != nil {
|
||||
c.blur(key)
|
||||
}
|
||||
|
|
@ -113,7 +110,8 @@ func (c *Component) GetSeriesColorNames() []string {
|
|||
func (c *Component) colorForSeries() (tcell.Color, tcell.Color) {
|
||||
c.mx.RLock()
|
||||
defer c.mx.RUnlock()
|
||||
if len(c.seriesColors) > 1 {
|
||||
|
||||
if len(c.seriesColors) == 2 {
|
||||
return c.seriesColors[0], c.seriesColors[1]
|
||||
}
|
||||
return okColor, faultColor
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package tchart
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/tview"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestComponentAsRect(t *testing.T) {
|
||||
c := NewComponent("fred")
|
||||
r := image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 15, Y: 10}}
|
||||
|
||||
assert.Equal(t, r, c.asRect())
|
||||
}
|
||||
|
||||
func TestComponentColorForSeries(t *testing.T) {
|
||||
c := NewComponent("fred")
|
||||
okC, errC := c.colorForSeries()
|
||||
|
||||
assert.Equal(t, tview.Styles.PrimaryTextColor, okC)
|
||||
assert.Equal(t, tview.Styles.FocusColor, errC)
|
||||
assert.Equal(t, []string{"white", "green"}, c.GetSeriesColorNames())
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package tchart_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/tchart"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCoSeriesColorNames(t *testing.T) {
|
||||
c := tchart.NewComponent("fred")
|
||||
|
||||
c.SetSeriesColors(tcell.ColorGreen, tcell.ColorBlue)
|
||||
|
||||
assert.Equal(t, []string{"green", "blue"}, c.GetSeriesColorNames())
|
||||
}
|
||||
|
||||
func TestComponentAsRect(t *testing.T) {
|
||||
c := tchart.NewComponent("fred")
|
||||
|
||||
c.SetSeriesColors(tcell.ColorGreen, tcell.ColorBlue)
|
||||
|
||||
assert.Equal(t, []string{"green", "blue"}, c.GetSeriesColorNames())
|
||||
}
|
||||
|
|
@ -38,12 +38,12 @@ func TestSegmentFor(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDial(t *testing.T) {
|
||||
func TestDial5x3(t *testing.T) {
|
||||
d := tchart.NewDotMatrix(5, 3)
|
||||
for n := 0; n <= 9; n++ {
|
||||
i := n
|
||||
t.Run(strconv.Itoa(n), func(t *testing.T) {
|
||||
assert.Equal(t, numbers[i], d.Print(i))
|
||||
assert.Equal(t, numbers3x5[i], d.Print(i))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ func TestDial(t *testing.T) {
|
|||
|
||||
const hChar, vChar = '▤', '▥'
|
||||
|
||||
var numbers = []tchart.Matrix{
|
||||
var numbers3x5 = []tchart.Matrix{
|
||||
[][]rune{
|
||||
{hChar, hChar, hChar},
|
||||
{vChar, ' ', vChar},
|
||||
|
|
|
|||
|
|
@ -52,33 +52,6 @@ func (g *Gauge) Add(m Metric) {
|
|||
g.data = m
|
||||
}
|
||||
|
||||
func (g *Gauge) drawNum(sc tcell.Screen, ok bool, o image.Point, n int, dn delta, ns string, style tcell.Style) {
|
||||
c1, _ := g.colorForSeries()
|
||||
if ok {
|
||||
o.X -= 1
|
||||
style = style.Foreground(c1)
|
||||
printDelta(sc, dn, o, style)
|
||||
o.X += 1
|
||||
}
|
||||
|
||||
dm, sig := NewDotMatrix(5, 3), n == 0
|
||||
if n == 0 {
|
||||
style = g.dimmed
|
||||
}
|
||||
for i := 0; i < len(ns); i++ {
|
||||
if ns[i] == '0' && !sig {
|
||||
g.drawDial(sc, dm.Print(int(ns[i]-48)), o, g.dimmed)
|
||||
} else {
|
||||
sig = true
|
||||
g.drawDial(sc, dm.Print(int(ns[i]-48)), o, style)
|
||||
}
|
||||
o.X += 5
|
||||
}
|
||||
if !ok {
|
||||
printDelta(sc, dn, o, style)
|
||||
}
|
||||
}
|
||||
|
||||
// Draw draws the primitive.
|
||||
func (g *Gauge) Draw(sc tcell.Screen) {
|
||||
g.Component.Draw(sc)
|
||||
|
|
@ -87,7 +60,7 @@ func (g *Gauge) Draw(sc tcell.Screen) {
|
|||
defer g.mx.RUnlock()
|
||||
|
||||
rect := g.asRect()
|
||||
mid := image.Point{X: rect.Min.X + rect.Dx()/2 - 2, Y: rect.Min.Y + rect.Dy()/2 - 2}
|
||||
mid := image.Point{X: rect.Min.X + rect.Dx()/2 - 1, Y: rect.Min.Y + rect.Dy()/2 - 2}
|
||||
|
||||
style := tcell.StyleDefault.Background(g.bgColor)
|
||||
style = style.Foreground(tcell.ColorYellow)
|
||||
|
|
@ -129,6 +102,33 @@ func (g *Gauge) drawDial(sc tcell.Screen, m Matrix, o image.Point, style tcell.S
|
|||
}
|
||||
}
|
||||
|
||||
func (g *Gauge) drawNum(sc tcell.Screen, ok bool, o image.Point, n int, dn delta, ns string, style tcell.Style) {
|
||||
c1, _ := g.colorForSeries()
|
||||
if ok {
|
||||
o.X -= 1
|
||||
style = style.Foreground(c1)
|
||||
printDelta(sc, dn, o, style)
|
||||
o.X += 1
|
||||
}
|
||||
|
||||
dm, sig := NewDotMatrix(5, 3), n == 0
|
||||
if n == 0 {
|
||||
style = g.dimmed
|
||||
}
|
||||
for i := 0; i < len(ns); i++ {
|
||||
if ns[i] == '0' && !sig {
|
||||
g.drawDial(sc, dm.Print(int(ns[i]-48)), o, g.dimmed)
|
||||
} else {
|
||||
sig = true
|
||||
g.drawDial(sc, dm.Print(int(ns[i]-48)), o, style)
|
||||
}
|
||||
o.X += 5
|
||||
}
|
||||
if !ok {
|
||||
printDelta(sc, dn, o, style)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package tchart
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestComputeDeltas(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
d1, d2 int
|
||||
e delta
|
||||
}{
|
||||
"same": {
|
||||
e: DeltaSame,
|
||||
},
|
||||
"more": {
|
||||
d1: 10,
|
||||
d2: 20,
|
||||
e: DeltaMore,
|
||||
},
|
||||
"less": {
|
||||
d1: 20,
|
||||
d2: 10,
|
||||
e: DeltaLess,
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
assert.Equal(t, u.e, computeDelta(u.d1, u.d2))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package tchart_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/tchart"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMetricsMaxDigits(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
m tchart.Metric
|
||||
e int
|
||||
}{
|
||||
"empty": {
|
||||
e: 1,
|
||||
},
|
||||
"oks": {
|
||||
m: tchart.Metric{OK: 100, Fault: 10},
|
||||
e: 3,
|
||||
},
|
||||
"errs": {
|
||||
m: tchart.Metric{OK: 10, Fault: 1000},
|
||||
e: 4,
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
assert.Equal(t, u.e, u.m.MaxDigits())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetricsMax(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
m tchart.Metric
|
||||
e int
|
||||
}{
|
||||
"empty": {
|
||||
e: 0,
|
||||
},
|
||||
"max_ok": {
|
||||
m: tchart.Metric{OK: 100, Fault: 10},
|
||||
e: 100,
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
assert.Equal(t, u.e, u.m.Max())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGauge(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
mm []tchart.Metric
|
||||
e int
|
||||
}{
|
||||
"empty": {
|
||||
e: 1,
|
||||
},
|
||||
"oks": {
|
||||
mm: []tchart.Metric{{OK: 100, Fault: 10}},
|
||||
e: 3,
|
||||
},
|
||||
"errs": {
|
||||
mm: []tchart.Metric{{OK: 10, Fault: 1000}},
|
||||
e: 4,
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
g := tchart.NewGauge("fred")
|
||||
assert.True(t, g.IsDial())
|
||||
for _, m := range u.mm {
|
||||
g.Add(m)
|
||||
}
|
||||
t.Run(k, func(t *testing.T) {
|
||||
// assert.Equal(t, u.e, u.m.MaxDigits())
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package tchart
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"math"
|
||||
|
||||
"github.com/derailed/tview"
|
||||
|
|
@ -24,13 +25,18 @@ type Metric struct {
|
|||
OK, Fault int
|
||||
}
|
||||
|
||||
// MaxDigits returns the max of the metric.
|
||||
// MaxDigits returns the max series number of digits.
|
||||
func (m Metric) MaxDigits() int {
|
||||
max := int(math.Max(float64(m.OK), float64(m.Fault)))
|
||||
s := fmt.Sprintf("%d", max)
|
||||
|
||||
s := fmt.Sprintf("%d", m.Max())
|
||||
return len(s)
|
||||
}
|
||||
|
||||
// Max returns the max of the series.
|
||||
func (m Metric) Max() int {
|
||||
return int(math.Max(float64(m.OK), float64(m.Fault)))
|
||||
}
|
||||
|
||||
// Sum returns the sum of the metrics.
|
||||
func (m Metric) Sum() int {
|
||||
return m.OK + m.Fault
|
||||
|
|
@ -40,16 +46,23 @@ func (m Metric) Sum() int {
|
|||
type SparkLine struct {
|
||||
*Component
|
||||
|
||||
data []Metric
|
||||
data []Metric
|
||||
multiSeries bool
|
||||
}
|
||||
|
||||
// NewSparkLine returns a new graph.
|
||||
func NewSparkLine(id string) *SparkLine {
|
||||
return &SparkLine{
|
||||
Component: NewComponent(id),
|
||||
Component: NewComponent(id),
|
||||
multiSeries: true,
|
||||
}
|
||||
}
|
||||
|
||||
// SetSingleSeries indicates multi series are in effect or not.
|
||||
func (s *SparkLine) SetMultiSeries(b bool) {
|
||||
s.multiSeries = b
|
||||
}
|
||||
|
||||
// Add adds a metric.
|
||||
func (s *SparkLine) Add(m Metric) {
|
||||
s.mx.Lock()
|
||||
|
|
@ -84,13 +97,17 @@ func (s *SparkLine) Draw(screen tcell.Screen) {
|
|||
idx = len(s.data) - rect.Dx()/2
|
||||
}
|
||||
|
||||
scale := float64(len(sparks)) * float64((rect.Dy() - pad)) / float64(max)
|
||||
factor := 2
|
||||
if !s.multiSeries {
|
||||
factor = 1
|
||||
}
|
||||
scale := float64(len(sparks)*(rect.Dy()-pad)/factor) / float64(max)
|
||||
c1, c2 := s.colorForSeries()
|
||||
for _, d := range s.data[idx:] {
|
||||
b := toBlocks(d, scale)
|
||||
cY := rect.Max.Y - pad
|
||||
s.drawBlock(screen, cX, cY, b.oks, c1)
|
||||
s.drawBlock(screen, cX, cY, b.errs, c2)
|
||||
cY = s.drawBlock(rect, screen, cX, cY, b.oks, c1)
|
||||
_ = s.drawBlock(rect, screen, cX, cY, b.errs, c2)
|
||||
cX += 2
|
||||
}
|
||||
|
||||
|
|
@ -103,16 +120,25 @@ func (s *SparkLine) Draw(screen tcell.Screen) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *SparkLine) drawBlock(screen tcell.Screen, x, y int, b block, c tcell.Color) {
|
||||
func (s *SparkLine) drawBlock(r image.Rectangle, screen tcell.Screen, x, y int, b block, c tcell.Color) int {
|
||||
style := tcell.StyleDefault.Foreground(c).Background(s.bgColor)
|
||||
|
||||
zeroY := r.Max.Y - r.Dy()
|
||||
for i := 0; i < b.full; i++ {
|
||||
screen.SetContent(x, y, sparks[len(sparks)-1], nil, style)
|
||||
y--
|
||||
if y <= zeroY {
|
||||
break
|
||||
}
|
||||
}
|
||||
if b.partial != 0 {
|
||||
screen.SetContent(x, y, b.partial, nil, style)
|
||||
if b.full == 0 {
|
||||
y--
|
||||
}
|
||||
}
|
||||
|
||||
return y
|
||||
}
|
||||
|
||||
func (s *SparkLine) cutSet(width int) {
|
||||
|
|
@ -128,8 +154,9 @@ func (s *SparkLine) cutSet(width int) {
|
|||
func (s *SparkLine) computeMax() int {
|
||||
var max int
|
||||
for _, d := range s.data {
|
||||
if max < d.OK {
|
||||
max = d.OK
|
||||
m := d.Max()
|
||||
if max < m {
|
||||
max = m
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,18 +167,17 @@ func toBlocks(m Metric, scale float64) blocks {
|
|||
if m.Sum() <= 0 {
|
||||
return blocks{}
|
||||
}
|
||||
return blocks{oks: makeBlocks(m.OK, false, scale), errs: makeBlocks(m.Fault, true, scale)}
|
||||
return blocks{oks: makeBlocks(m.OK, scale), errs: makeBlocks(m.Fault, scale)}
|
||||
}
|
||||
|
||||
func makeBlocks(v int, isErr bool, scale float64) block {
|
||||
func makeBlocks(v int, scale float64) block {
|
||||
scaled := int(math.Round(float64(v) * scale))
|
||||
part, b := scaled%len(sparks), block{full: scaled / len(sparks)}
|
||||
// Err might get scaled way down if so nudge.
|
||||
if v > 0 && isErr && scaled == 0 {
|
||||
part = 1
|
||||
p, b := scaled%len(sparks), block{full: scaled / len(sparks)}
|
||||
if b.full == 0 && v > 0 && p == 0 {
|
||||
p = 4
|
||||
}
|
||||
if part > 0 {
|
||||
b.partial = sparks[part-1]
|
||||
if v > 0 && p >= 0 && p < len(sparks) {
|
||||
b.partial = sparks[p]
|
||||
}
|
||||
|
||||
return b
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
package tchart
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCutSet(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
mm []Metric
|
||||
w, e int
|
||||
}{
|
||||
"empty": {
|
||||
w: 10,
|
||||
e: 0,
|
||||
},
|
||||
"at": {
|
||||
mm: make([]Metric, 10),
|
||||
w: 10,
|
||||
e: 10,
|
||||
},
|
||||
"under": {
|
||||
mm: make([]Metric, 5),
|
||||
w: 10,
|
||||
e: 5,
|
||||
},
|
||||
"over": {
|
||||
mm: make([]Metric, 10),
|
||||
w: 5,
|
||||
e: 5,
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
s := NewSparkLine("s")
|
||||
assert.False(t, s.IsDial())
|
||||
|
||||
for _, m := range u.mm {
|
||||
s.Add(m)
|
||||
}
|
||||
s.cutSet(u.w)
|
||||
assert.Equal(t, u.e, len(s.data))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToBlocks(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
m Metric
|
||||
s float64
|
||||
e blocks
|
||||
}{
|
||||
"empty": {
|
||||
e: blocks{},
|
||||
},
|
||||
"max_ok": {
|
||||
m: Metric{OK: 100, Fault: 10},
|
||||
s: 0.5,
|
||||
e: blocks{
|
||||
oks: block{full: 6, partial: sparks[2]},
|
||||
errs: block{full: 0, partial: sparks[5]},
|
||||
},
|
||||
},
|
||||
"max_fault": {
|
||||
m: Metric{OK: 10, Fault: 100},
|
||||
s: 0.5,
|
||||
e: blocks{
|
||||
oks: block{full: 0, partial: sparks[5]},
|
||||
errs: block{full: 6, partial: sparks[2]},
|
||||
},
|
||||
},
|
||||
"over": {
|
||||
m: Metric{OK: 22, Fault: 999},
|
||||
s: float64(8*20) / float64(999),
|
||||
e: blocks{
|
||||
oks: block{full: 0, partial: sparks[4]},
|
||||
errs: block{full: 20, partial: sparks[0]},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
assert.Equal(t, u.e, toBlocks(u.m, u.s))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeMax(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
mm []Metric
|
||||
e int
|
||||
}{
|
||||
"empty": {
|
||||
e: 0,
|
||||
},
|
||||
"max_ok": {
|
||||
mm: []Metric{{OK: 100, Fault: 10}},
|
||||
e: 100,
|
||||
},
|
||||
"max_fault": {
|
||||
mm: []Metric{{OK: 100, Fault: 1000}},
|
||||
e: 1000,
|
||||
},
|
||||
"many": {
|
||||
mm: []Metric{
|
||||
{OK: 100, Fault: 1000},
|
||||
{OK: 110, Fault: 1010},
|
||||
{OK: 120, Fault: 1020},
|
||||
{OK: 130, Fault: 1030},
|
||||
{OK: 140, Fault: 1040},
|
||||
},
|
||||
e: 1040,
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
s := NewSparkLine("s")
|
||||
for _, m := range u.mm {
|
||||
s.Add(m)
|
||||
}
|
||||
t.Run(k, func(t *testing.T) {
|
||||
assert.Equal(t, u.e, s.computeMax())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ func (s *StatusIndicator) StylesChanged(styles *config.Styles) {
|
|||
s.SetTextColor(styles.FgColor())
|
||||
}
|
||||
|
||||
const statusIndicatorFmt = "[orange::b]K9s [aqua::]%s [white::]%s:%s:%s [lawngreen::]%s%%[white::]::[darkturquoise::]%s%%"
|
||||
const statusIndicatorFmt = "[orange::b]K9s [aqua::]%s [white::]%s:%s:%s [lawngreen::]%s[white::]::[darkturquoise::]%s"
|
||||
|
||||
// ClusterInfoUpdated notifies the cluster meta was updated.
|
||||
func (s *StatusIndicator) ClusterInfoUpdated(data model.ClusterMeta) {
|
||||
|
|
@ -56,8 +56,8 @@ func (s *StatusIndicator) ClusterInfoUpdated(data model.ClusterMeta) {
|
|||
data.Cluster,
|
||||
data.User,
|
||||
data.K8sVer,
|
||||
render.AsPerc(data.Cpu),
|
||||
render.AsPerc(data.Mem),
|
||||
render.ToPerc(data.Cpu),
|
||||
render.ToPerc(data.Mem),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,9 @@ import (
|
|||
type SelectTable struct {
|
||||
*tview.Table
|
||||
|
||||
model Tabular
|
||||
selectedRow int
|
||||
selectedFn func(string) string
|
||||
marks map[string]struct{}
|
||||
model Tabular
|
||||
selectedFn func(string) string
|
||||
marks map[string]struct{}
|
||||
}
|
||||
|
||||
// SetModel sets the table model.
|
||||
|
|
@ -69,7 +68,8 @@ func (s *SelectTable) GetSelectedItem() string {
|
|||
|
||||
// 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)
|
||||
r, _ := s.GetSelection()
|
||||
return TrimCell(s, r, col)
|
||||
}
|
||||
|
||||
// SetSelectedFn defines a function that cleanse the current selection.
|
||||
|
|
@ -79,7 +79,8 @@ func (s *SelectTable) SetSelectedFn(f func(string) string) {
|
|||
|
||||
// GetSelectedRowIndex fetch the currently selected row index.
|
||||
func (s *SelectTable) GetSelectedRowIndex() int {
|
||||
return s.selectedRow
|
||||
r, _ := s.GetSelection()
|
||||
return r
|
||||
}
|
||||
|
||||
// SelectRow select a given row by index.
|
||||
|
|
@ -93,14 +94,14 @@ func (s *SelectTable) SelectRow(r int, broadcast bool) {
|
|||
|
||||
// UpdateSelection refresh selected row.
|
||||
func (s *SelectTable) updateSelection(broadcast bool) {
|
||||
s.SelectRow(s.selectedRow, broadcast)
|
||||
r, _ := s.GetSelection()
|
||||
s.SelectRow(r, broadcast)
|
||||
}
|
||||
|
||||
func (s *SelectTable) selectionChanged(r, c int) {
|
||||
if r < 0 {
|
||||
return
|
||||
}
|
||||
s.selectedRow = r
|
||||
cell := s.GetCell(r, c)
|
||||
s.SetSelectedStyle(tcell.ColorBlack, cell.Color, tcell.AttrBold)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,9 @@ type Table struct {
|
|||
func NewTable(gvr client.GVR) *Table {
|
||||
return &Table{
|
||||
SelectTable: &SelectTable{
|
||||
Table: tview.NewTable(),
|
||||
model: model.NewTable(gvr),
|
||||
selectedRow: 1,
|
||||
marks: make(map[string]struct{}),
|
||||
Table: tview.NewTable(),
|
||||
model: model.NewTable(gvr),
|
||||
marks: make(map[string]struct{}),
|
||||
},
|
||||
gvr: gvr,
|
||||
actions: make(KeyActions),
|
||||
|
|
@ -71,7 +70,7 @@ func (t *Table) Init(ctx context.Context) {
|
|||
t.SetSelectable(true, false)
|
||||
t.SetSelectionChangedFunc(t.selectionChanged)
|
||||
t.SetBackgroundColor(tcell.ColorDefault)
|
||||
|
||||
t.Select(1, 0)
|
||||
t.hasMetrics = false
|
||||
if mx, ok := ctx.Value(internal.KeyHasMetrics).(bool); ok {
|
||||
t.hasMetrics = mx
|
||||
|
|
|
|||
|
|
@ -159,10 +159,10 @@ func (h *Help) showNav() model.MenuHints {
|
|||
},
|
||||
{
|
||||
Mnemonic: "Ctrl-b",
|
||||
Description: "Page Down"},
|
||||
Description: "Page Up"},
|
||||
{
|
||||
Mnemonic: "Ctrl-f",
|
||||
Description: "Page Up",
|
||||
Description: "Page Down",
|
||||
},
|
||||
{
|
||||
Mnemonic: "h",
|
||||
|
|
|
|||
|
|
@ -80,25 +80,26 @@ func (p *Pulse) Init(ctx context.Context) error {
|
|||
}
|
||||
|
||||
p.charts = []Grapheable{
|
||||
p.makeGA(image.Point{X: 0, Y: 0}, image.Point{X: 4, Y: 2}, "apps/v1/deployments"),
|
||||
p.makeGA(image.Point{X: 0, Y: 2}, image.Point{X: 4, Y: 2}, "apps/v1/replicasets"),
|
||||
p.makeGA(image.Point{X: 0, Y: 4}, image.Point{X: 4, Y: 2}, "apps/v1/statefulsets"),
|
||||
p.makeGA(image.Point{X: 0, Y: 6}, image.Point{X: 4, Y: 2}, "apps/v1/daemonsets"),
|
||||
p.makeSP(image.Point{X: 4, Y: 0}, image.Point{X: 3, Y: 4}, "v1/pods"),
|
||||
p.makeSP(image.Point{X: 4, Y: 4}, image.Point{X: 3, Y: 4}, "v1/events"),
|
||||
p.makeSP(image.Point{X: 7, Y: 0}, image.Point{X: 3, Y: 4}, "batch/v1/jobs"),
|
||||
p.makeSP(image.Point{X: 7, Y: 4}, image.Point{X: 3, Y: 4}, "v1/persistentvolumes"),
|
||||
p.makeGA(image.Point{X: 0, Y: 0}, image.Point{X: 3, Y: 2}, "apps/v1/deployments"),
|
||||
p.makeGA(image.Point{X: 0, Y: 2}, image.Point{X: 3, Y: 2}, "apps/v1/replicasets"),
|
||||
p.makeGA(image.Point{X: 0, Y: 4}, image.Point{X: 3, Y: 2}, "apps/v1/statefulsets"),
|
||||
p.makeGA(image.Point{X: 0, Y: 6}, image.Point{X: 3, Y: 2}, "apps/v1/daemonsets"),
|
||||
p.makeSP(true, image.Point{X: 3, Y: 0}, image.Point{X: 3, Y: 4}, "v1/pods"),
|
||||
p.makeSP(true, image.Point{X: 3, Y: 4}, image.Point{X: 3, Y: 4}, "v1/events"),
|
||||
p.makeSP(true, image.Point{X: 6, Y: 0}, image.Point{X: 3, Y: 4}, "batch/v1/jobs"),
|
||||
p.makeSP(true, image.Point{X: 6, Y: 4}, image.Point{X: 3, Y: 4}, "v1/persistentvolumes"),
|
||||
}
|
||||
if p.app.Conn().HasMetrics() {
|
||||
p.charts = append(p.charts,
|
||||
p.makeSP(image.Point{X: 10, Y: 0}, image.Point{X: 2, Y: 4}, "cpu"),
|
||||
p.makeSP(image.Point{X: 10, Y: 4}, image.Point{X: 2, Y: 4}, "mem"),
|
||||
p.makeSP(false, image.Point{X: 9, Y: 0}, image.Point{X: 2, Y: 4}, "cpu"),
|
||||
p.makeSP(false, image.Point{X: 9, Y: 4}, image.Point{X: 2, Y: 4}, "mem"),
|
||||
)
|
||||
}
|
||||
p.bindKeys()
|
||||
p.model.AddListener(p)
|
||||
p.app.SetFocus(p.charts[0])
|
||||
p.app.Styles.AddListener(p)
|
||||
p.StylesChanged(p.app.Styles)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -135,9 +136,9 @@ func (p *Pulse) PulseChanged(c *health.Check) {
|
|||
gvr := client.NewGVR(c.GVR)
|
||||
switch c.GVR {
|
||||
case "cpu":
|
||||
v.SetLegend(fmt.Sprintf(" %s - %dm", strings.Title(gvr.R()), c.Tally(health.OK)))
|
||||
v.SetLegend(fmt.Sprintf(" %s(%dm)", strings.Title(gvr.R()), c.Tally(health.OK)))
|
||||
case "mem":
|
||||
v.SetLegend(fmt.Sprintf(" %s - %dMi", strings.Title(gvr.R()), c.Tally(health.OK)))
|
||||
v.SetLegend(fmt.Sprintf(" %s(%dMi)", strings.Title(gvr.R()), c.Tally(health.OK)))
|
||||
default:
|
||||
nn := v.GetSeriesColorNames()
|
||||
if c.Tally(health.OK) == 0 {
|
||||
|
|
@ -146,7 +147,7 @@ func (p *Pulse) PulseChanged(c *health.Check) {
|
|||
if c.Tally(health.Toast) == 0 {
|
||||
nn[1] = "gray"
|
||||
}
|
||||
v.SetLegend(fmt.Sprintf(" %s - [%s::]%d/[%s::b]%d[-::]",
|
||||
v.SetLegend(fmt.Sprintf(" %s([%s::]%d[white::]:[%s::b]%d[-::])",
|
||||
strings.Title(gvr.R()),
|
||||
nn[0],
|
||||
c.Tally(health.OK),
|
||||
|
|
@ -296,7 +297,7 @@ func (p *Pulse) nextFocusCmd(direction int) func(evt *tcell.EventKey) *tcell.Eve
|
|||
}
|
||||
}
|
||||
|
||||
func (p *Pulse) makeSP(loc image.Point, span image.Point, gvr string) *tchart.SparkLine {
|
||||
func (p *Pulse) makeSP(multi bool, loc image.Point, span image.Point, gvr string) *tchart.SparkLine {
|
||||
s := tchart.NewSparkLine(gvr)
|
||||
s.SetBackgroundColor(p.app.Styles.Charts().BgColor.Color())
|
||||
s.SetBorderPadding(0, 1, 0, 1)
|
||||
|
|
@ -307,6 +308,9 @@ func (p *Pulse) makeSP(loc image.Point, span image.Point, gvr string) *tchart.Sp
|
|||
}
|
||||
s.SetLegend(fmt.Sprintf(" %s ", strings.Title(client.NewGVR(gvr).R())))
|
||||
s.SetInputCapture(p.keyboard)
|
||||
if !multi {
|
||||
s.SetMultiSeries(multi)
|
||||
}
|
||||
p.AddItem(s, loc.X, loc.Y, span.X, span.Y, 0, 0, true)
|
||||
|
||||
return s
|
||||
|
|
@ -323,7 +327,7 @@ func (p *Pulse) makeGA(loc image.Point, span image.Point, gvr string) *tchart.Ga
|
|||
}
|
||||
g.SetLegend(fmt.Sprintf(" %s ", strings.Title(client.NewGVR(gvr).R())))
|
||||
g.SetInputCapture(p.keyboard)
|
||||
p.AddItem(g, loc.X, loc.Y, span.X, span.Y, 0, 0, true)
|
||||
p.AddItem(g, loc.X, loc.Y, span.X, span.Y, span.X, span.Y, true)
|
||||
|
||||
return g
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue