Commit 2dd9add6d0
2dd9add6d0d3a8264418dd74b1b4d3d8dc62c440
parent: d906ddff2e
Verified · cmc
cmc <hello@cleberg.net> · 2026-09-28 23:04 UTC
web: drop CLI commands from four empty states, per the register
issues, milestones, org milestones and releases named a gitbay
command in their empty state, missed when the rest of the pages
switched to the writer-gets-a-web-link-or-nothing register. Issues
links to issues/new for a signed-in viewer (issue create needs no
write access); milestones and org milestones have no web create form
yet, so they state the fact; releases already shows its create form
above the list for a writer with a free tag, so the empty note states
the fact too.
Ref #270
Layout: unified · split
internal/httpd/emptystates_test.go
added
+78
| @@ -0,0 +1,78 @@ |
| 1 | package httpd |
| 2 | |
| 3 | import ( |
| 4 | "html/template" |
| 5 | "strings" |
| 6 | "testing" |
| 7 | |
| 8 | "gitbay.org/gitbay/internal/store" |
| 9 | "gitbay.org/gitbay/internal/web" |
| 10 | ) |
| 11 | |
| 12 | // A signed-in viewer with zero issues gets a link to open one; a |
| 13 | // signed-out visitor gets only the fact, and no CLI command either way |
| 14 | // (#270). |
| 15 | func TestIssuesEmptyStateOffersOpenLinkForViewer(t *testing.T) { |
| 16 | render := func(viewer string) string { |
| 17 | var sb strings.Builder |
| 18 | p := testRepoPage() |
| 19 | p.Viewer = viewer |
| 20 | if err := web.Render(&sb, "issues.html", struct { |
| 21 | repoPage |
| 22 | State string |
| 23 | Label string |
| 24 | Query string |
| 25 | Filters []listFilter |
| 26 | Facets []facetGroup |
| 27 | Issues []store.Issue |
| 28 | LabelColors map[string]template.CSS |
| 29 | Older string |
| 30 | }{repoPage: p, State: "open"}); err != nil { |
| 31 | t.Fatalf("render: %v", err) |
| 32 | } |
| 33 | return sb.String() |
| 34 | } |
| 35 | |
| 36 | anon := render("") |
| 37 | if !strings.Contains(anon, "no open issues") { |
| 38 | t.Errorf("missing empty-state fact:\n%s", anon) |
| 39 | } |
| 40 | if strings.Contains(anon, "issues/new") { |
| 41 | t.Error("signed-out visitor should not see an open-issue link") |
| 42 | } |
| 43 | if strings.Contains(anon, "gitbay issue create") { |
| 44 | t.Error("empty state should not name a CLI command") |
| 45 | } |
| 46 | |
| 47 | viewer := render("alice") |
| 48 | if !strings.Contains(viewer, `href="/krz/gitbay/issues/new"`) { |
| 49 | t.Errorf("signed-in viewer missing the open-issue link:\n%s", viewer) |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | // An empty release list states the fact without a CLI command; the page |
| 54 | // already offers the create form above when the viewer can write and a |
| 55 | // tag is free to release (#270). |
| 56 | func TestReleasesEmptyStateHasNoCLICommand(t *testing.T) { |
| 57 | var sb strings.Builder |
| 58 | if err := web.Render(&sb, "releases.html", struct { |
| 59 | repoPage |
| 60 | Releases []struct { |
| 61 | store.Release |
| 62 | NotesHTML template.HTML |
| 63 | } |
| 64 | FreeTags []string |
| 65 | CanWrite bool |
| 66 | Notice string |
| 67 | Draft *draft |
| 68 | }{repoPage: testRepoPage()}); err != nil { |
| 69 | t.Fatalf("render: %v", err) |
| 70 | } |
| 71 | out := sb.String() |
| 72 | if !strings.Contains(out, "no releases yet") { |
| 73 | t.Errorf("missing empty-state fact:\n%s", out) |
| 74 | } |
| 75 | if strings.Contains(out, "gitbay release create") { |
| 76 | t.Error("empty state should not name a CLI command") |
| 77 | } |
| 78 | } |
internal/web/templates/issues.html
+1 −1
| @@ -25,7 +25,7 @@ |
| 25 | 25 | {{if eq $.State "all"}}<span class="chip {{if eq .State "open"}}chip-open{{else}}chip-done{{end}}">{{.State}}</span>{{end}} |
| 26 | 26 | </li> |
| 27 | 27 | {{else}}{{if .Query}}<li class="empty">no {{if ne .State "all"}}{{.State}} {{end}}issues matching “{{.Query}}”</li> |
| 28 | | {{else}}<li class="empty">no {{if ne .State "all"}}{{.State}} {{end}}issues — open one with <code>gitbay issue create {{.Repo.OwnerName}}/{{.Repo.Name}} --title "..."</code></li>{{end}}{{end}} |
| 28 | {{else}}<li class="empty">no {{if ne .State "all"}}{{.State}} {{end}}issues{{if .Viewer}} — <a href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/issues/new">open one</a>{{end}}</li>{{end}}{{end}} |
| 29 | 29 | </ul> |
| 30 | 30 | {{if .Older}}<p class="pager"><a href="{{.Older}}">older →</a></p>{{end}} |
| 31 | 31 | </div> |
internal/web/templates/milestones.html
+1 −1
| @@ -17,6 +17,6 @@ |
| 17 | 17 | <div class="progress"><div class="bar" style="width: {{.Percent}}%"></div></div> |
| 18 | 18 | </div> |
| 19 | 19 | </li> |
| 20 | | {{else}}<li class="empty">no {{if ne .State "all"}}{{.State}} {{end}}milestones — create one with <code>gitbay milestone create {{.Repo.OwnerName}}/{{.Repo.Name}} "v1.0"</code></li>{{end}} |
| 20 | {{else}}<li class="empty">no {{if ne .State "all"}}{{.State}} {{end}}milestones</li>{{end}} |
| 21 | 21 | </ul> |
| 22 | 22 | {{end}} |
internal/web/templates/orgmilestones.html
+1 −1
| @@ -18,6 +18,6 @@ |
| 18 | 18 | <div class="progress"><div class="bar" style="width: {{.Percent}}%"></div></div> |
| 19 | 19 | </div> |
| 20 | 20 | </li> |
| 21 | | {{else}}<li class="empty">no {{if ne .State "all"}}{{.State}} {{end}}org milestones — create one with <code>gitbay org milestone create {{.Org}} "v1.0"</code></li>{{end}} |
| 21 | {{else}}<li class="empty">no {{if ne .State "all"}}{{.State}} {{end}}org milestones</li>{{end}} |
| 22 | 22 | </ul> |
| 23 | 23 | {{end}} |
internal/web/templates/releases.html
+1 −1
| @@ -51,5 +51,5 @@ |
| 51 | 51 | </tr>{{end}} |
| 52 | 52 | </table>{{end}} |
| 53 | 53 | </article> |
| 54 | | {{else}}<p class="empty-note">no releases yet — tag a commit, push the tag, then <code>gitbay release create {{.Repo.OwnerName}}/{{.Repo.Name}} v1.0</code></p>{{end}} |
| 54 | {{else}}<p class="empty-note">no releases yet</p>{{end}} |
| 55 | 55 | {{end}} |