initial refactor of all column widgets to standard interface

This commit is contained in:
Bradley Cicenas 2019-06-08 21:34:43 +00:00
parent 9bcf2c2c7a
commit 8427b0c81d
9 changed files with 198 additions and 178 deletions

View File

@ -21,7 +21,7 @@ const (
type Container struct { type Container struct {
models.Metrics models.Metrics
Id string Id string
Meta map[string]string Meta models.Meta
Widgets *compact.Compact Widgets *compact.Compact
Display bool // display this container in compact view Display bool // display this container in compact view
updater cwidgets.WidgetUpdater updater cwidgets.WidgetUpdater
@ -34,7 +34,7 @@ func New(id string, collector collector.Collector, manager manager.Manager) *Con
return &Container{ return &Container{
Metrics: models.NewMetrics(), Metrics: models.NewMetrics(),
Id: id, Id: id,
Meta: make(map[string]string), Meta: models.NewMeta(),
Widgets: widgets, Widgets: widgets,
updater: widgets, updater: widgets,
collector: collector, collector: collector,
@ -44,21 +44,16 @@ func New(id string, collector collector.Collector, manager manager.Manager) *Con
func (c *Container) SetUpdater(u cwidgets.WidgetUpdater) { func (c *Container) SetUpdater(u cwidgets.WidgetUpdater) {
c.updater = u c.updater = u
for k, v := range c.Meta { c.updater.SetMeta(c.Meta)
c.updater.SetMeta(k, v)
}
} }
func (c *Container) SetMeta(k, v string) { func (c *Container) SetMeta(k, v string) {
c.Meta[k] = v c.Meta[k] = v
c.updater.SetMeta(k, v) c.updater.SetMeta(c.Meta)
} }
func (c *Container) GetMeta(k string) string { func (c *Container) GetMeta(k string) string {
if v, ok := c.Meta[k]; ok { return c.Meta.Get(k)
return v
}
return ""
} }
func (c *Container) SetState(s string) { func (c *Container) SetState(s string) {

View File

@ -1,21 +1,49 @@
package compact package compact
import ( import (
"fmt"
"github.com/bcicen/ctop/cwidgets"
"github.com/bcicen/ctop/models"
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
type CPUCol struct {
*GaugeCol
}
func (w *CPUCol) SetMetrics(m models.Metrics) {
val := m.CPUUtil
w.BarColor = colorScale(val)
w.Label = fmt.Sprintf("%d%%", val)
if val > 100 {
val = 100
}
w.Percent = val
}
type MemCol struct {
*GaugeCol
}
func (w *MemCol) SetMetrics(m models.Metrics) {
w.BarColor = ui.ThemeAttr("gauge.bar.bg")
w.Label = fmt.Sprintf("%s / %s", cwidgets.ByteFormat(m.MemUsage), cwidgets.ByteFormat(m.MemLimit))
w.Percent = m.MemPercent
}
type GaugeCol struct { type GaugeCol struct {
*ui.Gauge *ui.Gauge
} }
func NewGaugeCol() *GaugeCol { func NewGaugeCol() *GaugeCol {
g := ui.NewGauge() g := &GaugeCol{ui.NewGauge()}
g.Height = 1 g.Height = 1
g.Border = false g.Border = false
g.Percent = 0
g.PaddingBottom = 0 g.PaddingBottom = 0
g.Label = "-" g.Reset()
return &GaugeCol{g} return g
} }
func (w *GaugeCol) Reset() { func (w *GaugeCol) Reset() {
@ -23,11 +51,30 @@ func (w *GaugeCol) Reset() {
w.Percent = 0 w.Percent = 0
} }
func (w *GaugeCol) Buffer() ui.Buffer {
// if bar would not otherwise be visible, set a minimum
// percentage value and low-contrast color for structure
if w.Percent < 5 {
w.Percent = 5
w.BarColor = ui.ColorBlack
}
return w.Gauge.Buffer()
}
// GaugeCol implements CompactCol
func (w *GaugeCol) SetMeta(models.Meta) {}
// GaugeCol implements CompactCol
func (w *GaugeCol) SetMetrics(models.Metrics) {}
// GaugeCol implements CompactCol
func (w *GaugeCol) Highlight() { func (w *GaugeCol) Highlight() {
w.Bg = ui.ThemeAttr("par.text.fg") w.Bg = ui.ThemeAttr("par.text.fg")
w.PercentColor = ui.ThemeAttr("par.text.hi") w.PercentColor = ui.ThemeAttr("par.text.hi")
} }
// GaugeCol implements CompactCol
func (w *GaugeCol) UnHighlight() { func (w *GaugeCol) UnHighlight() {
w.Bg = ui.ThemeAttr("par.text.bg") w.Bg = ui.ThemeAttr("par.text.bg")
w.PercentColor = ui.ThemeAttr("par.text.bg") w.PercentColor = ui.ThemeAttr("par.text.bg")

View File

@ -9,16 +9,18 @@ import (
var log = logging.Init() var log = logging.Init()
type CompactCol interface {
ui.GridBufferer
Reset()
Highlight()
UnHighlight()
SetMeta(models.Meta)
SetMetrics(models.Metrics)
}
type Compact struct { type Compact struct {
Status *Status
Name *TextCol
Cid *TextCol
Cpu *GaugeCol
Mem *GaugeCol
Net *TextCol
IO *TextCol
Pids *TextCol
Bg *RowBg Bg *RowBg
Cols []CompactCol
X, Y int X, Y int
Width int Width int
Height int Height int
@ -30,64 +32,44 @@ func NewCompact(id string) *Compact {
id = id[:12] id = id[:12]
} }
row := &Compact{ row := &Compact{
Status: NewStatus(), Bg: NewRowBg(),
Name: NewTextCol("-"), Cols: []CompactCol{
Cid: NewTextCol(id), NewStatus(),
Cpu: NewGaugeCol(), &NameCol{NewTextCol("-")},
Mem: NewGaugeCol(), &CIDCol{NewTextCol(id)},
Net: NewTextCol("-"), &CPUCol{NewGaugeCol()},
IO: NewTextCol("-"), &MemCol{NewGaugeCol()},
Pids: NewTextCol("-"), &NetCol{NewTextCol("-")},
Bg: NewRowBg(), &IOCol{NewTextCol("-")},
&PIDCol{NewTextCol("-")},
},
X: 1, X: 1,
Height: 1, Height: 1,
} }
return row return row
} }
//func (row *Compact) ToggleExpand() { func (row *Compact) SetMeta(m models.Meta) {
//if row.Height == 1 { for _, w := range row.Cols {
//row.Height = 4 w.SetMeta(m)
//} else {
//row.Height = 1
//}
//}
func (row *Compact) SetMeta(k, v string) {
switch k {
case "name":
row.Name.Set(v)
case "state":
row.Status.Set(v)
case "health":
row.Status.SetHealth(v)
} }
} }
func (row *Compact) SetMetrics(m models.Metrics) { func (row *Compact) SetMetrics(m models.Metrics) {
row.SetCPU(m.CPUUtil) for _, w := range row.Cols {
row.SetNet(m.NetRx, m.NetTx) w.SetMetrics(m)
row.SetMem(m.MemUsage, m.MemLimit, m.MemPercent) }
row.SetIO(m.IOBytesRead, m.IOBytesWrite)
row.SetPids(m.Pids)
} }
// Set gauges, counters to default unread values // Set gauges, counters, etc. to default unread values
func (row *Compact) Reset() { func (row *Compact) Reset() {
row.Cpu.Reset() for _, w := range row.Cols {
row.Mem.Reset() w.Reset()
row.Net.Reset() }
row.IO.Reset()
row.Pids.Reset()
} }
func (row *Compact) GetHeight() int { func (row *Compact) GetHeight() int { return row.Height }
return row.Height func (row *Compact) SetX(x int) { row.X = x }
}
func (row *Compact) SetX(x int) {
row.X = x
}
func (row *Compact) SetY(y int) { func (row *Compact) SetY(y int) {
if y == row.Y { if y == row.Y {
@ -95,8 +77,8 @@ func (row *Compact) SetY(y int) {
} }
row.Bg.Y = y row.Bg.Y = y
for _, col := range row.all() { for _, w := range row.Cols {
col.SetY(y) w.SetY(y)
} }
row.Y = y row.Y = y
} }
@ -111,15 +93,17 @@ func (row *Compact) SetWidth(width int) {
row.Bg.SetWidth(width) row.Bg.SetWidth(width)
autoWidth := calcWidth(width) autoWidth := calcWidth(width)
for n, col := range row.all() { for n, w := range row.Cols {
// set static width, if provided
if colWidths[n] != 0 { if colWidths[n] != 0 {
col.SetX(x) w.SetX(x)
col.SetWidth(colWidths[n]) w.SetWidth(colWidths[n])
x += colWidths[n] x += colWidths[n]
continue continue
} }
col.SetX(x) // else use auto width
col.SetWidth(autoWidth) w.SetX(x)
w.SetWidth(autoWidth)
x += autoWidth + colSpacing x += autoWidth + colSpacing
} }
row.Width = width row.Width = width
@ -127,55 +111,28 @@ func (row *Compact) SetWidth(width int) {
func (row *Compact) Buffer() ui.Buffer { func (row *Compact) Buffer() ui.Buffer {
buf := ui.NewBuffer() buf := ui.NewBuffer()
buf.Merge(row.Bg.Buffer()) buf.Merge(row.Bg.Buffer())
buf.Merge(row.Status.Buffer()) for _, w := range row.Cols {
buf.Merge(row.Name.Buffer()) buf.Merge(w.Buffer())
buf.Merge(row.Cid.Buffer()) }
buf.Merge(row.Cpu.Buffer())
buf.Merge(row.Mem.Buffer())
buf.Merge(row.Net.Buffer())
buf.Merge(row.IO.Buffer())
buf.Merge(row.Pids.Buffer())
return buf return buf
} }
func (row *Compact) all() []ui.GridBufferer {
return []ui.GridBufferer{
row.Status,
row.Name,
row.Cid,
row.Cpu,
row.Mem,
row.Net,
row.IO,
row.Pids,
}
}
func (row *Compact) Highlight() { func (row *Compact) Highlight() {
row.Name.Highlight() row.Cols[1].Highlight()
if config.GetSwitchVal("fullRowCursor") { if config.GetSwitchVal("fullRowCursor") {
row.Bg.Highlight() for _, w := range row.Cols {
row.Cid.Highlight() w.Highlight()
row.Cpu.Highlight() }
row.Mem.Highlight()
row.Net.Highlight()
row.IO.Highlight()
row.Pids.Highlight()
} }
} }
func (row *Compact) UnHighlight() { func (row *Compact) UnHighlight() {
row.Name.UnHighlight() row.Cols[1].UnHighlight()
if config.GetSwitchVal("fullRowCursor") { if config.GetSwitchVal("fullRowCursor") {
row.Bg.UnHighlight() for _, w := range row.Cols {
row.Cid.UnHighlight() w.UnHighlight()
row.Cpu.UnHighlight() }
row.Mem.UnHighlight()
row.Net.UnHighlight()
row.IO.UnHighlight()
row.Pids.UnHighlight()
} }
} }

View File

@ -1,48 +0,0 @@
package compact
import (
"fmt"
"strconv"
"github.com/bcicen/ctop/cwidgets"
ui "github.com/gizak/termui"
)
func (row *Compact) SetNet(rx int64, tx int64) {
label := fmt.Sprintf("%s / %s", cwidgets.ByteFormat(rx), cwidgets.ByteFormat(tx))
row.Net.Set(label)
}
func (row *Compact) SetIO(read int64, write int64) {
label := fmt.Sprintf("%s / %s", cwidgets.ByteFormat(read), cwidgets.ByteFormat(write))
row.IO.Set(label)
}
func (row *Compact) SetPids(val int) {
label := strconv.Itoa(val)
row.Pids.Set(label)
}
func (row *Compact) SetCPU(val int) {
row.Cpu.BarColor = colorScale(val)
row.Cpu.Label = fmt.Sprintf("%s%%", strconv.Itoa(val))
if val < 5 {
val = 5
row.Cpu.BarColor = ui.ThemeAttr("gauge.bar.bg")
}
if val > 100 {
val = 100
}
row.Cpu.Percent = val
}
func (row *Compact) SetMem(val int64, limit int64, percent int) {
row.Mem.Label = fmt.Sprintf("%s / %s", cwidgets.ByteFormat(val), cwidgets.ByteFormat(limit))
if percent < 5 {
percent = 5
row.Mem.BarColor = ui.ColorBlack
} else {
row.Mem.BarColor = ui.ThemeAttr("gauge.bar.bg")
}
row.Mem.Percent = percent
}

View File

@ -1,6 +1,7 @@
package compact package compact
import ( import (
"github.com/bcicen/ctop/models"
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
@ -24,7 +25,7 @@ func NewStatus() *Status {
} }
s.Height = 1 s.Height = 1
s.Border = false s.Border = false
s.Set("") s.setState("")
return s return s
} }
@ -43,7 +44,18 @@ func (s *Status) Buffer() ui.Buffer {
return buf return buf
} }
func (s *Status) Set(val string) { func (s *Status) SetMeta(m models.Meta) {
s.setState(m.Get("state"))
s.setHealth(m.Get("health"))
}
// Status implements CompactCol
func (s *Status) Reset() {}
func (s *Status) SetMetrics(models.Metrics) {}
func (s *Status) Highlight() {}
func (s *Status) UnHighlight() {}
func (s *Status) setState(val string) {
// defaults // defaults
text := mark text := mark
color := ui.ColorDefault color := ui.ColorDefault
@ -60,21 +72,21 @@ func (s *Status) Set(val string) {
s.status = ui.TextCells(text, color, ui.ColorDefault) s.status = ui.TextCells(text, color, ui.ColorDefault)
} }
func (s *Status) SetHealth(val string) { func (s *Status) setHealth(val string) {
if val == "" {
return
}
color := ui.ColorDefault color := ui.ColorDefault
mark := healthMark mark := healthMark
switch val { switch val {
case "":
return
case "healthy": case "healthy":
color = ui.ThemeAttr("status.ok") color = ui.ThemeAttr("status.ok")
case "unhealthy": case "unhealthy":
color = ui.ThemeAttr("status.danger") color = ui.ThemeAttr("status.danger")
case "starting": case "starting":
color = ui.ThemeAttr("status.warn") color = ui.ThemeAttr("status.warn")
default:
log.Warningf("unknown health state string: \"%v\"", val)
} }
s.health = ui.TextCells(mark, color, ui.ColorDefault) s.health = ui.TextCells(mark, color, ui.ColorDefault)

View File

@ -1,9 +1,56 @@
package compact package compact
import ( import (
"fmt"
"github.com/bcicen/ctop/cwidgets"
"github.com/bcicen/ctop/models"
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
type NameCol struct {
*TextCol
}
func (w *NameCol) SetMeta(m models.Meta) {
if s, ok := m["name"]; ok {
w.Text = s
}
}
func (w *NameCol) SetMetrics(m models.Metrics) {
}
type CIDCol struct {
*TextCol
}
type NetCol struct {
*TextCol
}
func (w *NetCol) SetMetrics(m models.Metrics) {
label := fmt.Sprintf("%s / %s", cwidgets.ByteFormat(m.NetRx), cwidgets.ByteFormat(m.NetTx))
w.Text = label
}
type IOCol struct {
*TextCol
}
func (w *IOCol) SetMetrics(m models.Metrics) {
label := fmt.Sprintf("%s / %s", cwidgets.ByteFormat(m.IOBytesRead), cwidgets.ByteFormat(m.IOBytesWrite))
w.Text = label
}
type PIDCol struct {
*TextCol
}
func (w *PIDCol) SetMetrics(m models.Metrics) {
w.Text = fmt.Sprintf("%d", m.Pids)
}
type TextCol struct { type TextCol struct {
*ui.Par *ui.Par
} }
@ -28,10 +75,7 @@ func (w *TextCol) UnHighlight() {
w.TextBgColor = ui.ThemeAttr("par.text.bg") w.TextBgColor = ui.ThemeAttr("par.text.bg")
} }
func (w *TextCol) Reset() { //func (w *TextCol) Set(s string) { w.Text = s }
w.Text = "-" func (w *TextCol) Reset() { w.Text = "-" }
} func (w *TextCol) SetMeta(models.Meta) {}
func (w *TextCol) SetMetrics(models.Metrics) {}
func (w *TextCol) Set(s string) {
w.Text = s
}

View File

@ -8,6 +8,6 @@ import (
var log = logging.Init() var log = logging.Init()
type WidgetUpdater interface { type WidgetUpdater interface {
SetMeta(string, string) SetMeta(models.Meta)
SetMetrics(models.Metrics) SetMetrics(models.Metrics)
} }

View File

@ -55,11 +55,13 @@ func (e *Single) Down() {
} }
func (e *Single) SetWidth(w int) { e.Width = w } func (e *Single) SetWidth(w int) { e.Width = w }
func (e *Single) SetMeta(k, v string) { func (e *Single) SetMeta(m models.Meta) {
if k == "[ENV-VAR]" { for k, v := range m {
e.Env.Set(k, v) if k == "[ENV-VAR]" {
} else { e.Env.Set(k, v)
e.Info.Set(k, v) } else {
e.Info.Set(k, v)
}
} }
} }

View File

@ -7,6 +7,17 @@ type Log struct {
Message string Message string
} }
type Meta map[string]string
func NewMeta() Meta { return make(Meta) }
func (m Meta) Get(k string) string {
if s, ok := m[k]; ok {
return s
}
return ""
}
type Metrics struct { type Metrics struct {
CPUUtil int CPUUtil int
NetTx int64 NetTx int64