diff --git a/app/routes/account.go b/app/routes/account.go index 239aad0..0e5c6ce 100644 --- a/app/routes/account.go +++ b/app/routes/account.go @@ -6,81 +6,11 @@ import ( "net/http" "proxmoxaas-dashboard/app/common" + "github.com/gerow/go-color" "github.com/gin-gonic/gin" "github.com/go-viper/mapstructure/v2" ) -func HandleGETAccount(c *gin.Context) { - auth, err := common.GetAuth(c) - if err == nil { - account, err := GetUserAccount(auth) - if err != nil { - common.HandleNonFatalError(c, err) - return - } - - for k, v := range account.Resources { - switch t := v.(type) { - case NumericResource: - avail, prefix := FormatNumber(t.Total.Avail*t.Multiplier, t.Base) - account.Resources[k] = ResourceChart{ - Type: t.Type, - Display: t.Display, - Name: t.Name, - Used: t.Total.Used, - Max: t.Total.Max, - Avail: avail, - Prefix: prefix, - Unit: t.Unit, - } - case StorageResource: - avail, prefix := FormatNumber(t.Total.Avail*t.Multiplier, t.Base) - account.Resources[k] = ResourceChart{ - Type: t.Type, - Display: t.Display, - Name: t.Name, - Used: t.Total.Used, - Max: t.Total.Max, - Avail: avail, - Prefix: prefix, - Unit: t.Unit, - } - case ListResource: - l := struct { - Type string - Display bool - Resources []ResourceChart - }{ - Type: t.Type, - Display: t.Display, - Resources: []ResourceChart{}, - } - - for _, r := range t.Total { - l.Resources = append(l.Resources, ResourceChart{ - Type: t.Type, - Display: t.Display, - Name: r.Name, - Used: r.Used, - Max: r.Max, - Avail: float64(r.Avail), // usually an int - Unit: "", - }) - } - account.Resources[k] = l - } - } - - c.HTML(http.StatusOK, "html/account.html", gin.H{ - "global": common.Global, - "page": "account", - "account": account, - }) - } else { - c.Redirect(http.StatusFound, "/login") // if user is not authed, redirect user to login page - } -} - type Account struct { Username string Pools map[string]bool @@ -143,14 +73,101 @@ type ListResource struct { } type ResourceChart struct { - Type string - Display bool - Name string - Used int64 - Max int64 - Avail float64 - Prefix string - Unit string + Type string + Display bool + Name string + Used int64 + Max int64 + Avail float64 + Prefix string + Unit string + ColorHex string +} + +var Red = color.RGB{ + R: 1, + G: 0, + B: 0, +} + +var Green = color.RGB{ + R: 0, + G: 1, + B: 0, +} + +func HandleGETAccount(c *gin.Context) { + auth, err := common.GetAuth(c) + if err == nil { + account, err := GetUserAccount(auth) + if err != nil { + common.HandleNonFatalError(c, err) + return + } + + for k, v := range account.Resources { + switch t := v.(type) { + case NumericResource: + avail, prefix := FormatNumber(t.Total.Avail*t.Multiplier, t.Base) + account.Resources[k] = ResourceChart{ + Type: t.Type, + Display: t.Display, + Name: t.Name, + Used: t.Total.Used, + Max: t.Total.Max, + Avail: avail, + Prefix: prefix, + Unit: t.Unit, + ColorHex: InterpolateColorHSV(Green, Red, float64(t.Total.Used)/float64(t.Total.Max)).ToHTML(), + } + case StorageResource: + avail, prefix := FormatNumber(t.Total.Avail*t.Multiplier, t.Base) + account.Resources[k] = ResourceChart{ + Type: t.Type, + Display: t.Display, + Name: t.Name, + Used: t.Total.Used, + Max: t.Total.Max, + Avail: avail, + Prefix: prefix, + Unit: t.Unit, + ColorHex: InterpolateColorHSV(Green, Red, float64(t.Total.Used)/float64(t.Total.Max)).ToHTML(), + } + case ListResource: + l := struct { + Type string + Display bool + Resources []ResourceChart + }{ + Type: t.Type, + Display: t.Display, + Resources: []ResourceChart{}, + } + + for _, r := range t.Total { + l.Resources = append(l.Resources, ResourceChart{ + Type: t.Type, + Display: t.Display, + Name: r.Name, + Used: r.Used, + Max: r.Max, + Avail: float64(r.Avail), // usually an int + Unit: "", + ColorHex: InterpolateColorHSV(Green, Red, float64(r.Used)/float64(r.Max)).ToHTML(), + }) + } + account.Resources[k] = l + } + } + + c.HTML(http.StatusOK, "html/account.html", gin.H{ + "global": common.Global, + "page": "account", + "account": account, + }) + } else { + c.Redirect(http.StatusFound, "/login") // if user is not authed, redirect user to login page + } } func GetUserAccount(auth common.Auth) (Account, error) { @@ -261,3 +278,15 @@ func FormatNumber(val int64, base int64) (float64, string) { return 0, "" } } + +// interpolate between min and max by normalized (0 - 1) val +func InterpolateColorHSV(min color.RGB, max color.RGB, val float64) color.RGB { + minhsl := min.ToHSL() + maxhsl := max.ToHSL() + interphsl := color.HSL{ + H: (1-val)*minhsl.H + (val)*maxhsl.H, + S: (1-val)*minhsl.S + (val)*maxhsl.S, + L: (1-val)*minhsl.L + (val)*maxhsl.L, + } + return interphsl.ToRGB() +} diff --git a/web/templates/resource-chart.go.tmpl b/web/templates/resource-chart.go.tmpl index 4065071..e7b5b0b 100644 --- a/web/templates/resource-chart.go.tmpl +++ b/web/templates/resource-chart.go.tmpl @@ -13,15 +13,13 @@ margin: 0; width: 100%; height: fit-content; - padding: 10px 10px 10px 10px; + padding: 10px; border-radius: 5px; } progress { width: 100%; border: 0; height: 1em; - -webkit-appearance: none; - -moz-appearance: none; appearance: none; } #caption { @@ -30,14 +28,23 @@ display: flex; flex-direction: column; } + progress::-moz-progress-bar { + background: #{{.ColorHex}}; + } + progress::-webkit-progress-bar { + background: var(--main-text-color); + } + progress::-webkit-progress-value { + background: #{{.ColorHex}}; + }
+ +
+