diff --git a/modules/digitalocean/display.go b/modules/digitalocean/display.go index e3cd0d20..db83ec25 100644 --- a/modules/digitalocean/display.go +++ b/modules/digitalocean/display.go @@ -2,33 +2,65 @@ package digitalocean import ( "fmt" - "strings" "github.com/wtfutil/wtf/utils" ) +const maxColWidth = 10 + +// defaultColumns defines the default set of columns to display in the widget +// This can be over-ridden in the cofig by explicitly defining a set of columns +var defaultColumns = []string{ + "Name", + "Status", + "Vcpus", + "Disk", + "Memory", + "Region.Slug", +} + func (widget *Widget) content() (string, string, bool) { title := widget.CommonSettings().Title if widget.err != nil { return title, widget.err.Error(), true } - str := fmt.Sprintf( - " [%s]Droplets\n\n", - widget.settings.common.Colors.Subheading, - ) + if len(defaultColumns) < 1 { + return title, " no columns defined", false + } + + str := fmt.Sprintf(" [::b][%s]", widget.settings.common.Colors.Subheading) + + for _, colName := range defaultColumns { + truncName := utils.Truncate(colName, maxColWidth, false) + + str += fmt.Sprintf("%-10s", truncName) + } + + str += "\n" for idx, droplet := range widget.droplets { - dropletName := droplet.Name + // This defines the formatting for the row, one tab-seperated string + // for each defined column + fmtStr := " [%s]" + for range defaultColumns { + fmtStr += "%-10s" + } - row := fmt.Sprintf( - "[%s] %-8s %-24s %s", + vals := []interface{}{ widget.RowColor(idx), - droplet.Status, - dropletName, - utils.Truncate(strings.Join(droplet.Tags, ","), 24, true), - ) + } + // Dynamically access the droplet to get the requested columns values + for _, colName := range defaultColumns { + val := droplet.ValueForColumn(colName) + truncVal := utils.Truncate(val, maxColWidth, false) + + vals = append(vals, truncVal) + } + + // And format, print, and color the row + row := fmt.Sprintf(fmtStr, vals...) str += utils.HighlightableHelper(widget.View, row, idx, 33) } diff --git a/modules/digitalocean/droplet.go b/modules/digitalocean/droplet.go index d65fe9c7..cedd0dad 100644 --- a/modules/digitalocean/droplet.go +++ b/modules/digitalocean/droplet.go @@ -1,17 +1,87 @@ package digitalocean -import "github.com/digitalocean/godo" +import ( + "fmt" + "reflect" + "strings" + + "github.com/digitalocean/godo" +) // Droplet represents WTF's view of a DigitalOcean droplet type Droplet struct { godo.Droplet + + Image Image + Region Region +} + +// Image represents WTF's view of a DigitalOcean droplet image +type Image struct { + godo.Image +} + +// Region represents WTF's view of a DigitalOcean region +type Region struct { + godo.Region } // NewDroplet creates and returns an instance of Droplet func NewDroplet(doDroplet godo.Droplet) *Droplet { droplet := &Droplet{ doDroplet, + + Image{ + *doDroplet.Image, + }, + + Region{ + *doDroplet.Region, + }, } return droplet } + +// ValueForColumn returns a string value for the given column +func (drop *Droplet) ValueForColumn(colName string) string { + r := reflect.ValueOf(drop) + f := reflect.Indirect(r).FieldByName(colName) + + var strVal string + + // Figure out if we should forward this property to a sub-object + // Lets us support "Region.Name" column definitions + split := strings.Split(colName, ".") + + switch split[0] { + case "Image": + strVal = drop.Image.ValueForColumn(split[1]) + case "Region": + strVal = drop.Region.ValueForColumn(split[1]) + default: + strVal = fmt.Sprintf("%v", f) + } + + return strVal +} + +// ValueForColumn returns a string value for the given column +func (reg *Image) ValueForColumn(colName string) string { + r := reflect.ValueOf(reg) + f := reflect.Indirect(r).FieldByName(colName) + + strVal := fmt.Sprintf("%v", f) + + return strVal +} + +// ValueForColumn returns a string value for the given column +func (reg *Region) ValueForColumn(colName string) string { + r := reflect.ValueOf(reg) + f := reflect.Indirect(r).FieldByName(colName) + + strVal := fmt.Sprintf("%v", f) + + return strVal +} diff --git a/utils/text.go b/utils/text.go index 83d22b05..53d9669e 100644 --- a/utils/text.go +++ b/utils/text.go @@ -77,12 +77,13 @@ func Truncate(src string, maxLen int, withEllipse bool) string { return src } -// Formats number as string with 1000 delimiters and, if necessary, rounds it to 2 decimals +// PrettyNumber formats number as string with 1000 delimiters and, if necessary, rounds it to 2 decimals func PrettyNumber(number float64) string { p := message.NewPrinter(language.English) + if number == math.Trunc(number) { return p.Sprintf("%.0f", number) - } else { - return p.Sprintf("%.2f", number) } + + return p.Sprintf("%.2f", number) }