Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Add one Admin page with status, accounts, and the audit log

43e681d8a5d94567aa9530d32b2c89223c1a17f9 · Keenan Nemetz · 5d ago · parent af018ce8

Add one Admin page with status, accounts, and the audit log

Instance administration was split between the Status and Accounts pages,
and the audit log had no browser view at all. The new /admin page gathers
the status tabs, the account roster, and a read-only audit viewer into one
place with a tab for each, and /status, /runners, and /users redirect to
the tab they named so old links keep working.

The audit reader walks the file backwards a chunk at a time, returns the
newest records first, and shows one extra record to know whether an older
page exists. It skips a line it cannot parse rather than failing the page
and refuses a symlink or a non-regular file, as startup already does.

Refs #198 (01M6MK0NNZ2XR1D5TQKNWYT4HN).

server/web/status.go +18−36

@@ -1,12 +1,13 @@
1 1 package web
2 2
3 // The status page reports how much disk the instance uses, what the LFS pool
4 // contains, and whether people are reading it. It exposes counts and sizes, never
5 // repository contents; /healthz remains the separate liveness probe.
3 // The status tabs on the Admin page report how much disk the instance uses, what
4 // the LFS pool contains, and whether people are reading it. They expose counts and
5 // sizes, never repository contents; /healthz remains the separate liveness probe.
6 6
7 7 import (
8 8 "fmt"
9 9 "net/http"
10 "net/url"
10 11 "strings"
11 12 "sync"
12 13 "time"
@@ -78,30 +79,21 @@ type statusCache struct {
78 79 lfs statusLFSView
79 80 }
80 81
81 func (w *Web) StatusPage(rw http.ResponseWriter, r *http.Request) {
82 if _, ok := w.requireInstanceAdmin(rw, r); !ok {
83 return
84 }
85 tab := statusTab(r.URL.Query().Get("tab"))
86 view := struct {
87 Page
88 Tab string
89 Accounts int
90 Repos int
91 Queued int
92 Running int
93 Runners int
94 Started time.Time
95 Storage statusStorageView
96 LFS statusLFSView
97 Views statusViewsView
98 RunnerErr string
99 RunnerSessions []runnerView
100 RunnerQueue []queueView
101 RunnerWindow string
102 Config *statusConfigView
103 }{Page: w.page(r, "Status"), Tab: tab, Started: w.Started}
82 // StatusRedirect keeps old links working: the status tabs now live on the Admin
83 // page, and the tab name is preserved so a bookmark lands on the same section.
84 func (w *Web) StatusRedirect(rw http.ResponseWriter, r *http.Request) {
85 target := "/admin"
86 if tab := adminTabFrom(r.URL.Query().Get("tab")); tab != "overview" {
87 target += "?tab=" + url.QueryEscape(tab)
88 }
89 http.Redirect(rw, r, target, http.StatusMovedPermanently)
90 }
104 91
92 // fillStatusView reads the instance state the status tabs show. It is a method on
93 // the Admin view because those tabs are sections of that page, not a page of
94 // their own; each branch reads only what its tab renders.
95 func (w *Web) fillStatusView(view *adminPageView) {
96 tab := view.Tab
105 97 if tab == "overview" {
106 98 if w.Ident != nil {
107 99 view.Accounts = w.Ident.Snapshot().Count
@@ -161,16 +153,6 @@ func (w *Web) StatusPage(rw http.ResponseWriter, r *http.Request) {
161 153 if tab == "configuration" && w.Cfg != nil {
162 154 view.Config = w.statusConfig()
163 155 }
164 w.render(rw, "status", view, 0)
165 }
166
167 func statusTab(raw string) string {
168 switch raw {
169 case "storage", "runners", "configuration":
170 return raw
171 default:
172 return "overview"
173 }
174 156 }
175 157
176 158 func (w *Web) instanceStats() (storage.Stats, error, statusLFSView) {