From 2f0e79e6393df13930eaa419273d24dc2ef36cfa Mon Sep 17 00:00:00 2001 From: HesterG Date: Fri, 21 Jul 2023 19:20:04 +0800 Subject: [PATCH] Use frontend fetch for branch dropdown component (#25719) - Send request to get branch/tag list, use loading icon when waiting for response. - Only fetch when the first time branch/tag list shows. - For backend, removed assignment to `ctx.Data["Branches"]` and `ctx.Data["Tags"]` from `context/repo.go` and passed these data wherever needed. - Changed some `v-if` to `v-show` and used native `svg` as mentioned in https://github.com/go-gitea/gitea/pull/25719#issuecomment-1631712757 to improve perfomance when there are a lot of branches. - Places Used the dropdown component: Repo Home Page Screen Shot 2023-07-06 at 12 17 51 Commits Page Screen Shot 2023-07-06 at 12 18 34 Specific commit -> operations -> cherry-pick Screen Shot 2023-07-06 at 12 23 28 Release Page Screen Shot 2023-07-06 at 12 25 05 - Demo https://github.com/go-gitea/gitea/assets/17645053/d45d266b-3eb0-465a-82f9-57f78dc5f9f3 - Note: UI of dropdown menu could be improved in another PR as it should apply to more dropdown menus. Fix #14180 --------- Co-authored-by: silverwind Co-authored-by: wxiaoguang --- modules/context/repo.go | 30 ++---- routers/web/repo/compare.go | 6 ++ routers/web/repo/issue.go | 32 +++++-- routers/web/repo/pull.go | 10 ++ routers/web/repo/release.go | 21 ++++ routers/web/repo/repo.go | 61 ++++++++++++ routers/web/repo/setting/protected_branch.go | 11 +++ routers/web/web.go | 2 + templates/repo/branch_dropdown.tmpl | 2 - web_src/css/repo.css | 4 + .../js/components/RepoBranchTagSelector.vue | 95 +++++++++++++------ web_src/js/modules/toast.js | 2 +- web_src/js/svg.js | 8 +- 13 files changed, 218 insertions(+), 66 deletions(-) diff --git a/modules/context/repo.go b/modules/context/repo.go index eae71cfb7be6..2c67735c934c 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -660,13 +660,6 @@ func RepoAssignment(ctx *Context) context.CancelFunc { return cancel } - tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) - if err != nil { - ctx.ServerError("GetTagNamesByRepoID", err) - return cancel - } - ctx.Data["Tags"] = tags - branchOpts := git_model.FindBranchOptions{ RepoID: ctx.Repo.Repository.ID, IsDeletedBranch: util.OptionalBoolFalse, @@ -680,7 +673,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { return cancel } - // non empty repo should have at least 1 branch, so this repository's branches haven't been synced yet + // non-empty repo should have at least 1 branch, so this repository's branches haven't been synced yet if branchesTotal == 0 { // fallback to do a sync immediately branchesTotal, err = repo_module.SyncRepoBranches(ctx, ctx.Repo.Repository.ID, 0) if err != nil { @@ -689,24 +682,19 @@ func RepoAssignment(ctx *Context) context.CancelFunc { } } - // FIXME: use paganation and async loading - branchOpts.ExcludeBranchNames = []string{ctx.Repo.Repository.DefaultBranch} - brs, err := git_model.FindBranchNames(ctx, branchOpts) - if err != nil { - ctx.ServerError("GetBranches", err) - return cancel - } - // always put default branch on the top - ctx.Data["Branches"] = append(branchOpts.ExcludeBranchNames, brs...) ctx.Data["BranchesCount"] = branchesTotal - // If not branch selected, try default one. - // If default branch doesn't exist, fall back to some other branch. + // If no branch is set in the request URL, try to guess a default one. if len(ctx.Repo.BranchName) == 0 { if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch - } else if len(brs) > 0 { - ctx.Repo.BranchName = brs[0] + } else { + ctx.Repo.BranchName, _ = gitRepo.GetDefaultBranch() + if ctx.Repo.BranchName == "" { + // If it still can't get a default branch, fall back to default branch from setting. + // Something might be wrong. Either site admin should fix the repo sync or Gitea should fix a potential bug. + ctx.Repo.BranchName = setting.Repository.DefaultBranch + } } ctx.Repo.RefName = ctx.Repo.BranchName } diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 7089c219ad25..4ceb52d03994 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -754,6 +754,12 @@ func CompareDiff(ctx *context.Context) { } ctx.Data["HeadBranches"] = headBranches + // For compare repo branches + PrepareBranchList(ctx) + if ctx.Written() { + return + } + headTags, err := repo_model.GetTagNamesByRepoID(ctx, ci.HeadRepo.ID) if err != nil { ctx.ServerError("GetTagNamesByRepoID", err) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 8fb6fe04dfcf..f85551404849 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -785,18 +785,10 @@ func RetrieveRepoMetas(ctx *context.Context, repo *repo_model.Repository, isPull return nil } - brs, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{ - RepoID: ctx.Repo.Repository.ID, - ListOptions: db.ListOptions{ - ListAll: true, - }, - IsDeletedBranch: util.OptionalBoolFalse, - }) - if err != nil { - ctx.ServerError("GetBranches", err) + PrepareBranchList(ctx) + if ctx.Written() { return nil } - ctx.Data["Branches"] = brs // Contains true if the user can create issue dependencies ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.Doer, isPull) @@ -921,6 +913,13 @@ func NewIssue(ctx *context.Context) { RetrieveRepoMetas(ctx, ctx.Repo.Repository, false) + tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) + if err != nil { + ctx.ServerError("GetTagNamesByRepoID", err) + return + } + ctx.Data["Tags"] = tags + _, templateErrs := issue_service.GetTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) if errs := setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates); len(errs) > 0 { for k, v := range errs { @@ -1918,6 +1917,19 @@ func ViewIssue(ctx *context.Context) { ctx.Data["ShouldShowCommentType"] = func(commentType issues_model.CommentType) bool { return hiddenCommentTypes == nil || hiddenCommentTypes.Bit(int(commentType)) == 0 } + // For sidebar + PrepareBranchList(ctx) + + if ctx.Written() { + return + } + + tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) + if err != nil { + ctx.ServerError("GetTagNamesByRepoID", err) + return + } + ctx.Data["Tags"] = tags ctx.HTML(http.StatusOK, tplIssueView) } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index c5f260adfa74..adfc01c2517f 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -729,6 +729,11 @@ func ViewPullCommits(ctx *context.Context) { ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.Doer.ID) + // For PR commits page + PrepareBranchList(ctx) + if ctx.Written() { + return + } getBranchData(ctx, issue) ctx.HTML(http.StatusOK, tplPullCommits) } @@ -893,6 +898,11 @@ func ViewPullFiles(ctx *context.Context) { ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled + // For files changed page + PrepareBranchList(ctx) + if ctx.Written() { + return + } upload.AddUploadContext(ctx, "comment") ctx.HTML(http.StatusOK, tplPullFiles) diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 1a0303f1f21b..3d991384e56a 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -352,6 +352,20 @@ func NewRelease(ctx *context.Context) { ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) upload.AddUploadContext(ctx, "release") + + // For New Release page + PrepareBranchList(ctx) + if ctx.Written() { + return + } + + tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) + if err != nil { + ctx.ServerError("GetTagNamesByRepoID", err) + return + } + ctx.Data["Tags"] = tags + ctx.HTML(http.StatusOK, tplReleaseNew) } @@ -361,6 +375,13 @@ func NewReleasePost(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.release.new_release") ctx.Data["PageIsReleaseList"] = true + tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) + if err != nil { + ctx.ServerError("GetTagNamesByRepoID", err) + return + } + ctx.Data["Tags"] = tags + if ctx.HasError() { ctx.HTML(http.StatusOK, tplReleaseNew) return diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 0a2b334eb90a..0de804dbce6f 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -622,3 +622,64 @@ func SearchRepo(ctx *context.Context) { Data: results, }) } + +type branchTagSearchResponse struct { + Results []string `json:"results"` +} + +// GetBranchesList get branches for current repo' +func GetBranchesList(ctx *context.Context) { + branchOpts := git_model.FindBranchOptions{ + RepoID: ctx.Repo.Repository.ID, + IsDeletedBranch: util.OptionalBoolFalse, + ListOptions: db.ListOptions{ + ListAll: true, + }, + } + branches, err := git_model.FindBranchNames(ctx, branchOpts) + if err != nil { + ctx.JSON(http.StatusInternalServerError, err) + return + } + resp := &branchTagSearchResponse{} + // always put default branch on the top if it exists + if util.SliceContains(branches, ctx.Repo.Repository.DefaultBranch) { + branches = util.SliceRemoveAll(branches, ctx.Repo.Repository.DefaultBranch) + branches = append([]string{ctx.Repo.Repository.DefaultBranch}, branches...) + } + resp.Results = branches + ctx.JSON(http.StatusOK, resp) +} + +// GetTagList get tag list for current repo +func GetTagList(ctx *context.Context) { + tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) + if err != nil { + ctx.JSON(http.StatusInternalServerError, err) + return + } + resp := &branchTagSearchResponse{} + resp.Results = tags + ctx.JSON(http.StatusOK, resp) +} + +func PrepareBranchList(ctx *context.Context) { + branchOpts := git_model.FindBranchOptions{ + RepoID: ctx.Repo.Repository.ID, + IsDeletedBranch: util.OptionalBoolFalse, + ListOptions: db.ListOptions{ + ListAll: true, + }, + } + brs, err := git_model.FindBranchNames(ctx, branchOpts) + if err != nil { + ctx.ServerError("GetBranches", err) + return + } + // always put default branch on the top if it exists + if util.SliceContains(brs, ctx.Repo.Repository.DefaultBranch) { + brs = util.SliceRemoveAll(brs, ctx.Repo.Repository.DefaultBranch) + brs = append([]string{ctx.Repo.Repository.DefaultBranch}, brs...) + } + ctx.Data["Branches"] = brs +} diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index 777d52c85806..b8775cca2d3c 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/routers/web/repo" "code.gitea.io/gitea/services/forms" pull_service "code.gitea.io/gitea/services/pull" "code.gitea.io/gitea/services/repository" @@ -44,6 +45,11 @@ func ProtectedBranchRules(ctx *context.Context) { } ctx.Data["ProtectedBranches"] = rules + repo.PrepareBranchList(ctx) + if ctx.Written() { + return + } + ctx.HTML(http.StatusOK, tplBranches) } @@ -52,6 +58,11 @@ func SetDefaultBranchPost(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.settings.branches.update_default_branch") ctx.Data["PageIsSettingsBranches"] = true + repo.PrepareBranchList(ctx) + if ctx.Written() { + return + } + repo := ctx.Repo.Repository switch ctx.FormString("action") { diff --git a/routers/web/web.go b/routers/web/web.go index 00e0ca36dab0..f091bfefb86d 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1094,6 +1094,7 @@ func registerRoutes(m *web.Route) { }, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived()) m.Group("/branches", func() { + m.Get("/list", repo.GetBranchesList) m.Group("/_new", func() { m.Post("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.CreateBranch) m.Post("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.CreateBranch) @@ -1108,6 +1109,7 @@ func registerRoutes(m *web.Route) { m.Group("/{username}/{reponame}", func() { m.Group("/tags", func() { m.Get("", repo.TagsList) + m.Get("/list", repo.GetTagList) m.Get(".rss", feedEnabled, repo.TagsListFeedRSS) m.Get(".atom", feedEnabled, repo.TagsListFeedAtom) }, ctxDataSet("EnableFeed", setting.Other.EnableFeed), diff --git a/templates/repo/branch_dropdown.tmpl b/templates/repo/branch_dropdown.tmpl index 984899552dc0..4ec2fd557c76 100644 --- a/templates/repo/branch_dropdown.tmpl +++ b/templates/repo/branch_dropdown.tmpl @@ -44,8 +44,6 @@ 'tagName': {{.root.TagName}}, 'branchName': {{.root.BranchName}}, 'noTag': {{.noTag}}, - 'branches': {{.root.Branches}}, - 'tags': {{.root.Tags}}, 'defaultBranch': {{$defaultBranch}}, 'enableFeed': {{.root.EnableFeed}}, 'rssURLPrefix': '{{$.root.RepoLink}}/rss/branch/', diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 877f0d9c1734..6cd7c2537e51 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -3359,3 +3359,7 @@ tbody.commit-list { font-size: 18px; margin-left: 4px; } + +#cherry-pick-modal .scrolling.menu { + max-height: 200px; +} diff --git a/web_src/js/components/RepoBranchTagSelector.vue b/web_src/js/components/RepoBranchTagSelector.vue index 4fc393624469..e6e72e3886d7 100644 --- a/web_src/js/components/RepoBranchTagSelector.vue +++ b/web_src/js/components/RepoBranchTagSelector.vue @@ -11,7 +11,7 @@ -