mirror of
https://github.com/glanceapp/glance.git
synced 2025-06-21 10:27:45 +02:00
Add new functions to custom-api widget
This commit is contained in:
parent
c6e0230e5d
commit
233de7fc37
@ -325,13 +325,24 @@ The following helper functions provided by Glance are available:
|
|||||||
- `toFloat(i int) float`: Converts an integer to a float.
|
- `toFloat(i int) float`: Converts an integer to a float.
|
||||||
- `toInt(f float) int`: Converts a float to an integer.
|
- `toInt(f float) int`: Converts a float to an integer.
|
||||||
- `toRelativeTime(t time.Time) template.HTMLAttr`: Converts Time to a relative time such as 2h, 1d, etc which dynamically updates. **NOTE:** the value of this function should be used as an attribute in an HTML tag, e.g. `<span {{ toRelativeTime .Time }}></span>`.
|
- `toRelativeTime(t time.Time) template.HTMLAttr`: Converts Time to a relative time such as 2h, 1d, etc which dynamically updates. **NOTE:** the value of this function should be used as an attribute in an HTML tag, e.g. `<span {{ toRelativeTime .Time }}></span>`.
|
||||||
- `parseTime(layout string, s string) time.Time`: Parses a string into time.Time. The layout must be provided in Go's [date format](https://pkg.go.dev/time#pkg-constants). You can alternatively use these values instead of the literal format: "RFC3339", "RFC3339Nano", "DateTime", "DateOnly", "TimeOnly".
|
- `parseTime(layout string, s string) time.Time`: Parses a string into time.Time. The layout must be provided in Go's [date format](https://pkg.go.dev/time#pkg-constants). You can alternatively use these values instead of the literal format: "unix", "RFC3339", "RFC3339Nano", "DateTime", "DateOnly".
|
||||||
|
- `parseRelativeTime(layout string, s string) time.Time`: A shorthand for `{{ .String "date" | parseTime "rfc3339" | toRelativeTime }}`.
|
||||||
- `add(a, b float) float`: Adds two numbers.
|
- `add(a, b float) float`: Adds two numbers.
|
||||||
- `sub(a, b float) float`: Subtracts two numbers.
|
- `sub(a, b float) float`: Subtracts two numbers.
|
||||||
- `mul(a, b float) float`: Multiplies two numbers.
|
- `mul(a, b float) float`: Multiplies two numbers.
|
||||||
- `div(a, b float) float`: Divides two numbers.
|
- `div(a, b float) float`: Divides two numbers.
|
||||||
- `formatApproxNumber(n int) string`: Formats a number to be more human-readable, e.g. 1000 -> 1k.
|
- `formatApproxNumber(n int) string`: Formats a number to be more human-readable, e.g. 1000 -> 1k.
|
||||||
- `formatNumber(n float|int) string`: Formats a number with commas, e.g. 1000 -> 1,000.
|
- `formatNumber(n float|int) string`: Formats a number with commas, e.g. 1000 -> 1,000.
|
||||||
|
- `trimPrefix(prefix string, str string) string`: Trims the prefix from a string.
|
||||||
|
- `trimSuffix(suffix string, str string) string`: Trims the suffix from a string.
|
||||||
|
- `trimSpace(str string) string`: Trims whitespace from a string on both ends.
|
||||||
|
- `replaceAll(old string, new string, str string) string`: Replaces all occurrences of a string in a string.
|
||||||
|
- `findMatch(pattern string, str string) string`: Finds the first match of a regular expression in a string.
|
||||||
|
- `findSubmatch(pattern string, str string) string`: Finds the first submatch of a regular expression in a string.
|
||||||
|
- `sortByString(key string, order string, arr []JSON): []JSON`: Sorts an array of JSON objects by a string key in either ascending or descending order.
|
||||||
|
- `sortByInt(key string, order string, arr []JSON): []JSON`: Sorts an array of JSON objects by an integer key in either ascending or descending order.
|
||||||
|
- `sortByFloat(key string, order string, arr []JSON): []JSON`: Sorts an array of JSON objects by a float key in either ascending or descending order.
|
||||||
|
- `sortByTime(key string, layout string, order string, arr []JSON): []JSON`: Sorts an array of JSON objects by a time key in either ascending or descending order. The format must be provided in Go's [date format](https://pkg.go.dev/time#pkg-constants).
|
||||||
|
|
||||||
The following helper functions provided by Go's `text/template` are available:
|
The following helper functions provided by Go's `text/template` are available:
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -340,6 +343,22 @@ func (r *decoratedGJSONResult) Bool(key string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var customAPITemplateFuncs = func() template.FuncMap {
|
var customAPITemplateFuncs = func() template.FuncMap {
|
||||||
|
var regexpCacheMu sync.Mutex
|
||||||
|
var regexpCache = make(map[string]*regexp.Regexp)
|
||||||
|
|
||||||
|
getCachedRegexp := func(pattern string) *regexp.Regexp {
|
||||||
|
regexpCacheMu.Lock()
|
||||||
|
defer regexpCacheMu.Unlock()
|
||||||
|
|
||||||
|
regex, exists := regexpCache[pattern]
|
||||||
|
if !exists {
|
||||||
|
regex = regexp.MustCompile(pattern)
|
||||||
|
regexpCache[pattern] = regex
|
||||||
|
}
|
||||||
|
|
||||||
|
return regex
|
||||||
|
}
|
||||||
|
|
||||||
funcs := template.FuncMap{
|
funcs := template.FuncMap{
|
||||||
"toFloat": func(a int) float64 {
|
"toFloat": func(a int) float64 {
|
||||||
return float64(a)
|
return float64(a)
|
||||||
@ -369,6 +388,83 @@ var customAPITemplateFuncs = func() template.FuncMap {
|
|||||||
// Shorthand to do both of the above with a single function call
|
// Shorthand to do both of the above with a single function call
|
||||||
return dynamicRelativeTimeAttrs(customAPIFuncParseTime(layout, value))
|
return dynamicRelativeTimeAttrs(customAPIFuncParseTime(layout, value))
|
||||||
},
|
},
|
||||||
|
// The reason we flip the parameter order is so that you can chain multiple calls together like this:
|
||||||
|
// {{ .JSON.String "foo" | trimPrefix "bar" | doSomethingElse }}
|
||||||
|
// instead of doing this:
|
||||||
|
// {{ trimPrefix (.JSON.String "foo") "bar" | doSomethingElse }}
|
||||||
|
// since the piped value gets passed as the last argument to the function.
|
||||||
|
"trimPrefix": func(prefix, s string) string {
|
||||||
|
return strings.TrimPrefix(s, prefix)
|
||||||
|
},
|
||||||
|
"trimSuffix": func(suffix, s string) string {
|
||||||
|
return strings.TrimSuffix(s, suffix)
|
||||||
|
},
|
||||||
|
"trimSpace": strings.TrimSpace,
|
||||||
|
"replaceAll": func(old, new, s string) string {
|
||||||
|
return strings.ReplaceAll(s, old, new)
|
||||||
|
},
|
||||||
|
"findMatch": func(pattern, s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return getCachedRegexp(pattern).FindString(s)
|
||||||
|
},
|
||||||
|
"findSubmatch": func(pattern, s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
regex := getCachedRegexp(pattern)
|
||||||
|
return itemAtIndexOrDefault(regex.FindStringSubmatch(s), 1, "")
|
||||||
|
},
|
||||||
|
"sortByString": func(key, order string, results []decoratedGJSONResult) []decoratedGJSONResult {
|
||||||
|
sort.Slice(results, func(a, b int) bool {
|
||||||
|
if order == "asc" {
|
||||||
|
return results[a].String(key) < results[b].String(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results[a].String(key) > results[b].String(key)
|
||||||
|
})
|
||||||
|
|
||||||
|
return results
|
||||||
|
},
|
||||||
|
"sortByInt": func(key, order string, results []decoratedGJSONResult) []decoratedGJSONResult {
|
||||||
|
sort.Slice(results, func(a, b int) bool {
|
||||||
|
if order == "asc" {
|
||||||
|
return results[a].Int(key) < results[b].Int(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results[a].Int(key) > results[b].Int(key)
|
||||||
|
})
|
||||||
|
|
||||||
|
return results
|
||||||
|
},
|
||||||
|
"sortByFloat": func(key, order string, results []decoratedGJSONResult) []decoratedGJSONResult {
|
||||||
|
sort.Slice(results, func(a, b int) bool {
|
||||||
|
if order == "asc" {
|
||||||
|
return results[a].Float(key) < results[b].Float(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results[a].Float(key) > results[b].Float(key)
|
||||||
|
})
|
||||||
|
|
||||||
|
return results
|
||||||
|
},
|
||||||
|
"sortByTime": func(key, layout, order string, results []decoratedGJSONResult) []decoratedGJSONResult {
|
||||||
|
sort.Slice(results, func(a, b int) bool {
|
||||||
|
timeA := customAPIFuncParseTime(layout, results[a].String(key))
|
||||||
|
timeB := customAPIFuncParseTime(layout, results[b].String(key))
|
||||||
|
|
||||||
|
if order == "asc" {
|
||||||
|
return timeA.Before(timeB)
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeA.After(timeB)
|
||||||
|
})
|
||||||
|
|
||||||
|
return results
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range globalTemplateFunctions {
|
for key, value := range globalTemplateFunctions {
|
||||||
@ -382,6 +478,13 @@ var customAPITemplateFuncs = func() template.FuncMap {
|
|||||||
|
|
||||||
func customAPIFuncParseTime(layout, value string) time.Time {
|
func customAPIFuncParseTime(layout, value string) time.Time {
|
||||||
switch strings.ToLower(layout) {
|
switch strings.ToLower(layout) {
|
||||||
|
case "unix":
|
||||||
|
asInt, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return time.Unix(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Unix(asInt, 0)
|
||||||
case "rfc3339":
|
case "rfc3339":
|
||||||
layout = time.RFC3339
|
layout = time.RFC3339
|
||||||
case "rfc3339nano":
|
case "rfc3339nano":
|
||||||
@ -390,8 +493,6 @@ func customAPIFuncParseTime(layout, value string) time.Time {
|
|||||||
layout = time.DateTime
|
layout = time.DateTime
|
||||||
case "dateonly":
|
case "dateonly":
|
||||||
layout = time.DateOnly
|
layout = time.DateOnly
|
||||||
case "timeonly":
|
|
||||||
layout = time.TimeOnly
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parsed, err := time.Parse(layout, value)
|
parsed, err := time.Parse(layout, value)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user