From 705f3805ad8c2c81d42b27d7de4c641272711ea2 Mon Sep 17 00:00:00 2001 From: Alexander McRae Date: Wed, 5 Feb 2025 19:36:07 -0800 Subject: [PATCH] Modify Diff View FileTree to show all files == Changes * removes Show Status button on diff * uses `git diff-tree` to generate the file tree for the diff update locale to remove diff.show_diff_stats --- options/locale/locale_en-US.ini | 1 - routers/web/repo/commit.go | 12 +++ routers/web/repo/compare.go | 10 +++ routers/web/repo/pull.go | 23 ++++++ routers/web/repo/treelist.go | 39 ++++++++++ services/gitdiff/git_diff_tree.go | 7 ++ templates/repo/diff/box.tmpl | 3 +- templates/repo/diff/options_dropdown.tmpl | 1 - web_src/js/components/DiffFileList.vue | 60 --------------- web_src/js/components/DiffFileTree.vue | 76 ++---------------- web_src/js/components/DiffFileTreeItem.vue | 67 ++++++++-------- web_src/js/components/file_tree.ts | 90 ++++++++++++++++++++++ web_src/js/features/repo-diff-filetree.ts | 9 --- web_src/js/features/repo-diff.ts | 74 ++++++++++++++++-- 14 files changed, 290 insertions(+), 182 deletions(-) delete mode 100644 web_src/js/components/DiffFileList.vue create mode 100644 web_src/js/components/file_tree.ts diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4c25ba320555d..6d6781070c7d4 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2595,7 +2595,6 @@ diff.commit = commit diff.git-notes = Notes diff.data_not_available = Diff Content Not Available diff.options_button = Diff Options -diff.show_diff_stats = Show Stats diff.download_patch = Download Patch File diff.download_diff = Download Diff File diff.show_split_view = Split View diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 9c12ef9297813..abfa73ae7814a 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -344,18 +344,30 @@ func Diff(ctx *context.Context) { ctx.Data["Reponame"] = repoName var parentCommit *git.Commit + var parentCommitID string if commit.ParentCount() > 0 { parentCommit, err = gitRepo.GetCommit(parents[0]) if err != nil { ctx.NotFound(err) return } + parentCommitID = parentCommit.ID.String() } setCompareContext(ctx, parentCommit, commit, userName, repoName) ctx.Data["Title"] = commit.Summary() + " ยท " + base.ShortSha(commitID) ctx.Data["Commit"] = commit ctx.Data["Diff"] = diff + if !fileOnly { + diffTree, err := gitdiff.GetDiffTree(ctx, gitRepo, false, parentCommitID, commitID) + if err != nil { + ctx.ServerError("GetDiffTree", err) + return + } + + ctx.Data["DiffTree"] = transformDiffTreeForUI(diffTree, nil) + } + statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptionsAll) if err != nil { log.Error("GetLatestCommitStatus: %v", err) diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 71bce759a9252..25efb90defaf9 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -633,6 +633,16 @@ func PrepareCompareDiff( ctx.Data["Diff"] = diff ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0 + if !fileOnly { + diffTree, err := gitdiff.GetDiffTree(ctx, ci.HeadGitRepo, false, beforeCommitID, headCommitID) + if err != nil { + ctx.ServerError("GetDiffTree", err) + return false + } + + ctx.Data["DiffTree"] = transformDiffTreeForUI(diffTree, nil) + } + headCommit, err := ci.HeadGitRepo.GetCommit(headCommitID) if err != nil { ctx.ServerError("GetCommit", err) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 223f8d017ed30..809881cabb9fd 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -761,6 +761,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi var methodWithError string var diff *gitdiff.Diff + shouldGetUserSpecificDiff := false // if we're not logged in or only a single commit (or commit range) is shown we // have to load only the diff and not get the viewed information @@ -772,6 +773,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi } else { diff, err = gitdiff.SyncAndGetUserSpecificDiff(ctx, ctx.Doer.ID, pull, gitRepo, diffOptions, files...) methodWithError = "SyncAndGetUserSpecificDiff" + shouldGetUserSpecificDiff = true } if err != nil { ctx.ServerError(methodWithError, err) @@ -816,6 +818,27 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi } } + if !fileOnly { + // note: use mergeBase is set to false because we already have the merge base from the pull request info + diffTree, err := gitdiff.GetDiffTree(ctx, gitRepo, false, pull.MergeBase, headCommitID) + if err != nil { + ctx.ServerError("GetDiffTree", err) + return + } + + filesViewedState := make(map[string]pull_model.ViewedState) + if shouldGetUserSpecificDiff { + // This sort of sucks because we already fetch this when getting the diff + review, err := pull_model.GetNewestReviewState(ctx, ctx.Doer.ID, issue.ID) + if !(err != nil || review == nil || review.UpdatedFiles == nil) { + // If there wasn't an error and we have a review with updated files, use that + filesViewedState = review.UpdatedFiles + } + } + + ctx.Data["DiffFiles"] = transformDiffTreeForUI(diffTree, filesViewedState) + } + ctx.Data["Diff"] = diff ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0 diff --git a/routers/web/repo/treelist.go b/routers/web/repo/treelist.go index d11af4669f90c..04bf3ba298806 100644 --- a/routers/web/repo/treelist.go +++ b/routers/web/repo/treelist.go @@ -6,9 +6,11 @@ package repo import ( "net/http" + pull_model "code.gitea.io/gitea/models/pull" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/gitdiff" "github.com/go-enry/go-enry/v2" ) @@ -52,3 +54,40 @@ func isExcludedEntry(entry *git.TreeEntry) bool { return false } + +type FileDiffFile struct { + Name string + NameHash string + IsSubmodule bool + IsBinary bool + IsViewed bool + Status string +} + +// transformDiffTreeForUI transforms a DiffTree into a slice of FileDiffFile for UI rendering +// it also takes a map of file names to their viewed state, which is used to mark files as viewed +func transformDiffTreeForUI(diffTree *gitdiff.DiffTree, filesViewedState map[string]pull_model.ViewedState) []FileDiffFile { + files := make([]FileDiffFile, 0, len(diffTree.Files)) + + for _, file := range diffTree.Files { + nameHash := git.HashFilePathForWebUI(file.HeadPath) + isSubmodule := file.HeadMode == git.EntryModeCommit + isBinary := file.HeadMode == git.EntryModeExec + + isViewed := false + if fileViewedState, ok := filesViewedState[file.Path()]; ok { + isViewed = (fileViewedState == pull_model.Viewed) + } + + files = append(files, FileDiffFile{ + Name: file.HeadPath, + NameHash: nameHash, + IsSubmodule: isSubmodule, + IsBinary: isBinary, + IsViewed: isViewed, + Status: file.Status, + }) + } + + return files +} diff --git a/services/gitdiff/git_diff_tree.go b/services/gitdiff/git_diff_tree.go index 8039de145d2db..16b40bf508d20 100644 --- a/services/gitdiff/git_diff_tree.go +++ b/services/gitdiff/git_diff_tree.go @@ -34,6 +34,13 @@ type DiffTreeRecord struct { BaseBlobID string } +func (d *DiffTreeRecord) Path() string { + if d.HeadPath != "" { + return d.HeadPath + } + return d.BasePath +} + // GetDiffTree returns the list of path of the files that have changed between the two commits. // If useMergeBase is true, the diff will be calculated using the merge base of the two commits. // This is the same behavior as using a three-dot diff in git diff. diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index a3b64b8a11f79..1315e45cbe3de 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -58,7 +58,8 @@ {{end}} - - diff --git a/web_src/js/components/DiffFileTree.vue b/web_src/js/components/DiffFileTree.vue index d00d03565f217..7e462bd8324ff 100644 --- a/web_src/js/components/DiffFileTree.vue +++ b/web_src/js/components/DiffFileTree.vue @@ -1,75 +1,18 @@ diff --git a/web_src/js/components/DiffFileTreeItem.vue b/web_src/js/components/DiffFileTreeItem.vue index d3be10e3e9ca5..1d730d4e3aac6 100644 --- a/web_src/js/components/DiffFileTreeItem.vue +++ b/web_src/js/components/DiffFileTreeItem.vue @@ -2,21 +2,7 @@ import {SvgIcon, type SvgName} from '../svg.ts'; import {diffTreeStore} from '../modules/stores.ts'; import {ref} from 'vue'; - -type File = { - Name: string; - NameHash: string; - Type: number; - IsViewed: boolean; - IsSubmodule: boolean; -} - -export type Item = { - name: string; - isFile: boolean; - file?: File; - children?: Item[]; -}; +import {type Item, type File, type FileStatus} from './file_tree.ts'; defineProps<{ item: Item, @@ -25,15 +11,16 @@ defineProps<{ const store = diffTreeStore(); const collapsed = ref(false); -function getIconForDiffType(pType: number) { - const diffTypes: Record}> = { - '1': {name: 'octicon-diff-added', classes: ['text', 'green']}, - '2': {name: 'octicon-diff-modified', classes: ['text', 'yellow']}, - '3': {name: 'octicon-diff-removed', classes: ['text', 'red']}, - '4': {name: 'octicon-diff-renamed', classes: ['text', 'teal']}, - '5': {name: 'octicon-diff-renamed', classes: ['text', 'green']}, // there is no octicon for copied, so renamed should be ok +function getIconForDiffStatus(pType: FileStatus) { + const diffTypes: Record }> = { + 'added': {name: 'octicon-diff-added', classes: ['text', 'green']}, + 'modified': {name: 'octicon-diff-modified', classes: ['text', 'yellow']}, + 'deleted': {name: 'octicon-diff-removed', classes: ['text', 'red']}, + 'renamed': {name: 'octicon-diff-renamed', classes: ['text', 'teal']}, + 'copied': {name: 'octicon-diff-renamed', classes: ['text', 'green']}, + 'typechange': {name: 'octicon-diff-modified', classes: ['text', 'green']}, // there is no octicon for copied, so renamed should be ok }; - return diffTypes[String(pType)]; + return diffTypes[pType]; } function fileIcon(file: File) { @@ -48,27 +35,37 @@ function fileIcon(file: File) { {{ item.name }} - + -
- - - - {{ item.name }} -
-
- -
+