diff --git a/handlers/common.go b/handlers/common.go index 6695b72..6a70fd5 100644 --- a/handlers/common.go +++ b/handlers/common.go @@ -8,6 +8,7 @@ import ( "net" "net/http" "os" + "path/filepath" "strings" "sync" @@ -46,6 +47,49 @@ func LoadTemplates() map[string]*template.Template { return templates } +// templateFuncs exposes formatting helpers to every parsed template. +var templateFuncs = template.FuncMap{ + "formatBytes": formatBytes, +} + +// formatBytes renders a byte count as a human-readable string (e.g. "117.7 MB"). +// Non-numeric or negative inputs render as an empty string. +func formatBytes(v any) string { + var b int64 + switch n := v.(type) { + case int: + b = int64(n) + case int8: + b = int64(n) + case int16: + b = int64(n) + case int32: + b = int64(n) + case int64: + b = n + case uint: + b = int64(n) + case uint8: + b = int64(n) + case uint16: + b = int64(n) + case uint32: + b = int64(n) + case uint64: + b = int64(n) + case float32: + b = int64(n) + case float64: + b = int64(n) + default: + return "" + } + if b < 0 { + return "" + } + return humanReadableSize(b) +} + // parseTemplates parses every page/modal template exactly once. // A template that fails to parse is logged and left out of the map — // callers treat a missing entry as "template not available" instead of @@ -75,7 +119,7 @@ func parseTemplates() map[string]*template.Template { parsed := make(map[string]*template.Template, len(files)) for name, paths := range files { - tmpl, err := template.ParseFiles(paths...) + tmpl, err := template.New(filepath.Base(paths[0])).Funcs(templateFuncs).ParseFiles(paths...) if err != nil { log.Printf("Error parsing template %s: %v", name, err) continue diff --git a/handlers/tftp.go b/handlers/tftp.go index 37fb7fe..389bb6b 100644 --- a/handlers/tftp.go +++ b/handlers/tftp.go @@ -294,12 +294,19 @@ type FileInfo struct { IsDir bool } +// Breadcrumb is one segment of the TFTP directory trail shown in the UI. +type Breadcrumb struct { + Name string + Dir string +} + // TFTPData holds information for rendering the TFTP management page type TFTPData struct { Title string ServerRunning bool ServerDirectory string PrevDirectory string + Breadcrumbs []Breadcrumb Files []FileInfo } @@ -360,10 +367,30 @@ func (h *TFTPHandlers) getFileInfo(dir string) (*TFTPData, error) { ServerRunning: isTFTPRunning(), ServerDirectory: relDir, PrevDirectory: removeLastDir(relDir), + Breadcrumbs: buildBreadcrumbs(relDir), Files: fileInfos, }, nil } +// buildBreadcrumbs turns a TFTP-relative directory ("", "a", "a/b") into a +// trail of clickable segments for the file browser UI. +func buildBreadcrumbs(relDir string) []Breadcrumb { + if relDir == "" { + return nil + } + parts := strings.Split(relDir, string(filepath.Separator)) + crumbs := make([]Breadcrumb, 0, len(parts)) + accum := "" + for _, part := range parts { + if accum != "" { + accum += string(filepath.Separator) + } + accum += part + crumbs = append(crumbs, Breadcrumb{Name: part, Dir: accum}) + } + return crumbs +} + // mustAbs returns the absolute form of p, falling back to p itself on error. func mustAbs(p string) string { abs, err := filepath.Abs(p) diff --git a/templates/base.templ b/templates/base.templ index 7d5e9e6..3959a05 100755 --- a/templates/base.templ +++ b/templates/base.templ @@ -19,18 +19,18 @@
{{ end }} \ No newline at end of file diff --git a/templates/pages/tftp.templ b/templates/pages/tftp.templ index 23b95b4..c748e1e 100755 --- a/templates/pages/tftp.templ +++ b/templates/pages/tftp.templ @@ -1,23 +1,25 @@ {{ define "content" }} -
-
-

TFTP Server Overview

+
+
+

TFTP Server Overview

-
-

Directory: {{.ServerDirectory}}

- {{ if ne .ServerDirectory "./" }} -

- {{ end }} + -
+

Files in TFTP Directory

@@ -50,7 +52,7 @@
-
+ {{ template "uploadmodal" }} diff --git a/templates/partials/status-content.templ b/templates/partials/status-content.templ index d57a7d7..8a86120 100644 --- a/templates/partials/status-content.templ +++ b/templates/partials/status-content.templ @@ -4,7 +4,7 @@ {{if eq .OverallStatus "healthy"}}System Healthy{{else if eq .OverallStatus "partial"}}Partial Service{{else}}System Down{{end}} - Last Updated: {{.LastUpdated.Format "15:04:05"}} + Last Updated: {{.LastUpdated}}