Skip to content

Commit dd17521

Browse files
authored
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
1 parent f26f71f commit dd17521

16 files changed

Lines changed: 293 additions & 316 deletions

File tree

routers/web/repo/issue_view.go

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -835,14 +835,14 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
835835
}
836836

837837
canDelete := false
838-
allowMerge := false
839838
canWriteToHeadRepo := false
840839

841840
pull_service.StartPullRequestCheckOnView(ctx, pull)
842841

843842
if !prInfo.IsPullRequestBroken {
843+
data.ShowUpdatePullInfo = pull.CommitsBehind > 0 && !issue.IsClosed && !pull.IsChecking() && !pull.IsFilesConflicted() && !prInfo.IsPullRequestBroken
844844
var err error
845-
ctx.Data["UpdateAllowed"], ctx.Data["UpdateByRebaseAllowed"], err = pull_service.IsUserAllowedToUpdate(ctx, pull, ctx.Doer)
845+
data.UpdateAllowed, data.UpdateByRebaseAllowed, err = pull_service.IsUserAllowedToUpdate(ctx, pull, ctx.Doer)
846846
if err != nil {
847847
ctx.ServerError("IsUserAllowedToUpdate", err)
848848
return
@@ -888,7 +888,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
888888
if !canWriteToHeadRepo { // maintainers maybe allowed to push to head repo even if they can't write to it
889889
canWriteToHeadRepo = pull.AllowMaintainerEdit && perm.CanWrite(unit.TypeCode)
890890
}
891-
allowMerge, err = pull_service.IsUserAllowedToMerge(ctx, pull, perm, ctx.Doer)
891+
data.allowMerge, err = pull_service.IsUserAllowedToMerge(ctx, pull, perm, ctx.Doer)
892892
if err != nil {
893893
ctx.ServerError("IsUserAllowedToMerge", err)
894894
return
@@ -903,7 +903,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
903903
data.ReloadingInterval = util.Iif(pull.IsChecking(), 2000, 0)
904904
data.ShowMergeInstructions = canWriteToHeadRepo
905905
data.ShowPullCommands = pull.HeadRepo != nil && !pull.HasMerged && !issue.IsClosed
906-
ctx.Data["AllowMerge"] = allowMerge
906+
ctx.Data["AllowMerge"] = data.allowMerge
907907

908908
pb := prInfo.ProtectedBranchRule
909909
if pb != nil {
@@ -947,18 +947,6 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
947947
prConfig := issue.Repo.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig()
948948
data.AutodetectManualMerge = prConfig.AutodetectManualMerge
949949

950-
stillCanManualMerge := func() bool {
951-
if pull.HasMerged || issue.IsClosed || !ctx.IsSigned {
952-
return false
953-
}
954-
if pull.IsStatusMergeable() || pull.IsWorkInProgress(ctx) || pull.IsChecking() {
955-
return false
956-
}
957-
return allowMerge && prConfig.AllowManualMerge
958-
}
959-
960-
ctx.Data["StillCanManualMerge"] = stillCanManualMerge()
961-
962950
enableStatusCheck := pb != nil && pb.EnableStatusCheck
963951
ctx.Data["EnableStatusCheck"] = enableStatusCheck
964952

@@ -989,6 +977,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue *
989977

990978
ctx.Data["PullMergeBoxData"] = prInfo.MergeBoxData
991979
prInfo.prepareMergeBoxFormProps(ctx)
980+
prInfo.prepareMergeBoxIconColor()
992981
}
993982

994983
func prepareIssueViewContent(ctx *context.Context, issue *issues_model.Issue) {

routers/web/repo/pull.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,15 @@ type pullMergeBoxData struct {
266266
ShowMergeBox bool
267267
ReloadingInterval int
268268

269+
TimelineIconClass string
270+
269271
HasOverridableBlockers bool
270-
CanMergeNow bool
272+
CanMergeNow bool // PR is mergeable, either no blocker, or doer is admin and can bypass the blockers
273+
allowMerge bool // doer has permission to merge
274+
275+
ShowUpdatePullInfo bool
276+
UpdateAllowed bool
277+
UpdateByRebaseAllowed bool
271278

272279
MergeFormProps map[string]any
273280
ShowPullCommands bool
@@ -302,6 +309,9 @@ type pullRequestViewInfo struct {
302309
StatusCheckData *pullCommitStatusCheckData
303310
CommitStatuses []*git_model.CommitStatus
304311
MergeBoxData *pullMergeBoxData
312+
313+
enableStatusCheck bool
314+
workInProgressPrefix string
305315
}
306316

307317
func newPullRequestViewInfo() *pullRequestViewInfo {
@@ -430,8 +440,8 @@ func (prInfo *pullRequestViewInfo) prepareViewFillCommitStatusInfoForOpen(ctx *c
430440
}
431441

432442
pb := prInfo.ProtectedBranchRule
433-
enableStatusCheck := pb != nil && pb.EnableStatusCheck
434-
if !enableStatusCheck {
443+
prInfo.enableStatusCheck = pb != nil && pb.EnableStatusCheck
444+
if !prInfo.enableStatusCheck {
435445
return
436446
}
437447

@@ -549,9 +559,10 @@ func (prInfo *pullRequestViewInfo) prepareViewOpenPullInfo(ctx *context.Context)
549559
}
550560

551561
// this one is used by both sidebar and merge-box
562+
prInfo.workInProgressPrefix = pull.GetWorkInProgressPrefix(ctx)
552563
if pull.IsWorkInProgress(ctx) {
553-
ctx.Data["IsPullWorkInProgress"] = true
554-
ctx.Data["WorkInProgressPrefix"] = pull.GetWorkInProgressPrefix(ctx)
564+
ctx.Data["IsPullWorkInProgress"] = prInfo.workInProgressPrefix != ""
565+
ctx.Data["WorkInProgressPrefix"] = prInfo.workInProgressPrefix
555566
}
556567
}
557568

routers/web/repo/pull_merge_box.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2026 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package repo
5+
6+
func (prInfo *pullRequestViewInfo) prepareMergeBoxIconColor() {
7+
pull := prInfo.issue.PullRequest
8+
mergeBoxData := prInfo.MergeBoxData
9+
statusCheckData := prInfo.StatusCheckData
10+
switch {
11+
case pull.HasMerged:
12+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-purple"
13+
case prInfo.issue.IsClosed, prInfo.workInProgressPrefix != "", pull.IsFilesConflicted():
14+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-text-light"
15+
case prInfo.IsPullRequestBroken, mergeBoxData.isBlockedByApprovals, mergeBoxData.isBlockedByRejection,
16+
mergeBoxData.isBlockedByOfficialReviewRequests, mergeBoxData.isBlockedByOutdatedBranch, mergeBoxData.isBlockedByChangedProtectedFiles:
17+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-red"
18+
case prInfo.enableStatusCheck && (statusCheckData.RequiredChecksState.IsFailure() || statusCheckData.RequiredChecksState.IsError()):
19+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-red"
20+
case prInfo.enableStatusCheck && (statusCheckData.LatestCommitStatus == nil || statusCheckData.RequiredChecksState.IsPending() || statusCheckData.RequiredChecksState.IsWarning()):
21+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-yellow"
22+
case mergeBoxData.allowMerge && mergeBoxData.requireSigned && !mergeBoxData.willSign:
23+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-red"
24+
case pull.IsChecking():
25+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-yellow"
26+
case pull.IsEmpty():
27+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-text-light"
28+
case pull.IsStatusMergeable():
29+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-green"
30+
default:
31+
prInfo.MergeBoxData.TimelineIconClass = "tw-text-red"
32+
}
33+
}

routers/web/repo/pull_merge_form.go

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ import (
1616

1717
func (prInfo *pullRequestViewInfo) prepareMergeBoxFormProps(ctx *context.Context) {
1818
pull := prInfo.issue.PullRequest
19+
if pull.HasMerged || prInfo.issue.IsClosed {
20+
return
21+
}
22+
if !prInfo.MergeBoxData.allowMerge {
23+
return
24+
}
25+
1926
prConfig := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig()
2027

2128
// Check correct values and select default
@@ -69,7 +76,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBoxFormProps(ctx *context.Context
6976
}
7077

7178
allOverridableChecksOk := !prInfo.MergeBoxData.HasOverridableBlockers
72-
prInfo.MergeBoxData.MergeFormProps = map[string]any{
79+
mergeFormProps := map[string]any{
7380
"baseLink": prInfo.issue.Link(),
7481
"textCancel": ctx.Locale.Tr("cancel"),
7582
"textDeleteBranch": ctx.Locale.Tr("repo.branch.delete", prInfo.headTarget),
@@ -97,51 +104,75 @@ func (prInfo *pullRequestViewInfo) prepareMergeBoxFormProps(ctx *context.Context
97104
// if this pr can be merged now, then hide the auto merge
98105
generalHideAutoMerge := prInfo.MergeBoxData.CanMergeNow && allOverridableChecksOk
99106

100-
prInfo.MergeBoxData.MergeFormProps["mergeStyles"] = []any{
101-
map[string]any{
102-
"name": "merge",
103-
"allowed": prConfig.AllowMerge,
104-
"textDoMerge": ctx.Locale.Tr("repo.pulls.merge_pull_request"),
105-
"mergeTitleFieldText": defaultMergeTitle,
106-
"mergeMessageFieldText": defaultMergeBody,
107-
"hideAutoMerge": generalHideAutoMerge,
108-
},
109-
map[string]any{
110-
"name": "rebase",
111-
"allowed": prConfig.AllowRebase,
112-
"textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_pull_request"),
113-
"hideMergeMessageTexts": true,
114-
"hideAutoMerge": generalHideAutoMerge,
115-
},
116-
map[string]any{
117-
"name": "rebase-merge",
118-
"allowed": prConfig.AllowRebaseMerge,
119-
"textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_commit_pull_request"),
120-
"mergeTitleFieldText": defaultMergeTitle,
121-
"mergeMessageFieldText": defaultMergeBody,
122-
"hideAutoMerge": generalHideAutoMerge,
123-
},
124-
map[string]any{
125-
"name": "squash",
126-
"allowed": prConfig.AllowSquash,
127-
"textDoMerge": ctx.Locale.Tr("repo.pulls.squash_merge_pull_request"),
128-
"mergeTitleFieldText": defaultSquashMergeTitle,
129-
"mergeMessageFieldText": defaultSquashMergeCommitMessages + defaultSquashMergeBody,
130-
"hideAutoMerge": generalHideAutoMerge,
131-
},
132-
map[string]any{
133-
"name": "fast-forward-only",
134-
"allowed": prConfig.AllowFastForwardOnly && pull.CommitsBehind == 0,
135-
"textDoMerge": ctx.Locale.Tr("repo.pulls.fast_forward_only_merge_pull_request"),
136-
"hideMergeMessageTexts": true,
137-
"hideAutoMerge": generalHideAutoMerge,
138-
},
139-
map[string]any{
107+
var mergeStyles []any
108+
if pull.IsStatusMergeable() {
109+
mergeStyles = []any{
110+
map[string]any{
111+
"name": "merge",
112+
"allowed": prConfig.AllowMerge,
113+
"textDoMerge": ctx.Locale.Tr("repo.pulls.merge_pull_request"),
114+
"mergeTitleFieldText": defaultMergeTitle,
115+
"mergeMessageFieldText": defaultMergeBody,
116+
"hideAutoMerge": generalHideAutoMerge,
117+
},
118+
map[string]any{
119+
"name": "rebase",
120+
"allowed": prConfig.AllowRebase,
121+
"textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_pull_request"),
122+
"hideMergeMessageTexts": true,
123+
"hideAutoMerge": generalHideAutoMerge,
124+
},
125+
map[string]any{
126+
"name": "rebase-merge",
127+
"allowed": prConfig.AllowRebaseMerge,
128+
"textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_commit_pull_request"),
129+
"mergeTitleFieldText": defaultMergeTitle,
130+
"mergeMessageFieldText": defaultMergeBody,
131+
"hideAutoMerge": generalHideAutoMerge,
132+
},
133+
map[string]any{
134+
"name": "squash",
135+
"allowed": prConfig.AllowSquash,
136+
"textDoMerge": ctx.Locale.Tr("repo.pulls.squash_merge_pull_request"),
137+
"mergeTitleFieldText": defaultSquashMergeTitle,
138+
"mergeMessageFieldText": defaultSquashMergeCommitMessages + defaultSquashMergeBody,
139+
"hideAutoMerge": generalHideAutoMerge,
140+
},
141+
map[string]any{
142+
"name": "fast-forward-only",
143+
"allowed": prConfig.AllowFastForwardOnly && pull.CommitsBehind == 0,
144+
"textDoMerge": ctx.Locale.Tr("repo.pulls.fast_forward_only_merge_pull_request"),
145+
"hideMergeMessageTexts": true,
146+
"hideAutoMerge": generalHideAutoMerge,
147+
},
148+
}
149+
}
150+
151+
canUseManualMerge := func() bool {
152+
if pull.IsWorkInProgress(ctx) || pull.IsChecking() {
153+
return false
154+
}
155+
return prConfig.AllowManualMerge
156+
}
157+
// Manually Merged is not a well-known feature, it is used to mark a non-mergeable PR (already merged, conflicted) as merged
158+
// To test it:
159+
// Enable "Manually Merged" feature in the Repository Settings
160+
// Create a pull request, either:
161+
// - Merge the pull request branch locally and push the merged commit to Gitea
162+
// - Make some conflicts between the base branch and the pull request branch
163+
// Then the Manually Merged form will be shown in the merge form
164+
if canUseManualMerge() {
165+
mergeStyles = append(mergeStyles, map[string]any{
140166
"name": "manually-merged",
141167
"allowed": prConfig.AllowManualMerge,
142168
"textDoMerge": ctx.Locale.Tr("repo.pulls.merge_manually"),
143169
"hideMergeMessageTexts": true,
144170
"hideAutoMerge": true,
145-
},
171+
})
172+
}
173+
174+
if len(mergeStyles) > 0 {
175+
mergeFormProps["mergeStyles"] = mergeStyles
176+
prInfo.MergeBoxData.MergeFormProps = mergeFormProps
146177
}
147178
}

templates/devtest/flex-list.tmpl

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -102,34 +102,26 @@
102102
</div>
103103
</div>
104104
<h3>Flex List (with "ui segment fitted", items have their own padding)</h3>
105-
<div class="ui attached segment fitted container-divided">
106-
<div class="flex-divided-list container-divided">
105+
<div class="ui fitted segment">
106+
<div class="flex-divided-list items-px-default">
107107
<div class="item">item 1</div>
108108
<div class="item">item 2</div>
109-
<div class="item flex-divided-list">
110-
<div class="item">item nested 1</div>
111-
<div class="item">item nested 2</div>
112-
</div>
113109
<div class="item">item 3</div>
114110
</div>
115111
</div>
116112

117113
<h3>If parent provides padding or items need their own flex and/or padding:</h3>
118-
<div class="container-divided tw-border tw-border-secondary">
114+
<div class="tw-border tw-border-secondary">
119115
<div class="tw-m-3">before divider</div>
120116
<div class="divider"></div>
121-
<div class="flex-divided-list container-divided flex-items-block">
117+
<div class="flex-divided-list flex-items-block items-px-default">
122118
<div class="item">item 1</div>
123119
<div class="item">item 2</div>
124-
<div class="item flex-divided-list">
125-
<div class="item">item nested 1</div>
126-
<div class="item">item nested 2</div>
127-
</div>
128120
</div>
129121
<div class="divider"></div>
130122
<div class="tw-m-3">after divider</div>
131123
</div>
132-
<div class="container-padded tw-border tw-border-secondary tw-p-4 tw-my-2">
124+
<div class="tw-border tw-border-secondary tw-p-4 tw-my-2">
133125
<div>before divider</div>
134126
<div class="divider"></div>
135127
<div class="flex-divided-list">

templates/repo/commit_statuses.tmpl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@
99
</span>
1010
{{end}}
1111
<div class="tippy-target">
12-
<div class="ui segment">
13-
<div class="flex-divided-list">
14-
{{template "repo/pulls/status" (dict "CommitStatuses" .Statuses "CommitStatus" .Status)}}
15-
</div>
12+
<div class="flex-divided-list items-px-default">
13+
{{template "repo/pulls/status_items" (dict "CommitStatuses" .Statuses)}}
1614
</div>
1715
</div>
1816
{{end}}

0 commit comments

Comments
 (0)