fix: display full branch names in breadcrumbs

Amolith and Crush created

Previously, the breadcrumb navigation would truncate all refs using
shortHash, causing branch names like "generate-promo-codes" to display
as just "generate".

This change adds an IsCommitHash field to template data structures and
updates the templates to conditionally apply shortHash only for actual
commit hashes while showing full names for branches and tags.

Implements: bug-bf0175a
Co-Authored-By: Crush <crush@charm.land>

Change summary

pkg/web/templates/blob.html | 2 +-
pkg/web/templates/tree.html | 4 ++--
pkg/web/webui_blob.go       | 6 ++++--
pkg/web/webui_commits.go    | 2 +-
pkg/web/webui_git.go        | 7 ++++---
pkg/web/webui_tree.go       | 4 +++-
6 files changed, 15 insertions(+), 10 deletions(-)

Detailed changes

pkg/web/templates/blob.html 🔗

@@ -2,7 +2,7 @@
 <nav aria-label="breadcrumb">
   <ul>
     <li><a href="/{{.Repo.Name}}">{{.Repo.Name}}</a></li>
-    <li><a href="/{{.Repo.Name}}/tree/{{.Ref}}">{{.Ref | shortHash}}</a></li>
+    <li><a href="/{{.Repo.Name}}/tree/{{.Ref}}">{{if .IsCommitHash}}{{.Ref | shortHash}}{{else}}{{.Ref}}{{end}}</a></li>
     {{range $i, $part := splitPath .Path}}
     <li{{if eq $i (dec (len (splitPath $.Path)))}} aria-current="page"{{end}}>
       {{if eq $i (dec (len (splitPath $.Path)))}}

pkg/web/templates/tree.html 🔗

@@ -3,7 +3,7 @@
   <ul>
     <li><a href="/{{.Repo.Name}}">{{.Repo.Name}}</a></li>
     {{if ne .Path "."}}
-    <li><a href="/{{.Repo.Name}}/tree/{{.Ref}}">{{.Ref | shortHash}}</a></li>
+    <li><a href="/{{.Repo.Name}}/tree/{{.Ref}}">{{if .IsCommitHash}}{{.Ref | shortHash}}{{else}}{{.Ref}}{{end}}</a></li>
     {{range $i, $part := splitPath .Path}}
     <li{{if eq $i (dec (len (splitPath $.Path)))}} aria-current="page"{{end}}>
       {{if eq $i (dec (len (splitPath $.Path)))}}
@@ -14,7 +14,7 @@
     </li>
     {{end}}
     {{else}}
-    <li>{{.Ref | shortHash}}</li>
+    <li>{{if .IsCommitHash}}{{.Ref | shortHash}}{{else}}{{.Ref}}{{end}}</li>
     {{end}}
   </ul>
 </nav>

pkg/web/webui_blob.go 🔗

@@ -30,6 +30,7 @@ type BlobData struct {
 	ShowSource    bool
 	ActiveTab     string
 	ServerName    string
+	IsCommitHash  bool
 }
 
 // repoBlob handles file content view.
@@ -55,7 +56,7 @@ func repoBlob(w http.ResponseWriter, r *http.Request) {
 	refAndPath := vars["refAndPath"]
 	ref, path := parseRefAndPath(gr, refAndPath)
 
-	refObj, err := resolveAndBuildRef(gr, ref)
+	refObj, isCommitHash, err := resolveAndBuildRef(gr, ref)
 	if err != nil {
 		logger.Debug("failed to resolve ref or commit", "repo", repo.Name(), "ref", ref, "err", err)
 		renderNotFound(w, r)
@@ -112,6 +113,7 @@ func repoBlob(w http.ResponseWriter, r *http.Request) {
 		ShowSource:    showSource,
 		ActiveTab:     "tree",
 		ServerName:    cfg.Name,
+		IsCommitHash:  isCommitHash,
 	}
 
 	renderHTML(w, "blob.html", data)
@@ -134,7 +136,7 @@ func repoBlobRaw(w http.ResponseWriter, r *http.Request) {
 	refAndPath := vars["refAndPath"]
 	ref, path := parseRefAndPath(gr, refAndPath)
 
-	refObj, err := resolveAndBuildRef(gr, ref)
+	refObj, _, err := resolveAndBuildRef(gr, ref)
 	if err != nil {
 		logger.Debug("failed to resolve ref or commit", "repo", repo.Name(), "ref", ref, "err", err)
 		renderNotFound(w, r)

pkg/web/webui_commits.go 🔗

@@ -46,7 +46,7 @@ func repoCommits(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	refObj, err := resolveAndBuildRef(gr, ref)
+	refObj, _, err := resolveAndBuildRef(gr, ref)
 	if err != nil {
 		logger.Debug("failed to resolve ref or commit", "repo", repo.Name(), "ref", ref, "err", err)
 		renderNotFound(w, r)

pkg/web/webui_git.go 🔗

@@ -78,10 +78,11 @@ func parseRefAndPath(gr *git.Repository, refAndPath string) (ref string, path st
 }
 
 // resolveAndBuildRef resolves a ref or hash and builds a git.Reference object.
-func resolveAndBuildRef(gr *git.Repository, refOrHash string) (*git.Reference, error) {
+// Returns the reference, whether it's a commit hash (vs named ref), and any error.
+func resolveAndBuildRef(gr *git.Repository, refOrHash string) (*git.Reference, bool, error) {
 	hash, isRef, err := resolveRefOrHash(gr, refOrHash)
 	if err != nil {
-		return nil, err
+		return nil, false, err
 	}
 
 	refSpec := refOrHash
@@ -100,7 +101,7 @@ func resolveAndBuildRef(gr *git.Repository, refOrHash string) (*git.Reference, e
 			ID:      hash,
 			Refspec: refSpec,
 		},
-	}, nil
+	}, !isRef, nil
 }
 
 // FetchRefsPaginated efficiently fetches a paginated subset of refs sorted by date.

pkg/web/webui_tree.go 🔗

@@ -19,6 +19,7 @@ type TreeData struct {
 	Entries       git.Entries
 	ActiveTab     string
 	ServerName    string
+	IsCommitHash  bool
 }
 
 func repoTree(w http.ResponseWriter, r *http.Request) {
@@ -49,7 +50,7 @@ func repoTree(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
-	refObj, err := resolveAndBuildRef(gr, ref)
+	refObj, isCommitHash, err := resolveAndBuildRef(gr, ref)
 	if err != nil {
 		logger.Debug("failed to resolve ref or commit", "repo", repo.Name(), "ref", ref, "err", err)
 		renderNotFound(w, r)
@@ -82,6 +83,7 @@ func repoTree(w http.ResponseWriter, r *http.Request) {
 		Entries:       entries,
 		ActiveTab:     "tree",
 		ServerName:    cfg.Name,
+		IsCommitHash:  isCommitHash,
 	}
 
 	renderHTML(w, "tree.html", data)