web: dashboard shows populated queues first and says what the open lists cover !405

merged merged by cmc on 2026-09-18 06:06 UTC · krz/gitbay:stack-222 into main

3 files changed, +30 −13

Layout: unified · split

e2e/dashboard_test.go +16 −3
@@ -97,12 +97,26 @@ func TestDashboard(t *testing.T) {
97 "Waiting on your review", "Assigned to you", "Recent activity", 97 "Waiting on your review", "Assigned to you", "Recent activity",
98 "from bob", "alice/app!1", "todo one", "alice/app#1", 98 "from bob", "alice/app!1", "todo one", "alice/app#1",
99 `href="/alice/app/mrs/1"`, `href="/alice/app/issues/1"`, 99 `href="/alice/app/mrs/1"`, `href="/alice/app/issues/1"`,
100 "Yours anywhere, and every one in a repository you can write to.",
100 } { 101 } {
101 if !strings.Contains(body, want) { 102 if !strings.Contains(body, want) {
102 t.Errorf("dashboard missing %q", want) 103 t.Errorf("dashboard missing %q", want)
103 } 104 }
104 } 105 }
105 106
107 // D01: alice has nothing assigned to her, so that section condenses to
108 // an empty heading, and populated sections (she has a review waiting)
109 // sort before it.
110 emptyHeading := `<h2 class="empty">Assigned to you <span class="count">0</span></h2>`
111 if !strings.Contains(body, emptyHeading) {
112 t.Fatalf("dashboard missing condensed empty heading %q:\n%s", emptyHeading, body)
113 }
114 reviewIdx := strings.Index(body, "Waiting on your review")
115 assignedIdx := strings.Index(body, emptyHeading)
116 if reviewIdx < 0 || assignedIdx < 0 || reviewIdx > assignedIdx {
117 t.Fatalf("populated heading should come before the empty one: review=%d assigned=%d", reviewIdx, assignedIdx)
118 }
119
106 // The diff has its own view rather than a fold at the foot of the 120 // The diff has its own view rather than a fold at the foot of the
107 // conversation: the default view offers it, and asking for it renders 121 // conversation: the default view offers it, and asking for it renders
108 // the stat line and the patch. 122 // the stat line and the patch.
@@ -338,8 +352,7 @@ func TestDashboardQueues(t *testing.T) {
338 t.Fatalf("review: %s", errOut) 352 t.Fatalf("review: %s", errOut)
339 } 353 }
340 _, after := browserGet(t, inst.login(t, aliceKey), inst.base()+"/") 354 _, after := browserGet(t, inst.login(t, aliceKey), inst.base()+"/")
341 queue := after[strings.Index(after, "Waiting on your review"):strings.Index(after, "Assigned to you")] 355 if !strings.Contains(after, `<h2 class="empty">Waiting on your review <span class="count">0</span></h2>`) {
342 if strings.Contains(queue, "needs a look") { 356 t.Fatalf("reviewed MR still waiting:\n%s", after)
343 t.Fatalf("reviewed MR still waiting:\n%s", queue)
344 } 357 }
345} 358}
internal/web/static/style.css +1
@@ -1393,6 +1393,7 @@ pre.quickstart { margin: 0 0 var(--sp-4); }
1393.profilehead .meta { margin: var(--sp-1) 0 0; } 1393.profilehead .meta { margin: var(--sp-1) 0 0; }
1394.activity { margin-bottom: var(--sp-5); } 1394.activity { margin-bottom: var(--sp-5); }
1395h2 .count { background: none; color: var(--muted); font-weight: 400; font-size: var(--fs-2); margin-left: var(--sp-2); padding: 0; } 1395h2 .count { background: none; color: var(--muted); font-weight: 400; font-size: var(--fs-2); margin-left: var(--sp-2); padding: 0; }
1396h2.empty { color: var(--muted); font-weight: 500; font-size: var(--fs-3); margin: var(--sp-2) 0; }
1396/* 53 week columns x 7 day rows, tinted with the link blue */ 1397/* 53 week columns x 7 day rows, tinted with the link blue */
1397.actgraph-scroll { overflow-x: auto; padding-bottom: var(--sp-1); } 1398.actgraph-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
1398.actgraph { display: flex; gap: 3px; width: max-content; padding-top: 18px; } 1399.actgraph { display: flex; gap: 3px; width: max-content; padding-top: 18px; }
internal/web/templates/dashboard.html +13 −10
@@ -10,23 +10,26 @@
10{{else}}<li class="empty">{{$.Empty}}</li>{{end}} 10{{else}}<li class="empty">{{$.Empty}}</li>{{end}}
11</ul> 11</ul>
12{{end}} 12{{end}}
13{{define "queue"}}
14<h2>{{$.Title}} <span class="count">{{len $.Items}}</span></h2>
15{{if $.Hint}}<p class="hint">{{$.Hint}}</p>{{end}}
16{{template "itemlist" dict "Items" $.Items "Kind" $.Kind "Empty" $.Empty}}
17{{end}}
13{{define "content"}} 18{{define "content"}}
14<h1>Dashboard</h1> 19<h1>Dashboard</h1>
15 20
16<div class="withaside"> 21<div class="withaside">
17<div class="mainside"> 22<div class="mainside">
18 23
19<h2>Waiting on your review <span class="count">{{len .Reviews}}</span></h2> 24{{if .Reviews}}{{template "queue" dict "Title" "Waiting on your review" "Items" .Reviews "Kind" "mrs" "Empty" "Nothing waiting on you"}}{{end}}
20{{template "itemlist" dict "Items" .Reviews "Kind" "mrs" "Empty" "Nothing waiting on you"}} 25{{if .Assigned}}{{template "queue" dict "Title" "Assigned to you" "Items" .Assigned "Kind" "issues" "Empty" "Nothing assigned to you"}}{{end}}
21 26{{if .MRs}}{{template "queue" dict "Title" "Open merge requests" "Items" .MRs "Kind" "mrs" "Empty" "No open merge requests" "Hint" "Yours anywhere, and every one in a repository you can write to."}}{{end}}
22<h2>Assigned to you <span class="count">{{len .Assigned}}</span></h2> 27{{if .Issues}}{{template "queue" dict "Title" "Open issues" "Items" .Issues "Kind" "issues" "Empty" "No open issues" "Hint" "Yours anywhere, and every one in a repository you can write to."}}{{end}}
23{{template "itemlist" dict "Items" .Assigned "Kind" "issues" "Empty" "Nothing assigned to you"}}
24
25<h2>Open merge requests <span class="count">{{len .MRs}}</span></h2>
26{{template "itemlist" dict "Items" .MRs "Kind" "mrs" "Empty" "No open merge requests"}}
27 28
28<h2>Open issues <span class="count">{{len .Issues}}</span></h2> 29{{if not .Reviews}}<h2 class="empty">Waiting on your review <span class="count">0</span></h2>{{end}}
29{{template "itemlist" dict "Items" .Issues "Kind" "issues" "Empty" "No open issues"}} 30{{if not .Assigned}}<h2 class="empty">Assigned to you <span class="count">0</span></h2>{{end}}
31{{if not .MRs}}<h2 class="empty">Open merge requests <span class="count">0</span></h2>{{end}}
32{{if not .Issues}}<h2 class="empty">Open issues <span class="count">0</span></h2>{{end}}
30 33
31</div> 34</div>
32 35