From f99d22738ce3ed8e1297a1cd4448ccbb81d33c03 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Wed, 9 Apr 2025 17:05:18 +0100 Subject: [PATCH 01/10] Add replaceMatches --- docs/custom-api.md | 1 + internal/glance/widget-custom-api.go | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/custom-api.md b/docs/custom-api.md index 99e3a5e..1930f40 100644 --- a/docs/custom-api.md +++ b/docs/custom-api.md @@ -389,6 +389,7 @@ The following helper functions provided by Glance are available: - `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. +- `replaceMatches(pattern string, replacement string, str string) string`: Replaces all occurrences of a regular expression 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. diff --git a/internal/glance/widget-custom-api.go b/internal/glance/widget-custom-api.go index e092fc3..5d82c5a 100644 --- a/internal/glance/widget-custom-api.go +++ b/internal/glance/widget-custom-api.go @@ -468,16 +468,15 @@ var customAPITemplateFuncs = func() template.FuncMap { return strings.TrimSuffix(s, suffix) }, "trimSpace": strings.TrimSpace, - "replaceAll": func(oldOrPattern, new, s string) string { + "replaceAll": func(old, new, s string) string { + return strings.ReplaceAll(s, old, new) + }, + "replaceMatches": func(pattern, replacement, s string) string { if s == "" { return "" } - regex := getCachedRegexp(oldOrPattern) - if regex == nil { - return strings.ReplaceAll(s, oldOrPattern, new) - } - return regex.ReplaceAllString(s, new) + return getCachedRegexp(pattern).ReplaceAllString(s, replacement) }, "findMatch": func(pattern, s string) string { if s == "" { From 3177af9524695a0e1b9bb16bb93eef5b277ab856 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Fri, 11 Apr 2025 22:34:53 +0100 Subject: [PATCH 02/10] Add rounded class --- internal/glance/static/main.css | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/glance/static/main.css b/internal/glance/static/main.css index a715565..2975a73 100644 --- a/internal/glance/static/main.css +++ b/internal/glance/static/main.css @@ -2038,6 +2038,7 @@ details[open] .summary::after { .color-primary { color: var(--color-primary); } .cursor-help { cursor: help; } +.rounded { border-radius: var(--border-radius); } .break-all { word-break: break-all; } .text-left { text-align: left; } .text-right { text-align: right; } From 97f43f88eb90a038208762dc6d2817dd69604c36 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Fri, 11 Apr 2025 23:14:06 +0100 Subject: [PATCH 03/10] Only set title if attribute isn't set --- internal/glance/static/js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/glance/static/js/main.js b/internal/glance/static/js/main.js index dcd8946..41d2ae3 100644 --- a/internal/glance/static/js/main.js +++ b/internal/glance/static/js/main.js @@ -649,7 +649,7 @@ function setupTruncatedElementTitles() { for (let i = 0; i < elements.length; i++) { const element = elements[i]; - if (element.title === "") element.title = element.textContent; + if (element.getAttribute("title") === null) element.title = element.textContent; } } From d5b89d512ac66a5fdc019cfa8f1b096a9fb8b1a4 Mon Sep 17 00:00:00 2001 From: Ralph Ocdol Date: Sun, 13 Apr 2025 10:46:43 +0800 Subject: [PATCH 04/10] added unique to filter arrays with unique items in custom-api --- internal/glance/widget-custom-api.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/internal/glance/widget-custom-api.go b/internal/glance/widget-custom-api.go index 5d82c5a..93d51c0 100644 --- a/internal/glance/widget-custom-api.go +++ b/internal/glance/widget-custom-api.go @@ -543,6 +543,18 @@ var customAPITemplateFuncs = func() template.FuncMap { "concat": func(items ...string) string { return strings.Join(items, "") }, + "unique": func(key string, results []decoratedGJSONResult) []decoratedGJSONResult { + seen := make(map[string]struct{}) + out := make([]decoratedGJSONResult, 0, len(results)) + for _, result := range results { + val := result.String(key) + if _, ok := seen[val]; !ok { + seen[val] = struct{}{} + out = append(out, result) + } + } + return out + }, } for key, value := range globalTemplateFunctions { From 5a91154eab83e43ac0dfbe2b15b673b94385bd33 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Sun, 13 Apr 2025 15:52:16 +0100 Subject: [PATCH 05/10] Document function --- docs/custom-api.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/custom-api.md b/docs/custom-api.md index 1930f40..d42d1fc 100644 --- a/docs/custom-api.md +++ b/docs/custom-api.md @@ -397,6 +397,7 @@ The following helper functions provided by Glance are available: - `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). - `concat(strings ...string) string`: Concatenates multiple strings together. +- `unique(key string, arr []JSON) []JSON`: Returns a unique array of JSON objects based on the given key. The following helper functions provided by Go's `text/template` are available: From 50dae22ff4999fc2276c0653642c6497e8f36706 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Sun, 13 Apr 2025 16:15:59 +0100 Subject: [PATCH 06/10] Add restart: unless-stopped --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 85047d3..ca16c49 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,7 @@ services: glance: container_name: glance image: glanceapp/glance + restart: unless-stopped volumes: - ./config:/app/config ports: From a3bc133bcbd1cab43c670a1c69ace10dcf7118c2 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Sun, 13 Apr 2025 16:52:17 +0100 Subject: [PATCH 07/10] Maybe fix for missing mountpoint info --- pkg/sysinfo/sysinfo.go | 71 +++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/pkg/sysinfo/sysinfo.go b/pkg/sysinfo/sysinfo.go index 673b9d2..1ed8c75 100644 --- a/pkg/sysinfo/sysinfo.go +++ b/pkg/sysinfo/sysinfo.go @@ -227,35 +227,50 @@ func Collect(req *SystemInfoRequest) (*SystemInfo, []error) { } } - filesystems, err := disk.Partitions(false) - if err == nil { - for _, fs := range filesystems { - mpReq, ok := req.Mountpoints[fs.Mountpoint] - isHidden := req.HideMountpointsByDefault - if ok && mpReq.Hide != nil { - isHidden = *mpReq.Hide - } - if isHidden { - continue - } - - usage, err := disk.Usage(fs.Mountpoint) - if err == nil { - mpInfo := MountpointInfo{ - Path: fs.Mountpoint, - Name: mpReq.Name, - TotalMB: usage.Total / 1024 / 1024, - UsedMB: usage.Used / 1024 / 1024, - UsedPercent: uint8(math.Min(usage.UsedPercent, 100)), - } - - info.Mountpoints = append(info.Mountpoints, mpInfo) - } else { - addErr(fmt.Errorf("getting filesystem usage for %s: %v", fs.Mountpoint, err)) - } + addedMountpoints := map[string]struct{}{} + addMountpointInfo := func(requestedPath string, mpReq MointpointRequest) { + if _, exists := addedMountpoints[requestedPath]; exists { + return } - } else { - addErr(fmt.Errorf("getting filesystems: %v", err)) + + isHidden := req.HideMountpointsByDefault + if mpReq.Hide != nil { + isHidden = *mpReq.Hide + } + if isHidden { + return + } + + usage, err := disk.Usage(requestedPath) + if err == nil { + mpInfo := MountpointInfo{ + Path: requestedPath, + Name: mpReq.Name, + TotalMB: usage.Total / 1024 / 1024, + UsedMB: usage.Used / 1024 / 1024, + UsedPercent: uint8(math.Min(usage.UsedPercent, 100)), + } + + info.Mountpoints = append(info.Mountpoints, mpInfo) + addedMountpoints[requestedPath] = struct{}{} + } else { + addErr(fmt.Errorf("getting filesystem usage for %s: %v", requestedPath, err)) + } + } + + if !req.HideMountpointsByDefault { + filesystems, err := disk.Partitions(false) + if err == nil { + for _, fs := range filesystems { + addMountpointInfo(fs.Mountpoint, req.Mountpoints[fs.Mountpoint]) + } + } else { + addErr(fmt.Errorf("getting filesystems: %v", err)) + } + } + + for mountpoint, mpReq := range req.Mountpoints { + addMountpointInfo(mountpoint, mpReq) } sort.Slice(info.Mountpoints, func(a, b int) bool { From f8f50b26d82b91edf0f924484ba21f371d331101 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Sun, 13 Apr 2025 17:09:51 +0100 Subject: [PATCH 08/10] Add mountpoint:info CLI command --- internal/glance/cli.go | 31 +++++++++++++++++++++++++++++++ internal/glance/main.go | 2 ++ 2 files changed, 33 insertions(+) diff --git a/internal/glance/cli.go b/internal/glance/cli.go index 9cbb607..693aa1f 100644 --- a/internal/glance/cli.go +++ b/internal/glance/cli.go @@ -6,6 +6,7 @@ import ( "os" "strings" + "github.com/shirou/gopsutil/v4/disk" "github.com/shirou/gopsutil/v4/sensors" ) @@ -18,11 +19,13 @@ const ( cliIntentConfigPrint cliIntentDiagnose cliIntentSensorsPrint + cliIntentMountpointInfo ) type cliOptions struct { intent cliIntent configPath string + args []string } func parseCliOptions() (*cliOptions, error) { @@ -46,6 +49,7 @@ func parseCliOptions() (*cliOptions, error) { fmt.Println(" config:validate Validate the config file") fmt.Println(" config:print Print the parsed config file with embedded includes") fmt.Println(" sensors:print List all sensors") + fmt.Println(" mountpoint:info Print information about a given mountpoint path") fmt.Println(" diagnose Run diagnostic checks") } configPath := flags.String("config", "glance.yml", "Set config path") @@ -72,6 +76,12 @@ func parseCliOptions() (*cliOptions, error) { } else { return nil, unknownCommandErr } + } else if len(args) == 2 { + if args[0] == "mountpoint:info" { + intent = cliIntentMountpointInfo + } else { + return nil, unknownCommandErr + } } else { return nil, unknownCommandErr } @@ -79,6 +89,7 @@ func parseCliOptions() (*cliOptions, error) { return &cliOptions{ intent: intent, configPath: *configPath, + args: args, }, nil } @@ -106,3 +117,23 @@ func cliSensorsPrint() int { return 0 } + +func cliMountpointInfo(requestedPath string) int { + usage, err := disk.Usage(requestedPath) + if err != nil { + fmt.Printf("Failed to retrieve info for path %s: %v\n", requestedPath, err) + if warns, ok := err.(*disk.Warnings); ok { + for _, w := range warns.List { + fmt.Printf(" - %v\n", w) + } + } + + return 1 + } + + fmt.Println("Path:", usage.Path) + fmt.Println("FS type:", ternary(usage.Fstype == "", "unknown", usage.Fstype)) + fmt.Printf("Used percent: %.1f%%", usage.UsedPercent) + + return 0 +} diff --git a/internal/glance/main.go b/internal/glance/main.go index 3dd43dc..67a980c 100644 --- a/internal/glance/main.go +++ b/internal/glance/main.go @@ -51,6 +51,8 @@ func Main() int { fmt.Println(string(contents)) case cliIntentSensorsPrint: return cliSensorsPrint() + case cliIntentMountpointInfo: + return cliMountpointInfo(options.args[1]) case cliIntentDiagnose: runDiagnostic() } From 50e1da01fef1b11df166fbf91c6ab49eff77bcf7 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Sun, 13 Apr 2025 17:40:30 +0100 Subject: [PATCH 09/10] Add newline --- internal/glance/cli.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/glance/cli.go b/internal/glance/cli.go index 693aa1f..f5a16fb 100644 --- a/internal/glance/cli.go +++ b/internal/glance/cli.go @@ -133,7 +133,7 @@ func cliMountpointInfo(requestedPath string) int { fmt.Println("Path:", usage.Path) fmt.Println("FS type:", ternary(usage.Fstype == "", "unknown", usage.Fstype)) - fmt.Printf("Used percent: %.1f%%", usage.UsedPercent) + fmt.Printf("Used percent: %.1f%%\n", usage.UsedPercent) return 0 } From 03b616622e7f511e40c7360d72e5ea4efe38f626 Mon Sep 17 00:00:00 2001 From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com> Date: Mon, 14 Apr 2025 01:07:04 +0100 Subject: [PATCH 10/10] Fix bug when making single request in job --- internal/glance/widget-utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/glance/widget-utils.go b/internal/glance/widget-utils.go index 4aaf5d5..9489cbf 100644 --- a/internal/glance/widget-utils.go +++ b/internal/glance/widget-utils.go @@ -182,8 +182,8 @@ func workerPoolDo[I any, O any](job *workerPoolJob[I, O]) ([]O, []error, error) } if len(job.data) == 1 { - output, err := job.task(job.data[0]) - return append(results, output), append(errs, err), nil + results[0], errs[0] = job.task(job.data[0]) + return results, errs, nil } tasksQueue := make(chan *workerPoolTask[I, O])