Refactor pull request view (6) (#37522)
Clean up legacy logic. * Use backend logic to choose PR timeline icon color * Always use the Vue form to merge, remove the "StillCanManualMerge" logic
This commit is contained in:
@@ -835,14 +835,14 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
|
||||
}
|
||||
|
||||
canDelete := false
|
||||
allowMerge := false
|
||||
canWriteToHeadRepo := false
|
||||
|
||||
pull_service.StartPullRequestCheckOnView(ctx, pull)
|
||||
|
||||
if !prInfo.IsPullRequestBroken {
|
||||
data.ShowUpdatePullInfo = pull.CommitsBehind > 0 && !issue.IsClosed && !pull.IsChecking() && !pull.IsFilesConflicted() && !prInfo.IsPullRequestBroken
|
||||
var err error
|
||||
ctx.Data["UpdateAllowed"], ctx.Data["UpdateByRebaseAllowed"], err = pull_service.IsUserAllowedToUpdate(ctx, pull, ctx.Doer)
|
||||
data.UpdateAllowed, data.UpdateByRebaseAllowed, err = pull_service.IsUserAllowedToUpdate(ctx, pull, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.ServerError("IsUserAllowedToUpdate", err)
|
||||
return
|
||||
@@ -888,7 +888,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
|
||||
if !canWriteToHeadRepo { // maintainers maybe allowed to push to head repo even if they can't write to it
|
||||
canWriteToHeadRepo = pull.AllowMaintainerEdit && perm.CanWrite(unit.TypeCode)
|
||||
}
|
||||
allowMerge, err = pull_service.IsUserAllowedToMerge(ctx, pull, perm, ctx.Doer)
|
||||
data.allowMerge, err = pull_service.IsUserAllowedToMerge(ctx, pull, perm, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.ServerError("IsUserAllowedToMerge", err)
|
||||
return
|
||||
@@ -903,7 +903,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
|
||||
data.ReloadingInterval = util.Iif(pull.IsChecking(), 2000, 0)
|
||||
data.ShowMergeInstructions = canWriteToHeadRepo
|
||||
data.ShowPullCommands = pull.HeadRepo != nil && !pull.HasMerged && !issue.IsClosed
|
||||
ctx.Data["AllowMerge"] = allowMerge
|
||||
ctx.Data["AllowMerge"] = data.allowMerge
|
||||
|
||||
pb := prInfo.ProtectedBranchRule
|
||||
if pb != nil {
|
||||
@@ -947,18 +947,6 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
|
||||
prConfig := issue.Repo.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig()
|
||||
data.AutodetectManualMerge = prConfig.AutodetectManualMerge
|
||||
|
||||
stillCanManualMerge := func() bool {
|
||||
if pull.HasMerged || issue.IsClosed || !ctx.IsSigned {
|
||||
return false
|
||||
}
|
||||
if pull.IsStatusMergeable() || pull.IsWorkInProgress(ctx) || pull.IsChecking() {
|
||||
return false
|
||||
}
|
||||
return allowMerge && prConfig.AllowManualMerge
|
||||
}
|
||||
|
||||
ctx.Data["StillCanManualMerge"] = stillCanManualMerge()
|
||||
|
||||
enableStatusCheck := pb != nil && pb.EnableStatusCheck
|
||||
ctx.Data["EnableStatusCheck"] = enableStatusCheck
|
||||
|
||||
@@ -989,6 +977,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
|
||||
|
||||
ctx.Data["PullMergeBoxData"] = prInfo.MergeBoxData
|
||||
prInfo.prepareMergeBoxFormProps(ctx)
|
||||
prInfo.prepareMergeBoxIconColor()
|
||||
}
|
||||
|
||||
func prepareIssueViewContent(ctx *context.Context, issue *issues_model.Issue) {
|
||||
|
||||
@@ -266,8 +266,15 @@ type pullMergeBoxData struct {
|
||||
ShowMergeBox bool
|
||||
ReloadingInterval int
|
||||
|
||||
TimelineIconClass string
|
||||
|
||||
HasOverridableBlockers bool
|
||||
CanMergeNow bool
|
||||
CanMergeNow bool // PR is mergeable, either no blocker, or doer is admin and can bypass the blockers
|
||||
allowMerge bool // doer has permission to merge
|
||||
|
||||
ShowUpdatePullInfo bool
|
||||
UpdateAllowed bool
|
||||
UpdateByRebaseAllowed bool
|
||||
|
||||
MergeFormProps map[string]any
|
||||
ShowPullCommands bool
|
||||
@@ -302,6 +309,9 @@ type pullRequestViewInfo struct {
|
||||
StatusCheckData *pullCommitStatusCheckData
|
||||
CommitStatuses []*git_model.CommitStatus
|
||||
MergeBoxData *pullMergeBoxData
|
||||
|
||||
enableStatusCheck bool
|
||||
workInProgressPrefix string
|
||||
}
|
||||
|
||||
func newPullRequestViewInfo() *pullRequestViewInfo {
|
||||
@@ -430,8 +440,8 @@ func (prInfo *pullRequestViewInfo) prepareViewFillCommitStatusInfoForOpen(ctx *c
|
||||
}
|
||||
|
||||
pb := prInfo.ProtectedBranchRule
|
||||
enableStatusCheck := pb != nil && pb.EnableStatusCheck
|
||||
if !enableStatusCheck {
|
||||
prInfo.enableStatusCheck = pb != nil && pb.EnableStatusCheck
|
||||
if !prInfo.enableStatusCheck {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -549,9 +559,10 @@ func (prInfo *pullRequestViewInfo) prepareViewOpenPullInfo(ctx *context.Context)
|
||||
}
|
||||
|
||||
// this one is used by both sidebar and merge-box
|
||||
prInfo.workInProgressPrefix = pull.GetWorkInProgressPrefix(ctx)
|
||||
if pull.IsWorkInProgress(ctx) {
|
||||
ctx.Data["IsPullWorkInProgress"] = true
|
||||
ctx.Data["WorkInProgressPrefix"] = pull.GetWorkInProgressPrefix(ctx)
|
||||
ctx.Data["IsPullWorkInProgress"] = prInfo.workInProgressPrefix != ""
|
||||
ctx.Data["WorkInProgressPrefix"] = prInfo.workInProgressPrefix
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repo
|
||||
|
||||
func (prInfo *pullRequestViewInfo) prepareMergeBoxIconColor() {
|
||||
pull := prInfo.issue.PullRequest
|
||||
mergeBoxData := prInfo.MergeBoxData
|
||||
statusCheckData := prInfo.StatusCheckData
|
||||
switch {
|
||||
case pull.HasMerged:
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-purple"
|
||||
case prInfo.issue.IsClosed, prInfo.workInProgressPrefix != "", pull.IsFilesConflicted():
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-text-light"
|
||||
case prInfo.IsPullRequestBroken, mergeBoxData.isBlockedByApprovals, mergeBoxData.isBlockedByRejection,
|
||||
mergeBoxData.isBlockedByOfficialReviewRequests, mergeBoxData.isBlockedByOutdatedBranch, mergeBoxData.isBlockedByChangedProtectedFiles:
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-red"
|
||||
case prInfo.enableStatusCheck && (statusCheckData.RequiredChecksState.IsFailure() || statusCheckData.RequiredChecksState.IsError()):
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-red"
|
||||
case prInfo.enableStatusCheck && (statusCheckData.LatestCommitStatus == nil || statusCheckData.RequiredChecksState.IsPending() || statusCheckData.RequiredChecksState.IsWarning()):
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-yellow"
|
||||
case mergeBoxData.allowMerge && mergeBoxData.requireSigned && !mergeBoxData.willSign:
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-red"
|
||||
case pull.IsChecking():
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-yellow"
|
||||
case pull.IsEmpty():
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-text-light"
|
||||
case pull.IsStatusMergeable():
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-green"
|
||||
default:
|
||||
prInfo.MergeBoxData.TimelineIconClass = "tw-text-red"
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,13 @@ import (
|
||||
|
||||
func (prInfo *pullRequestViewInfo) prepareMergeBoxFormProps(ctx *context.Context) {
|
||||
pull := prInfo.issue.PullRequest
|
||||
if pull.HasMerged || prInfo.issue.IsClosed {
|
||||
return
|
||||
}
|
||||
if !prInfo.MergeBoxData.allowMerge {
|
||||
return
|
||||
}
|
||||
|
||||
prConfig := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig()
|
||||
|
||||
// Check correct values and select default
|
||||
@@ -69,7 +76,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBoxFormProps(ctx *context.Context
|
||||
}
|
||||
|
||||
allOverridableChecksOk := !prInfo.MergeBoxData.HasOverridableBlockers
|
||||
prInfo.MergeBoxData.MergeFormProps = map[string]any{
|
||||
mergeFormProps := map[string]any{
|
||||
"baseLink": prInfo.issue.Link(),
|
||||
"textCancel": ctx.Locale.Tr("cancel"),
|
||||
"textDeleteBranch": ctx.Locale.Tr("repo.branch.delete", prInfo.headTarget),
|
||||
@@ -97,51 +104,75 @@ func (prInfo *pullRequestViewInfo) prepareMergeBoxFormProps(ctx *context.Context
|
||||
// if this pr can be merged now, then hide the auto merge
|
||||
generalHideAutoMerge := prInfo.MergeBoxData.CanMergeNow && allOverridableChecksOk
|
||||
|
||||
prInfo.MergeBoxData.MergeFormProps["mergeStyles"] = []any{
|
||||
map[string]any{
|
||||
"name": "merge",
|
||||
"allowed": prConfig.AllowMerge,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.merge_pull_request"),
|
||||
"mergeTitleFieldText": defaultMergeTitle,
|
||||
"mergeMessageFieldText": defaultMergeBody,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
map[string]any{
|
||||
"name": "rebase",
|
||||
"allowed": prConfig.AllowRebase,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_pull_request"),
|
||||
"hideMergeMessageTexts": true,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
map[string]any{
|
||||
"name": "rebase-merge",
|
||||
"allowed": prConfig.AllowRebaseMerge,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_commit_pull_request"),
|
||||
"mergeTitleFieldText": defaultMergeTitle,
|
||||
"mergeMessageFieldText": defaultMergeBody,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
map[string]any{
|
||||
"name": "squash",
|
||||
"allowed": prConfig.AllowSquash,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.squash_merge_pull_request"),
|
||||
"mergeTitleFieldText": defaultSquashMergeTitle,
|
||||
"mergeMessageFieldText": defaultSquashMergeCommitMessages + defaultSquashMergeBody,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
map[string]any{
|
||||
"name": "fast-forward-only",
|
||||
"allowed": prConfig.AllowFastForwardOnly && pull.CommitsBehind == 0,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.fast_forward_only_merge_pull_request"),
|
||||
"hideMergeMessageTexts": true,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
map[string]any{
|
||||
var mergeStyles []any
|
||||
if pull.IsStatusMergeable() {
|
||||
mergeStyles = []any{
|
||||
map[string]any{
|
||||
"name": "merge",
|
||||
"allowed": prConfig.AllowMerge,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.merge_pull_request"),
|
||||
"mergeTitleFieldText": defaultMergeTitle,
|
||||
"mergeMessageFieldText": defaultMergeBody,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
map[string]any{
|
||||
"name": "rebase",
|
||||
"allowed": prConfig.AllowRebase,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_pull_request"),
|
||||
"hideMergeMessageTexts": true,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
map[string]any{
|
||||
"name": "rebase-merge",
|
||||
"allowed": prConfig.AllowRebaseMerge,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_commit_pull_request"),
|
||||
"mergeTitleFieldText": defaultMergeTitle,
|
||||
"mergeMessageFieldText": defaultMergeBody,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
map[string]any{
|
||||
"name": "squash",
|
||||
"allowed": prConfig.AllowSquash,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.squash_merge_pull_request"),
|
||||
"mergeTitleFieldText": defaultSquashMergeTitle,
|
||||
"mergeMessageFieldText": defaultSquashMergeCommitMessages + defaultSquashMergeBody,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
map[string]any{
|
||||
"name": "fast-forward-only",
|
||||
"allowed": prConfig.AllowFastForwardOnly && pull.CommitsBehind == 0,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.fast_forward_only_merge_pull_request"),
|
||||
"hideMergeMessageTexts": true,
|
||||
"hideAutoMerge": generalHideAutoMerge,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
canUseManualMerge := func() bool {
|
||||
if pull.IsWorkInProgress(ctx) || pull.IsChecking() {
|
||||
return false
|
||||
}
|
||||
return prConfig.AllowManualMerge
|
||||
}
|
||||
// Manually Merged is not a well-known feature, it is used to mark a non-mergeable PR (already merged, conflicted) as merged
|
||||
// To test it:
|
||||
// Enable "Manually Merged" feature in the Repository Settings
|
||||
// Create a pull request, either:
|
||||
// - Merge the pull request branch locally and push the merged commit to Gitea
|
||||
// - Make some conflicts between the base branch and the pull request branch
|
||||
// Then the Manually Merged form will be shown in the merge form
|
||||
if canUseManualMerge() {
|
||||
mergeStyles = append(mergeStyles, map[string]any{
|
||||
"name": "manually-merged",
|
||||
"allowed": prConfig.AllowManualMerge,
|
||||
"textDoMerge": ctx.Locale.Tr("repo.pulls.merge_manually"),
|
||||
"hideMergeMessageTexts": true,
|
||||
"hideAutoMerge": true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if len(mergeStyles) > 0 {
|
||||
mergeFormProps["mergeStyles"] = mergeStyles
|
||||
prInfo.MergeBoxData.MergeFormProps = mergeFormProps
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user