mirror of
https://github.com/go-gitea/gitea.git
synced 2026-06-17 19:10:22 +03:00
feat(ui): add "follow rename" to file commit history list (#34994)
Fix #28253 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -222,17 +222,20 @@ type CommitsByFileAndRangeOptions struct {
|
|||||||
Page int
|
Page int
|
||||||
Since string
|
Since string
|
||||||
Until string
|
Until string
|
||||||
|
|
||||||
|
// when using FollowRename, there is no quick way to know the total count, so use hasMore to indicate if there are more commits to load
|
||||||
|
FollowRename bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitsByFileAndRange return the commits according revision file and the page
|
// CommitsByFileAndRange return the commits according revision file and the page
|
||||||
func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions) ([]*Commit, error) {
|
func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions) (commits []*Commit, hasMore bool, _ error) {
|
||||||
gitCmd := gitcmd.NewCommand("rev-list").
|
limit := setting.Git.CommitsRangeSize
|
||||||
AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize).
|
gitCmd := gitcmd.NewCommand("--no-pager", "log").
|
||||||
|
AddArguments("--pretty=tformat:%H").
|
||||||
|
AddOptionFormat("--max-count=%d", limit+1).
|
||||||
AddOptionFormat("--skip=%d", (opts.Page-1)*setting.Git.CommitsRangeSize)
|
AddOptionFormat("--skip=%d", (opts.Page-1)*setting.Git.CommitsRangeSize)
|
||||||
gitCmd.AddDynamicArguments(opts.Revision)
|
if opts.FollowRename {
|
||||||
|
gitCmd.AddArguments("--follow")
|
||||||
if opts.Not != "" {
|
|
||||||
gitCmd.AddOptionValues("--not", opts.Not)
|
|
||||||
}
|
}
|
||||||
if opts.Since != "" {
|
if opts.Since != "" {
|
||||||
gitCmd.AddOptionFormat("--since=%s", opts.Since)
|
gitCmd.AddOptionFormat("--since=%s", opts.Since)
|
||||||
@@ -240,9 +243,12 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
|
|||||||
if opts.Until != "" {
|
if opts.Until != "" {
|
||||||
gitCmd.AddOptionFormat("--until=%s", opts.Until)
|
gitCmd.AddOptionFormat("--until=%s", opts.Until)
|
||||||
}
|
}
|
||||||
|
gitCmd.AddDynamicArguments(opts.Revision)
|
||||||
|
if opts.Not != "" {
|
||||||
|
gitCmd.AddOptionValues("--not", opts.Not)
|
||||||
|
}
|
||||||
gitCmd.AddDashesAndList(opts.File)
|
gitCmd.AddDashesAndList(opts.File)
|
||||||
|
|
||||||
var commits []*Commit
|
|
||||||
stdoutReader, stdoutReaderClose := gitCmd.MakeStdoutPipe()
|
stdoutReader, stdoutReaderClose := gitCmd.MakeStdoutPipe()
|
||||||
defer stdoutReaderClose()
|
defer stdoutReaderClose()
|
||||||
err := gitCmd.WithDir(repo.Path).
|
err := gitCmd.WithDir(repo.Path).
|
||||||
@@ -274,7 +280,12 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
|
|||||||
}
|
}
|
||||||
}).
|
}).
|
||||||
RunWithStderr(repo.Ctx)
|
RunWithStderr(repo.Ctx)
|
||||||
return commits, err
|
|
||||||
|
hasMore = len(commits) > limit
|
||||||
|
if hasMore {
|
||||||
|
commits = commits[:limit]
|
||||||
|
}
|
||||||
|
return commits, hasMore, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilesCountBetween return the number of files changed between two commits
|
// FilesCountBetween return the number of files changed between two commits
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ package git
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"gitea.dev/modules/git/gitcmd"
|
||||||
"gitea.dev/modules/setting"
|
"gitea.dev/modules/setting"
|
||||||
"gitea.dev/modules/test"
|
"gitea.dev/modules/test"
|
||||||
|
|
||||||
@@ -140,11 +142,52 @@ func TestCommitsByFileAndRange(t *testing.T) {
|
|||||||
defer bareRepo1.Close()
|
defer bareRepo1.Close()
|
||||||
|
|
||||||
// "foo" has 3 commits in "master" branch
|
// "foo" has 3 commits in "master" branch
|
||||||
commits, err := bareRepo1.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "foo", Page: 1})
|
commits, hasMore, err := bareRepo1.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "foo", Page: 1})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
assert.True(t, hasMore)
|
||||||
assert.Len(t, commits, 2)
|
assert.Len(t, commits, 2)
|
||||||
|
|
||||||
commits, err = bareRepo1.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "foo", Page: 2})
|
commits, hasMore, err = bareRepo1.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "foo", Page: 2})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, commits, 1)
|
assert.Len(t, commits, 1)
|
||||||
|
assert.False(t, hasMore)
|
||||||
|
|
||||||
|
repoFollowRenameDir := filepath.Join(t.TempDir(), "repo.git")
|
||||||
|
require.NoError(t, gitcmd.NewCommand("init").AddDynamicArguments(repoFollowRenameDir).Run(t.Context()))
|
||||||
|
_, _, runErr := gitcmd.NewCommand("fast-import").WithDir(repoFollowRenameDir).WithStdinBytes([]byte(strings.TrimSpace(`
|
||||||
|
blob
|
||||||
|
mark :1
|
||||||
|
data 0
|
||||||
|
|
||||||
|
reset refs/heads/master
|
||||||
|
commit refs/heads/master
|
||||||
|
mark :2
|
||||||
|
author Chi-Iroh <user@example.com> 1778660718 +0200
|
||||||
|
committer Chi-Iroh <user@example.com> 1778660718 +0200
|
||||||
|
data 10
|
||||||
|
Add a.txt
|
||||||
|
M 100644 :1 a.txt
|
||||||
|
|
||||||
|
commit refs/heads/master
|
||||||
|
mark :3
|
||||||
|
author Chi-Iroh <user@example.com> 1778660741 +0200
|
||||||
|
committer Chi-Iroh <user@example.com> 1778660741 +0200
|
||||||
|
data 22
|
||||||
|
Rename a.txt to b.txt
|
||||||
|
from :2
|
||||||
|
D a.txt
|
||||||
|
M 100644 :1 b.txt
|
||||||
|
`))).RunStdString(t.Context())
|
||||||
|
require.NoError(t, runErr)
|
||||||
|
|
||||||
|
repoFollowRename, err := OpenRepository(t.Context(), repoFollowRenameDir)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer repoFollowRename.Close()
|
||||||
|
|
||||||
|
commits, _, err = repoFollowRename.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "b.txt", Page: 1})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, commits, 1)
|
||||||
|
commits, _, err = repoFollowRename.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "b.txt", Page: 1, FollowRename: true})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, commits, 2)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,10 +37,11 @@ type Paginator struct {
|
|||||||
total int // total rows count, -1 means unknown
|
total int // total rows count, -1 means unknown
|
||||||
totalPages int // total pages count, -1 means unknown
|
totalPages int // total pages count, -1 means unknown
|
||||||
current int // current page number
|
current int // current page number
|
||||||
curRows int // current page rows count
|
|
||||||
|
|
||||||
pagingNum int // how many rows in one page
|
pagingNum int // how many rows in one page
|
||||||
numPages int // how many pages to show on the UI
|
numPages int // how many pages to show on the UI
|
||||||
|
|
||||||
|
hasNext *bool // used for total=-1 ("unlimited paging")
|
||||||
}
|
}
|
||||||
|
|
||||||
// New initialize a new pagination calculation and returns a Paginator as result.
|
// New initialize a new pagination calculation and returns a Paginator as result.
|
||||||
@@ -60,15 +61,13 @@ func New(total, pagingNum, current, numPages int) *Paginator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Paginator) SetCurRows(rows int) {
|
func (p *Paginator) SetUnlimitedPaging(curRows int, hasNext bool) {
|
||||||
// For "unlimited paging", we need to know the rows of current page to determine if there is a next page.
|
// For "unlimited paging", we need to know the rows of current page to determine if there is a next page.
|
||||||
// There is still an edge case: when curRows==pagingNum, then the "next page" will be an empty page.
|
p.hasNext = &hasNext
|
||||||
// Ideally we should query one more row to determine if there is really a next page, but it's impossible in current framework.
|
if p.total == -1 && p.current == 1 && !hasNext {
|
||||||
p.curRows = rows
|
|
||||||
if p.total == -1 && p.current == 1 && !p.HasNext() {
|
|
||||||
// if there is only one page for the "unlimited paging", set total rows/pages count
|
// if there is only one page for the "unlimited paging", set total rows/pages count
|
||||||
// then the tmpl could decide to hide the nav bar.
|
// then the tmpl could decide to hide the nav bar.
|
||||||
p.total = rows
|
p.total = curRows
|
||||||
p.totalPages = util.Iif(p.total == 0, 0, 1)
|
p.totalPages = util.Iif(p.total == 0, 0, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,8 +91,8 @@ func (p *Paginator) Previous() int {
|
|||||||
|
|
||||||
// HasNext returns true if there is a next page relative to current page.
|
// HasNext returns true if there is a next page relative to current page.
|
||||||
func (p *Paginator) HasNext() bool {
|
func (p *Paginator) HasNext() bool {
|
||||||
if p.total == -1 {
|
if p.hasNext != nil {
|
||||||
return p.curRows >= p.pagingNum
|
return *p.hasNext
|
||||||
}
|
}
|
||||||
return p.current*p.pagingNum < p.total
|
return p.current*p.pagingNum < p.total
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1321,6 +1321,7 @@
|
|||||||
"repo.editor.fork_branch_exists": "Branch \"%s\" already exists in your fork. Please choose a new branch name.",
|
"repo.editor.fork_branch_exists": "Branch \"%s\" already exists in your fork. Please choose a new branch name.",
|
||||||
"repo.commits.desc": "Browse source code change history.",
|
"repo.commits.desc": "Browse source code change history.",
|
||||||
"repo.commits.commits": "Commits",
|
"repo.commits.commits": "Commits",
|
||||||
|
"repo.commits.history_enable_follow_renames": "Include renames",
|
||||||
"repo.commits.no_commits": "No commits in common. \"%s\" and \"%s\" have entirely different histories.",
|
"repo.commits.no_commits": "No commits in common. \"%s\" and \"%s\" have entirely different histories.",
|
||||||
"repo.commits.nothing_to_compare": "There are no differences to show.",
|
"repo.commits.nothing_to_compare": "There are no differences to show.",
|
||||||
"repo.commits.search.tooltip": "You can prefix keywords with \"author:\", \"committer:\", \"after:\", or \"before:\", e.g. \"revert author:Alice before:2019-01-13\".",
|
"repo.commits.search.tooltip": "You can prefix keywords with \"author:\", \"committer:\", \"after:\", or \"before:\", e.g. \"revert author:Alice before:2019-01-13\".",
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ func GetAllCommits(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, err = ctx.Repo.GitRepo.CommitsByFileAndRange(
|
commits, _, err = ctx.Repo.GitRepo.CommitsByFileAndRange(
|
||||||
git.CommitsByFileAndRangeOptions{
|
git.CommitsByFileAndRangeOptions{
|
||||||
Revision: sha,
|
Revision: sha,
|
||||||
File: path,
|
File: path,
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ func ListPageRevisions(ctx *context.APIContext) {
|
|||||||
page := max(ctx.FormInt("page"), 1)
|
page := max(ctx.FormInt("page"), 1)
|
||||||
|
|
||||||
// get Commit Count
|
// get Commit Count
|
||||||
commitsHistory, err := wikiRepo.CommitsByFileAndRange(
|
commitsHistory, _, err := wikiRepo.CommitsByFileAndRange(
|
||||||
git.CommitsByFileAndRangeOptions{
|
git.CommitsByFileAndRangeOptions{
|
||||||
Revision: ctx.Repo.Repository.DefaultWikiBranch,
|
Revision: ctx.Repo.Repository.DefaultWikiBranch,
|
||||||
File: pageFilename,
|
File: pageFilename,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func ShowFileFeed(ctx *context.Context, repo *repo.Repository, formatType string
|
|||||||
if len(fileName) == 0 {
|
if len(fileName) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(
|
commits, _, err := ctx.Repo.GitRepo.CommitsByFileAndRange(
|
||||||
git.CommitsByFileAndRangeOptions{
|
git.CommitsByFileAndRangeOptions{
|
||||||
Revision: ctx.Repo.RefFullName.ShortName(), // FIXME: legacy code used ShortName
|
Revision: ctx.Repo.RefFullName.ShortName(), // FIXME: legacy code used ShortName
|
||||||
File: fileName,
|
File: fileName,
|
||||||
|
|||||||
+31
-16
@@ -214,37 +214,52 @@ func FileHistory(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
commitsCount, err := gitrepo.FileCommitsCount(ctx, ctx.Repo.Repository, ctx.Repo.RefFullName.ShortName(), ctx.Repo.TreePath)
|
followRename := ctx.FormBool("follow-rename")
|
||||||
if err != nil {
|
ctx.Data["ShowFollowRename"] = true
|
||||||
ctx.ServerError("FileCommitsCount", err)
|
ctx.Data["FollowRenameChecked"] = followRename
|
||||||
return
|
|
||||||
} else if commitsCount == 0 {
|
|
||||||
ctx.NotFound(nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page := max(ctx.FormInt("page"), 1)
|
page := max(ctx.FormInt("page"), 1)
|
||||||
|
commits, hasMore, err := ctx.Repo.GitRepo.CommitsByFileAndRange(
|
||||||
commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(
|
|
||||||
git.CommitsByFileAndRangeOptions{
|
git.CommitsByFileAndRangeOptions{
|
||||||
Revision: ctx.Repo.RefFullName.ShortName(), // FIXME: legacy code used ShortName
|
Revision: ctx.Repo.RefFullName.ShortName(), // FIXME: legacy code used ShortName
|
||||||
File: ctx.Repo.TreePath,
|
File: ctx.Repo.TreePath,
|
||||||
Page: page,
|
Page: page,
|
||||||
|
FollowRename: followRename,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("CommitsByFileAndRange", err)
|
ctx.ServerError("CommitsByFileAndRange", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var commitsCount int64
|
||||||
|
if followRename {
|
||||||
|
// there is no quick method to know the total count when "follow rename"
|
||||||
|
commitsCount = -1
|
||||||
|
} else {
|
||||||
|
commitsCount, err = gitrepo.FileCommitsCount(ctx, ctx.Repo.Repository, ctx.Repo.RefFullName.ShortName(), ctx.Repo.TreePath)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("FileCommitsCount", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(commits) == 0 {
|
||||||
|
ctx.NotFound(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["FileTreePath"] = ctx.Repo.TreePath
|
||||||
|
ctx.Data["CommitCount"] = commitsCount
|
||||||
ctx.Data["Commits"], err = processGitCommits(ctx, commits)
|
ctx.Data["Commits"], err = processGitCommits(ctx, commits)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("processGitCommits", err)
|
ctx.ServerError("processGitCommits", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["FileTreePath"] = ctx.Repo.TreePath
|
|
||||||
ctx.Data["CommitCount"] = commitsCount
|
|
||||||
|
|
||||||
pager := context.NewPagination(commitsCount, setting.Git.CommitsRangeSize, page, 5)
|
pager := context.NewPagination(commitsCount, setting.Git.CommitsRangeSize, page, 5)
|
||||||
|
if commitsCount == -1 {
|
||||||
|
pager.WithUnlimitedPaging(len(commits), hasMore)
|
||||||
|
}
|
||||||
pager.AddParamFromRequest(ctx.Req)
|
pager.AddParamFromRequest(ctx.Req)
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
ctx.HTML(http.StatusOK, tplCommits)
|
ctx.HTML(http.StatusOK, tplCommits)
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
|
|||||||
page := max(ctx.FormInt("page"), 1)
|
page := max(ctx.FormInt("page"), 1)
|
||||||
|
|
||||||
// get Commit Count
|
// get Commit Count
|
||||||
commitsHistory, err := wikiGitRepo.CommitsByFileAndRange(
|
commitsHistory, _, err := wikiGitRepo.CommitsByFileAndRange(
|
||||||
git.CommitsByFileAndRangeOptions{
|
git.CommitsByFileAndRangeOptions{
|
||||||
Revision: ctx.Repo.Repository.DefaultWikiBranch,
|
Revision: ctx.Repo.Repository.DefaultWikiBranch,
|
||||||
File: pageFilename,
|
File: pageFilename,
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ func Dashboard(ctx *context.Context) {
|
|||||||
|
|
||||||
prepareHeatmapURL(ctx)
|
prepareHeatmapURL(ctx)
|
||||||
|
|
||||||
|
pageSize := setting.UI.User.RepoPagingNum
|
||||||
feeds, count, err := feed_service.GetFeedsForDashboard(ctx, activities_model.GetFeedsOptions{
|
feeds, count, err := feed_service.GetFeedsForDashboard(ctx, activities_model.GetFeedsOptions{
|
||||||
RequestedUser: ctxUser,
|
RequestedUser: ctxUser,
|
||||||
RequestedTeam: ctx.Org.Team,
|
RequestedTeam: ctx.Org.Team,
|
||||||
@@ -119,17 +120,17 @@ func Dashboard(ctx *context.Context) {
|
|||||||
OnlyPerformedBy: false,
|
OnlyPerformedBy: false,
|
||||||
IncludeDeleted: false,
|
IncludeDeleted: false,
|
||||||
Date: ctx.FormString("date"),
|
Date: ctx.FormString("date"),
|
||||||
ListOptions: db.ListOptions{
|
ListOptions: db.ListOptions{Page: page, PageSize: pageSize},
|
||||||
Page: page,
|
|
||||||
PageSize: setting.UI.FeedPagingNum,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetFeeds", err)
|
ctx.ServerError("GetFeeds", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pager := context.NewPagination(count, setting.UI.FeedPagingNum, page, 5).WithCurRows(len(feeds))
|
// FIXME: UNLIMITE-PAGING-ONE-MORE-ROW: here is still an edge case: when curRows==pagingNum, then the "next page" will be an empty page.
|
||||||
|
// Ideally we should query one more row to determine if there is really a next page, but it's impossible in current framework.
|
||||||
|
pager := context.NewPagination(count, pageSize, page, 5).WithUnlimitedPaging(len(feeds), len(feeds) == pageSize)
|
||||||
|
|
||||||
pager.AddParamFromRequest(ctx.Req)
|
pager.AddParamFromRequest(ctx.Req)
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
ctx.Data["Feeds"] = feeds
|
ctx.Data["Feeds"] = feeds
|
||||||
|
|||||||
@@ -312,7 +312,8 @@ func prepareUserProfileTabData(ctx *context.Context, profileDbRepo *repo_model.R
|
|||||||
|
|
||||||
pager := context.NewPagination(total, pagingNum, page, 5)
|
pager := context.NewPagination(total, pagingNum, page, 5)
|
||||||
if tab == "activity" {
|
if tab == "activity" {
|
||||||
pager.WithCurRows(curRows)
|
// FIXME: UNLIMITE-PAGING-ONE-MORE-ROW: see another comment
|
||||||
|
pager.WithUnlimitedPaging(curRows, curRows == pagingNum)
|
||||||
}
|
}
|
||||||
pager.AddParamFromRequest(ctx.Req)
|
pager.AddParamFromRequest(ctx.Req)
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ func NewPagination(total int64, pagingNum, current, numPages int) *Pagination {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pagination) WithCurRows(n int) *Pagination {
|
func (p *Pagination) WithUnlimitedPaging(curRows int, hasNext bool) *Pagination {
|
||||||
p.Paginater.SetCurRows(n)
|
p.Paginater.SetUnlimitedPaging(curRows, hasNext)
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,4 +32,24 @@ func TestPagination(t *testing.T) {
|
|||||||
params.Del("foo")
|
params.Del("foo")
|
||||||
v, _ = url.ParseQuery(string(p.GetParams()))
|
v, _ = url.ParseQuery(string(p.GetParams()))
|
||||||
assert.Equal(t, params, v)
|
assert.Equal(t, params, v)
|
||||||
|
|
||||||
|
p = NewPagination(-1, 1, 1, 1)
|
||||||
|
p.WithUnlimitedPaging(0, false)
|
||||||
|
assert.Zero(t, p.Paginater.TotalPages())
|
||||||
|
assert.False(t, p.Paginater.HasNext())
|
||||||
|
|
||||||
|
p = NewPagination(-1, 1, 1, 1)
|
||||||
|
p.WithUnlimitedPaging(10, false)
|
||||||
|
assert.Equal(t, 1, p.Paginater.TotalPages()) // first page, no next, so it should know that the total page number is 1
|
||||||
|
assert.False(t, p.Paginater.HasNext())
|
||||||
|
|
||||||
|
p = NewPagination(-1, 1, 2, 1)
|
||||||
|
p.WithUnlimitedPaging(10, false)
|
||||||
|
assert.Equal(t, -1, p.Paginater.TotalPages())
|
||||||
|
assert.False(t, p.Paginater.HasNext())
|
||||||
|
|
||||||
|
p = NewPagination(-1, 1, 1, 1)
|
||||||
|
p.WithUnlimitedPaging(10, true)
|
||||||
|
assert.Equal(t, -1, p.Paginater.TotalPages())
|
||||||
|
assert.True(t, p.Paginater.HasNext())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,30 @@
|
|||||||
<h4 class="ui top attached header commits-table flex-left-right">
|
<div class="ui top attached header flex-left-right">
|
||||||
<div class="commits-table-left flex-text-block">
|
<div class="flex-text-block">
|
||||||
{{if or .PageIsCommits (gt .CommitCount 0)}}
|
{{if .Commits}}
|
||||||
{{.CommitCount}} {{ctx.Locale.Tr "repo.commits.commits"}}
|
{{if gt .CommitCount 0}}{{.CommitCount}}{{end}}{{/* CommitCount is -1 when "follow rename" */}}
|
||||||
|
{{ctx.Locale.Tr "repo.commits.commits"}}
|
||||||
{{else if .IsNothingToCompare}}
|
{{else if .IsNothingToCompare}}
|
||||||
{{ctx.Locale.Tr "repo.commits.nothing_to_compare"}}
|
{{ctx.Locale.Tr "repo.commits.nothing_to_compare"}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{ctx.Locale.Tr "repo.commits.no_commits" $.BaseBranch $.HeadBranch}}
|
{{ctx.Locale.Tr "repo.commits.no_commits" $.BaseBranch $.HeadBranch}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{if .IsDiffCompare}}
|
<div class="flex-text-block">
|
||||||
<div class="commits-table-right tw-whitespace-nowrap">
|
{{if .ShowFollowRename}}
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input type="checkbox" {{if .FollowRenameChecked}}checked{{end}} data-global-init="initCommitHistoryFollowRename">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.commits.history_enable_follow_renames"}}</label>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{if .IsDiffCompare}}
|
||||||
|
<div class="flex-text-inline">
|
||||||
<a href="{{$.CommitRepoLink}}/commit/{{.BeforeCommitID | PathEscape}}" class="ui green sha label tw-mx-0">{{template "repo/commits_ref_name" .CompareInfo.BaseRef}}</a>
|
<a href="{{$.CommitRepoLink}}/commit/{{.BeforeCommitID | PathEscape}}" class="ui green sha label tw-mx-0">{{template "repo/commits_ref_name" .CompareInfo.BaseRef}}</a>
|
||||||
{{$.CompareInfo.CompareSeparator}}
|
{{$.CompareInfo.CompareSeparator}}
|
||||||
<a href="{{$.CommitRepoLink}}/commit/{{.AfterCommitID | PathEscape}}" class="ui green sha label tw-mx-0">{{template "repo/commits_ref_name" .CompareInfo.HeadRef}}</a>
|
<a href="{{$.CommitRepoLink}}/commit/{{.AfterCommitID | PathEscape}}" class="ui green sha label tw-mx-0">{{template "repo/commits_ref_name" .CompareInfo.HeadRef}}</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</h4>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{if .PageIsCommits}}
|
{{if .PageIsCommits}}
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
@@ -29,7 +38,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if and .Commits (gt .CommitCount 0)}}
|
{{if .Commits}}
|
||||||
{{template "repo/commits_list" .}}
|
{{template "repo/commits_list" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|||||||
@@ -1816,14 +1816,6 @@ tbody.commit-list {
|
|||||||
box-shadow: 0 0.5rem 1rem var(--color-shadow) !important;
|
box-shadow: 0 0.5rem 1rem var(--color-shadow) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commits-table .commits-table-right form {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.75em;
|
|
||||||
justify-content: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
.repository.view.issue .comment-list,
|
.repository.view.issue .comment-list,
|
||||||
.repository.view.issue .comment-list .timeline-item {
|
.repository.view.issue .comment-list .timeline-item {
|
||||||
@@ -1848,22 +1840,6 @@ tbody.commit-list {
|
|||||||
flex-basis: auto !important;
|
flex-basis: auto !important;
|
||||||
margin-bottom: 0.5rem !important;
|
margin-bottom: 0.5rem !important;
|
||||||
}
|
}
|
||||||
.commits-table {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.commits-table .commits-table-left {
|
|
||||||
align-items: initial !important;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
.commits-table .commits-table-right form > div:nth-child(1) {
|
|
||||||
order: 1; /* the "commit search" input */
|
|
||||||
}
|
|
||||||
.commits-table .commits-table-right form > div:nth-child(2) {
|
|
||||||
order: 3; /* the "search all" checkbox */
|
|
||||||
}
|
|
||||||
.commits-table .commits-table-right form > button:nth-child(3) {
|
|
||||||
order: 2; /* the "search" button */
|
|
||||||
}
|
|
||||||
.commit-table {
|
.commit-table {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,3 +24,13 @@ export function initCommitStatuses() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initCommitFileHistoryFollowRename() {
|
||||||
|
registerGlobalInitFunc('initCommitHistoryFollowRename', (el: HTMLInputElement) => {
|
||||||
|
el.addEventListener('change', () => {
|
||||||
|
const url = new URL(window.location.toString());
|
||||||
|
url.searchParams.set('follow-rename', `${el.checked}`);
|
||||||
|
window.location.assign(url.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
+2
-1
@@ -21,7 +21,7 @@ import {initMarkupContent} from './markup/content.ts';
|
|||||||
import {initRepoFileView} from './features/file-view.ts';
|
import {initRepoFileView} from './features/file-view.ts';
|
||||||
import {initUserExternalLogins, initUserCheckAppUrl} from './features/user-auth.ts';
|
import {initUserExternalLogins, initUserCheckAppUrl} from './features/user-auth.ts';
|
||||||
import {initRepoPullRequestReview, initRepoIssueFilterItemLabel} from './features/repo-issue.ts';
|
import {initRepoPullRequestReview, initRepoIssueFilterItemLabel} from './features/repo-issue.ts';
|
||||||
import {initRepoEllipsisButton, initCommitStatuses} from './features/repo-commit.ts';
|
import {initRepoEllipsisButton, initCommitStatuses, initCommitFileHistoryFollowRename} from './features/repo-commit.ts';
|
||||||
import {initRepoTopicBar} from './features/repo-home.ts';
|
import {initRepoTopicBar} from './features/repo-home.ts';
|
||||||
import {initAdminCommon} from './features/admin/common.ts';
|
import {initAdminCommon} from './features/admin/common.ts';
|
||||||
import {initRepoCodeView} from './features/repo-code.ts';
|
import {initRepoCodeView} from './features/repo-code.ts';
|
||||||
@@ -123,6 +123,7 @@ const initPerformanceTracer = callInitFunctions([
|
|||||||
initRepoCodeView,
|
initRepoCodeView,
|
||||||
initBranchSelectorTabs,
|
initBranchSelectorTabs,
|
||||||
initRepoEllipsisButton,
|
initRepoEllipsisButton,
|
||||||
|
initCommitFileHistoryFollowRename,
|
||||||
initRepoDiffCommitBranchesAndTags,
|
initRepoDiffCommitBranchesAndTags,
|
||||||
initRepoEditor,
|
initRepoEditor,
|
||||||
initRepoGraphGit,
|
initRepoGraphGit,
|
||||||
|
|||||||
Reference in New Issue
Block a user