diff --git a/cmd/main.go b/cmd/main.go index e862a88..cee0eac 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -10,6 +10,11 @@ import ( ) func main() { + // Set FUNCTION_TARGET if not already set + if os.Getenv("FUNCTION_TARGET") == "" { + os.Setenv("FUNCTION_TARGET", "Progress") + } + // Use PORT environment variable, or default to 8080. port := "8080" if envPort := os.Getenv("PORT"); envPort != "" { diff --git a/progress.go b/progress.go index b20081e..660e929 100644 --- a/progress.go +++ b/progress.go @@ -13,12 +13,14 @@ import ( "github.com/GoogleCloudPlatform/functions-framework-go/functions" ) -// Data ... is the collection of inputs we need to fill our template type Data struct { BackgroundColor string - Percentage int - Progress int + Percentage float64 + Progress float64 PickedColor string + Label string + ShowLabel bool + BarWidth float64 } var grey = "#555" @@ -35,19 +37,20 @@ func fixDir() { } } -func pickColor(percentage int, successColor string, warningColor string, dangerColor string) string { +func pickColor(percentage float64, successColor, warningColor, dangerColor string) string { pickedColor := green if successColor != "" { pickedColor = "#" + successColor } - if percentage >= 0 && percentage < 33 { + switch { + case percentage >= 0 && percentage < 33: if dangerColor != "" { pickedColor = "#" + dangerColor } else { pickedColor = red } - } else if percentage >= 33 && percentage < 70 { + case percentage >= 33 && percentage < 70: if warningColor != "" { pickedColor = "#" + warningColor } else { @@ -63,39 +66,112 @@ func init() { functions.HTTP("Progress", Progress) } -// Progress ... Entrypoint of our Cloud Function -func Progress(w http.ResponseWriter, r *http.Request) { - var id = fmt.Sprintf(path.Base(r.URL.Path)) - - if percentage, err := strconv.Atoi(id); err == nil { +// Template helper to check if a float is an integer +func isInt(f float64) bool { + return f == float64(int(f)) +} - // Read (with the intention to overwrite) success, warning, and danger colors if provided - successColor := r.URL.Query().Get("successColor") - warningColor := r.URL.Query().Get("warningColor") - dangerColor := r.URL.Query().Get("dangerColor") +// Template helper for division +func div(a, b float64) float64 { + if b == 0 { + return 0 + } + return a / b +} - data := Data{ - BackgroundColor: grey, - Percentage: percentage, - Progress: percentage - (percentage / 10), - PickedColor: pickColor(percentage, successColor, warningColor, dangerColor), - } +func Progress(w http.ResponseWriter, r *http.Request) { + id := path.Base(r.URL.Path) - tpl, err := template.ParseFiles("progress.html") + value, err := strconv.ParseFloat(id, 64) + if err != nil { + http.Error(w, "Invalid value", http.StatusBadRequest) + return + } - if err != nil { - log.Fatalln(err) + successColor := r.URL.Query().Get("successColor") + warningColor := r.URL.Query().Get("warningColor") + dangerColor := r.URL.Query().Get("dangerColor") + barColor := r.URL.Query().Get("barColor") + customLabel := r.URL.Query().Get("label") + minStr := r.URL.Query().Get("min") + maxStr := r.URL.Query().Get("max") + + // Determine if we're using custom label mode (data bar mode) + showLabel := customLabel != "" + + // Calculate percentage and bar width + var percentage float64 + var barWidth float64 + const defaultWidth = 90.0 + + if showLabel && minStr != "" && maxStr != "" { + // Data bar mode: scale proportionally based on min/max + min, errMin := strconv.ParseFloat(minStr, 64) + max, errMax := strconv.ParseFloat(maxStr, 64) + + if errMin != nil || errMax != nil || min >= max { + http.Error(w, "Invalid min/max values", http.StatusBadRequest) + return } + + // Calculate percentage for color picking (0-100) + if max > min { + percentage = ((value - min) / (max - min)) * 100 + } else { + percentage = 0 + } + + // Calculate bar width proportionally (leave some padding) + if max > min { + barWidth = ((value - min) / (max - min)) * (defaultWidth * 0.95) + } else { + barWidth = 0 + } + } else { + // Original percentage mode + percentage = value + if percentage > 100 { + percentage = 100 + } + barWidth = percentage - (percentage / 10) + } - buf := new(bytes.Buffer) + // Determine bar color + var pickedColor string + if barColor != "" { + // Use custom bar color if provided (for data bars) + pickedColor = "#" + barColor + } else { + // Use percentage-based color logic + pickedColor = pickColor(percentage, successColor, warningColor, dangerColor) + } - err = tpl.Execute(buf, data) - if err != nil { - log.Fatalln(err) - } + data := Data{ + BackgroundColor: grey, + Percentage: percentage, + Progress: barWidth, + BarWidth: defaultWidth, + PickedColor: pickedColor, + Label: customLabel, + ShowLabel: showLabel, + } - fmt.Printf("The percentage is: %d\n", percentage) - w.Header().Add("Content-Type", "image/svg+xml") - fmt.Fprintf(w, buf.String()) + // Parse template with custom functions + tpl := template.New("progress.html").Funcs(template.FuncMap{ + "isInt": isInt, + "div": div, + }) + tpl, err = tpl.ParseFiles("progress.html") + if err != nil { + log.Fatalln("Error parsing template:", err) } -} + + buf := new(bytes.Buffer) + if err := tpl.Execute(buf, data); err != nil { + log.Fatalln("Error executing template:", err) + } + + fmt.Printf("The percentage is: %v\n", percentage) + w.Header().Set("Content-Type", "image/svg+xml") + _, _ = w.Write(buf.Bytes()) +} \ No newline at end of file diff --git a/progress.html b/progress.html index b4b927b..0c31912 100644 --- a/progress.html +++ b/progress.html @@ -1,14 +1,22 @@ - - + + - + - + - - {{.Percentage}}%% + + {{if .ShowLabel}} + {{.Label}} + {{else}} + {{if isInt .Percentage}} + {{printf "%.0f%%" .Percentage}} + {{else}} + {{printf "%.2f%%" .Percentage}} + {{end}} + {{end}} - + \ No newline at end of file