Commit 3aa67f5b23
3aa67f5b235467c575e82131cc73858de5032d14
parent: e1a9f52605
Verified · cmc
cmc <hello@cleberg.net> · 2026-09-19 22:52 UTC
web: the dashboard's counts and build state in text
The pinned column carried its two counts and the build state in colour
and a title only, and the legend under it is hidden below 80rem. Each
count and the dot now carry visually hidden text naming what it is, and
the title stays.
A cancelled build read as the pending orange, because everything that
was not success or failure fell to pend. It reads neutral now, the way
.chip.check-cancelled does; pending and running keep the orange.
The tiles run in the queues' order, so the first tile no longer links to
the last section.
Two elements on the repository settings page answered to #deps, one of
them now the target of the section column's link. The checkbox is
deps-enabled; the section keeps the anchor.
Ref #226
internal/httpd/dashpins_test.go
+20 −2
| @@ -24,7 +24,10 @@ func TestDashboardTilesAndPins(t *testing.T) { |
| 24 | 24 | MRs []store.DashboardItem |
| 25 | 25 | Issues []store.DashboardItem |
| 26 | 26 | Feed []feedLine |
| 27 | | }{base, "dashboard", []pinnedRow{{Owner: "krz", Name: "gitbay", Issues: 3, MRs: 0, Build: "success"}}, nil, nil, nil, |
| 27 | }{base, "dashboard", []pinnedRow{ |
| 28 | {Owner: "krz", Name: "gitbay", Issues: 3, MRs: 0, Build: "success"}, |
| 29 | {Owner: "krz", Name: "old", Build: "cancelled"}, |
| 30 | }, nil, nil, nil, |
| 28 | 31 | []store.DashboardItem{{RepoPath: "krz/gitbay", Number: 1, Title: "one", Author: "alice", State: "open"}}, nil}) |
| 29 | 32 | if err != nil { |
| 30 | 33 | t.Fatal(err) |
| @@ -34,7 +37,11 @@ func TestDashboardTilesAndPins(t *testing.T) { |
| 34 | 37 | `<div class="dashgrid">`, |
| 35 | 38 | `<aside class="dashpins" aria-label="Pinned repositories">`, |
| 36 | 39 | `<span class="owner">krz/</span>gitbay</a>`, |
| 37 | | `<b class="wants">3</b>`, `<span class="dot ok"></span>`, |
| 40 | `<b class="wants">3 <span class="vh">open issues</span></b>`, |
| 41 | `<b>0 <span class="vh">open merge requests</span></b>`, |
| 42 | `<span class="dot ok"><span class="vh">last build success</span></span>`, |
| 43 | // cancelled is neutral, not the pending orange |
| 44 | `<span class="dot"><span class="vh">last build cancelled</span></span>`, |
| 38 | 45 | `<a class="tile wants" href="#issues"><b>1</b><span>open issues</span></a>`, |
| 39 | 46 | `<div class="tile"><b>0</b><span>waiting on your review</span></div>`, |
| 40 | 47 | `<div class="tile"><b>0</b><span>assigned to you</span></div>`, |
| @@ -49,4 +56,15 @@ func TestDashboardTilesAndPins(t *testing.T) { |
| 49 | 56 | if strings.Contains(out, `<h2 class="empty">`) { |
| 50 | 57 | t.Error("an empty queue still renders as a heading; the tile carries it") |
| 51 | 58 | } |
| 59 | // The tiles run in the queues' order, so the first tile does not jump |
| 60 | // to the last section. |
| 61 | at := 0 |
| 62 | for _, label := range []string{"waiting on your review", "assigned to you", "open merge requests", "open issues"} { |
| 63 | i := strings.Index(out, "<span>"+label+"</span>") |
| 64 | if i < at { |
| 65 | t.Errorf("tile %q is out of order", label) |
| 66 | break |
| 67 | } |
| 68 | at = i |
| 69 | } |
| 52 | 70 | } |
internal/web/templates/dashboard.html
+2 −2
| @@ -23,7 +23,7 @@ |
| 23 | 23 | <aside class="dashpins" aria-label="Pinned repositories"> |
| 24 | 24 | <h2 class="colhead">Pinned</h2> |
| 25 | 25 | {{if .Pins}}<ul class="pins"> |
| 26 | | {{range .Pins}}<li><a href="/{{.Owner}}/{{.Name}}"><span class="owner">{{.Owner}}/</span>{{.Name}}</a><span class="n" title="{{.Issues}} open issue{{if ne .Issues 1}}s{{end}}, {{.MRs}} open merge request{{if ne .MRs 1}}s{{end}}{{with .Build}}, last build {{.}}{{end}}">{{if .Issues}}<b class="wants">{{.Issues}}</b>{{else}}<b>0</b>{{end}} {{if .MRs}}<b class="wants">{{.MRs}}</b>{{else}}<b>0</b>{{end}} <span class="dot{{if eq .Build "success"}} ok{{else if eq .Build "failure"}} bad{{else if .Build}} pend{{end}}"></span></span></li> |
| 26 | {{range .Pins}}<li><a href="/{{.Owner}}/{{.Name}}"><span class="owner">{{.Owner}}/</span>{{.Name}}</a><span class="n" title="{{.Issues}} open issue{{if ne .Issues 1}}s{{end}}, {{.MRs}} open merge request{{if ne .MRs 1}}s{{end}}{{with .Build}}, last build {{.}}{{end}}"><b{{if .Issues}} class="wants"{{end}}>{{.Issues}} <span class="vh">open issues</span></b> <b{{if .MRs}} class="wants"{{end}}>{{.MRs}} <span class="vh">open merge requests</span></b> <span class="dot{{if eq .Build "success"}} ok{{else if or (eq .Build "failure") (eq .Build "error")}} bad{{else if or (eq .Build "pending") (eq .Build "running")}} pend{{end}}"><span class="vh">{{with .Build}}last build {{.}}{{else}}no builds{{end}}</span></span></span></li> |
| 27 | 27 | {{end}}</ul> |
| 28 | 28 | <p class="meta">issues · merge requests · last build</p> |
| 29 | 29 | {{else}}<p class="none">Nothing pinned yet. Press Pin on a repository.</p>{{end}} |
| @@ -32,10 +32,10 @@ |
| 32 | 32 | <section class="dashmain"> |
| 33 | 33 | <h1>Dashboard</h1> |
| 34 | 34 | <div class="tiles"> |
| 35 | | {{template "tile" dict "N" (len .Issues) "ID" "issues" "Label" "open issues"}} |
| 36 | 35 | {{template "tile" dict "N" (len .Reviews) "ID" "reviews" "Label" "waiting on your review"}} |
| 37 | 36 | {{template "tile" dict "N" (len .Assigned) "ID" "assigned" "Label" "assigned to you"}} |
| 38 | 37 | {{template "tile" dict "N" (len .MRs) "ID" "mrs" "Label" "open merge requests"}} |
| 38 | {{template "tile" dict "N" (len .Issues) "ID" "issues" "Label" "open issues"}} |
| 39 | 39 | </div> |
| 40 | 40 | {{if .Reviews}}{{template "queue" dict "ID" "reviews" "Title" "Waiting on your review" "Items" .Reviews "Kind" "mrs" "Empty" "Nothing waiting on you"}}{{end}} |
| 41 | 41 | {{if .Assigned}}{{template "queue" dict "ID" "assigned" "Title" "Assigned to you" "Items" .Assigned "Kind" "issues" "Empty" "Nothing assigned to you"}}{{end}} |
internal/web/templates/settings.html
+2 −2
| @@ -148,8 +148,8 @@ |
| 148 | 148 | <section id="deps"><h2>Dependencies</h2> |
| 149 | 149 | <form method="post" action="{{$base}}" class="setform"> |
| 150 | 150 | <input type="hidden" name="field" value="deps"> |
| 151 | | <div><label for="deps">Check for updates</label><p class="hint">Compares the manifests on <code>{{.Repo.DefaultBranch}}</code> against proxy.golang.org, npm, crates.io, and PyPI once a day, and tracks what is behind in an issue. Checking a private repository tells those registries what it depends on.</p></div> |
| 152 | | <div class="check"><input type="checkbox" id="deps" name="deps" value="on"{{if .DepsEnabled}} checked{{end}}></div> |
| 151 | <div><label for="deps-enabled">Check for updates</label><p class="hint">Compares the manifests on <code>{{.Repo.DefaultBranch}}</code> against proxy.golang.org, npm, crates.io, and PyPI once a day, and tracks what is behind in an issue. Checking a private repository tells those registries what it depends on.</p></div> |
| 152 | <div class="check"><input type="checkbox" id="deps-enabled" name="deps" value="on"{{if .DepsEnabled}} checked{{end}}></div> |
| 153 | 153 | <div><button type="submit" class="btn">Save</button></div> |
| 154 | 154 | </form> |
| 155 | 155 | {{if .DepsEnabled}} |