From a98274bf81a49bf9f1d6a08fdecb4f30f8fbe2a5 Mon Sep 17 00:00:00 2001 From: Ethan Li Date: Fri, 24 Apr 2026 13:44:10 -0400 Subject: [PATCH 1/5] Show identity/access info on the home page --- internal/app/server/client/globals.go | 10 +- internal/app/server/routes/home/routes.go | 74 ++++++--- .../server/routes/internet/conn-profiles.go | 2 + internal/app/server/routes/routes.go | 2 +- internal/clients/diskusage/du.go | 1 + internal/clients/identity/client.go | 67 +++++++++ internal/clients/versioning/client.go | 34 +++++ web/templates/home/index.page.tmpl | 140 +++++++++++++++++- 8 files changed, 298 insertions(+), 32 deletions(-) create mode 100644 internal/clients/identity/client.go create mode 100644 internal/clients/versioning/client.go diff --git a/internal/app/server/client/globals.go b/internal/app/server/client/globals.go index 510d9f9..15b7d3c 100644 --- a/internal/app/server/client/globals.go +++ b/internal/app/server/client/globals.go @@ -9,11 +9,13 @@ import ( "github.com/sargassum-world/godest/turbostreams" "github.com/openUC2/device-admin/internal/app/server/conf" + "github.com/openUC2/device-admin/internal/clients/identity" "github.com/openUC2/device-admin/internal/clients/networkmanager" "github.com/openUC2/device-admin/internal/clients/sidecar" "github.com/openUC2/device-admin/internal/clients/tailscale" "github.com/openUC2/device-admin/internal/clients/templates" "github.com/openUC2/device-admin/internal/clients/udisks2" + "github.com/openUC2/device-admin/internal/clients/versioning" ) // Server @@ -32,10 +34,13 @@ type Globals struct { Config conf.Config Base *BaseGlobals - Sidecar *sidecar.Client + Sidecar *sidecar.Client + + Identity *identity.Client NetworkManager *networkmanager.Client Tailscale *tailscale.Client UDisks2 *udisks2.Client + Versioning *versioning.Client } func NewBaseGlobals(config conf.Config, l godest.Logger) (g *BaseGlobals, err error) { @@ -70,9 +75,12 @@ func NewGlobals(config conf.Config, l godest.Logger) (g *Globals, err error) { } g.Sidecar = sidecar.NewClient(config.Sidecar) + + g.Identity = identity.NewClient(identity.Config{}, g.Base.Logger) g.NetworkManager = networkmanager.NewClient(networkmanager.Config{}, g.Base.Logger) g.Tailscale = tailscale.NewClient(tailscale.Config{}, g.Base.Logger) g.UDisks2 = udisks2.NewClient(udisks2.Config{}, g.Base.Logger) + g.Versioning = versioning.NewClient(versioning.Config{}, g.Base.Logger) return g, nil } diff --git a/internal/app/server/routes/home/routes.go b/internal/app/server/routes/home/routes.go index 6a9d7ba..46ded34 100644 --- a/internal/app/server/routes/home/routes.go +++ b/internal/app/server/routes/home/routes.go @@ -2,23 +2,38 @@ package home import ( + "context" "strings" "github.com/labstack/echo/v4" "github.com/pkg/errors" "github.com/sargassum-world/godest" + + "github.com/openUC2/device-admin/internal/clients/identity" + "github.com/openUC2/device-admin/internal/clients/tailscale" + "github.com/openUC2/device-admin/internal/clients/versioning" ) type Handlers struct { r godest.TemplateRenderer + ic *identity.Client + vc *versioning.Client + tsc *tailscale.Client + l godest.Logger } -func New(r godest.TemplateRenderer, l godest.Logger) *Handlers { +func New( + r godest.TemplateRenderer, ic *identity.Client, vc *versioning.Client, tsc *tailscale.Client, + l godest.Logger, +) *Handlers { return &Handlers{ - r: r, - l: l, + r: r, + ic: ic, + vc: vc, + tsc: tsc, + l: l, } } @@ -29,32 +44,12 @@ func (h *Handlers) Register(er godest.EchoRouter) { } } -type HomeViewData struct { - Hostname string - Port string -} - -func getHomeViewData(host string) (vd HomeViewData, err error) { - split := strings.Split(host, ":") - const expectedComponents = 2 - if len(split) > expectedComponents { - return HomeViewData{}, errors.Errorf( - "unable to split host '%s' into a hostname and a port", host, - ) - } - vd.Hostname = split[0] - if len(split) == expectedComponents { - vd.Port = split[expectedComponents-1] - } - return vd, nil -} - func (h *Handlers) HandleHomeGet() echo.HandlerFunc { t := "home/index.page.tmpl" h.r.MustHave(t) return func(c echo.Context) error { // Run queries - homeViewData, err := getHomeViewData(c.Request().Host) + homeViewData, err := getHomeViewData(c.Request().Context(), h.vc, h.ic, h.tsc) if err != nil { return err } @@ -62,3 +57,34 @@ func (h *Handlers) HandleHomeGet() echo.HandlerFunc { return h.r.CacheablePage(c.Response(), c.Request(), t, homeViewData, struct{}{}) } } + +type HomeViewData struct { + ForkliftVersioning versioning.Forklift + MachineName string + Hostname string + TailscaleDNS string +} + +func getHomeViewData( + ctx context.Context, vc *versioning.Client, ic *identity.Client, tsc *tailscale.Client, +) (vd HomeViewData, err error) { + vd.ForkliftVersioning, _ = vc.GetForklift() + + vd.MachineName, _ = ic.GetMachineName() + vd.Hostname, _ = ic.GetHostname() + vd.TailscaleDNS, _ = getTailscaleDNSName(ctx, tsc) + + return vd, nil +} + +func getTailscaleDNSName(ctx context.Context, tsc *tailscale.Client) (name string, err error) { + status, err := tsc.GetStatus(ctx) + if err != nil { + return "", errors.Wrap(err, "couldn't get tailscale daemon status") + } + selfStatus := status.Self + if selfStatus == nil { + return "", nil + } + return selfStatus.DNSName, nil +} diff --git a/internal/app/server/routes/internet/conn-profiles.go b/internal/app/server/routes/internet/conn-profiles.go index 80526b9..3b64245 100644 --- a/internal/app/server/routes/internet/conn-profiles.go +++ b/internal/app/server/routes/internet/conn-profiles.go @@ -315,6 +315,8 @@ func updateConnProfile( if err := checkConnProfile(formValues); err != nil { return err } + // TODO: if the conn profile is generated from drop-in files and the updateType is safe, then also + // use the sidecar to modify the drop-in files appropriately return nmc.UpdateConnProfileByUUID(ctx, uid, updateType, updateValues) } diff --git a/internal/app/server/routes/routes.go b/internal/app/server/routes/routes.go index da49730..9e757cf 100644 --- a/internal/app/server/routes/routes.go +++ b/internal/app/server/routes/routes.go @@ -47,7 +47,7 @@ func (h *Handlers) Register(er godest.EchoRouter, tsr turbostreams.Router, em go cable.New( h.r, h.globals.Base.ACSigner, h.globals.Base.TSBroker, l, ).Register(er) - home.New(h.r, l).Register(er) + home.New(h.r, h.globals.Identity, h.globals.Versioning, h.globals.Tailscale, l).Register(er) identity.New(h.r).Register(er) internet.New(h.r, tsh, h.globals.NetworkManager, h.globals.Sidecar, l).Register(er, tsr) h.remote = remote.New(h.r, h.globals.Tailscale) diff --git a/internal/clients/diskusage/du.go b/internal/clients/diskusage/du.go index 60b38ba..3e234f7 100644 --- a/internal/clients/diskusage/du.go +++ b/internal/clients/diskusage/du.go @@ -1,3 +1,4 @@ +// Package diskusage exposes information about the machine's filesystem disk usage package diskusage import ( diff --git a/internal/clients/identity/client.go b/internal/clients/identity/client.go new file mode 100644 index 0000000..00b27d3 --- /dev/null +++ b/internal/clients/identity/client.go @@ -0,0 +1,67 @@ +// Package identity loads and exposes identity information about the machine +package identity + +import ( + "cmp" + "os" + "path" + "strings" + + "github.com/pkg/errors" + "github.com/sargassum-world/godest" +) + +type Config struct { + MachineNamePath string +} + +type Client struct { + Config Config + + l godest.Logger +} + +func NewClient(c Config, l godest.Logger) *Client { + return &Client{ + Config: c, + l: l, + } +} + +func (c *Client) GetMachineName() (name string, err error) { + p := cmp.Or(c.Config.MachineNamePath, "/run/machine-name") + lines, err := readFile(p) + if err != nil { + return "", errors.Wrap(err, "couldn't read machine name file %s") + } + return strings.Join(lines, ""), nil +} + +func readFile(filePath string) (lines []string, err error) { + parent := path.Dir(filePath) + fsys, err := os.OpenRoot(parent) + if err != nil { + return nil, errors.Wrapf(err, "couldn't open directory %s", parent) + } + if lines, err = readLines(fsys, path.Base(filePath)); err != nil { + return nil, errors.Wrapf(err, "couldn't read file %s", filePath) + } + for i, l := range lines { + before, _, _ := strings.Cut(l, "#") + lines[i] = strings.TrimSpace(before) + } + return lines, nil +} + +func readLines(fsys *os.Root, filePath string) ([]string, error) { + contents, err := fsys.ReadFile(filePath) + if err != nil { + return nil, errors.Wrapf(err, "couldn't read file %s", filePath) + } + + return strings.Split(string(contents), "\n"), nil +} + +func (c *Client) GetHostname() (name string, err error) { + return os.Hostname() +} diff --git a/internal/clients/versioning/client.go b/internal/clients/versioning/client.go new file mode 100644 index 0000000..1dbb9fc --- /dev/null +++ b/internal/clients/versioning/client.go @@ -0,0 +1,34 @@ +// Package versioning loads and exposes versioning information about the machine +package versioning + +import ( + "github.com/pkg/errors" + "github.com/sargassum-world/godest" +) + +type Config struct{} + +type Client struct { + Config Config + + l godest.Logger +} + +func NewClient(c Config, l godest.Logger) *Client { + return &Client{ + Config: c, + l: l, + } +} + +type Forklift struct { + Factory string + Current string + Pallet string + UpgradeSource string + Upgrade string +} + +func (c *Client) GetForklift() (f Forklift, err error) { + return Forklift{}, errors.New("unimplemented") +} diff --git a/web/templates/home/index.page.tmpl b/web/templates/home/index.page.tmpl index 5e24115..880e531 100644 --- a/web/templates/home/index.page.tmpl +++ b/web/templates/home/index.page.tmpl @@ -6,9 +6,6 @@ {{define "description"}}Machine system settings{{end}} {{define "content"}} - {{$hostname := .Data.Hostname}} - {{$port := .Data.Port}} -
@@ -42,10 +39,141 @@ manage any attached USB drives and hard drives. +

About this machine

-

- TODO: show versioning info, machine name, etc. -

+

Version

+
+ + + + + + + + + + + + + + + + + + + {{if .Data.ForkliftVersioning.Upgrade}} + + + + + + {{end}} + +
+ + Originally installed + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.Factory}} + {{.Data.ForkliftVersioning.Factory}} + {{else}} + unknown + {{end}} +
+ + Currently booted + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.Current}} + {{.Data.ForkliftVersioning.Current}} + {{else}} + unknown + {{end}} +
+ + Local pallet + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.Pallet}} + {{.Data.ForkliftVersioning.Pallet}} + {{else}} + unknown + {{end}} +
+ + Update source + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.UpgradeSource}} + {{.Data.ForkliftVersioning.UpgradeSource}} + {{else}} + unknown + {{end}} +
Update available + + Update available + {{- /* make template ignore the line break */ -}} + + {{.Data.ForkliftVersioning.Upgrade}}
+
+

Access

+
+ + + + + + + + + + + + + + + {{if not (eq .Data.TailscaleDNS "")}} + + + + + {{end}} + +
+ + Machine name + {{- /* make template ignore the line break */ -}} + + + {{.Data.MachineName}} +
+ + Hostname + {{- /* make template ignore the line break */ -}} + + + {{.Data.Hostname}} +
+ + mDNS domain name + {{- /* make template ignore the line break */ -}} + + + {{.Data.Hostname}}.local +
+ + Remote-access domain name + {{- /* make template ignore the line break */ -}} + + + {{trimSuffix "." .Data.TailscaleDNS}} +
+
+

Boot

A soft reboot speeds up the reboot process by leaving the OS kernel running, while From c910c59992f13589f63f45c8b827b2ebd8673c0a Mon Sep 17 00:00:00 2001 From: Ethan Li Date: Fri, 24 Apr 2026 13:51:49 -0400 Subject: [PATCH 2/5] Fix layout issues with the home page --- web/templates/home/index.page.tmpl | 330 ++++++++++++++--------------- 1 file changed, 164 insertions(+), 166 deletions(-) diff --git a/web/templates/home/index.page.tmpl b/web/templates/home/index.page.tmpl index 880e531..b4924b4 100644 --- a/web/templates/home/index.page.tmpl +++ b/web/templates/home/index.page.tmpl @@ -6,188 +6,186 @@ {{define "description"}}Machine system settings{{end}} {{define "content"}} -

+
-
-

Machine Administration

-

- Welcome! Here you can adjust system-level settings for your machine's operating system. -

-

- Specific pages are available to configure settings for various functionalities: -

-
    -
  • - Internet Access: - connect your machine to the internet. -
  • -
  • - Remote Access: - make your machine available for remote assistance or remote access. -
  • -
  • - Storage Drives: - manage any attached USB drives and hard drives. -
  • -
+

Machine Administration

+

+ Welcome! Here you can adjust system-level settings for your machine's operating system. +

+

+ Specific pages are available to configure settings for various functionalities: +

+
    +
  • + Internet Access: + connect your machine to the internet. +
  • +
  • + Remote Access: + make your machine available for remote assistance or remote access. +
  • +
  • + Storage Drives: + manage any attached USB drives and hard drives. +
  • +
-

About this machine

-

Version

-
- - - - - - - - - - - - - - +

About this machine

+

Identity & access

+
+
- - Originally installed - {{- /* make template ignore the line break */ -}} - - - {{if .Data.ForkliftVersioning.Factory}} - {{.Data.ForkliftVersioning.Factory}} - {{else}} - unknown - {{end}} -
- - Currently booted - {{- /* make template ignore the line break */ -}} - - - {{if .Data.ForkliftVersioning.Current}} - {{.Data.ForkliftVersioning.Current}} - {{else}} - unknown - {{end}} -
- - Local pallet - {{- /* make template ignore the line break */ -}} - - - {{if .Data.ForkliftVersioning.Pallet}} - {{.Data.ForkliftVersioning.Pallet}} - {{else}} - unknown - {{end}} -
+ + + + + + + + + + + + + + {{if not (eq .Data.TailscaleDNS "")}} - {{if .Data.ForkliftVersioning.Upgrade}} - - - - - - {{end}} - -
+ + Machine name + {{- /* make template ignore the line break */ -}} + + + {{.Data.MachineName}} +
+ + Hostname + {{- /* make template ignore the line break */ -}} + + + {{.Data.Hostname}} +
+ + mDNS domain name + {{- /* make template ignore the line break */ -}} + + + {{.Data.Hostname}}.local +
- - Update source + + Remote-access domain name {{- /* make template ignore the line break */ -}} - {{if .Data.ForkliftVersioning.UpgradeSource}} - {{.Data.ForkliftVersioning.UpgradeSource}} - {{else}} - unknown - {{end}} + {{trimSuffix "." .Data.TailscaleDNS}}
Update available - - Update available - {{- /* make template ignore the line break */ -}} - - {{.Data.ForkliftVersioning.Upgrade}}
-
-

Access

-
- - - - - - - - - - - + {{end}} + +
- - Machine name - {{- /* make template ignore the line break */ -}} - - - {{.Data.MachineName}} -
- - Hostname - {{- /* make template ignore the line break */ -}} - - - {{.Data.Hostname}} -
+
+

Version

+
+ + + + + + + + + + + + + + + + + + + {{if .Data.ForkliftVersioning.Upgrade}} + + - + - {{if not (eq .Data.TailscaleDNS "")}} - - - - - {{end}} - -
+ + Originally installed + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.Factory}} + {{.Data.ForkliftVersioning.Factory}} + {{else}} + unknown + {{end}} +
+ + Currently booted + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.Current}} + {{.Data.ForkliftVersioning.Current}} + {{else}} + unknown + {{end}} +
+ + Local pallet + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.Pallet}} + {{.Data.ForkliftVersioning.Pallet}} + {{else}} + unknown + {{end}} +
+ + Update source + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.UpgradeSource}} + {{.Data.ForkliftVersioning.UpgradeSource}} + {{else}} + unknown + {{end}} +
Update available - - mDNS domain name + + Update available {{- /* make template ignore the line break */ -}} - {{.Data.Hostname}}.local - {{.Data.ForkliftVersioning.Upgrade}}
- - Remote-access domain name - {{- /* make template ignore the line break */ -}} - - - {{trimSuffix "." .Data.TailscaleDNS}} -
-
- -

Boot

-

- A soft reboot speeds up the reboot process by leaving the OS kernel running, while - a full reboot includes a full restart of the kernel and hardware: -

- {{ - template "shared/boot/buttons.partial.tmpl" dict - "basePath" .Meta.BasePath - "redirectTarget" (urlJoin (dict - "path" .Meta.Path - "query" .Meta.Form.Encode - )) - }} + {{end}} + +
+ +

Boot

+

+ A soft reboot speeds up the reboot process by leaving the OS kernel running, while + a full reboot includes a full restart of the kernel and hardware: +

+ {{ + template "shared/boot/buttons.partial.tmpl" dict + "basePath" .Meta.BasePath + "redirectTarget" (urlJoin (dict + "path" .Meta.Path + "query" .Meta.Form.Encode + )) + }}
{{end}} From ac51493078ea99e61392830360425f39fc9ee489 Mon Sep 17 00:00:00 2001 From: Ethan Li Date: Fri, 24 Apr 2026 14:36:00 -0400 Subject: [PATCH 3/5] Show Forklift-related version info loaded from a report YAML file --- internal/app/server/routes/home/routes.go | 5 +- internal/clients/identity/client.go | 14 +- internal/clients/versioning/client.go | 35 ++- web/templates/home/index.page.tmpl | 233 +++++++++--------- .../devices/access-points/table.partial.tmpl | 12 +- 5 files changed, 156 insertions(+), 143 deletions(-) diff --git a/internal/app/server/routes/home/routes.go b/internal/app/server/routes/home/routes.go index 46ded34..d5050f8 100644 --- a/internal/app/server/routes/home/routes.go +++ b/internal/app/server/routes/home/routes.go @@ -68,7 +68,10 @@ type HomeViewData struct { func getHomeViewData( ctx context.Context, vc *versioning.Client, ic *identity.Client, tsc *tailscale.Client, ) (vd HomeViewData, err error) { - vd.ForkliftVersioning, _ = vc.GetForklift() + vd.ForkliftVersioning, err = vc.GetForklift() + if err != nil { + return vd, err + } vd.MachineName, _ = ic.GetMachineName() vd.Hostname, _ = ic.GetHostname() diff --git a/internal/clients/identity/client.go b/internal/clients/identity/client.go index 00b27d3..2ec9b1d 100644 --- a/internal/clients/identity/client.go +++ b/internal/clients/identity/client.go @@ -4,7 +4,6 @@ package identity import ( "cmp" "os" - "path" "strings" "github.com/pkg/errors" @@ -32,18 +31,13 @@ func (c *Client) GetMachineName() (name string, err error) { p := cmp.Or(c.Config.MachineNamePath, "/run/machine-name") lines, err := readFile(p) if err != nil { - return "", errors.Wrap(err, "couldn't read machine name file %s") + return "", errors.Wrapf(err, "couldn't read machine name file %s", p) } return strings.Join(lines, ""), nil } func readFile(filePath string) (lines []string, err error) { - parent := path.Dir(filePath) - fsys, err := os.OpenRoot(parent) - if err != nil { - return nil, errors.Wrapf(err, "couldn't open directory %s", parent) - } - if lines, err = readLines(fsys, path.Base(filePath)); err != nil { + if lines, err = readLines(filePath); err != nil { return nil, errors.Wrapf(err, "couldn't read file %s", filePath) } for i, l := range lines { @@ -53,8 +47,8 @@ func readFile(filePath string) (lines []string, err error) { return lines, nil } -func readLines(fsys *os.Root, filePath string) ([]string, error) { - contents, err := fsys.ReadFile(filePath) +func readLines(filePath string) ([]string, error) { + contents, err := os.ReadFile(filePath) if err != nil { return nil, errors.Wrapf(err, "couldn't read file %s", filePath) } diff --git a/internal/clients/versioning/client.go b/internal/clients/versioning/client.go index 1dbb9fc..55e7f47 100644 --- a/internal/clients/versioning/client.go +++ b/internal/clients/versioning/client.go @@ -2,11 +2,17 @@ package versioning import ( + "cmp" + "os" + "github.com/pkg/errors" "github.com/sargassum-world/godest" + "gopkg.in/yaml.v3" ) -type Config struct{} +type Config struct { + ForkliftPath string +} type Client struct { Config Config @@ -22,13 +28,28 @@ func NewClient(c Config, l godest.Logger) *Client { } type Forklift struct { - Factory string - Current string - Pallet string - UpgradeSource string - Upgrade string + Factory string `yaml:"factory,omitempty"` + Current string `yaml:"current,omitempty"` + Pallet string `yaml:"pallet,omitempty"` + UpgradeSource string `yaml:"upgrade-source,omitempty"` + Upgrade string `yaml:"upgrade,omitempty"` } func (c *Client) GetForklift() (f Forklift, err error) { - return Forklift{}, errors.New("unimplemented") + p := cmp.Or(c.Config.ForkliftPath, "/run/versioning/forklift.yml") + if f, err = readForklift(p); err != nil { + return f, errors.Wrapf(err, "couldn't read Forklift versioning file %s", p) + } + return f, nil +} + +func readForklift(filePath string) (f Forklift, err error) { + bytes, err := os.ReadFile(filePath) + if err != nil { + return f, errors.Wrapf(err, "couldn't read Forklift versioning report %s", filePath) + } + if err = yaml.Unmarshal(bytes, &f); err != nil { + return f, errors.Wrap(err, "couldn't parse Forklift versioning report") + } + return f, nil } diff --git a/web/templates/home/index.page.tmpl b/web/templates/home/index.page.tmpl index b4924b4..c670094 100644 --- a/web/templates/home/index.page.tmpl +++ b/web/templates/home/index.page.tmpl @@ -41,137 +41,132 @@

About this machine

Identity & access

-
- - +
+ + + + + + + + + + + + + + {{if not (eq .Data.TailscaleDNS "")}} - - - - - - - - - - {{if not (eq .Data.TailscaleDNS "")}} - - - - - {{end}} - -
+ + Machine name + {{- /* make template ignore the line break */ -}} + + + {{.Data.MachineName}} +
+ + Hostname + {{- /* make template ignore the line break */ -}} + + + {{.Data.Hostname}} +
+ + mDNS + {{- /* make template ignore the line break */ -}} + + + {{.Data.Hostname}}.local +
- - Machine name + + + Tailscale DNS {{- /* make template ignore the line break */ -}} - {{.Data.MachineName}} + {{trimSuffix "." .Data.TailscaleDNS}}
- - Hostname - {{- /* make template ignore the line break */ -}} - - - {{.Data.Hostname}} -
- - mDNS domain name - {{- /* make template ignore the line break */ -}} - - - {{.Data.Hostname}}.local -
- - Remote-access domain name - {{- /* make template ignore the line break */ -}} - - - {{trimSuffix "." .Data.TailscaleDNS}} -
-
+ {{end}} + +

Version

-
- - - - - - - - - - - - +
- - Originally installed - {{- /* make template ignore the line break */ -}} - - - {{if .Data.ForkliftVersioning.Factory}} - {{.Data.ForkliftVersioning.Factory}} - {{else}} - unknown - {{end}} -
- - Currently booted - {{- /* make template ignore the line break */ -}} - - - {{if .Data.ForkliftVersioning.Current}} - {{.Data.ForkliftVersioning.Current}} - {{else}} - unknown - {{end}} -
- - Local pallet + + + + + + + + + + + + + + + + + + + {{if .Data.ForkliftVersioning.Upgrade}} + + - - - - - + - {{if .Data.ForkliftVersioning.Upgrade}} - - - - - - {{end}} - -
+ + Originally installed + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.Factory}} + {{.Data.ForkliftVersioning.Factory}} + {{else}} + unknown + {{end}} +
+ + Currently booted + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.Current}} + {{.Data.ForkliftVersioning.Current}} + {{else}} + unknown + {{end}} +
+ + Local pallet + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.Pallet}} + {{.Data.ForkliftVersioning.Pallet}} + {{else}} + unknown + {{end}} +
+ + Update source + {{- /* make template ignore the line break */ -}} + + + {{if .Data.ForkliftVersioning.UpgradeSource}} + {{.Data.ForkliftVersioning.UpgradeSource}} + {{else}} + unknown + {{end}} +
+ + Update available {{- /* make template ignore the line break */ -}} - {{if .Data.ForkliftVersioning.Pallet}} - {{.Data.ForkliftVersioning.Pallet}} - {{else}} - unknown - {{end}} -
- - Update source - {{- /* make template ignore the line break */ -}} - - - {{if .Data.ForkliftVersioning.UpgradeSource}} - {{.Data.ForkliftVersioning.UpgradeSource}} - {{else}} - unknown - {{end}} - {{.Data.ForkliftVersioning.Upgrade}}
Update available - - Update available - {{- /* make template ignore the line break */ -}} - - {{.Data.ForkliftVersioning.Upgrade}}
- + {{end}} +

Boot

diff --git a/web/templates/internet/devices/access-points/table.partial.tmpl b/web/templates/internet/devices/access-points/table.partial.tmpl index 97f74db..1b26eeb 100644 --- a/web/templates/internet/devices/access-points/table.partial.tmpl +++ b/web/templates/internet/devices/access-points/table.partial.tmpl @@ -19,13 +19,13 @@ Freq (GHz) {{end}} {{if hasKey $columns "mode"}} - Mode + Mode {{end}} {{if hasKey $columns "security"}} - Security + Security {{end}} {{if hasKey $columns "last-seen"}} - + Last Seen @@ -95,7 +95,7 @@ {{end}} {{if hasKey $columns "mode"}} - + {{$modeInfo := $accessPoint.Mode.Info}} {{if eq $modeInfo.Short "infrastructure"}} @@ -109,7 +109,7 @@ {{end}} {{if hasKey $columns "security"}} - + {{if $accessPoint.RSN.IsNone}} None {{end}} @@ -128,7 +128,7 @@ {{end}} {{if hasKey $columns "last-seen"}} - + {{if eq $accessPoint.LastSeen -1}} never From e91bd7d0d5d2a908f351b0883448e64aa7608151 Mon Sep 17 00:00:00 2001 From: Ethan Li Date: Fri, 24 Apr 2026 14:43:05 -0400 Subject: [PATCH 4/5] Address gosec linter complaints --- internal/clients/identity/client.go | 2 +- internal/clients/versioning/client.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/clients/identity/client.go b/internal/clients/identity/client.go index 2ec9b1d..5387be9 100644 --- a/internal/clients/identity/client.go +++ b/internal/clients/identity/client.go @@ -48,7 +48,7 @@ func readFile(filePath string) (lines []string, err error) { } func readLines(filePath string) ([]string, error) { - contents, err := os.ReadFile(filePath) + contents, err := os.ReadFile(filePath) //nolint:gosec // We trust this file if err != nil { return nil, errors.Wrapf(err, "couldn't read file %s", filePath) } diff --git a/internal/clients/versioning/client.go b/internal/clients/versioning/client.go index 55e7f47..2151f6e 100644 --- a/internal/clients/versioning/client.go +++ b/internal/clients/versioning/client.go @@ -44,7 +44,7 @@ func (c *Client) GetForklift() (f Forklift, err error) { } func readForklift(filePath string) (f Forklift, err error) { - bytes, err := os.ReadFile(filePath) + bytes, err := os.ReadFile(filePath) //nolint:gosec // We trust this file if err != nil { return f, errors.Wrapf(err, "couldn't read Forklift versioning report %s", filePath) } From bc956aaf2b9bb7ff2d01b76e74839f777acb3eef Mon Sep 17 00:00:00 2001 From: Ethan Li Date: Fri, 24 Apr 2026 14:45:53 -0400 Subject: [PATCH 5/5] Run `go mod tidy` --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 383d065..025da10 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/urfave/cli/v3 v3.8.0 github.com/varlink/go v0.4.0 golang.org/x/sync v0.20.0 + gopkg.in/yaml.v3 v3.0.1 tailscale.com v1.96.5 ) @@ -526,7 +527,6 @@ require ( gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/mail.v2 v2.3.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.2 // indirect honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0 // indirect k8s.io/klog/v2 v2.130.1 // indirect