From a5b0664b9c7e1d3b9ca7375e1f754c10eaafeae4 Mon Sep 17 00:00:00 2001 From: Anant Jain Date: Wed, 14 May 2025 22:38:13 -0700 Subject: [PATCH 1/9] Add Mod operation --- docs/custom-api.md | 3 ++- internal/glance/widget-custom-api.go | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/custom-api.md b/docs/custom-api.md index 566aa58..09a0858 100644 --- a/docs/custom-api.md +++ b/docs/custom-api.md @@ -238,7 +238,7 @@ Output:
90
``` -Other operations include `add`, `mul`, and `div`. +Other operations include `add`, `mul`, `div` and `mod`.
@@ -431,6 +431,7 @@ The following helper functions provided by Glance are available: - `sub(a, b float) float`: Subtracts two numbers. - `mul(a, b float) float`: Multiplies two numbers. - `div(a, b float) float`: Divides two numbers. +- `mod(a, b int) int`: Remainder after dividing a by b (a % b). - `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. - `trimPrefix(prefix string, str string) string`: Trims the prefix from a string. diff --git a/internal/glance/widget-custom-api.go b/internal/glance/widget-custom-api.go index e9c744f..54eca9c 100644 --- a/internal/glance/widget-custom-api.go +++ b/internal/glance/widget-custom-api.go @@ -414,6 +414,14 @@ func customAPIDoMathOp[T int | float64](a, b T, op string) T { return 0 } return a / b + case "mod": + ai, bi := any(a), any(b) + aint, aok := ai.(int) + bint, bok := bi.(int) + if aok && bok && bint != 0 { + return T(aint % bint) + } + return 0 } return 0 } @@ -479,6 +487,9 @@ var customAPITemplateFuncs = func() template.FuncMap { "div": func(a, b any) any { return doMathOpWithAny(a, b, "div") }, + "mod": func(a, b int) any { + return doMathOpWithAny(a, b, "mod") + }, "now": func() time.Time { return time.Now() }, From 0ec9cf4aaa47a557f2be96956f0c37e0013b1b49 Mon Sep 17 00:00:00 2001 From: Dmitry Rubtsov Date: Thu, 15 May 2025 13:34:17 +0600 Subject: [PATCH 2/9] Add http proxy support --- internal/glance/widget-utils.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/glance/widget-utils.go b/internal/glance/widget-utils.go index fa2fad5..6d752e5 100644 --- a/internal/glance/widget-utils.go +++ b/internal/glance/widget-utils.go @@ -26,6 +26,7 @@ const defaultClientTimeout = 5 * time.Second var defaultHTTPClient = &http.Client{ Transport: &http.Transport{ MaxIdleConnsPerHost: 10, + Proxy: http.ProxyFromEnvironment, }, Timeout: defaultClientTimeout, } @@ -34,6 +35,7 @@ var defaultInsecureHTTPClient = &http.Client{ Timeout: defaultClientTimeout, Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + Proxy: http.ProxyFromEnvironment, }, } From aa3b2c3b1bd5758938b2e2e399439308f99b3c6f Mon Sep 17 00:00:00 2001 From: Ralph Ocdol Date: Sun, 18 May 2025 20:33:03 +0800 Subject: [PATCH 3/9] Fix text-truncate or related formatting --- internal/glance/static/js/page.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/glance/static/js/page.js b/internal/glance/static/js/page.js index e3a3a84..d2c3925 100644 --- a/internal/glance/static/js/page.js +++ b/internal/glance/static/js/page.js @@ -661,7 +661,7 @@ function setupTruncatedElementTitles() { for (let i = 0; i < elements.length; i++) { const element = elements[i]; - if (element.getAttribute("title") === null) element.title = element.textContent; + if (element.getAttribute("title") === null) element.title = element.textContent.trim(); } } From 92bc68b61a34ccbc7d30dee4746197d21c902407 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Mon, 19 May 2025 21:11:11 +0100 Subject: [PATCH 4/9] Use innerText instead of textContent --- internal/glance/static/js/page.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/glance/static/js/page.js b/internal/glance/static/js/page.js index d2c3925..1273a1e 100644 --- a/internal/glance/static/js/page.js +++ b/internal/glance/static/js/page.js @@ -661,7 +661,7 @@ function setupTruncatedElementTitles() { for (let i = 0; i < elements.length; i++) { const element = elements[i]; - if (element.getAttribute("title") === null) element.title = element.textContent.trim(); + if (element.getAttribute("title") === null) element.title = element.innerText; } } From bcef9fbd6183d61fcc1757f745d88cd4308ba712 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Fri, 16 May 2025 18:44:54 +0100 Subject: [PATCH 5/9] Simplify implementation of func --- internal/glance/widget-custom-api.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/internal/glance/widget-custom-api.go b/internal/glance/widget-custom-api.go index d95d885..1d8bf2f 100644 --- a/internal/glance/widget-custom-api.go +++ b/internal/glance/widget-custom-api.go @@ -414,14 +414,6 @@ func customAPIDoMathOp[T int | float64](a, b T, op string) T { return 0 } return a / b - case "mod": - ai, bi := any(a), any(b) - aint, aok := ai.(int) - bint, bok := bi.(int) - if aok && bok && bint != 0 { - return T(aint % bint) - } - return 0 } return 0 } @@ -487,8 +479,11 @@ var customAPITemplateFuncs = func() template.FuncMap { "div": func(a, b any) any { return doMathOpWithAny(a, b, "div") }, - "mod": func(a, b int) any { - return doMathOpWithAny(a, b, "mod") + "mod": func(a, b int) int { + if b == 0 { + return 0 + } + return a % b }, "now": func() time.Time { return time.Now() From c1aaec5ffcfb4c60b1c24f80d92c0e7f8ef336da Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Fri, 16 May 2025 19:25:48 +0100 Subject: [PATCH 6/9] Add .Options.JSON to custom API --- docs/custom-api.md | 8 ++++++++ internal/glance/widget-custom-api.go | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/docs/custom-api.md b/docs/custom-api.md index f4102f7..f065e1b 100644 --- a/docs/custom-api.md +++ b/docs/custom-api.md @@ -415,6 +415,14 @@ The following functions are available on the `JSON` object: - `Array(key string) []JSON`: Returns the value of the key as an array of `JSON` objects. - `Exists(key string) bool`: Returns true if the key exists in the JSON object. +The following functions are available on the `Options` object: + +- `StringOr(key string, default string) string`: Returns the value of the key as a string, or the default value if the key does not exist. +- `IntOr(key string, default int) int`: Returns the value of the key as an integer, or the default value if the key does not exist. +- `FloatOr(key string, default float) float`: Returns the value of the key as a float, or the default value if the key does not exist. +- `BoolOr(key string, default bool) bool`: Returns the value of the key as a boolean, or the default value if the key does not exist. +- `JSON(key string) JSON`: Returns the value of the key as a stringified `JSON` object, or throws an error if the key does not exist. + The following helper functions provided by Glance are available: - `toFloat(i int) float`: Converts an integer to a float. diff --git a/internal/glance/widget-custom-api.go b/internal/glance/widget-custom-api.go index 1d8bf2f..3c2ca75 100644 --- a/internal/glance/widget-custom-api.go +++ b/internal/glance/widget-custom-api.go @@ -108,6 +108,20 @@ func (o *customAPIOptions) BoolOr(key string, defaultValue bool) bool { return customAPIGetOptionOrDefault(*o, key, defaultValue) } +func (o *customAPIOptions) JSON(key string) string { + value, exists := (*o)[key] + if !exists { + panic(fmt.Sprintf("key %q does not exist in options", key)) + } + + encoded, err := json.Marshal(value) + if err != nil { + panic(fmt.Sprintf("marshaling %s: %v", key, err)) + } + + return string(encoded) +} + func customAPIGetOptionOrDefault[T any](o customAPIOptions, key string, defaultValue T) T { if value, exists := o[key]; exists { if typedValue, ok := value.(T); ok { From a2247c0b6cd4a204c42b0f37302b849389ef8cd2 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Fri, 16 May 2025 20:15:26 +0100 Subject: [PATCH 7/9] Use default client in diagnose command defaultHTTPClient may behave differently to http.DefaultClient and is used for almost all widgets, using it within the diagnose command will make debugging and replicating issues easier --- internal/glance/diagnose.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/glance/diagnose.go b/internal/glance/diagnose.go index 1ee1bc3..0f76263 100644 --- a/internal/glance/diagnose.go +++ b/internal/glance/diagnose.go @@ -165,7 +165,7 @@ func testHttpRequestWithHeaders(method, url string, headers map[string]string, e request.Header.Add(key, value) } - response, err := http.DefaultClient.Do(request) + response, err := defaultHTTPClient.Do(request) if err != nil { return "", err } From d9239acbcea9789fe47d112a98df8c7055ae4313 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Fri, 16 May 2025 20:17:12 +0100 Subject: [PATCH 8/9] Increase diagnose command timeout --- internal/glance/diagnose.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/glance/diagnose.go b/internal/glance/diagnose.go index 0f76263..7978699 100644 --- a/internal/glance/diagnose.go +++ b/internal/glance/diagnose.go @@ -12,7 +12,7 @@ import ( "time" ) -const httpTestRequestTimeout = 10 * time.Second +const httpTestRequestTimeout = 15 * time.Second var diagnosticSteps = []diagnosticStep{ { From 14a21de37fe15a003cce2ce50f612ddfb7af6572 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Fri, 16 May 2025 20:17:38 +0100 Subject: [PATCH 9/9] Add user agent to test reddit request --- internal/glance/diagnose.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/glance/diagnose.go b/internal/glance/diagnose.go index 7978699..2839a23 100644 --- a/internal/glance/diagnose.go +++ b/internal/glance/diagnose.go @@ -75,7 +75,9 @@ var diagnosticSteps = []diagnosticStep{ { name: "fetch data from Reddit API", fn: func() (string, error) { - return testHttpRequest("GET", "https://www.reddit.com/search.json", 200) + return testHttpRequestWithHeaders("GET", "https://www.reddit.com/search.json", map[string]string{ + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0", + }, 200) }, }, {