0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-09 22:51:50 +02:00

Refactor pull request view (5) (#37517)

Clean up templates, remove various CSS patches.

By the way, fix incorrect NewRequest URLs in tests.
This commit is contained in:
wxiaoguang 2026-05-04 02:53:24 +08:00 committed by GitHub
parent c4c50bee7f
commit f26f71f1b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 144 additions and 167 deletions

View File

@ -12,7 +12,7 @@
{{ctx.ScriptImport "js/index.js" "module"}}
{{template "custom/footer" .}}
<script nonce="{{ctx.CspScriptNonce}}" type="module">
if (!window.config?.frontendInited) alert("Frontend is not initialized, check console errors or asset files.")
if (!window.config?.frontendInited && window.config?.runModeIsProd) alert("Frontend is not initialized, check console errors or asset files.");
</script>
</body>
</html>

View File

@ -101,21 +101,30 @@
<div class="item">item 2</div>
</div>
</div>
<h3>Flex List (with "ui segment fitted")</h3>
<div class="ui attached segment fitted">
<div class="flex-divided-list">
<h3>Flex List (with "ui segment fitted", items have their own padding)</h3>
<div class="ui attached segment fitted container-divided">
<div class="flex-divided-list container-divided">
<div class="item">item 1</div>
<div class="item">item 2</div>
<div class="item flex-divided-list">
<div class="item">item nested 1</div>
<div class="item">item nested 2</div>
</div>
<div class="item">item 3</div>
</div>
</div>
<h3>If parent provides border or padding:</h3>
<div class="container-segmented tw-border tw-border-secondary">
<h3>If parent provides padding or items need their own flex and/or padding:</h3>
<div class="container-divided tw-border tw-border-secondary">
<div class="tw-m-3">before divider</div>
<div class="divider"></div>
<div class="flex-divided-list">
<div class="flex-divided-list container-divided flex-items-block">
<div class="item">item 1</div>
<div class="item">item 2</div>
<div class="item flex-divided-list">
<div class="item">item nested 1</div>
<div class="item">item nested 2</div>
</div>
</div>
<div class="divider"></div>
<div class="tw-m-3">after divider</div>

View File

@ -9,6 +9,10 @@
</span>
{{end}}
<div class="tippy-target">
{{template "repo/pulls/status" (dict "CommitStatuses" .Statuses "CommitStatus" .Status)}}
<div class="ui segment">
<div class="flex-divided-list">
{{template "repo/pulls/status" (dict "CommitStatuses" .Statuses "CommitStatus" .Status)}}
</div>
</div>
</div>
{{end}}

View File

@ -27,18 +27,18 @@
{{- else if .Issue.PullRequest.IsStatusMergeable}}tw-text-green
{{- else}}tw-text-red{{end}}">{{svg "octicon-git-merge" 40}}</div>
<div class="content">
{{if .LatestCommitStatus}}
<div class="ui attached segment fitted">
{{template "repo/pulls/status" (dict
"CommitStatus" .LatestCommitStatus
"CommitStatuses" .LatestCommitStatuses
"ShowHideChecks" true
"StatusCheckData" $statusCheckData
)}}
</div>
{{end}}
{{$showGeneralMergeForm := false}}
<div class="ui attached segment merge-section {{if not $.LatestCommitStatus}}avatar-content-left-arrow{{end}} flex-items-block">
<div class="ui segment fitted avatar-content-left-arrow container-divided">
<div class="merge-section flex-divided-list flex-items-block container-divided">
{{if .LatestCommitStatus}}
{{template "repo/pulls/status" (dict
"CommitStatus" .LatestCommitStatus
"CommitStatuses" .LatestCommitStatuses
"ShowHideChecks" true
"StatusCheckData" $statusCheckData
)}}
{{end}}
{{$showGeneralMergeForm := false}}
{{if .Issue.PullRequest.HasMerged}}
{{if .IsPullBranchDeletable}}
<div class="item item-section text tw-flex-1">
@ -78,7 +78,7 @@
{{svg "octicon-x"}}
{{ctx.Locale.Tr "repo.pulls.files_conflicted"}}
</div>
<ul>
<ul class="item">
{{range .ConflictedFiles}}
<li>{{.}}</li>
{{else}}
@ -143,7 +143,7 @@
{{svg "octicon-x"}}
{{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}}
</div>
<ul>
<ul class="item">
{{range .ChangedProtectedFiles}}
<li>{{.}}</li>
{{end}}
@ -200,7 +200,6 @@
{{template "repo/issue/view_content/update_branch_by_merge" $}}
{{if .Issue.PullRequest.IsEmpty}}
<div class="divider"></div>
<div class="item">
{{svg "octicon-alert"}}
{{ctx.Locale.Tr "repo.pulls.is_empty"}}
@ -209,13 +208,13 @@
{{if .AllowMerge}} {{/* user is allowed to merge */}}
{{if $data.MergeFormProps}}
<div class="divider"></div>
{{$showGeneralMergeForm = true}}
{{/* The merge form is a Vue component. After mounted, it has a button for choosing merge style, so make it have min-height to avoid layout shifting */}}
<div id="pull-request-merge-form" class="tw-min-h-[40px]" data-merge-form-props="{{JsonUtils.EncodeToString $data.MergeFormProps}}"></div>
<div class="item">
<div id="pull-request-merge-form" class="tw-min-h-[40px]" data-merge-form-props="{{JsonUtils.EncodeToString $data.MergeFormProps}}"></div>
</div>
{{else}}
{{/* no merge style was set in repo setting: not or ($prUnit.PullRequestsConfig.AllowMerge ...) */}}
<div class="divider"></div>
<div class="item tw-text-red">
{{svg "octicon-x"}}
{{ctx.Locale.Tr "repo.pulls.no_merge_desc"}}
@ -227,7 +226,6 @@
{{end}} {{/* end if the repo was set to use any merge style */}}
{{else}}
{{/* user is not allowed to merge */}}
<div class="divider"></div>
<div class="item">
{{svg "octicon-info"}}
{{ctx.Locale.Tr "repo.pulls.no_merge_access"}}
@ -260,7 +258,7 @@
{{svg "octicon-x"}}
{{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}}
</div>
<ul>
<ul class="item">
{{range .ChangedProtectedFiles}}
<li>{{.}}</li>
{{end}}
@ -296,20 +294,24 @@
* Then the Manually Merged form will be shown in the merge form
*/}}
{{if and $.StillCanManualMerge (not $showGeneralMergeForm)}}
<div class="divider"></div>
<form class="ui form form-fetch-action" action="{{.Issue.Link}}/merge" method="post">{{/* another similar form is in PullRequestMergeForm.vue*/}}
<div class="field">
<input type="text" name="merge_commit_id" placeholder="{{ctx.Locale.Tr "repo.pulls.merge_commit_id"}}">
</div>
<button class="ui red button" type="submit" name="do" value="manually-merged">
{{ctx.Locale.Tr "repo.pulls.merge_manually"}}
</button>
</form>
<div class="item">
<form class="ui form form-fetch-action tw-flex-1" action="{{.Issue.Link}}/merge" method="post">{{/* another similar form is in PullRequestMergeForm.vue*/}}
<div class="field">
<input type="text" name="merge_commit_id" placeholder="{{ctx.Locale.Tr "repo.pulls.merge_commit_id"}}">
</div>
<button class="ui red button" type="submit" name="do" value="manually-merged">
{{ctx.Locale.Tr "repo.pulls.merge_manually"}}
</button>
</form>
</div>
{{end}}
{{if $data.ShowPullCommands}}
{{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "MergeBoxData" $data}}
<div class="item">
{{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "MergeBoxData" $data}}
</div>
{{end}}
</div>
</div>
</div>
</div>

View File

@ -1,6 +1,5 @@
{{$data := $.MergeBoxData}}
{{$pull := $.PullRequest}}
<div class="divider"></div>
<details>
<summary>{{ctx.Locale.Tr "repo.pulls.cmd_instruction_hint"}}</summary>
<div class="tw-mt-2">

View File

@ -1,5 +1,4 @@
{{if and (gt $.Issue.PullRequest.CommitsBehind 0) (not $.Issue.IsClosed) (not $.Issue.PullRequest.IsChecking) (not $.IsPullFilesConflicted) (not $.IsPullRequestBroken)}}
<div class="divider"></div>
<div class="item item-section">
<div class="item-section-left flex-text-inline">
{{svg "octicon-alert"}}

View File

@ -6,22 +6,19 @@
*/}}
{{$statusCheckData := .StatusCheckData}}
{{if .CommitStatus}}
<div class="commit-status-panel">
<div class="ui top attached header commit-status-header">
{{$statusCheckData.CommitStatusCheckPrompt ctx.Locale}}
{{if $statusCheckData}}
<div class="item flex-left-right commit-status-toggle">
<div>{{$statusCheckData.CommitStatusCheckPrompt ctx.Locale}}</div>
{{if .ShowHideChecks}}
<div class="ui right">
<button class="commit-status-hide-checks btn interact-fg"
<button data-global-click="onCommitStatusChecksToggle" class="btn interact-fg"
data-show-all="{{ctx.Locale.Tr "repo.pulls.status_checks_show_all"}}"
data-hide-all="{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}}">
{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}}</button>
</div>
data-hide-all="{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}}"
>{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}}</button>
{{end}}
</div>
{{end}}
{{if and $statusCheckData $statusCheckData.RequireApprovalRunCount}}
<div class="ui attached segment flex-left-right" id="approve-status-checks">
<div class="item flex-left-right" id="approve-status-checks">
<div>
<strong>
{{ctx.Locale.Tr "repo.pulls.status_checks_need_approvals" $statusCheckData.RequireApprovalRunCount}}
@ -36,28 +33,31 @@
</div>
{{end}}
<div class="commit-status-list">
<div class="item flex-divided-list commit-status-list">
{{range .CommitStatuses}}
<div class="commit-status-item">
{{template "repo/commit_status" .}}
<div class="status-context gt-ellipsis">{{.Context}} <span class="tw-text-text-light-2">{{.Description}}</span></div>
<div class="ui status-details">
<div class="item commit-status-item">
<div class="flex-text-block">
{{template "repo/commit_status" .}}
<div class="status-context gt-ellipsis">{{.Context}} <span class="tw-text-text-light-2">{{.Description}}</span></div>
</div>
<div class="status-details">
{{if and $statusCheckData $statusCheckData.IsContextRequired}}
{{if (call $statusCheckData.IsContextRequired .Context)}}<div class="ui label">{{ctx.Locale.Tr "repo.pulls.status_checks_requested"}}</div>{{end}}
{{end}}
<span>{{if .TargetURL}}<a href="{{.TargetURL}}">{{ctx.Locale.Tr "repo.pulls.status_checks_details"}}</a>{{end}}</span>
{{if .TargetURL}}<a href="{{.TargetURL}}">{{ctx.Locale.Tr "repo.pulls.status_checks_details"}}</a>{{end}}
</div>
</div>
{{end}}
{{if $statusCheckData}}
{{range $statusCheckData.MissingRequiredChecks}}
<div class="commit-status-item">
{{svg "octicon-dot-fill" 18 "commit-status icon tw-text-yellow"}}
<div class="status-context gt-ellipsis">{{.}}</div>
<div class="item commit-status-item">
<div class="flex-text-block">
{{svg "octicon-dot-fill" 16 "commit-status icon tw-text-yellow"}}
<div class="status-context gt-ellipsis">{{.}}</div>
</div>
<div class="ui label">{{ctx.Locale.Tr "repo.pulls.status_checks_requested"}}</div>
</div>
{{end}}
{{end}}
</div>
</div>
{{end}}

View File

@ -149,7 +149,7 @@ func TestActionsArtifactDownload(t *testing.T) {
assert.Contains(t, listResp.Value[artifactIdx].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts")
idx := strings.Index(listResp.Value[artifactIdx].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
url := listResp.Value[artifactIdx].FileContainerResourceURL[idx+1:] + "?itemPath=artifact-download"
url := listResp.Value[artifactIdx].FileContainerResourceURL[idx:] + "?itemPath=artifact-download"
req = NewRequest(t, "GET", url).
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
resp = MakeRequest(t, req, http.StatusOK)
@ -245,7 +245,7 @@ func TestActionsArtifactDownloadMultiFiles(t *testing.T) {
assert.Contains(t, fileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts")
idx := strings.Index(fileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
url := fileContainerResourceURL[idx+1:] + "?itemPath=" + testArtifactName
url := fileContainerResourceURL[idx:] + "?itemPath=" + testArtifactName
req = NewRequest(t, "GET", url).
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
resp = MakeRequest(t, req, http.StatusOK)
@ -323,7 +323,7 @@ func TestActionsArtifactOverwrite(t *testing.T) {
listResp := DecodeJSON(t, resp, &listArtifactsResponse{})
idx := strings.Index(listResp.Value[0].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
url := listResp.Value[0].FileContainerResourceURL[idx+1:] + "?itemPath=artifact-download"
url := listResp.Value[0].FileContainerResourceURL[idx:] + "?itemPath=artifact-download"
req = NewRequest(t, "GET", url).
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
resp = MakeRequest(t, req, http.StatusOK)
@ -380,7 +380,7 @@ func TestActionsArtifactOverwrite(t *testing.T) {
assert.Equal(t, "artifact-download", uploadedItem.Name)
idx := strings.Index(uploadedItem.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/")
url := uploadedItem.FileContainerResourceURL[idx+1:] + "?itemPath=artifact-download"
url := uploadedItem.FileContainerResourceURL[idx:] + "?itemPath=artifact-download"
req = NewRequest(t, "GET", url).
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
resp = MakeRequest(t, req, http.StatusOK)

View File

@ -348,7 +348,7 @@ func TestAPIUpdateBranchReference(t *testing.T) {
func testAPIRenameBranch(t *testing.T, doerName, ownerName, repoName, from, to string, expectedHTTPStatus int) *httptest.ResponseRecorder {
token := getUserToken(t, doerName, auth_model.AccessTokenScopeWriteRepository)
req := NewRequestWithJSON(t, "PATCH", "api/v1/repos/"+ownerName+"/"+repoName+"/branches/"+from, &api.RenameBranchRepoOption{
req := NewRequestWithJSON(t, "PATCH", "/api/v1/repos/"+ownerName+"/"+repoName+"/branches/"+from, &api.RenameBranchRepoOption{
Name: to,
}).AddTokenAuth(token)
return MakeRequest(t, req, expectedHTTPStatus)

View File

@ -96,18 +96,18 @@ func testUploadAttachmentDeleteTemp(t *testing.T) {
defer web.RouteMock(route_web.RouterMockPointBeforeWebRoutes, func(resp http.ResponseWriter, req *http.Request) {
tmpFileCountDuringUpload = countTmpFile()
})()
_ = testCreateIssueAttachment(t, session, "user2/repo1", "image.png", testGeneratePngBytes(), http.StatusOK)
_ = testCreateIssueAttachment(t, session, "/user2/repo1", "image.png", testGeneratePngBytes(), http.StatusOK)
assert.Equal(t, 1, tmpFileCountDuringUpload, "the temp file should exist when uploaded size exceeds the parse form's max memory")
assert.Equal(t, 0, countTmpFile(), "the temp file should be deleted after upload")
}
func testCreateAnonymousAttachment(t *testing.T) {
session := emptyTestSession(t)
testCreateIssueAttachment(t, session, "user2/repo1", "image.png", testGeneratePngBytes(), http.StatusSeeOther)
testCreateIssueAttachment(t, session, "/user2/repo1", "image.png", testGeneratePngBytes(), http.StatusSeeOther)
}
func testCreateUser2IssueAttachment(t *testing.T) {
const repoURL = "user2/repo1"
const repoURL = "/user2/repo1"
session := loginUser(t, "user2")
uuid := testCreateIssueAttachment(t, session, repoURL, "image.png", testGeneratePngBytes(), http.StatusOK)
@ -177,7 +177,7 @@ func testGetAttachment(t *testing.T) {
}
func testDeleteAttachmentPermissions(t *testing.T) {
const repoURL = "user2/repo1"
const repoURL = "/user2/repo1"
ownerSession := loginUser(t, "user2")
readonlySession := loginUser(t, "user5")
@ -191,12 +191,12 @@ func testDeleteAttachmentPermissions(t *testing.T) {
testCreateReleaseAttachment(t, readonlySession, repoURL, "reader-release.png", testGeneratePngBytes(), http.StatusNotFound)
crossRepoUUID := testCreateIssueAttachment(t, ownerSession, repoURL, "cross-repo.png", testGeneratePngBytes(), http.StatusOK)
testDeleteIssueAttachment(t, ownerSession, "user2/repo2", crossRepoUUID, http.StatusBadRequest)
testDeleteIssueAttachment(t, ownerSession, "/user2/repo2", crossRepoUUID, http.StatusBadRequest)
testDeleteIssueAttachment(t, ownerSession, repoURL, crossRepoUUID, http.StatusOK)
releaseUUID := testCreateReleaseAttachment(t, ownerSession, repoURL, "reader-release.png", testGeneratePngBytes(), http.StatusOK)
testDeleteReleaseAttachment(t, ownerSession, repoURL, releaseUUID, http.StatusOK)
// test deleting release attachment from another repo
testDeleteReleaseAttachment(t, ownerSession, "user2/repo2", crossRepoUUID, http.StatusBadRequest)
testDeleteReleaseAttachment(t, ownerSession, "/user2/repo2", crossRepoUUID, http.StatusBadRequest)
}

View File

@ -124,7 +124,7 @@ func testEditorActionEdit(t *testing.T, session *TestSession, user, repo, editor
resp := testEditorActionPostRequest(t, session, fmt.Sprintf("/%s/%s/%s/%s/%s", user, repo, editorAction, branch, filePath), params)
assert.Equal(t, http.StatusOK, resp.Code)
assert.NotEmpty(t, test.RedirectURL(resp))
req := NewRequest(t, "GET", path.Join(user, repo, "raw/branch", newBranchName, params["tree_path"]))
req := NewRequest(t, "GET", "/"+path.Join(user, repo, "raw/branch", newBranchName, params["tree_path"]))
resp = session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, params["content"], resp.Body.String())
return resp
@ -330,18 +330,18 @@ index 0000000000..bbbbbbbbbb
func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, branch, filePath string) {
forkToEdit := func(t *testing.T, session *TestSession, owner, repo, operation, branch, filePath string) {
// visit the base repo, see the "Add File" button
req := NewRequest(t, "GET", path.Join(owner, repo))
req := NewRequest(t, "GET", "/"+path.Join(owner, repo))
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
AssertHTMLElement(t, htmlDoc, ".repo-add-file", 1)
// attempt to edit a file, see the guideline page
req = NewRequest(t, "GET", path.Join(owner, repo, operation, branch, filePath))
req = NewRequest(t, "GET", "/"+path.Join(owner, repo, operation, branch, filePath))
resp = session.MakeRequest(t, req, http.StatusOK)
assert.Contains(t, resp.Body.String(), "Fork Repository to Propose Changes")
// fork the repository
req = NewRequest(t, "POST", path.Join(owner, repo, "_fork", branch))
req = NewRequest(t, "POST", "/"+path.Join(owner, repo, "_fork", branch))
resp = session.MakeRequest(t, req, http.StatusOK)
assert.JSONEq(t, `{"redirect":""}`, resp.Body.String())
}
@ -351,7 +351,7 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b
forkToEdit(t, session, owner, repo, "_edit", branch, filePath)
// Archive the repository
req := NewRequestWithValues(t, "POST", path.Join(user, repo, "settings"),
req := NewRequestWithValues(t, "POST", "/"+path.Join(user, repo, "settings"),
map[string]string{
"repo_name": repo,
"action": "archive",
@ -360,12 +360,12 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b
session.MakeRequest(t, req, http.StatusSeeOther)
// Check editing archived repository is disabled
req = NewRequest(t, "GET", path.Join(owner, repo, "_edit", branch, filePath)).SetHeader("Accept", "text/html")
req = NewRequest(t, "GET", "/"+path.Join(owner, repo, "_edit", branch, filePath)).SetHeader("Accept", "text/html")
resp := session.MakeRequest(t, req, http.StatusNotFound)
assert.Contains(t, resp.Body.String(), "You have forked this repository but your fork is not editable.")
// Unfork the repository
req = NewRequestWithValues(t, "POST", path.Join(user, repo, "settings"),
req = NewRequestWithValues(t, "POST", "/"+path.Join(user, repo, "settings"),
map[string]string{
"repo_name": repo,
"action": "convert_fork",
@ -381,7 +381,7 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b
t.Run("CheckBaseRepoForm", func(t *testing.T) {
// the base repo's edit form should have the correct action and upload links (pointing to the forked repo)
req := NewRequest(t, "GET", path.Join(owner, repo, "_upload", branch, filePath)+"?foo=bar")
req := NewRequest(t, "GET", "/"+path.Join(owner, repo, "_upload", branch, filePath)+"?foo=bar")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
@ -399,7 +399,7 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b
})
t.Run("ViewBaseEditFormAndCommitToFork", func(t *testing.T) {
req := NewRequest(t, "GET", path.Join(owner, repo, "_edit", branch, filePath))
req := NewRequest(t, "GET", "/"+path.Join(owner, repo, "_edit", branch, filePath))
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
editRequestForm := map[string]string{
@ -437,16 +437,16 @@ func testEditFileNotAllowed(t *testing.T) {
for _, operation := range operations {
t.Run(operation, func(t *testing.T) {
// Branch does not exist
targetLink := path.Join("user2", "repo1", operation, "missing", "README.md")
targetLink := path.Join("/user2/repo1", operation, "missing", "README.md")
sessionUser1.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound)
// Private repository
targetLink = path.Join("user2", "repo2", operation, "master", "Home.md")
targetLink = path.Join("/user2/repo2", operation, "master", "Home.md")
sessionUser1.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusOK)
sessionUser4.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound)
// Empty repository
targetLink = path.Join("org41", "repo61", operation, "master", "README.md")
targetLink = path.Join("/org41/repo61", operation, "master", "README.md")
sessionUser1.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound)
})
}

View File

@ -326,14 +326,18 @@ func NewRequestWithJSON(t testing.TB, method, urlStr string, v any) *RequestWrap
func NewRequestWithBody(t testing.TB, method, urlStr string, body io.Reader) *RequestWrapper {
t.Helper()
if !strings.HasPrefix(urlStr, "http") && !strings.HasPrefix(urlStr, "/") {
urlStr = "/" + urlStr
if !strings.HasPrefix(urlStr, "http:") && !strings.HasPrefix(urlStr, "https:") && !strings.HasPrefix(urlStr, "/") {
t.Fatalf("invalid url str: %s", urlStr)
}
req, err := http.NewRequest(method, urlStr, body)
require.NoError(t, err)
if req.URL.User != nil {
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(req.URL.User.String())))
}
req.RequestURI = req.URL.Path
if req.URL.RawQuery != "" {
req.RequestURI += "?" + req.URL.RawQuery
}
return &RequestWrapper{req}
}

View File

@ -123,7 +123,7 @@ func TestNoLoginViewIssue(t *testing.T) {
}
func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content string) string {
req := NewRequest(t, "GET", path.Join(user, repo, "issues", "new"))
req := NewRequest(t, "GET", "/"+path.Join(user, repo, "issues", "new"))
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
@ -667,7 +667,7 @@ func TestUpdateIssueDeadline(t *testing.T) {
assert.Equal(t, api.StateOpen, issueBefore.State())
session := loginUser(t, owner.Name)
urlStr := fmt.Sprintf("%s/%s/issues/%d/deadline", owner.Name, repoBefore.Name, issueBefore.Index)
urlStr := fmt.Sprintf("/%s/%s/issues/%d/deadline", owner.Name, repoBefore.Name, issueBefore.Index)
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{"deadline": "2022-04-06"})
session.MakeRequest(t, req, http.StatusOK)
@ -687,7 +687,7 @@ func TestIssueReferenceURL(t *testing.T) {
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
req := NewRequest(t, "GET", fmt.Sprintf("%s/issues/%d", repo.FullName(), issue.Index))
req := NewRequest(t, "GET", fmt.Sprintf("%s/issues/%d", repo.Link(), issue.Index))
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)

View File

@ -66,7 +66,7 @@ func testOrgProfile(t *testing.T, u *url.URL) {
createTestProfile(t, "org3", user.RepoNameProfilePrivate, contentPrivateReadme)
// Anonymous User
req := NewRequest(t, "GET", "org3")
req := NewRequest(t, "GET", "/org3")
resp := MakeRequest(t, req, http.StatusOK)
bodyString := util.UnsafeBytesToString(resp.Body.Bytes())
assert.Contains(t, bodyString, contentPublicReadme)
@ -74,7 +74,7 @@ func testOrgProfile(t *testing.T, u *url.URL) {
// Logged in but not member
session := loginUser(t, "user24")
req = NewRequest(t, "GET", "org3")
req = NewRequest(t, "GET", "/org3")
resp = session.MakeRequest(t, req, http.StatusOK)
bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
assert.Contains(t, bodyString, contentPublicReadme)

View File

@ -26,7 +26,7 @@ import (
)
func testPullCreate(t *testing.T, session *TestSession, user, repo string, toSelf bool, targetBranch, sourceBranch, title string) *httptest.ResponseRecorder {
req := NewRequest(t, "GET", path.Join(user, repo))
req := NewRequest(t, "GET", "/"+path.Join(user, repo))
resp := session.MakeRequest(t, req, http.StatusOK)
// Click the PR button to create a pull

View File

@ -80,7 +80,7 @@ func testPullMerge(t *testing.T, session *TestSession, user, repo, pullNum strin
}
func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum string) *httptest.ResponseRecorder {
req := NewRequest(t, "GET", path.Join(user, repo, "pulls", pullnum))
req := NewRequest(t, "GET", "/"+path.Join(user, repo, "pulls", pullnum))
resp := session.MakeRequest(t, req, http.StatusOK)
// Click the little button to create a pull
@ -322,11 +322,8 @@ func TestCantMergeWorkInProgress(t *testing.T) {
req := NewRequest(t, "GET", test.RedirectURL(resp))
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
text := strings.TrimSpace(htmlDoc.doc.Find(".merge-section > .item").Last().Text())
assert.NotEmpty(t, text, "Can't find WIP text")
assert.Contains(t, text, translation.NewLocale("en-US").TrString("repo.pulls.cannot_merge_work_in_progress"), "Unable to find WIP text")
assert.Contains(t, text, "[wip]", "Unable to find WIP text")
wipToggleButtonCount := htmlDoc.Find(`.merge-section > .item button[data-global-init="initPullRequestWipToggle"]`).Length()
assert.Equal(t, 1, wipToggleButtonCount)
})
}

View File

@ -264,13 +264,13 @@ func testSubmitReview(t *testing.T, session *TestSession, owner, repo, pullNumbe
"type": reviewType,
}
submitURL := path.Join(owner, repo, "pulls", pullNumber, "files", "reviews", "submit")
submitURL := "/" + path.Join(owner, repo, "pulls", pullNumber, "files", "reviews", "submit")
req := NewRequestWithValues(t, "POST", submitURL, options)
return session.MakeRequest(t, req, expectedSubmitStatus)
}
func testIssueClose(t *testing.T, session *TestSession, owner, repo, issueNumber string) *httptest.ResponseRecorder {
closeURL := path.Join(owner, repo, "issues", issueNumber, "comments")
closeURL := "/" + path.Join(owner, repo, "issues", issueNumber, "comments")
options := map[string]string{
"status": "close",

View File

@ -31,7 +31,7 @@ func TestPullCreate_CommitStatus(t *testing.T) {
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
url := path.Join("user1", "repo1", "compare", "master...status1")
url := "/" + path.Join("user1", "repo1", "compare", "master...status1")
req := NewRequestWithValues(t, "POST", url,
map[string]string{
"title": "pull request from status1",
@ -121,7 +121,7 @@ func TestPullCreate_EmptyChangesWithDifferentCommits(t *testing.T) {
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
testEditFile(t, session, "user1", "repo1", "status1", "README.md", "# repo1\n\nDescription for repo1")
url := path.Join("user1", "repo1", "compare", "master...status1")
url := "/" + path.Join("user1", "repo1", "compare", "master...status1")
req := NewRequestWithValues(t, "POST", url,
map[string]string{
"title": "pull request from status1",
@ -143,7 +143,7 @@ func TestPullCreate_EmptyChangesWithSameCommits(t *testing.T) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testCreateBranch(t, session, "user1", "repo1", "branch/master", "status1", http.StatusSeeOther)
url := path.Join("user1", "repo1", "compare", "master...status1")
url := "/" + path.Join("user1", "repo1", "compare", "master...status1")
req := NewRequestWithValues(t, "POST", url,
map[string]string{
"title": "pull request from status1",

View File

@ -21,7 +21,7 @@ import (
)
func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubURL, newBranchName string, expectedStatus int) string {
req := NewRequestWithValues(t, "POST", path.Join(user, repo, "branches/_new", oldRefSubURL), map[string]string{
req := NewRequestWithValues(t, "POST", "/"+path.Join(user, repo, "branches/_new", oldRefSubURL), map[string]string{
"new_branch_name": newBranchName,
})
resp := session.MakeRequest(t, req, expectedStatus)
@ -221,7 +221,7 @@ func prepareRepoPR(t *testing.T, baseSession, headSession *TestSession, baseRepo
func checkRecentlyPushedNewBranches(t *testing.T, session *TestSession, repoPath string, expected []string) {
branches := make([]string, 0, 2)
req := NewRequest(t, "GET", repoPath)
req := NewRequest(t, "GET", "/"+repoPath)
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
doc.doc.Find(".ui.positive.message div a").Each(func(index int, branch *goquery.Selection) {

View File

@ -37,7 +37,7 @@ func TestViewTimetrackingControls(t *testing.T) {
}
func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo, issue string, canTrackTime bool) {
req := NewRequest(t, "GET", path.Join(user, repo, "issues", issue))
req := NewRequest(t, "GET", "/"+path.Join(user, repo, "issues", issue))
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
@ -45,7 +45,7 @@ func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo
AssertHTMLElement(t, htmlDoc, ".issue-start-time", canTrackTime)
AssertHTMLElement(t, htmlDoc, ".issue-add-time", canTrackTime)
issueLink := path.Join(user, repo, "issues", issue)
issueLink := "/" + path.Join(user, repo, "issues", issue)
reqStart := NewRequest(t, "POST", path.Join(issueLink, "times", "stopwatch", "start"))
if canTrackTime {
session.MakeRequest(t, reqStart, http.StatusOK)

View File

@ -596,8 +596,10 @@ td .commit-summary {
}
}
.repository.view.issue .comment-list .comment .merge-section {
background-color: var(--color-box-body);
.repository.view.issue .comment-list .comment .merge-section .item + ul.item {
border-top: 0;
padding: 0 1em 0 52px;
margin-top: -0.5em;
}
.repository.view.issue .comment-list .comment .merge-section .item-section {
@ -605,15 +607,9 @@ td .commit-summary {
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: 0;
gap: 0.5em;
}
.repository.view.issue .comment-list .comment .merge-section .divider {
margin-left: -1rem;
width: calc(100% + 2rem);
}
.merge-section-info code {
border: 1px solid var(--color-light-border);
border-radius: var(--border-radius);
@ -1937,42 +1933,11 @@ tbody.commit-list {
.commit-status-item {
height: 40px;
padding: 0 10px;
display: flex;
gap: 8px;
gap: var(--gap-block);
align-items: center;
}
.commit-status-item + .commit-status-item {
border-top: 1px solid var(--color-secondary);
}
.commit-status-item .commit-status {
flex-shrink: 0;
}
.commit-status-item .status-context {
color: var(--color-text);
flex: 1;
}
.commit-status-item .status-details {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
}
@media (max-width: 767.98px) {
.commit-status-item .status-details {
flex-direction: column;
align-items: flex-end;
justify-content: center;
}
}
.commit-status-item .status-details > span {
padding-right: 0.5em; /* To match the alignment with the "required" label */
justify-content: space-between;
flex-wrap: wrap;
}
.username-display {

View File

@ -10,10 +10,12 @@
}
/* items have dividers between them, the dividers align with items (use parent padding) */
.flex-divided-list {
list-style: none;
.flex-divided-list,
.flex-divided-list > .item.flex-divided-list {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 0;
}
.flex-divided-list > .item {
@ -99,22 +101,21 @@
}
/* special rules to make the list work with existing UI elements */
.container-segmented > .flex-divided-list > .item {
.container-divided > .flex-divided-list > .item {
padding-left: 1em;
padding-right: 1em;
}
.ui.segment.fitted > .flex-divided-list > .item {
padding: 1em;
.container-divided > .flex-divided-list > .item.flex-divided-list {
padding: 0;
}
.container-padded > .flex-divided-list > .item:first-child,
.ui.segment:not(.fitted) > .flex-divided-list > .item:first-child {
.ui.segment:not(.container-divided) > .flex-divided-list > .item:first-child {
padding-top: 0;
}
.container-padded > .flex-divided-list > .item:last-child,
.ui.segment:not(.fitted) > .flex-divided-list > .item:last-child {
.ui.segment:not(.container-divided) > .flex-divided-list > .item:last-child {
padding-bottom: 0;
}

View File

@ -2,6 +2,7 @@ import {createApp} from 'vue';
import {GET, POST} from '../modules/fetch.ts';
import {fomanticQuery} from '../modules/fomantic/base.ts';
import {createElementFromHTML} from '../utils/dom.ts';
import {registerGlobalEventFunc} from '../modules/observer.ts';
function initRepoPullRequestUpdate(el: HTMLElement) {
const prUpdateButtonContainer = el.querySelector('#update-pr-branch-with-base');
@ -48,15 +49,11 @@ function initRepoPullRequestUpdate(el: HTMLElement) {
});
}
function initRepoPullRequestCommitStatus(el: HTMLElement) {
for (const btn of el.querySelectorAll('.commit-status-hide-checks')) {
const panel = btn.closest('.commit-status-panel')!;
const list = panel.querySelector<HTMLElement>('.commit-status-list')!;
btn.addEventListener('click', () => {
list.style.maxHeight = list.style.maxHeight ? '' : '0px'; // toggle
btn.textContent = btn.getAttribute(list.style.maxHeight ? 'data-show-all' : 'data-hide-all');
});
}
function onCommitStatusChecksToggle(btn: HTMLElement) {
const panel = btn.closest('.commit-status-toggle')!.parentElement!;
const list = panel.querySelector<HTMLElement>('.commit-status-list')!;
list.style.maxHeight = list.style.maxHeight ? '' : '0px'; // toggle
btn.textContent = btn.getAttribute(list.style.maxHeight ? 'data-show-all' : 'data-hide-all');
}
async function initRepoPullRequestMergeForm(box: HTMLElement) {
@ -70,7 +67,7 @@ async function initRepoPullRequestMergeForm(box: HTMLElement) {
}
export function initRepoPullMergeBox(el: HTMLElement) {
initRepoPullRequestCommitStatus(el);
registerGlobalEventFunc('click', 'onCommitStatusChecksToggle', onCommitStatusChecksToggle);
initRepoPullRequestUpdate(el);
initRepoPullRequestMergeForm(el);