diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go index 50e900551113..019c9bc806ed 100644 --- a/modules/git/repo_compare.go +++ b/modules/git/repo_compare.go @@ -46,7 +46,7 @@ func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (strin } // GetCompareInfo generates and returns compare information between base and head branches of repositories. -func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, directComparison bool) (_ *CompareInfo, err error) { +func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, directComparison, fileOnly bool) (_ *CompareInfo, err error) { var ( remoteBranch string tmpRemote string @@ -87,13 +87,17 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, } // We have a common base - therefore we know that ... should work - logs, err := NewCommand("log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) - if err != nil { - return nil, err - } - compareInfo.Commits, err = repo.parsePrettyFormatLogToList(logs) - if err != nil { - return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err) + if !fileOnly { + logs, err := NewCommand("log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) + if err != nil { + return nil, err + } + compareInfo.Commits, err = repo.parsePrettyFormatLogToList(logs) + if err != nil { + return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err) + } + } else { + compareInfo.Commits = []*Commit{} } } else { compareInfo.Commits = []*Commit{} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 67ca8ff558b3..2cb1bcd1a99f 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2027,7 +2027,8 @@ diff.file_image_height = Height diff.file_byte_size = Size diff.file_suppressed = File diff suppressed because it is too large diff.file_suppressed_line_too_long = File diff suppressed because one or more lines are too long -diff.too_many_files = Some files were not shown because too many files changed in this diff +diff.too_many_files = Some files were not shown because too many files have changed in this diff +diff.show_more = Show More diff.generated = generated diff.vendored = vendored diff.comment.placeholder = Leave a comment diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index d8e0d8099ab0..f2a1d7fe630d 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -1016,7 +1016,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) return nil, nil, nil, nil, "", "" } - compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch, true) + compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch, true, false) if err != nil { headGitRepo.Close() ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err) @@ -1193,9 +1193,9 @@ func GetPullRequestCommits(ctx *context.APIContext) { } defer baseGitRepo.Close() if pr.HasMerged { - prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true) + prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true, false) } else { - prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true) + prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true, false) } if err != nil { ctx.ServerError("GetCompareInfo", err) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index c5f3f70c1c85..4c0f94f15db7 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -264,6 +264,8 @@ func Diff(ctx *context.Context) { err error ) + fileOnly := ctx.FormBool("file-only") + if ctx.Data["PageIsWiki"] != nil { gitRepo, err = git.OpenRepository(ctx.Repo.Repository.WikiPath()) if err != nil { @@ -288,16 +290,8 @@ func Diff(ctx *context.Context) { commitID = commit.ID.String() } - statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, commitID, db.ListOptions{}) - if err != nil { - log.Error("GetLatestCommitStatus: %v", err) - } - - ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses) - ctx.Data["CommitStatuses"] = statuses - diff, err := gitdiff.GetDiffCommitWithWhitespaceBehavior(gitRepo, - commitID, setting.Git.MaxGitDiffLines, + commitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), false) @@ -333,10 +327,23 @@ func Diff(ctx *context.Context) { setCompareContext(ctx, parentCommit, commit, headTarget) ctx.Data["Title"] = commit.Summary() + " ยท " + base.ShortSha(commitID) ctx.Data["Commit"] = commit + ctx.Data["Diff"] = diff + if fileOnly { + ctx.HTML(http.StatusOK, tplDiffBox) + return + } + + statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, commitID, db.ListOptions{}) + if err != nil { + log.Error("GetLatestCommitStatus: %v", err) + } + + ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses) + ctx.Data["CommitStatuses"] = statuses + verification := models.ParseCommitWithSignature(commit) ctx.Data["Verification"] = verification ctx.Data["Author"] = models.ValidateCommitWithEmail(commit) - ctx.Data["Diff"] = diff ctx.Data["Parents"] = parents ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0 diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 556a6218a6b8..33b95838c7be 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -31,6 +31,7 @@ import ( const ( tplCompare base.TplName = "repo/diff/compare" tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt" + tplDiffBox base.TplName = "repo/diff/box" ) // setCompareContext sets context data. @@ -161,6 +162,8 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { baseRepo := ctx.Repo.Repository ci := &CompareInfo{} + fileOnly := ctx.FormBool("file-only") + // Get compared branches information // A full compare url is of the form: // @@ -411,15 +414,19 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { if rootRepo != nil && rootRepo.ID != ci.HeadRepo.ID && rootRepo.ID != baseRepo.ID { - perm, branches, tags, err := getBranchesAndTagsForRepo(ctx.User, rootRepo) - if err != nil { - ctx.ServerError("GetBranchesForRepo", err) - return nil - } - if perm { + canRead := rootRepo.CheckUnitUser(ctx.User, models.UnitTypeCode) + if canRead { ctx.Data["RootRepo"] = rootRepo - ctx.Data["RootRepoBranches"] = branches - ctx.Data["RootRepoTags"] = tags + if !fileOnly { + branches, tags, err := getBranchesAndTagsForRepo(ctx.User, rootRepo) + if err != nil { + ctx.ServerError("GetBranchesForRepo", err) + return nil + } + + ctx.Data["RootRepoBranches"] = branches + ctx.Data["RootRepoTags"] = tags + } } } @@ -432,15 +439,18 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { ownForkRepo.ID != ci.HeadRepo.ID && ownForkRepo.ID != baseRepo.ID && (rootRepo == nil || ownForkRepo.ID != rootRepo.ID) { - perm, branches, tags, err := getBranchesAndTagsForRepo(ctx.User, ownForkRepo) - if err != nil { - ctx.ServerError("GetBranchesForRepo", err) - return nil - } - if perm { + canRead := ownForkRepo.CheckUnitUser(ctx.User, models.UnitTypeCode) + if canRead { ctx.Data["OwnForkRepo"] = ownForkRepo - ctx.Data["OwnForkRepoBranches"] = branches - ctx.Data["OwnForkRepoTags"] = tags + if !fileOnly { + branches, tags, err := getBranchesAndTagsForRepo(ctx.User, ownForkRepo) + if err != nil { + ctx.ServerError("GetBranchesForRepo", err) + return nil + } + ctx.Data["OwnForkRepoBranches"] = branches + ctx.Data["OwnForkRepoTags"] = tags + } } } @@ -492,7 +502,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { headBranchRef = git.TagPrefix + ci.HeadBranch } - ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, ci.DirectComparison) + ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, ci.DirectComparison, fileOnly) if err != nil { ctx.ServerError("GetCompareInfo", err) return nil @@ -545,7 +555,7 @@ func PrepareCompareDiff( } diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(ci.HeadGitRepo, - beforeCommitID, headCommitID, setting.Git.MaxGitDiffLines, + beforeCommitID, headCommitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, whitespaceBehavior, ci.DirectComparison) if err != nil { ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err) @@ -606,29 +616,22 @@ func PrepareCompareDiff( return false } -func getBranchesAndTagsForRepo(user *models.User, repo *models.Repository) (bool, []string, []string, error) { - perm, err := models.GetUserRepoPermission(repo, user) - if err != nil { - return false, nil, nil, err - } - if !perm.CanRead(models.UnitTypeCode) { - return false, nil, nil, nil - } +func getBranchesAndTagsForRepo(user *models.User, repo *models.Repository) (branches, tags []string, err error) { gitRepo, err := git.OpenRepository(repo.RepoPath()) if err != nil { - return false, nil, nil, err + return nil, nil, err } defer gitRepo.Close() - branches, _, err := gitRepo.GetBranches(0, 0) + branches, _, err = gitRepo.GetBranches(0, 0) if err != nil { - return false, nil, nil, err + return nil, nil, err } - tags, err := gitRepo.GetTags(0, 0) + tags, err = gitRepo.GetTags(0, 0) if err != nil { - return false, nil, nil, err + return nil, nil, err } - return true, branches, tags, nil + return branches, tags, nil } // CompareDiff show different from one commit to another commit @@ -665,6 +668,12 @@ func CompareDiff(ctx *context.Context) { } ctx.Data["Tags"] = baseTags + fileOnly := ctx.FormBool("file-only") + if fileOnly { + ctx.HTML(http.StatusOK, tplDiffBox) + return + } + headBranches, _, err := ci.HeadGitRepo.GetBranches(0, 0) if err != nil { ctx.ServerError("GetBranches", err) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index dde556135177..153ebc306fbe 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -318,7 +318,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C ctx.Data["HasMerged"] = true compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), - pull.MergeBase, pull.GetGitRefName(), true) + pull.MergeBase, pull.GetGitRefName(), true, false) if err != nil { if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "unknown revision or path not in the working tree") { ctx.Data["IsPullRequestBroken"] = true @@ -401,7 +401,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare } compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), - pull.MergeBase, pull.GetGitRefName(), true) + pull.MergeBase, pull.GetGitRefName(), true, false) if err != nil { if strings.Contains(err.Error(), "fatal: Not a valid object name") { ctx.Data["IsPullRequestBroken"] = true @@ -517,7 +517,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare } compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), - git.BranchPrefix+pull.BaseBranch, pull.GetGitRefName(), true) + git.BranchPrefix+pull.BaseBranch, pull.GetGitRefName(), true, false) if err != nil { if strings.Contains(err.Error(), "fatal: Not a valid object name") { ctx.Data["IsPullRequestBroken"] = true @@ -633,7 +633,7 @@ func ViewPullFiles(ctx *context.Context) { ctx.Data["AfterCommitID"] = endCommitID diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(gitRepo, - startCommitID, endCommitID, setting.Git.MaxGitDiffLines, + startCommitID, endCommitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), false) if err != nil { diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index ef66675c5bb1..f843bc4dcf9d 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -653,6 +653,7 @@ func getCommitFileLineCount(commit *git.Commit, filePath string) int { // Diff represents a difference between two git trees. type Diff struct { + Start, End string NumFiles, TotalAddition, TotalDeletion int Files []*DiffFile IsIncomplete bool @@ -719,6 +720,9 @@ parsingLoop: // TODO: Handle skipping first n files if len(diff.Files) >= maxFiles { + + lastFile := createDiffFile(diff, line) + diff.End = lastFile.Name diff.IsIncomplete = true _, err := io.Copy(io.Discard, reader) if err != nil { @@ -1217,7 +1221,7 @@ func readFileName(rd *strings.Reader) (string, bool) { // GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository. // Passing the empty string as beforeCommitID returns a diff from the parent commit. // The whitespaceBehavior is either an empty string or a git flag -func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) { +func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, afterCommitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) { repoPath := gitRepo.Path commit, err := gitRepo.GetCommit(afterCommitID) @@ -1228,31 +1232,42 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, ctx, cancel := context.WithTimeout(git.DefaultContext, time.Duration(setting.Git.Timeout.Default)*time.Second) defer cancel() - var cmd *exec.Cmd + argsLength := 6 + if len(whitespaceBehavior) > 0 { + argsLength++ + } + if len(skipTo) > 0 { + argsLength++ + } + + diffArgs := make([]string, 0, argsLength) if (len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 { - diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"} + diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M") if len(whitespaceBehavior) != 0 { diffArgs = append(diffArgs, whitespaceBehavior) } // append empty tree ref diffArgs = append(diffArgs, "4b825dc642cb6eb9a060e54bf8d69288fbee4904") diffArgs = append(diffArgs, afterCommitID) - cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...) } else { actualBeforeCommitID := beforeCommitID if len(actualBeforeCommitID) == 0 { parentCommit, _ := commit.Parent(0) actualBeforeCommitID = parentCommit.ID.String() } - diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"} + diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M") if len(whitespaceBehavior) != 0 { diffArgs = append(diffArgs, whitespaceBehavior) } diffArgs = append(diffArgs, actualBeforeCommitID) diffArgs = append(diffArgs, afterCommitID) - cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...) beforeCommitID = actualBeforeCommitID } + if skipTo != "" { + diffArgs = append(diffArgs, "--skip-to="+skipTo) + } + cmd := exec.CommandContext(ctx, git.GitExecutable, diffArgs...) + cmd.Dir = repoPath cmd.Stderr = os.Stderr @@ -1272,6 +1287,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, if err != nil { return nil, fmt.Errorf("ParsePatch: %v", err) } + diff.Start = skipTo var checker *git.CheckAttributeReader @@ -1299,7 +1315,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err) } else { go func() { - err = checker.Run() + err := checker.Run() if err != nil && err != ctx.Err() { log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err) } @@ -1382,8 +1398,8 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, // GetDiffCommitWithWhitespaceBehavior builds a Diff representing the given commitID. // The whitespaceBehavior is either an empty string or a git flag -func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) { - return GetDiffRangeWithWhitespaceBehavior(gitRepo, "", commitID, maxLines, maxLineCharacters, maxFiles, whitespaceBehavior, directComparison) +func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) { + return GetDiffRangeWithWhitespaceBehavior(gitRepo, "", commitID, skipTo, maxLines, maxLineCharacters, maxFiles, whitespaceBehavior, directComparison) } // CommentAsDiff returns c.Patch as *Diff diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index 0c216ccb54bb..d69d0c01d8df 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -522,7 +522,7 @@ func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) { } defer gitRepo.Close() for _, behavior := range []string{"-w", "--ignore-space-at-eol", "-b", ""} { - diffs, err := GetDiffRangeWithWhitespaceBehavior(gitRepo, "559c156f8e0178b71cb44355428f24001b08fc68", "bd7063cc7c04689c4d082183d32a604ed27a24f9", + diffs, err := GetDiffRangeWithWhitespaceBehavior(gitRepo, "559c156f8e0178b71cb44355428f24001b08fc68", "bd7063cc7c04689c4d082183d32a604ed27a24f9", "", setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffFiles, behavior, false) assert.NoError(t, err, fmt.Sprintf("Error when diff with %s", behavior)) for _, f := range diffs.Files { diff --git a/services/pull/pull.go b/services/pull/pull.go index f7d154cfd023..5f6198a39314 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -80,7 +80,7 @@ func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int6 defer baseGitRepo.Close() compareInfo, err := baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), - git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName(), true) + git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName(), true, false) if err != nil { return err } diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 8c4b972bbc9a..d2651d7e08f7 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -42,105 +42,115 @@ {{.Name}} {{end}} + {{if .Diff.IsIncomplete}} +
  • + {{$.i18n.Tr "repo.diff.too_many_files"}} + {{.i18n.Tr "repo.diff.show_more"}} + +
  • + {{end}} - {{range $i, $file := .Diff.Files}} - {{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}} - {{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}} - {{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}} - {{$isCsv := (call $.IsCsvFile $file)}} - {{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}} -
    -

    -
    - +
    + {{range $i, $file := .Diff.Files}} + {{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}} + {{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}} + {{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}} + {{$isCsv := (call $.IsCsvFile $file)}} + {{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}} +
    +

    +
    + + {{if $file.IsGenerated}} + {{svg "octicon-chevron-right" 18}} + {{else}} + {{svg "octicon-chevron-down" 18}} + {{end}} + +
    + {{if $file.IsBin}} + + {{$.i18n.Tr "repo.diff.bin"}} + + {{else}} + {{template "repo/diff/stats" dict "file" . "root" $}} + {{end}} +
    + {{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}{{if .IsLFSFile}} ({{$.i18n.Tr "repo.stored_lfs"}}){{end}} {{if $file.IsGenerated}} - {{svg "octicon-chevron-right" 18}} - {{else}} - {{svg "octicon-chevron-down" 18}} + {{$.i18n.Tr "repo.diff.generated"}} {{end}} - -
    - {{if $file.IsBin}} - - {{$.i18n.Tr "repo.diff.bin"}} - - {{else}} - {{template "repo/diff/stats" dict "file" . "root" $}} + {{if $file.IsVendored}} + {{$.i18n.Tr "repo.diff.vendored"}} {{end}}
    - {{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}{{if .IsLFSFile}} ({{$.i18n.Tr "repo.stored_lfs"}}){{end}} - {{if $file.IsGenerated}} - {{$.i18n.Tr "repo.diff.generated"}} - {{end}} - {{if $file.IsVendored}} - {{$.i18n.Tr "repo.diff.vendored"}} - {{end}} -
    -
    - {{if $showFileViewToggle}} -
    - {{svg "octicon-code"}} - {{svg "octicon-file"}} -
    - {{end}} - {{if $file.IsProtected}} - {{$.i18n.Tr "repo.diff.protected"}} - {{end}} - {{if and (not $file.IsSubmodule) (not $.PageIsWiki)}} - {{if $file.IsDeleted}} - {{$.i18n.Tr "repo.diff.view_file"}} +
    + {{if $showFileViewToggle}} +
    + {{svg "octicon-code"}} + {{svg "octicon-file"}} +
    + {{end}} + {{if $file.IsProtected}} + {{$.i18n.Tr "repo.diff.protected"}} + {{end}} + {{if and (not $file.IsSubmodule) (not $.PageIsWiki)}} + {{if $file.IsDeleted}} + {{$.i18n.Tr "repo.diff.view_file"}} + {{else}} + {{$.i18n.Tr "repo.diff.view_file"}} + {{end}} + {{end}} +
    +

    +
    +
    + {{if or $file.IsIncomplete $file.IsBin}} +
    + {{if $file.IsIncomplete}} + {{if $file.IsIncompleteLineTooLong}} + {{$.i18n.Tr "repo.diff.file_suppressed_line_too_long"}} + {{else}} + {{$.i18n.Tr "repo.diff.file_suppressed"}} + {{end}} + {{else}} + {{$.i18n.Tr "repo.diff.bin_not_shown"}} + {{end}} +
    {{else}} - {{$.i18n.Tr "repo.diff.view_file"}} + + {{if $.IsSplitStyle}} + {{template "repo/diff/section_split" dict "file" . "root" $}} + {{else}} + {{template "repo/diff/section_unified" dict "file" . "root" $}} + {{end}} +
    {{end}} - {{end}} -
    -

    -
    -
    - {{if or $file.IsIncomplete $file.IsBin}} -
    - {{if $file.IsIncomplete}} - {{if $file.IsIncompleteLineTooLong}} - {{$.i18n.Tr "repo.diff.file_suppressed_line_too_long"}} +
    + {{if $showFileViewToggle}} +
    + + {{if $isImage}} + {{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}} {{else}} - {{$.i18n.Tr "repo.diff.file_suppressed"}} + {{template "repo/diff/csv_diff" dict "file" . "root" $}} {{end}} - {{else}} - {{$.i18n.Tr "repo.diff.bin_not_shown"}} - {{end}} +
    - {{else}} - - {{if $.IsSplitStyle}} - {{template "repo/diff/section_split" dict "file" . "root" $}} - {{else}} - {{template "repo/diff/section_unified" dict "file" . "root" $}} - {{end}} -
    {{end}}
    - {{if $showFileViewToggle}} -
    - - {{if $isImage}} - {{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}} - {{else}} - {{template "repo/diff/csv_diff" dict "file" . "root" $}} - {{end}} -
    -
    - {{end}}
    -
    - {{end}} + {{end}} - {{if .Diff.IsIncomplete}} -
    -

    - {{$.i18n.Tr "repo.diff.too_many_files"}} -

    -
    - {{end}} + {{if .Diff.IsIncomplete}} +
    +

    + {{$.i18n.Tr "repo.diff.too_many_files"}} + {{.i18n.Tr "repo.diff.show_more"}} +

    +
    + {{end}} + {{if not $.Repository.IsArchived}}
    diff --git a/web_src/js/features/diff.js b/web_src/js/features/diff.js new file mode 100644 index 000000000000..ef0aaceeeb50 --- /dev/null +++ b/web_src/js/features/diff.js @@ -0,0 +1,24 @@ +export function initDiffShowMore() { + $('#diff-files, #diff-file-boxes').on('click', '#diff-show-more-files, #diff-show-more-files-stats', (e) => { + e.preventDefault(); + + if ($(e.target).hasClass('disabled')) { + return; + } + $('#diff-show-more-files, #diff-show-more-files-stats').addClass('disabled'); + + const url = $('#diff-show-more-files, #diff-show-more-files-stats').data('href'); + $.ajax({ + type: 'GET', + url, + }).done((resp) => { + if (!resp || resp.html === '' || resp.empty) { + $('#diff-show-more-files, #diff-show-more-files-stats').removeClass('disabled'); + return; + } + $('#diff-too-many-files-stats').remove(); + $('#diff-files').append($(resp).find('#diff-files li')); + $('#diff-incomplete').replaceWith($(resp).find('#diff-file-boxes').children()); + }); + }); +} diff --git a/web_src/js/index.js b/web_src/js/index.js index e6269c8abfe6..74aca6913b45 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -27,6 +27,7 @@ import {initNotificationsTable, initNotificationCount} from './features/notifica import {initLastCommitLoader} from './features/lastcommitloader.js'; import {initIssueContentHistory} from './features/issue-content-history.js'; import {initStopwatch} from './features/stopwatch.js'; +import {initDiffShowMore} from './features/diff.js'; import {showLineButton} from './code/linebutton.js'; import {initMarkupContent, initCommentContent} from './markup/content.js'; import {stripTags, mqBinarySearch} from './utils.js'; @@ -2881,6 +2882,7 @@ $(document).ready(async () => { initFileViewToggle(); initReleaseEditor(); initRelease(); + initDiffShowMore(); initIssueContentHistory(); initAdminUserListSearchForm();