added gauge component type
This commit is contained in:
parent
a40cc50f3f
commit
7b22a083a4
|
@ -1,7 +1,7 @@
|
||||||
package asciibox
|
package asciibox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
fl "github.com/sqshq/figlet4go"
|
fl "github.com/mbndr/figlet4go"
|
||||||
"github.com/sqshq/sampler/asset"
|
"github.com/sqshq/sampler/asset"
|
||||||
"github.com/sqshq/sampler/data"
|
"github.com/sqshq/sampler/data"
|
||||||
ui "github.com/sqshq/termui"
|
ui "github.com/sqshq/termui"
|
||||||
|
@ -24,6 +24,8 @@ const (
|
||||||
AsciiFont3D AsciiFont = "3d"
|
AsciiFont3D AsciiFont = "3d"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const asciiFontExtension = ".flf"
|
||||||
|
|
||||||
func NewAsciiBox(title string, font AsciiFont, color ui.Color) *AsciiBox {
|
func NewAsciiBox(title string, font AsciiFont, color ui.Color) *AsciiBox {
|
||||||
|
|
||||||
block := *ui.NewBlock()
|
block := *ui.NewBlock()
|
||||||
|
@ -32,7 +34,7 @@ func NewAsciiBox(title string, font AsciiFont, color ui.Color) *AsciiBox {
|
||||||
options := fl.NewRenderOptions()
|
options := fl.NewRenderOptions()
|
||||||
options.FontName = string(font)
|
options.FontName = string(font)
|
||||||
|
|
||||||
fontStr, err := asset.Asset(options.FontName + ".flf")
|
fontStr, err := asset.Asset(options.FontName + asciiFontExtension)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("Can't load the font: " + err.Error())
|
panic("Can't load the font: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
barSymbol rune = '⠿'
|
|
||||||
barIndent int = 1
|
barIndent int = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -106,7 +105,7 @@ func (b *BarChart) Draw(buf *ui.Buffer) {
|
||||||
maxYCoordinate := b.Inner.Max.Y - height
|
maxYCoordinate := b.Inner.Max.Y - height
|
||||||
for x := barXCoordinate; x < ui.MinInt(barXCoordinate+barWidth, b.Inner.Max.X-barIndent); x++ {
|
for x := barXCoordinate; x < ui.MinInt(barXCoordinate+barWidth, b.Inner.Max.X-barIndent); x++ {
|
||||||
for y := b.Inner.Max.Y - 2; y >= maxYCoordinate; y-- {
|
for y := b.Inner.Max.Y - 2; y >= maxYCoordinate; y-- {
|
||||||
c := ui.NewCell(barSymbol, ui.NewStyle(bar.color))
|
c := ui.NewCell(console.SymbolShade, ui.NewStyle(bar.color))
|
||||||
buf.SetCell(c, image.Pt(x, y))
|
buf.SetCell(c, image.Pt(x, y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@ import (
|
||||||
ui "github.com/sqshq/termui"
|
ui "github.com/sqshq/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
minDimension = 3
|
||||||
|
)
|
||||||
|
|
||||||
type Component struct {
|
type Component struct {
|
||||||
Type config.ComponentType
|
Type config.ComponentType
|
||||||
Drawable ui.Drawable
|
Drawable ui.Drawable
|
||||||
|
@ -27,11 +31,11 @@ func (c *Component) Resize(x, y int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Component) normalize() {
|
func (c *Component) normalize() {
|
||||||
if c.Size.X < 0 {
|
if c.Size.X < minDimension {
|
||||||
c.Size.X = 0
|
c.Size.X = minDimension
|
||||||
}
|
}
|
||||||
if c.Size.Y < 0 {
|
if c.Size.Y < minDimension {
|
||||||
c.Size.Y = 0
|
c.Size.Y = minDimension
|
||||||
}
|
}
|
||||||
if c.Position.X < 0 {
|
if c.Position.X < 0 {
|
||||||
c.Position.X = 0
|
c.Position.X = 0
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
package gauge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/sqshq/sampler/console"
|
||||||
|
"github.com/sqshq/sampler/data"
|
||||||
|
ui "github.com/sqshq/termui"
|
||||||
|
"image"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MinValueLabel = "min"
|
||||||
|
MaxValueLabel = "max"
|
||||||
|
CurValueLabel = "cur"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Gauge struct {
|
||||||
|
ui.Block
|
||||||
|
minValue float64
|
||||||
|
maxValue float64
|
||||||
|
curValue float64
|
||||||
|
scale int
|
||||||
|
color ui.Color
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGauge(title string, scale int, color ui.Color) *Gauge {
|
||||||
|
block := *ui.NewBlock()
|
||||||
|
block.Title = title
|
||||||
|
return &Gauge{
|
||||||
|
Block: block,
|
||||||
|
scale: scale,
|
||||||
|
color: color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Gauge) ConsumeSample(sample data.Sample) {
|
||||||
|
|
||||||
|
float, err := strconv.ParseFloat(sample.Value, 64)
|
||||||
|
if err != nil {
|
||||||
|
// TODO visual notification + check sample.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sample.Label {
|
||||||
|
case MinValueLabel:
|
||||||
|
g.minValue = float
|
||||||
|
break
|
||||||
|
case MaxValueLabel:
|
||||||
|
g.maxValue = float
|
||||||
|
break
|
||||||
|
case CurValueLabel:
|
||||||
|
g.curValue = float
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Gauge) Draw(buf *ui.Buffer) {
|
||||||
|
|
||||||
|
g.Block.Draw(buf)
|
||||||
|
|
||||||
|
percent := 0.0
|
||||||
|
if g.curValue != 0 {
|
||||||
|
percent = (100 * g.curValue) / (g.maxValue - g.minValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
label := fmt.Sprintf("%v%% (%v)", formatValue(percent, g.scale), g.curValue)
|
||||||
|
|
||||||
|
// plot bar
|
||||||
|
barWidth := int((percent / 100) * float64(g.Inner.Dx()))
|
||||||
|
if barWidth == 0 {
|
||||||
|
barWidth = 1
|
||||||
|
} else if barWidth > g.Dx()-2 {
|
||||||
|
barWidth = g.Dx() - 2
|
||||||
|
}
|
||||||
|
buf.Fill(
|
||||||
|
ui.NewCell(console.SymbolVerticalBar, ui.NewStyle(g.color)),
|
||||||
|
image.Rect(g.Inner.Min.X+1, g.Inner.Min.Y, g.Inner.Min.X+barWidth, g.Inner.Max.Y),
|
||||||
|
)
|
||||||
|
|
||||||
|
// plot label
|
||||||
|
labelXCoordinate := g.Inner.Min.X + (g.Inner.Dx() / 2) - int(float64(len(label))/2)
|
||||||
|
labelYCoordinate := g.Inner.Min.Y + ((g.Inner.Dy() - 1) / 2)
|
||||||
|
if labelYCoordinate < g.Inner.Max.Y {
|
||||||
|
for i, char := range label {
|
||||||
|
style := ui.NewStyle(console.ColorWhite)
|
||||||
|
if labelXCoordinate+i+1 <= g.Inner.Min.X+barWidth {
|
||||||
|
style = ui.NewStyle(console.ColorWhite, ui.ColorClear)
|
||||||
|
}
|
||||||
|
buf.SetCell(ui.NewCell(char, style), image.Pt(labelXCoordinate+i, labelYCoordinate))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO extract to utils
|
||||||
|
func formatValue(value float64, scale int) string {
|
||||||
|
if math.Abs(value) == math.MaxFloat64 {
|
||||||
|
return "Inf"
|
||||||
|
} else {
|
||||||
|
format := "%." + strconv.Itoa(scale) + "f"
|
||||||
|
return fmt.Sprintf(format, value)
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,8 +29,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
columnsCount = 60
|
columnsCount = 80
|
||||||
rowsCount = 40
|
rowsCount = 60
|
||||||
statusbarHeight = 1
|
statusbarHeight = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,10 @@ const (
|
||||||
MenuOptionResume MenuOption = "RESUME"
|
MenuOptionResume MenuOption = "RESUME"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
minimalMenuHeight = 8
|
||||||
|
)
|
||||||
|
|
||||||
func NewMenu() *Menu {
|
func NewMenu() *Menu {
|
||||||
block := *ui.NewBlock()
|
block := *ui.NewBlock()
|
||||||
block.Border = true
|
block.Border = true
|
||||||
|
@ -99,7 +103,12 @@ func (m *Menu) Draw(buffer *ui.Buffer) {
|
||||||
|
|
||||||
m.updateDimensions()
|
m.updateDimensions()
|
||||||
buffer.Fill(ui.NewCell(' ', ui.NewStyle(ui.ColorBlack)), m.GetRect())
|
buffer.Fill(ui.NewCell(' ', ui.NewStyle(ui.ColorBlack)), m.GetRect())
|
||||||
|
|
||||||
|
if m.Dy() > minimalMenuHeight {
|
||||||
m.drawInnerBorder(buffer)
|
m.drawInnerBorder(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Block.Draw(buffer)
|
||||||
|
|
||||||
switch m.mode {
|
switch m.mode {
|
||||||
case MenuModeHighlight:
|
case MenuModeHighlight:
|
||||||
|
@ -109,15 +118,25 @@ func (m *Menu) Draw(buffer *ui.Buffer) {
|
||||||
case MenuModeOptionSelect:
|
case MenuModeOptionSelect:
|
||||||
m.renderOptions(buffer)
|
m.renderOptions(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Block.Draw(buffer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Menu) renderHighlight(buffer *ui.Buffer) {
|
func (m *Menu) renderHighlight(buffer *ui.Buffer) {
|
||||||
|
|
||||||
|
arrowsText := "Use arrows for selection"
|
||||||
|
optionsText := "<ENTER> to view options"
|
||||||
|
resumeText := "<ESC> to resume"
|
||||||
|
|
||||||
|
if m.Dy() <= minimalMenuHeight {
|
||||||
|
buffer.SetString(
|
||||||
|
optionsText,
|
||||||
|
ui.NewStyle(console.ColorDarkGrey),
|
||||||
|
getMiddlePoint(m.Block, optionsText, -1),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
m.printAllDirectionsArrowSign(buffer, -2)
|
m.printAllDirectionsArrowSign(buffer, -2)
|
||||||
|
|
||||||
arrowsText := "Use arrows for selection"
|
|
||||||
arrowsTextPoint := getMiddlePoint(m.Block, arrowsText, 2)
|
arrowsTextPoint := getMiddlePoint(m.Block, arrowsText, 2)
|
||||||
if arrowsTextPoint.Y+1 < m.Inner.Max.Y {
|
if arrowsTextPoint.Y+1 < m.Inner.Max.Y {
|
||||||
buffer.SetString(
|
buffer.SetString(
|
||||||
|
@ -127,7 +146,6 @@ func (m *Menu) renderHighlight(buffer *ui.Buffer) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
optionsText := "<ENTER> to view options"
|
|
||||||
optionsTextPoint := getMiddlePoint(m.Block, optionsText, 3)
|
optionsTextPoint := getMiddlePoint(m.Block, optionsText, 3)
|
||||||
if optionsTextPoint.Y+1 < m.Inner.Max.Y {
|
if optionsTextPoint.Y+1 < m.Inner.Max.Y {
|
||||||
buffer.SetString(
|
buffer.SetString(
|
||||||
|
@ -137,7 +155,6 @@ func (m *Menu) renderHighlight(buffer *ui.Buffer) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
resumeText := "<ESC> to resume"
|
|
||||||
resumeTextPoint := getMiddlePoint(m.Block, resumeText, 4)
|
resumeTextPoint := getMiddlePoint(m.Block, resumeText, 4)
|
||||||
if resumeTextPoint.Y+1 < m.Inner.Max.Y {
|
if resumeTextPoint.Y+1 < m.Inner.Max.Y {
|
||||||
buffer.SetString(
|
buffer.SetString(
|
||||||
|
@ -150,17 +167,15 @@ func (m *Menu) renderHighlight(buffer *ui.Buffer) {
|
||||||
|
|
||||||
func (m *Menu) renderMoveAndResize(buffer *ui.Buffer) {
|
func (m *Menu) renderMoveAndResize(buffer *ui.Buffer) {
|
||||||
|
|
||||||
m.printAllDirectionsArrowSign(buffer, -2)
|
|
||||||
|
|
||||||
saveText := "<ENTER> to save changes"
|
saveText := "<ENTER> to save changes"
|
||||||
saveTextPoint := getMiddlePoint(m.Block, saveText, 4)
|
|
||||||
if saveTextPoint.In(m.Rectangle) {
|
if m.Dy() <= minimalMenuHeight {
|
||||||
buffer.SetString(
|
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), getMiddlePoint(m.Block, saveText, -1))
|
||||||
saveText,
|
return
|
||||||
ui.NewStyle(console.ColorDarkGrey),
|
|
||||||
saveTextPoint,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.printAllDirectionsArrowSign(buffer, -1)
|
||||||
|
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), getMiddlePoint(m.Block, saveText, 3))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
|
func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
|
||||||
|
@ -184,7 +199,7 @@ func (m *Menu) renderOptions(buffer *ui.Buffer) {
|
||||||
|
|
||||||
// TODO extract styles to console.Palette
|
// TODO extract styles to console.Palette
|
||||||
highlightedStyle := ui.NewStyle(console.ColorOlive, console.ColorBlack, ui.ModifierReverse)
|
highlightedStyle := ui.NewStyle(console.ColorOlive, console.ColorBlack, ui.ModifierReverse)
|
||||||
regularStyle := ui.NewStyle(console.ColorWhite)
|
regularStyle := ui.NewStyle(console.ColorWhite, console.ColorBlack)
|
||||||
|
|
||||||
offset := 1
|
offset := 1
|
||||||
for _, option := range m.options {
|
for _, option := range m.options {
|
||||||
|
@ -197,9 +212,10 @@ func (m *Menu) renderOptions(buffer *ui.Buffer) {
|
||||||
if option != MenuOptionPinpoint || m.component.Type == config.TypeRunChart {
|
if option != MenuOptionPinpoint || m.component.Type == config.TypeRunChart {
|
||||||
offset += 2
|
offset += 2
|
||||||
point := getMiddlePoint(m.Block, string(option), offset-5)
|
point := getMiddlePoint(m.Block, string(option), offset-5)
|
||||||
if point.In(m.GetRect()) {
|
|
||||||
buffer.SetString(string(option), style, point)
|
buffer.SetString(string(option), style, point)
|
||||||
}
|
//if point.In(m.GetRect()) {
|
||||||
|
// buffer.SetString(string(option), style, point)
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
45
config.yml
45
config.yml
|
@ -9,11 +9,11 @@ runcharts:
|
||||||
scale: 3
|
scale: 3
|
||||||
items:
|
items:
|
||||||
- label: GOOGLE
|
- label: GOOGLE
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' https://www.google.com
|
value: curl -o /dev/null -s -w '%{time_total}' https://www.google.com
|
||||||
- label: YAHOO
|
- label: YAHOO
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' https://search.yahoo.com
|
value: curl -o /dev/null -s -w '%{time_total}' https://search.yahoo.com
|
||||||
- label: BING
|
- label: BING
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' https://www.bing.com
|
value: curl -o /dev/null -s -w '%{time_total}' https://www.bing.com
|
||||||
- title: SEARCH ENGINE RESPONSE TIME 2 (sec)
|
- title: SEARCH ENGINE RESPONSE TIME 2 (sec)
|
||||||
refresh-rate-ms: 5000
|
refresh-rate-ms: 5000
|
||||||
position:
|
position:
|
||||||
|
@ -27,11 +27,11 @@ runcharts:
|
||||||
details: false
|
details: false
|
||||||
items:
|
items:
|
||||||
- label: GOOGLE
|
- label: GOOGLE
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' https://www.google.com
|
value: curl -o /dev/null -s -w '%{time_total}' https://www.google.com
|
||||||
- label: YAHOO
|
- label: YAHOO
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' https://search.yahoo.com
|
value: curl -o /dev/null -s -w '%{time_total}' https://search.yahoo.com
|
||||||
- label: BING
|
- label: BING
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' https://www.bing.com
|
value: curl -o /dev/null -s -w '%{time_total}' https://www.bing.com
|
||||||
- title: MONGO COLLECTIONS COUNT
|
- title: MONGO COLLECTIONS COUNT
|
||||||
position:
|
position:
|
||||||
w: 21
|
w: 21
|
||||||
|
@ -42,9 +42,9 @@ runcharts:
|
||||||
scale: 0
|
scale: 0
|
||||||
items:
|
items:
|
||||||
- label: ACTIVE
|
- label: ACTIVE
|
||||||
script: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'ACTIVE'}).itcount()"
|
value: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'ACTIVE'}).itcount()"
|
||||||
- label: INACTIVE
|
- label: INACTIVE
|
||||||
script: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'INACTIVE'}).itcount()"
|
value: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'INACTIVE'}).itcount()"
|
||||||
barcharts:
|
barcharts:
|
||||||
- title: EVENTS BY STATUS
|
- title: EVENTS BY STATUS
|
||||||
refresh-rate-ms: 1000
|
refresh-rate-ms: 1000
|
||||||
|
@ -57,15 +57,28 @@ barcharts:
|
||||||
scale: 0
|
scale: 0
|
||||||
items:
|
items:
|
||||||
- label: NEW
|
- label: NEW
|
||||||
script: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'ACTIVE'}).itcount()"
|
value: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'ACTIVE'}).itcount()"
|
||||||
- label: TRIGGERED
|
- label: TRIGGERED
|
||||||
script: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'INACTIVE'}).itcount()"
|
value: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'INACTIVE'}).itcount()"
|
||||||
- label: IN_PROCESS
|
- label: IN_PROCESS
|
||||||
script: echo 0
|
value: echo 0
|
||||||
- label: FINISHED
|
|
||||||
script: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'ACTIVE'}).itcount()"
|
|
||||||
- label: FAILED
|
- label: FAILED
|
||||||
script: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'INACTIVE'}).itcount()"
|
value: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'ACTIVE'}).itcount()"
|
||||||
|
- label: FINISHED
|
||||||
|
value: mongo --quiet --host=localhost blog --eval "db.getCollection('posts').find({status:'INACTIVE'}).itcount()"
|
||||||
|
gauges:
|
||||||
|
- title: YEAR PROGRESS
|
||||||
|
position:
|
||||||
|
w: 21
|
||||||
|
h: 33
|
||||||
|
size:
|
||||||
|
w: 20
|
||||||
|
h: 3
|
||||||
|
values:
|
||||||
|
cur: echo 245
|
||||||
|
max: echo 365
|
||||||
|
min: echo 0
|
||||||
|
items: []
|
||||||
asciiboxes:
|
asciiboxes:
|
||||||
- title: LOCAL TIME
|
- title: LOCAL TIME
|
||||||
position:
|
position:
|
||||||
|
@ -74,7 +87,7 @@ asciiboxes:
|
||||||
size:
|
size:
|
||||||
w: 20
|
w: 20
|
||||||
h: 6
|
h: 6
|
||||||
script: date +%r
|
value: date +%r
|
||||||
- title: UTC TIME
|
- title: UTC TIME
|
||||||
position:
|
position:
|
||||||
w: 40
|
w: 40
|
||||||
|
@ -82,5 +95,5 @@ asciiboxes:
|
||||||
size:
|
size:
|
||||||
w: 20
|
w: 20
|
||||||
h: 7
|
h: 7
|
||||||
script: env TZ=UTC date +%r
|
value: env TZ=UTC date +%r
|
||||||
font: 3d
|
font: 3d
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sqshq/sampler/component/asciibox"
|
||||||
|
"github.com/sqshq/sampler/data"
|
||||||
|
ui "github.com/sqshq/termui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ComponentConfig struct {
|
||||||
|
Title string `yaml:"title"`
|
||||||
|
RefreshRateMs *int `yaml:"refresh-rate-ms,omitempty"`
|
||||||
|
Position Position `yaml:"position"`
|
||||||
|
Size Size `yaml:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GaugeConfig struct {
|
||||||
|
ComponentConfig `yaml:",inline"`
|
||||||
|
Scale *int `yaml:"scale,omitempty"`
|
||||||
|
Color *ui.Color `yaml:"color,omitempty"`
|
||||||
|
Values map[string]string `yaml:"values"`
|
||||||
|
Items []data.Item
|
||||||
|
}
|
||||||
|
|
||||||
|
type BarChartConfig struct {
|
||||||
|
ComponentConfig `yaml:",inline"`
|
||||||
|
Scale *int `yaml:"scale,omitempty"`
|
||||||
|
Items []data.Item `yaml:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AsciiBoxConfig struct {
|
||||||
|
ComponentConfig `yaml:",inline"`
|
||||||
|
data.Item `yaml:",inline"`
|
||||||
|
Font *asciibox.AsciiFont `yaml:"font,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunChartConfig struct {
|
||||||
|
ComponentConfig `yaml:",inline"`
|
||||||
|
Legend *LegendConfig `yaml:"legend,omitempty"`
|
||||||
|
Scale *int `yaml:"scale,omitempty"`
|
||||||
|
Items []data.Item `yaml:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LegendConfig struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Details bool `yaml:"details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Position struct {
|
||||||
|
X int `yaml:"w"`
|
||||||
|
Y int `yaml:"h"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Size struct {
|
||||||
|
X int `yaml:"w"`
|
||||||
|
Y int `yaml:"h"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ComponentType rune
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeRunChart ComponentType = 0
|
||||||
|
TypeBarChart ComponentType = 1
|
||||||
|
TypeTextBox ComponentType = 2
|
||||||
|
TypeAsciiBox ComponentType = 3
|
||||||
|
TypeGauge ComponentType = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
type ComponentSettings struct {
|
||||||
|
Type ComponentType
|
||||||
|
Title string
|
||||||
|
Size Size
|
||||||
|
Position Position
|
||||||
|
}
|
|
@ -2,9 +2,7 @@ package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/sqshq/sampler/component/asciibox"
|
|
||||||
"github.com/sqshq/sampler/console"
|
"github.com/sqshq/sampler/console"
|
||||||
"github.com/sqshq/sampler/data"
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
@ -15,6 +13,7 @@ type Config struct {
|
||||||
Theme *console.Theme `yaml:"theme,omitempty"`
|
Theme *console.Theme `yaml:"theme,omitempty"`
|
||||||
RunCharts []RunChartConfig `yaml:"runcharts,omitempty"`
|
RunCharts []RunChartConfig `yaml:"runcharts,omitempty"`
|
||||||
BarCharts []BarChartConfig `yaml:"barcharts,omitempty"`
|
BarCharts []BarChartConfig `yaml:"barcharts,omitempty"`
|
||||||
|
Gauges []GaugeConfig `yaml:"gauges,omitempty"`
|
||||||
AsciiBoxes []AsciiBoxConfig `yaml:"asciiboxes,omitempty"`
|
AsciiBoxes []AsciiBoxConfig `yaml:"asciiboxes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,63 +22,6 @@ type Flags struct {
|
||||||
Variables map[string]string
|
Variables map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ComponentConfig struct {
|
|
||||||
Title string `yaml:"title"`
|
|
||||||
RefreshRateMs *int `yaml:"refresh-rate-ms,omitempty"`
|
|
||||||
Position Position `yaml:"position"`
|
|
||||||
Size Size `yaml:"size"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RunChartConfig struct {
|
|
||||||
ComponentConfig `yaml:",inline"`
|
|
||||||
Legend *LegendConfig `yaml:"legend,omitempty"`
|
|
||||||
Scale *int `yaml:"scale,omitempty"`
|
|
||||||
Items []data.Item `yaml:"items"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BarChartConfig struct {
|
|
||||||
ComponentConfig `yaml:",inline"`
|
|
||||||
Scale *int `yaml:"scale,omitempty"`
|
|
||||||
Items []data.Item `yaml:"items"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AsciiBoxConfig struct {
|
|
||||||
ComponentConfig `yaml:",inline"`
|
|
||||||
data.Item `yaml:",inline"`
|
|
||||||
Font *asciibox.AsciiFont `yaml:"font,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LegendConfig struct {
|
|
||||||
Enabled bool `yaml:"enabled"`
|
|
||||||
Details bool `yaml:"details"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Position struct {
|
|
||||||
X int `yaml:"w"`
|
|
||||||
Y int `yaml:"h"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Size struct {
|
|
||||||
X int `yaml:"w"`
|
|
||||||
Y int `yaml:"h"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ComponentType rune
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeRunChart ComponentType = 0
|
|
||||||
TypeBarChart ComponentType = 1
|
|
||||||
TypeTextBox ComponentType = 2
|
|
||||||
TypeAsciiBox ComponentType = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
type ComponentSettings struct {
|
|
||||||
Type ComponentType
|
|
||||||
Title string
|
|
||||||
Size Size
|
|
||||||
Position Position
|
|
||||||
}
|
|
||||||
|
|
||||||
func Load() (Config, Flags) {
|
func Load() (Config, Flags) {
|
||||||
|
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
|
@ -121,6 +63,12 @@ func (c *Config) findComponent(componentType ComponentType, componentTitle strin
|
||||||
return &c.BarCharts[i].ComponentConfig
|
return &c.BarCharts[i].ComponentConfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case TypeGauge:
|
||||||
|
for i, component := range c.Gauges {
|
||||||
|
if component.Title == componentTitle {
|
||||||
|
return &c.Gauges[i].ComponentConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
case TypeAsciiBox:
|
case TypeAsciiBox:
|
||||||
for i, component := range c.AsciiBoxes {
|
for i, component := range c.AsciiBoxes {
|
||||||
if component.Title == componentTitle {
|
if component.Title == componentTitle {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package config
|
||||||
import (
|
import (
|
||||||
"github.com/sqshq/sampler/component/asciibox"
|
"github.com/sqshq/sampler/component/asciibox"
|
||||||
"github.com/sqshq/sampler/console"
|
"github.com/sqshq/sampler/console"
|
||||||
|
"github.com/sqshq/sampler/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -52,6 +53,24 @@ func (c *Config) setDefaultValues() {
|
||||||
c.BarCharts[i] = chart
|
c.BarCharts[i] = chart
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i, g := range c.Gauges {
|
||||||
|
if g.RefreshRateMs == nil {
|
||||||
|
r := defaultRefreshRateMs
|
||||||
|
g.RefreshRateMs = &r
|
||||||
|
}
|
||||||
|
if g.Scale == nil {
|
||||||
|
p := defaultScale
|
||||||
|
g.Scale = &p
|
||||||
|
}
|
||||||
|
var items []data.Item
|
||||||
|
for label, script := range g.Values {
|
||||||
|
l := label
|
||||||
|
items = append(items, data.Item{Label: &l, Script: script})
|
||||||
|
}
|
||||||
|
g.Items = items
|
||||||
|
c.Gauges[i] = g
|
||||||
|
}
|
||||||
|
|
||||||
for i, box := range c.AsciiBoxes {
|
for i, box := range c.AsciiBoxes {
|
||||||
if box.RefreshRateMs == nil {
|
if box.RefreshRateMs == nil {
|
||||||
r := defaultRefreshRateMs
|
r := defaultRefreshRateMs
|
||||||
|
@ -99,4 +118,11 @@ func (c *Config) setDefaultColors() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i, g := range c.Gauges {
|
||||||
|
if g.Color == nil {
|
||||||
|
g.Color = &palette.Colors[i%colorsCount]
|
||||||
|
c.Gauges[i] = g
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MenuColorBackground ui.Color = 236
|
MenuColorBackground ui.Color = 234
|
||||||
MenuColorText ui.Color = 255
|
MenuColorText ui.Color = 255
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,4 +2,6 @@ package console
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SymbolSelection rune = '▲'
|
SymbolSelection rune = '▲'
|
||||||
|
SymbolVerticalBar rune = '⢸'
|
||||||
|
SymbolShade rune = '⣿'
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
type Item struct {
|
type Item struct {
|
||||||
Label *string `yaml:"label,omitempty"`
|
Label *string `yaml:"label,omitempty"`
|
||||||
Script string `yaml:"script"`
|
Script string `yaml:"value"`
|
||||||
Color *ui.Color `yaml:"color,omitempty"`
|
Color *ui.Color `yaml:"color,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -4,8 +4,8 @@ require (
|
||||||
github.com/hajimehoshi/go-mp3 v0.1.1
|
github.com/hajimehoshi/go-mp3 v0.1.1
|
||||||
github.com/hajimehoshi/oto v0.1.1
|
github.com/hajimehoshi/oto v0.1.1
|
||||||
github.com/mattn/go-runewidth v0.0.4
|
github.com/mattn/go-runewidth v0.0.4
|
||||||
|
github.com/mbndr/figlet4go v0.0.0-20190224160619-d6cef5b186ea
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
||||||
github.com/sqshq/figlet4go v0.0.0-20190224060604-5ce91d55ba00
|
|
||||||
github.com/sqshq/termui v0.0.0-20190125032456-731556c09f2c
|
github.com/sqshq/termui v0.0.0-20190125032456-731556c09f2c
|
||||||
gopkg.in/yaml.v2 v2.2.2
|
gopkg.in/yaml.v2 v2.2.2
|
||||||
)
|
)
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -11,13 +11,13 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mbndr/figlet4go v0.0.0-20190224160619-d6cef5b186ea h1:mQncVDBpKkAecPcH2IMGpKUQYhwowlafQbfkz2QFqkc=
|
||||||
|
github.com/mbndr/figlet4go v0.0.0-20190224160619-d6cef5b186ea/go.mod h1:QzTGLGoOqLHUBK8/EZ0v4Fa4CdyXmdyRwCHcl0YbeO4=
|
||||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
|
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
|
||||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||||
github.com/sqshq/figlet4go v0.0.0-20190224060604-5ce91d55ba00 h1:HDXBCtVmmsZ0uMTd7CduTASlVECbRZhyAc0m3C+Dbjk=
|
|
||||||
github.com/sqshq/figlet4go v0.0.0-20190224060604-5ce91d55ba00/go.mod h1:8MTXZj469VoimW9vWH9LcL9Q3k1SRa+dgZdni8ZZw0o=
|
|
||||||
github.com/sqshq/termui v0.0.0-20190125032456-731556c09f2c h1:BBEmIcD4UhAHDVWi3PVuA5TxVTZxcjmYzmdvhWkPfvE=
|
github.com/sqshq/termui v0.0.0-20190125032456-731556c09f2c h1:BBEmIcD4UhAHDVWi3PVuA5TxVTZxcjmYzmdvhWkPfvE=
|
||||||
github.com/sqshq/termui v0.0.0-20190125032456-731556c09f2c/go.mod h1:puWaguPLLYPPKabYPVhZ8sDNe0nKSMiKWRfLVaaX8Zs=
|
github.com/sqshq/termui v0.0.0-20190125032456-731556c09f2c/go.mod h1:puWaguPLLYPPKabYPVhZ8sDNe0nKSMiKWRfLVaaX8Zs=
|
||||||
golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
|
golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
|
||||||
|
|
21
main.go
21
main.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/sqshq/sampler/component"
|
"github.com/sqshq/sampler/component"
|
||||||
"github.com/sqshq/sampler/component/asciibox"
|
"github.com/sqshq/sampler/component/asciibox"
|
||||||
"github.com/sqshq/sampler/component/barchart"
|
"github.com/sqshq/sampler/component/barchart"
|
||||||
|
"github.com/sqshq/sampler/component/gauge"
|
||||||
"github.com/sqshq/sampler/component/runchart"
|
"github.com/sqshq/sampler/component/runchart"
|
||||||
"github.com/sqshq/sampler/config"
|
"github.com/sqshq/sampler/config"
|
||||||
"github.com/sqshq/sampler/console"
|
"github.com/sqshq/sampler/console"
|
||||||
|
@ -40,14 +41,24 @@ func main() {
|
||||||
data.NewSampler(box, a.Item, *a.RefreshRateMs)
|
data.NewSampler(box, a.Item, *a.RefreshRateMs)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cfg.BarCharts {
|
for _, b := range cfg.BarCharts {
|
||||||
|
|
||||||
chart := barchart.NewBarChart(c.Title, *c.Scale)
|
chart := barchart.NewBarChart(b.Title, *b.Scale)
|
||||||
layout.AddComponent(config.TypeBarChart, chart, c.Title, c.Position, c.Size, *c.RefreshRateMs)
|
layout.AddComponent(config.TypeBarChart, chart, b.Title, b.Position, b.Size, *b.RefreshRateMs)
|
||||||
|
|
||||||
for _, item := range c.Items {
|
for _, item := range b.Items {
|
||||||
chart.AddBar(*item.Label, *item.Color)
|
chart.AddBar(*item.Label, *item.Color)
|
||||||
data.NewSampler(chart, item, *c.RefreshRateMs)
|
data.NewSampler(chart, item, *b.RefreshRateMs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, gc := range cfg.Gauges {
|
||||||
|
|
||||||
|
g := gauge.NewGauge(gc.Title, *gc.Scale, *gc.Color)
|
||||||
|
layout.AddComponent(config.TypeGauge, g, gc.Title, gc.Position, gc.Size, *gc.RefreshRateMs)
|
||||||
|
|
||||||
|
for _, item := range gc.Items {
|
||||||
|
data.NewSampler(g, item, *gc.RefreshRateMs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
sampler.zip
BIN
sampler.zip
Binary file not shown.
Loading…
Reference in New Issue