feat: show breadcrumb path in path filtered commit history view (#12116)

Resolves forgejo/forgejo#8754

Add the breadcrumb path that already exists when browsing directories to the commit history of files/directories.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12116
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
This commit is contained in:
Mauritz Sjödin 2026-05-01 01:53:10 +02:00 committed by Gusted
parent 75cfa31af5
commit 254a44b97b
7 changed files with 44 additions and 18 deletions

View file

@ -45,10 +45,19 @@ const (
func RefCommits(ctx *context.Context) {
switch {
case len(ctx.Repo.TreePath) == 0:
ctx.Data["TreeNames"] = []string{}
Commits(ctx)
case ctx.Repo.TreePath == "search":
ctx.Data["TreeNames"] = []string{}
SearchCommits(ctx)
default:
treeNames := strings.Split(ctx.Repo.TreePath, "/")
paths := make([]string, len(treeNames))
for i := range treeNames {
paths[i] = strings.Join(treeNames[:i+1], "/")
}
ctx.Data["TreeNames"] = treeNames
ctx.Data["Paths"] = paths
FileHistory(ctx)
}
}
@ -272,6 +281,9 @@ func FileHistory(ctx *context.Context) {
}
}
branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
ctx.Data["BranchLink"] = branchLink
ctx.Data["Commits"] = git_model.ParseCommitsWithStatus(ctx, commits, ctx.Repo.Repository)
ctx.Data["Username"] = ctx.Repo.Owner.Name

View file

@ -10,6 +10,7 @@
{{svg "octicon-git-branch"}}
{{ctx.Locale.Tr "repo.commit_graph"}}
</a>
{{template "repo/filepath" .}}
</div>
</div>
{{template "repo/commits_table" .}}

View file

@ -0,0 +1,17 @@
{{$n := len .TreeNames}}
{{$l := Eval $n "-" 1}}
{{$showFilePath := (gt $n 0)}}
{{if $showFilePath}}
<span class="breadcrumb repo-path tw-ml-1">
<a class="section" href="{{$.BranchLink}}" title="{{.Repository.Name}}">{{StringUtils.EllipsisString .Repository.Name 30}}</a>
{{- range $i, $v := .TreeNames -}}
<span class="breadcrumb-divider">/</span>
{{- if eq $i $l -}}
<span class="active section" title="{{$v}}">{{$v}}</span>
<button class="btn interact-fg tw-p-2" data-clipboard-text="{{$.TreePath}}" data-tooltip-content="{{ctx.Locale.Tr "copy_path"}}">{{svg "octicon-copy" 14}}</button>
{{- else -}}
{{$p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{$v}}</a></span>
{{- end -}}
{{- end -}}
</span>
{{end}}

View file

@ -102,20 +102,7 @@
{{ctx.Locale.Tr "repo.use_template"}}
</a>
{{end}}
{{if (not $isHomepage)}}
<span class="breadcrumb repo-path tw-ml-1">
<a class="section" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}" title="{{.Repository.Name}}">{{StringUtils.EllipsisString .Repository.Name 30}}</a>
{{- range $i, $v := .TreeNames -}}
<span class="breadcrumb-divider">/</span>
{{- if eq $i $l -}}
<span class="active section" title="{{$v}}">{{$v}}</span>
<button class="btn interact-fg tw-p-2" data-clipboard-text="{{$.TreePath}}" data-tooltip-content="{{ctx.Locale.Tr "copy_path"}}">{{svg "octicon-copy" 14}}</button>
{{- else -}}
{{$p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{$v}}</a></span>
{{- end -}}
{{- end -}}
</span>
{{end}}
{{template "repo/filepath" .}}
</div>
<div class="tw-flex tw-items-center max-[390px]:tw-w-full">
<!-- Only show clone panel in repository home page -->

View file

@ -24,6 +24,7 @@ func testRepoCommitsSearch(t *testing.T, query, commit string) {
doc := NewHTMLParser(t, resp.Body)
sel := doc.doc.Find("#commits-table tbody tr td.sha a")
assert.Equal(t, commit, strings.TrimSpace(sel.Text()))
doc.AssertElement(t, ".repo-path", false)
}
func TestRepoCommitsSearch(t *testing.T) {

View file

@ -34,6 +34,7 @@ func TestRepoCommits(t *testing.T) {
commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Attr("href")
assert.True(t, exists)
assert.NotEmpty(t, commitURL)
doc.AssertElement(t, ".repo-path", false)
}
func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {

View file

@ -139,7 +139,7 @@ func TestCommitListActions(t *testing.T) {
[]*files_service.ChangeRepoFile{
{
Operation: "create",
TreePath: "test.sh",
TreePath: "test/test.sh",
ContentReader: strings.NewReader("Hello there!"),
},
},
@ -162,7 +162,7 @@ func TestCommitListActions(t *testing.T) {
htmlDoc.AssertElement(t, fmt.Sprintf(".commit-list a[href^='/%s/src/commit/']", repo.FullName()), false)
})
fileDiffSelector := fmt.Sprintf(".commit-list a[href='/%s/commit/%s?files=test.sh']", repo.FullName(), commitID)
fileDiffSelector := fmt.Sprintf(".commit-list a[href='/%s/commit/%s?files=test/test.sh']", repo.FullName(), commitID)
t.Run("Commit list", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@ -177,12 +177,19 @@ func TestCommitListActions(t *testing.T) {
t.Run("File history", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", repo.Link()+"/commits/branch/main/test.sh")
req := NewRequest(t, "GET", repo.Link()+"/commits/branch/main/test/test.sh")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
htmlDoc.AssertElement(t, fmt.Sprintf(".commit-list a[href='/%s/src/commit/%s/test.sh']", repo.FullName(), commitID), true)
htmlDoc.AssertElement(t, fmt.Sprintf(".commit-list a[href='/%s/src/commit/%s/test/test.sh']", repo.FullName(), commitID), true)
htmlDoc.AssertElement(t, fileDiffSelector, true)
htmlDoc.AssertElement(t, ".repo-path", true)
htmlDoc.AssertElement(t, fmt.Sprintf(".repo-path a[href='/%s/src/branch/main'][title='%s']", repo.FullName(), repo.Name), true)
assert.Equal(t, 2, htmlDoc.Find(".repo-path .breadcrumb-divider").Length())
htmlDoc.AssertElement(t, fmt.Sprintf(".repo-path .section a[href='/%s/src/branch/main/test'][title='test']", repo.FullName()), true)
htmlDoc.AssertElement(t, ".repo-path .active[title='test.sh']", true)
htmlDoc.AssertElement(t, ".repo-path button[data-clipboard-text='test/test.sh']", true)
})
})
}