Commit 7756246a08

7756246a087737fe2633ac6e794424e139120737

parent: 4e7f0573d0

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-17 16:03 UTC

web: repository overview leads with the files

Ref #218
e2e/bookmarks_test.go +1 −1
@@ -61,7 +61,7 @@ func TestBookmarks(t *testing.T) {
6161 }
6262
6363 // The count is public and shows on the repository page.
64 if _, body := inst.get(t, "/alice/app"); !strings.Contains(body, "1</strong> bookmark") {
64 if _, body := inst.get(t, "/alice/app"); !strings.Contains(body, "1</b> bookmark") {
6565 t.Errorf("count not on the repo page:\n%s", body)
6666 }
6767
e2e/design_test.go +28
@@ -335,3 +335,31 @@ func TestAuthorNamesResolve(t *testing.T) {
335335 t.Fatalf("tipbar name is not a link:\n%s", tree)
336336 }
337337}
338
339// TestTreeSearchCodeAndClone: the overview links "Search code", not
340// "Find file", and shows two labelled clone blocks after the file table.
341func TestTreeSearchCodeAndClone(t *testing.T) {
342 inst := startInstance(t)
343 key := inst.newKey(t, "alice")
344 inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub")
345 inst.ssh(t, key, "", "repo", "create", "alice/app")
346 work := t.TempDir()
347 env := inst.gitEnv(key)
348 mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
349 dir := filepath.Join(work, "w")
350 os.WriteFile(filepath.Join(dir, "README.md"), []byte("# app\n"), 0o644)
351 mustGit(t, dir, env, "checkout", "-q", "-b", "main")
352 mustGit(t, dir, env, "add", ".")
353 mustGit(t, dir, env, "commit", "-q", "-m", "init")
354 mustGit(t, dir, env, "push", "-q", "origin", "main")
355 _, body := inst.get(t, "/alice/app")
356 if strings.Contains(body, ">Find file<") || !strings.Contains(body, ">Search code<") {
357 t.Error("overview still says Find file")
358 }
359 if i, j := strings.Index(body, `<table class="tree">`), strings.Index(body, `<div class="clone">`); i < 0 || j < i {
360 t.Error("clone block does not follow the file table")
361 }
362 if !strings.Contains(body, `<label>SSH</label>`) || !strings.Contains(body, `<label>HTTPS</label>`) {
363 t.Error("clone blocks are not labelled")
364 }
365}
e2e/facts_test.go +3 −3
@@ -46,9 +46,9 @@ func TestRepoFacts(t *testing.T) {
4646 t.Fatalf("repo home: %d", status)
4747 }
4848 for _, want := range []string{
49 "<strong>2</strong> commit", // both commits counted
50 "<strong>1</strong> branch",
51 "<strong>1</strong> tag",
49 "<b>2</b> commit", // both commits counted
50 "<b>1</b> branch",
51 "<b>1</b> tag",
5252 "0BSD", // license detected and surfaced
5353 "Go", // language census
5454 "Shell", // and it is not single-language
internal/web/static/style.css +2
@@ -1262,6 +1262,7 @@ a.memberchip .role { color: var(--muted); }
12621262.pathbar { display: flex; align-items: center; gap: var(--sp-2) var(--sp-3); margin: 0 0 var(--sp-3); flex-wrap: wrap; font-size: var(--fs-2); }
12631263.pathbar .spacer { flex: 1; }
12641264.pathbar .actions { display: flex; gap: var(--sp-2); }
1265.pathbar .acts { display: flex; gap: var(--sp-2); }
12651266.crumbs { color: var(--muted); }
12661267.crumbs a { color: var(--link); }
12671268.crumbs strong { color: var(--fg); }
@@ -1323,6 +1324,7 @@ details.refmenu .refdrop a.allrefs {
13231324 color: var(--muted);
13241325}
13251326.clone { margin: 0 0 var(--sp-3); }
1327.facts .about { min-width: 0; }
13261328.clone label { font-size: var(--fs-1); color: var(--muted); font-weight: 500; margin-bottom: 2px; }
13271329.clone pre { margin-bottom: var(--sp-3); user-select: all; }
13281330.factgrid { display: grid; grid-template-columns: repeat(4, auto); gap: var(--sp-2) var(--sp-4); font-size: var(--fs-2); margin-bottom: var(--sp-3); }
internal/web/templates/tree.html +28 −26
@@ -6,35 +6,15 @@
66<div class="pathbar">
77 {{template "refmenu" .}}
88 <span class="crumbs"><a href="/{{.Repo.OwnerName}}/{{.Repo.Name}}">{{.Repo.Name}}</a>/{{range .Crumbs}}<a href="{{.URL}}">{{.Name}}</a>/{{end}}</span>
9 <span class="spacer"></span>
10 <a class="act" href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/search">Find file</a>
11 <a class="act" href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/log/{{.Ref}}">History</a>
12 <a class="act" href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/archive/{{.Ref}}.tar.gz">Download</a>
9 <div class="acts">
10 <a class="button btn" href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/search">Search code</a>
11 <a class="button btn" href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/log/{{.Ref}}">History</a>
12 <a class="button btn" href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/archive/{{.Ref}}.tar.gz">Download</a>
13 </div>
1314</div>
14{{if .Entries}}<p class="clone">Clone: <code>git clone {{.SSHCloneURL}}</code> · <code>git clone {{.CloneURL}}</code></p>{{end}}
15{{if .Facts.Commits}}{{$r := printf "/%s/%s" .Repo.OwnerName .Repo.Name}}<div class="facts">
16 <p class="counts">
17 <a href="{{$r}}/log/{{.Ref}}"><strong>{{.Facts.Commits}}</strong> commit{{if ne .Facts.Commits 1}}s{{end}}</a>
18 <a href="{{$r}}/refs"><strong>{{.Facts.Branches}}</strong> branch{{if ne .Facts.Branches 1}}es{{end}}</a>
19 <a href="{{$r}}/refs"><strong>{{.Facts.Tags}}</strong> tag{{if ne .Facts.Tags 1}}s{{end}}</a>
20 {{if .Facts.Bookmarks}}<span><strong>{{.Facts.Bookmarks}}</strong> bookmark{{if ne .Facts.Bookmarks 1}}s{{end}}</span>{{end}}
21 {{with .Facts.License}}<span class="fact">{{.}}</span>{{end}}
22 {{with .Facts.Release}}<a href="{{$r}}/releases">latest <strong>{{.}}</strong></a>{{end}}
23 {{with .Facts.Build}}<a href="{{$r}}/builds">build <span class="badge badge-{{.}}">{{.}}</span></a>{{end}}
24 </p>
25 {{with .Facts.Languages}}<p class="langbar" aria-hidden="true">{{range .}}<span class="lang lang-{{slug .Name}}" style="width:{{pct .Percent}}%"></span>{{end}}</p>
26 <p class="langs">{{range .}}<span class="lang-name"><span class="dot lang-{{slug .Name}}"></span>{{.Name}} <span class="muted">{{pct .Percent}}%</span></span>{{end}}</p>{{end}}
27 {{with .Facts.Contributors}}<p class="contribs"><span class="label">{{len .}} contributor{{if ne (len .) 1}}s{{end}}</span>{{range .}}{{template "authorname" dict "Name" .Name "User" .User "Email" .Title}}{{end}}</p>{{end}}
28</div>{{end}}
29{{with .Tip}}{{if .SHA}}<div class="tipbar">
30 <span class="who">{{template "authorname" dict "Name" .Author "User" .User "Email" .Email}}</span>
31 <a class="subject" href="/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/commit/{{.SHA}}">{{.Subject}}</a>
32 <span class="spacer"></span>
33 <a class="sha" href="/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/commit/{{.SHA}}"><code>{{short .SHA}}</code></a>
34 <span class="age"{{if not .When.IsZero}} title="{{whenT .When}}"{{end}}>{{ago .When}}</span>
35</div>{{end}}{{end}}
3615<div class="tablewrap">
3716<table class="tree">
17{{with .Tip}}{{if .SHA}}<tr class="tipbar"><td colspan="3"><span class="who">{{template "authorname" dict "Name" .Author "User" .User "Email" .Email}}</span> <a class="subject" href="/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/commit/{{.SHA}}">{{.Subject}}</a><span class="spacer"></span><a class="sha" href="/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/commit/{{.SHA}}"><code>{{short .SHA}}</code></a> <span class="age"{{if not .When.IsZero}} title="{{whenT .When}}"{{end}}>{{ago .When}}</span></td></tr>{{end}}{{end}}
3818<tr class="cols"><th scope="col">name</th><th scope="col" class="lastcommit">last commit</th><th scope="col" class="age">updated</th></tr>
3919{{range .Entries}}{{$c := index $.LastCommits .Name}}<tr>
4020 {{if eq .Type "tree"}}<td class="name dir"><a href="/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/tree/{{$.Ref}}/{{$.Prefix}}{{.Name}}">{{.Name}}/</a></td>
@@ -49,4 +29,26 @@
4929<div class="cardhead"><a href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/blob/{{.Ref}}/{{.Prefix}}{{.ReadmeName}}">{{.ReadmeName}}</a></div>
5030<div class="rendered">{{.ReadmeHTML}}</div>
5131</section>{{end}}
32{{if .Entries}}<div class="facts">
33 <div class="clone">
34 <h2>Clone</h2>
35 <label>SSH</label><pre><code>git clone {{.SSHCloneURL}}</code></pre>
36 <label>HTTPS</label><pre><code>git clone {{.CloneURL}}</code></pre>
37 </div>
38 {{if .Facts.Commits}}{{$r := printf "/%s/%s" .Repo.OwnerName .Repo.Name}}<div class="about">
39 <h2>About</h2>
40 <div class="factgrid">
41 <a href="{{$r}}/log/{{.Ref}}"><b>{{.Facts.Commits}}</b> commit{{if ne .Facts.Commits 1}}s{{end}}</a>
42 <a href="{{$r}}/refs"><b>{{.Facts.Branches}}</b> branch{{if ne .Facts.Branches 1}}es{{end}}</a>
43 <a href="{{$r}}/refs"><b>{{.Facts.Tags}}</b> tag{{if ne .Facts.Tags 1}}s{{end}}</a>
44 {{if .Facts.Bookmarks}}<span><b>{{.Facts.Bookmarks}}</b> bookmark{{if ne .Facts.Bookmarks 1}}s{{end}}</span>{{end}}
45 {{with .Facts.License}}<span class="fact">{{.}}</span>{{end}}
46 {{with .Facts.Release}}<a href="{{$r}}/releases">latest <b>{{.}}</b></a>{{end}}
47 {{with .Facts.Build}}<a href="{{$r}}/builds">build <span class="badge badge-{{.}}">{{.}}</span></a>{{end}}
48 </div>
49 {{with .Facts.Languages}}<p class="langbar" aria-hidden="true">{{range .}}<span class="lang lang-{{slug .Name}}" style="width:{{pct .Percent}}%"></span>{{end}}</p>
50 <p class="langs">{{range .}}<span class="lang-name"><span class="dot lang-{{slug .Name}}"></span>{{.Name}} <span class="muted">{{pct .Percent}}%</span></span>{{end}}</p>{{end}}
51 {{with .Facts.Contributors}}<p class="contribs"><span class="label">{{len .}} contributor{{if ne (len .) 1}}s{{end}}</span>{{range .}}{{template "authorname" dict "Name" .Name "User" .User "Email" .Title}}{{end}}</p>{{end}}
52 </div>{{end}}
53</div>{{end}}
5254{{end}}