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
23 changed files with 144 additions and 167 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
{{ctx.ScriptImport "js/index.js" "module"}} {{ctx.ScriptImport "js/index.js" "module"}}
{{template "custom/footer" .}} {{template "custom/footer" .}}
<script nonce="{{ctx.CspScriptNonce}}" type="module"> <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> </script>
</body> </body>
</html> </html>
+15 -6
View File
@@ -101,21 +101,30 @@
<div class="item">item 2</div> <div class="item">item 2</div>
</div> </div>
</div> </div>
<h3>Flex List (with "ui segment fitted")</h3> <h3>Flex List (with "ui segment fitted", items have their own padding)</h3>
<div class="ui attached segment fitted"> <div class="ui attached segment fitted container-divided">
<div class="flex-divided-list"> <div class="flex-divided-list container-divided">
<div class="item">item 1</div> <div class="item">item 1</div>
<div class="item">item 2</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>
</div> </div>
<h3>If parent provides border or padding:</h3> <h3>If parent provides padding or items need their own flex and/or padding:</h3>
<div class="container-segmented tw-border tw-border-secondary"> <div class="container-divided tw-border tw-border-secondary">
<div class="tw-m-3">before divider</div> <div class="tw-m-3">before divider</div>
<div class="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 1</div>
<div class="item">item 2</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>
<div class="divider"></div> <div class="divider"></div>
<div class="tw-m-3">after divider</div> <div class="tw-m-3">after divider</div>
+5 -1
View File
@@ -9,6 +9,10 @@
</span> </span>
{{end}} {{end}}
<div class="tippy-target"> <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> </div>
{{end}} {{end}}
@@ -27,18 +27,18 @@
{{- else if .Issue.PullRequest.IsStatusMergeable}}tw-text-green {{- else if .Issue.PullRequest.IsStatusMergeable}}tw-text-green
{{- else}}tw-text-red{{end}}">{{svg "octicon-git-merge" 40}}</div> {{- else}}tw-text-red{{end}}">{{svg "octicon-git-merge" 40}}</div>
<div class="content"> <div class="content">
{{if .LatestCommitStatus}} <div class="ui segment fitted avatar-content-left-arrow container-divided">
<div class="ui attached segment fitted"> <div class="merge-section flex-divided-list flex-items-block container-divided">
{{template "repo/pulls/status" (dict {{if .LatestCommitStatus}}
"CommitStatus" .LatestCommitStatus {{template "repo/pulls/status" (dict
"CommitStatuses" .LatestCommitStatuses "CommitStatus" .LatestCommitStatus
"ShowHideChecks" true "CommitStatuses" .LatestCommitStatuses
"StatusCheckData" $statusCheckData "ShowHideChecks" true
)}} "StatusCheckData" $statusCheckData
</div> )}}
{{end}} {{end}}
{{$showGeneralMergeForm := false}}
<div class="ui attached segment merge-section {{if not $.LatestCommitStatus}}avatar-content-left-arrow{{end}} flex-items-block"> {{$showGeneralMergeForm := false}}
{{if .Issue.PullRequest.HasMerged}} {{if .Issue.PullRequest.HasMerged}}
{{if .IsPullBranchDeletable}} {{if .IsPullBranchDeletable}}
<div class="item item-section text tw-flex-1"> <div class="item item-section text tw-flex-1">
@@ -78,7 +78,7 @@
{{svg "octicon-x"}} {{svg "octicon-x"}}
{{ctx.Locale.Tr "repo.pulls.files_conflicted"}} {{ctx.Locale.Tr "repo.pulls.files_conflicted"}}
</div> </div>
<ul> <ul class="item">
{{range .ConflictedFiles}} {{range .ConflictedFiles}}
<li>{{.}}</li> <li>{{.}}</li>
{{else}} {{else}}
@@ -143,7 +143,7 @@
{{svg "octicon-x"}} {{svg "octicon-x"}}
{{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}} {{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}}
</div> </div>
<ul> <ul class="item">
{{range .ChangedProtectedFiles}} {{range .ChangedProtectedFiles}}
<li>{{.}}</li> <li>{{.}}</li>
{{end}} {{end}}
@@ -200,7 +200,6 @@
{{template "repo/issue/view_content/update_branch_by_merge" $}} {{template "repo/issue/view_content/update_branch_by_merge" $}}
{{if .Issue.PullRequest.IsEmpty}} {{if .Issue.PullRequest.IsEmpty}}
<div class="divider"></div>
<div class="item"> <div class="item">
{{svg "octicon-alert"}} {{svg "octicon-alert"}}
{{ctx.Locale.Tr "repo.pulls.is_empty"}} {{ctx.Locale.Tr "repo.pulls.is_empty"}}
@@ -209,13 +208,13 @@
{{if .AllowMerge}} {{/* user is allowed to merge */}} {{if .AllowMerge}} {{/* user is allowed to merge */}}
{{if $data.MergeFormProps}} {{if $data.MergeFormProps}}
<div class="divider"></div>
{{$showGeneralMergeForm = true}} {{$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 */}} {{/* 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}} {{else}}
{{/* no merge style was set in repo setting: not or ($prUnit.PullRequestsConfig.AllowMerge ...) */}} {{/* no merge style was set in repo setting: not or ($prUnit.PullRequestsConfig.AllowMerge ...) */}}
<div class="divider"></div>
<div class="item tw-text-red"> <div class="item tw-text-red">
{{svg "octicon-x"}} {{svg "octicon-x"}}
{{ctx.Locale.Tr "repo.pulls.no_merge_desc"}} {{ctx.Locale.Tr "repo.pulls.no_merge_desc"}}
@@ -227,7 +226,6 @@
{{end}} {{/* end if the repo was set to use any merge style */}} {{end}} {{/* end if the repo was set to use any merge style */}}
{{else}} {{else}}
{{/* user is not allowed to merge */}} {{/* user is not allowed to merge */}}
<div class="divider"></div>
<div class="item"> <div class="item">
{{svg "octicon-info"}} {{svg "octicon-info"}}
{{ctx.Locale.Tr "repo.pulls.no_merge_access"}} {{ctx.Locale.Tr "repo.pulls.no_merge_access"}}
@@ -260,7 +258,7 @@
{{svg "octicon-x"}} {{svg "octicon-x"}}
{{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}} {{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}}
</div> </div>
<ul> <ul class="item">
{{range .ChangedProtectedFiles}} {{range .ChangedProtectedFiles}}
<li>{{.}}</li> <li>{{.}}</li>
{{end}} {{end}}
@@ -296,20 +294,24 @@
* Then the Manually Merged form will be shown in the merge form * Then the Manually Merged form will be shown in the merge form
*/}} */}}
{{if and $.StillCanManualMerge (not $showGeneralMergeForm)}} {{if and $.StillCanManualMerge (not $showGeneralMergeForm)}}
<div class="divider"></div> <div class="item">
<form class="ui form form-fetch-action" action="{{.Issue.Link}}/merge" method="post">{{/* another similar form is in PullRequestMergeForm.vue*/}} <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"> <div class="field">
<input type="text" name="merge_commit_id" placeholder="{{ctx.Locale.Tr "repo.pulls.merge_commit_id"}}"> <input type="text" name="merge_commit_id" placeholder="{{ctx.Locale.Tr "repo.pulls.merge_commit_id"}}">
</div> </div>
<button class="ui red button" type="submit" name="do" value="manually-merged"> <button class="ui red button" type="submit" name="do" value="manually-merged">
{{ctx.Locale.Tr "repo.pulls.merge_manually"}} {{ctx.Locale.Tr "repo.pulls.merge_manually"}}
</button> </button>
</form> </form>
</div>
{{end}} {{end}}
{{if $data.ShowPullCommands}} {{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}} {{end}}
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -1,6 +1,5 @@
{{$data := $.MergeBoxData}} {{$data := $.MergeBoxData}}
{{$pull := $.PullRequest}} {{$pull := $.PullRequest}}
<div class="divider"></div>
<details> <details>
<summary>{{ctx.Locale.Tr "repo.pulls.cmd_instruction_hint"}}</summary> <summary>{{ctx.Locale.Tr "repo.pulls.cmd_instruction_hint"}}</summary>
<div class="tw-mt-2"> <div class="tw-mt-2">
@@ -1,5 +1,4 @@
{{if and (gt $.Issue.PullRequest.CommitsBehind 0) (not $.Issue.IsClosed) (not $.Issue.PullRequest.IsChecking) (not $.IsPullFilesConflicted) (not $.IsPullRequestBroken)}} {{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 item-section">
<div class="item-section-left flex-text-inline"> <div class="item-section-left flex-text-inline">
{{svg "octicon-alert"}} {{svg "octicon-alert"}}
+21 -21
View File
@@ -6,22 +6,19 @@
*/}} */}}
{{$statusCheckData := .StatusCheckData}} {{$statusCheckData := .StatusCheckData}}
{{if .CommitStatus}} {{if .CommitStatus}}
<div class="commit-status-panel"> {{if $statusCheckData}}
<div class="ui top attached header commit-status-header"> <div class="item flex-left-right commit-status-toggle">
{{$statusCheckData.CommitStatusCheckPrompt ctx.Locale}} <div>{{$statusCheckData.CommitStatusCheckPrompt ctx.Locale}}</div>
{{if .ShowHideChecks}} {{if .ShowHideChecks}}
<div class="ui right"> <button data-global-click="onCommitStatusChecksToggle" class="btn interact-fg"
<button class="commit-status-hide-checks btn interact-fg"
data-show-all="{{ctx.Locale.Tr "repo.pulls.status_checks_show_all"}}" data-show-all="{{ctx.Locale.Tr "repo.pulls.status_checks_show_all"}}"
data-hide-all="{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}}"> data-hide-all="{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}}"
{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}}</button> >{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}}</button>
</div>
{{end}} {{end}}
</div> </div>
{{end}}
{{if and $statusCheckData $statusCheckData.RequireApprovalRunCount}} {{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> <div>
<strong> <strong>
{{ctx.Locale.Tr "repo.pulls.status_checks_need_approvals" $statusCheckData.RequireApprovalRunCount}} {{ctx.Locale.Tr "repo.pulls.status_checks_need_approvals" $statusCheckData.RequireApprovalRunCount}}
@@ -36,28 +33,31 @@
</div> </div>
{{end}} {{end}}
<div class="commit-status-list"> <div class="item flex-divided-list commit-status-list">
{{range .CommitStatuses}} {{range .CommitStatuses}}
<div class="commit-status-item"> <div class="item commit-status-item">
{{template "repo/commit_status" .}} <div class="flex-text-block">
<div class="status-context gt-ellipsis">{{.Context}} <span class="tw-text-text-light-2">{{.Description}}</span></div> {{template "repo/commit_status" .}}
<div class="ui status-details"> <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 and $statusCheckData $statusCheckData.IsContextRequired}}
{{if (call $statusCheckData.IsContextRequired .Context)}}<div class="ui label">{{ctx.Locale.Tr "repo.pulls.status_checks_requested"}}</div>{{end}} {{if (call $statusCheckData.IsContextRequired .Context)}}<div class="ui label">{{ctx.Locale.Tr "repo.pulls.status_checks_requested"}}</div>{{end}}
{{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>
</div> </div>
{{end}} {{end}}
{{if $statusCheckData}} {{if $statusCheckData}}
{{range $statusCheckData.MissingRequiredChecks}} {{range $statusCheckData.MissingRequiredChecks}}
<div class="commit-status-item"> <div class="item commit-status-item">
{{svg "octicon-dot-fill" 18 "commit-status icon tw-text-yellow"}} <div class="flex-text-block">
<div class="status-context gt-ellipsis">{{.}}</div> {{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 class="ui label">{{ctx.Locale.Tr "repo.pulls.status_checks_requested"}}</div>
</div> </div>
{{end}} {{end}}
{{end}} {{end}}
</div> </div>
</div>
{{end}} {{end}}
@@ -149,7 +149,7 @@ func TestActionsArtifactDownload(t *testing.T) {
assert.Contains(t, listResp.Value[artifactIdx].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts") 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/") 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). req = NewRequest(t, "GET", url).
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
resp = MakeRequest(t, req, http.StatusOK) 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") assert.Contains(t, fileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts")
idx := strings.Index(fileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 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). req = NewRequest(t, "GET", url).
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
resp = MakeRequest(t, req, http.StatusOK) resp = MakeRequest(t, req, http.StatusOK)
@@ -323,7 +323,7 @@ func TestActionsArtifactOverwrite(t *testing.T) {
listResp := DecodeJSON(t, resp, &listArtifactsResponse{}) listResp := DecodeJSON(t, resp, &listArtifactsResponse{})
idx := strings.Index(listResp.Value[0].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 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). req = NewRequest(t, "GET", url).
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
resp = MakeRequest(t, req, http.StatusOK) resp = MakeRequest(t, req, http.StatusOK)
@@ -380,7 +380,7 @@ func TestActionsArtifactOverwrite(t *testing.T) {
assert.Equal(t, "artifact-download", uploadedItem.Name) assert.Equal(t, "artifact-download", uploadedItem.Name)
idx := strings.Index(uploadedItem.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 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). req = NewRequest(t, "GET", url).
AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a")
resp = MakeRequest(t, req, http.StatusOK) resp = MakeRequest(t, req, http.StatusOK)
+1 -1
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 { func testAPIRenameBranch(t *testing.T, doerName, ownerName, repoName, from, to string, expectedHTTPStatus int) *httptest.ResponseRecorder {
token := getUserToken(t, doerName, auth_model.AccessTokenScopeWriteRepository) 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, Name: to,
}).AddTokenAuth(token) }).AddTokenAuth(token)
return MakeRequest(t, req, expectedHTTPStatus) return MakeRequest(t, req, expectedHTTPStatus)
+6 -6
View File
@@ -96,18 +96,18 @@ func testUploadAttachmentDeleteTemp(t *testing.T) {
defer web.RouteMock(route_web.RouterMockPointBeforeWebRoutes, func(resp http.ResponseWriter, req *http.Request) { defer web.RouteMock(route_web.RouterMockPointBeforeWebRoutes, func(resp http.ResponseWriter, req *http.Request) {
tmpFileCountDuringUpload = countTmpFile() 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, 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") assert.Equal(t, 0, countTmpFile(), "the temp file should be deleted after upload")
} }
func testCreateAnonymousAttachment(t *testing.T) { func testCreateAnonymousAttachment(t *testing.T) {
session := emptyTestSession(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) { func testCreateUser2IssueAttachment(t *testing.T) {
const repoURL = "user2/repo1" const repoURL = "/user2/repo1"
session := loginUser(t, "user2") session := loginUser(t, "user2")
uuid := testCreateIssueAttachment(t, session, repoURL, "image.png", testGeneratePngBytes(), http.StatusOK) uuid := testCreateIssueAttachment(t, session, repoURL, "image.png", testGeneratePngBytes(), http.StatusOK)
@@ -177,7 +177,7 @@ func testGetAttachment(t *testing.T) {
} }
func testDeleteAttachmentPermissions(t *testing.T) { func testDeleteAttachmentPermissions(t *testing.T) {
const repoURL = "user2/repo1" const repoURL = "/user2/repo1"
ownerSession := loginUser(t, "user2") ownerSession := loginUser(t, "user2")
readonlySession := loginUser(t, "user5") readonlySession := loginUser(t, "user5")
@@ -191,12 +191,12 @@ func testDeleteAttachmentPermissions(t *testing.T) {
testCreateReleaseAttachment(t, readonlySession, repoURL, "reader-release.png", testGeneratePngBytes(), http.StatusNotFound) testCreateReleaseAttachment(t, readonlySession, repoURL, "reader-release.png", testGeneratePngBytes(), http.StatusNotFound)
crossRepoUUID := testCreateIssueAttachment(t, ownerSession, repoURL, "cross-repo.png", testGeneratePngBytes(), http.StatusOK) 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) testDeleteIssueAttachment(t, ownerSession, repoURL, crossRepoUUID, http.StatusOK)
releaseUUID := testCreateReleaseAttachment(t, ownerSession, repoURL, "reader-release.png", testGeneratePngBytes(), http.StatusOK) releaseUUID := testCreateReleaseAttachment(t, ownerSession, repoURL, "reader-release.png", testGeneratePngBytes(), http.StatusOK)
testDeleteReleaseAttachment(t, ownerSession, repoURL, releaseUUID, http.StatusOK) testDeleteReleaseAttachment(t, ownerSession, repoURL, releaseUUID, http.StatusOK)
// test deleting release attachment from another repo // test deleting release attachment from another repo
testDeleteReleaseAttachment(t, ownerSession, "user2/repo2", crossRepoUUID, http.StatusBadRequest) testDeleteReleaseAttachment(t, ownerSession, "/user2/repo2", crossRepoUUID, http.StatusBadRequest)
} }
+12 -12
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) 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.Equal(t, http.StatusOK, resp.Code)
assert.NotEmpty(t, test.RedirectURL(resp)) 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) resp = session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, params["content"], resp.Body.String()) assert.Equal(t, params["content"], resp.Body.String())
return resp return resp
@@ -330,18 +330,18 @@ index 0000000000..bbbbbbbbbb
func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, branch, filePath string) { 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) { forkToEdit := func(t *testing.T, session *TestSession, owner, repo, operation, branch, filePath string) {
// visit the base repo, see the "Add File" button // 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) resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
AssertHTMLElement(t, htmlDoc, ".repo-add-file", 1) AssertHTMLElement(t, htmlDoc, ".repo-add-file", 1)
// attempt to edit a file, see the guideline page // 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) resp = session.MakeRequest(t, req, http.StatusOK)
assert.Contains(t, resp.Body.String(), "Fork Repository to Propose Changes") assert.Contains(t, resp.Body.String(), "Fork Repository to Propose Changes")
// fork the repository // 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) resp = session.MakeRequest(t, req, http.StatusOK)
assert.JSONEq(t, `{"redirect":""}`, resp.Body.String()) 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) forkToEdit(t, session, owner, repo, "_edit", branch, filePath)
// Archive the repository // Archive the repository
req := NewRequestWithValues(t, "POST", path.Join(user, repo, "settings"), req := NewRequestWithValues(t, "POST", "/"+path.Join(user, repo, "settings"),
map[string]string{ map[string]string{
"repo_name": repo, "repo_name": repo,
"action": "archive", "action": "archive",
@@ -360,12 +360,12 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b
session.MakeRequest(t, req, http.StatusSeeOther) session.MakeRequest(t, req, http.StatusSeeOther)
// Check editing archived repository is disabled // 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) resp := session.MakeRequest(t, req, http.StatusNotFound)
assert.Contains(t, resp.Body.String(), "You have forked this repository but your fork is not editable.") assert.Contains(t, resp.Body.String(), "You have forked this repository but your fork is not editable.")
// Unfork the repository // Unfork the repository
req = NewRequestWithValues(t, "POST", path.Join(user, repo, "settings"), req = NewRequestWithValues(t, "POST", "/"+path.Join(user, repo, "settings"),
map[string]string{ map[string]string{
"repo_name": repo, "repo_name": repo,
"action": "convert_fork", "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) { 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) // 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) resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body) 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) { 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) resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
editRequestForm := map[string]string{ editRequestForm := map[string]string{
@@ -437,16 +437,16 @@ func testEditFileNotAllowed(t *testing.T) {
for _, operation := range operations { for _, operation := range operations {
t.Run(operation, func(t *testing.T) { t.Run(operation, func(t *testing.T) {
// Branch does not exist // 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) sessionUser1.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound)
// Private repository // 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) sessionUser1.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusOK)
sessionUser4.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound) sessionUser4.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound)
// Empty repository // 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) sessionUser1.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound)
}) })
} }
+6 -2
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 { func NewRequestWithBody(t testing.TB, method, urlStr string, body io.Reader) *RequestWrapper {
t.Helper() t.Helper()
if !strings.HasPrefix(urlStr, "http") && !strings.HasPrefix(urlStr, "/") { if !strings.HasPrefix(urlStr, "http:") && !strings.HasPrefix(urlStr, "https:") && !strings.HasPrefix(urlStr, "/") {
urlStr = "/" + urlStr t.Fatalf("invalid url str: %s", urlStr)
} }
req, err := http.NewRequest(method, urlStr, body) req, err := http.NewRequest(method, urlStr, body)
require.NoError(t, err) require.NoError(t, err)
if req.URL.User != nil { if req.URL.User != nil {
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(req.URL.User.String()))) 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} return &RequestWrapper{req}
} }
+3 -3
View File
@@ -123,7 +123,7 @@ func TestNoLoginViewIssue(t *testing.T) {
} }
func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content string) string { 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) resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
@@ -667,7 +667,7 @@ func TestUpdateIssueDeadline(t *testing.T) {
assert.Equal(t, api.StateOpen, issueBefore.State()) assert.Equal(t, api.StateOpen, issueBefore.State())
session := loginUser(t, owner.Name) 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"}) req := NewRequestWithValues(t, "POST", urlStr, map[string]string{"deadline": "2022-04-06"})
session.MakeRequest(t, req, http.StatusOK) session.MakeRequest(t, req, http.StatusOK)
@@ -687,7 +687,7 @@ func TestIssueReferenceURL(t *testing.T) {
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) 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) resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
+2 -2
View File
@@ -66,7 +66,7 @@ func testOrgProfile(t *testing.T, u *url.URL) {
createTestProfile(t, "org3", user.RepoNameProfilePrivate, contentPrivateReadme) createTestProfile(t, "org3", user.RepoNameProfilePrivate, contentPrivateReadme)
// Anonymous User // Anonymous User
req := NewRequest(t, "GET", "org3") req := NewRequest(t, "GET", "/org3")
resp := MakeRequest(t, req, http.StatusOK) resp := MakeRequest(t, req, http.StatusOK)
bodyString := util.UnsafeBytesToString(resp.Body.Bytes()) bodyString := util.UnsafeBytesToString(resp.Body.Bytes())
assert.Contains(t, bodyString, contentPublicReadme) assert.Contains(t, bodyString, contentPublicReadme)
@@ -74,7 +74,7 @@ func testOrgProfile(t *testing.T, u *url.URL) {
// Logged in but not member // Logged in but not member
session := loginUser(t, "user24") session := loginUser(t, "user24")
req = NewRequest(t, "GET", "org3") req = NewRequest(t, "GET", "/org3")
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
bodyString = util.UnsafeBytesToString(resp.Body.Bytes()) bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
assert.Contains(t, bodyString, contentPublicReadme) assert.Contains(t, bodyString, contentPublicReadme)
+1 -1
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 { 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) resp := session.MakeRequest(t, req, http.StatusOK)
// Click the PR button to create a pull // Click the PR button to create a pull
+3 -6
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 { 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) resp := session.MakeRequest(t, req, http.StatusOK)
// Click the little button to create a pull // Click the little button to create a pull
@@ -322,11 +322,8 @@ func TestCantMergeWorkInProgress(t *testing.T) {
req := NewRequest(t, "GET", test.RedirectURL(resp)) req := NewRequest(t, "GET", test.RedirectURL(resp))
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
text := strings.TrimSpace(htmlDoc.doc.Find(".merge-section > .item").Last().Text()) wipToggleButtonCount := htmlDoc.Find(`.merge-section > .item button[data-global-init="initPullRequestWipToggle"]`).Length()
assert.NotEmpty(t, text, "Can't find WIP text") assert.Equal(t, 1, wipToggleButtonCount)
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")
}) })
} }
+2 -2
View File
@@ -264,13 +264,13 @@ func testSubmitReview(t *testing.T, session *TestSession, owner, repo, pullNumbe
"type": reviewType, "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) req := NewRequestWithValues(t, "POST", submitURL, options)
return session.MakeRequest(t, req, expectedSubmitStatus) return session.MakeRequest(t, req, expectedSubmitStatus)
} }
func testIssueClose(t *testing.T, session *TestSession, owner, repo, issueNumber string) *httptest.ResponseRecorder { 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{ options := map[string]string{
"status": "close", "status": "close",
+3 -3
View File
@@ -31,7 +31,7 @@ func TestPullCreate_CommitStatus(t *testing.T) {
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1") 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, req := NewRequestWithValues(t, "POST", url,
map[string]string{ map[string]string{
"title": "pull request from status1", "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") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
testEditFile(t, session, "user1", "repo1", "status1", "README.md", "# repo1\n\nDescription for repo1") 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, req := NewRequestWithValues(t, "POST", url,
map[string]string{ map[string]string{
"title": "pull request from status1", "title": "pull request from status1",
@@ -143,7 +143,7 @@ func TestPullCreate_EmptyChangesWithSameCommits(t *testing.T) {
session := loginUser(t, "user1") session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testCreateBranch(t, session, "user1", "repo1", "branch/master", "status1", http.StatusSeeOther) 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, req := NewRequestWithValues(t, "POST", url,
map[string]string{ map[string]string{
"title": "pull request from status1", "title": "pull request from status1",
+2 -2
View File
@@ -21,7 +21,7 @@ import (
) )
func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubURL, newBranchName string, expectedStatus int) string { 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, "new_branch_name": newBranchName,
}) })
resp := session.MakeRequest(t, req, expectedStatus) 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) { func checkRecentlyPushedNewBranches(t *testing.T, session *TestSession, repoPath string, expected []string) {
branches := make([]string, 0, 2) branches := make([]string, 0, 2)
req := NewRequest(t, "GET", repoPath) req := NewRequest(t, "GET", "/"+repoPath)
resp := session.MakeRequest(t, req, http.StatusOK) resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body) doc := NewHTMLParser(t, resp.Body)
doc.doc.Find(".ui.positive.message div a").Each(func(index int, branch *goquery.Selection) { doc.doc.Find(".ui.positive.message div a").Each(func(index int, branch *goquery.Selection) {
+2 -2
View File
@@ -37,7 +37,7 @@ func TestViewTimetrackingControls(t *testing.T) {
} }
func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo, issue string, canTrackTime bool) { 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) resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body) 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-start-time", canTrackTime)
AssertHTMLElement(t, htmlDoc, ".issue-add-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")) reqStart := NewRequest(t, "POST", path.Join(issueLink, "times", "stopwatch", "start"))
if canTrackTime { if canTrackTime {
session.MakeRequest(t, reqStart, http.StatusOK) session.MakeRequest(t, reqStart, http.StatusOK)
+7 -42
View File
@@ -596,8 +596,10 @@ td .commit-summary {
} }
} }
.repository.view.issue .comment-list .comment .merge-section { .repository.view.issue .comment-list .comment .merge-section .item + ul.item {
background-color: var(--color-box-body); border-top: 0;
padding: 0 1em 0 52px;
margin-top: -0.5em;
} }
.repository.view.issue .comment-list .comment .merge-section .item-section { .repository.view.issue .comment-list .comment .merge-section .item-section {
@@ -605,15 +607,9 @@ td .commit-summary {
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 0;
gap: 0.5em; gap: 0.5em;
} }
.repository.view.issue .comment-list .comment .merge-section .divider {
margin-left: -1rem;
width: calc(100% + 2rem);
}
.merge-section-info code { .merge-section-info code {
border: 1px solid var(--color-light-border); border: 1px solid var(--color-light-border);
border-radius: var(--border-radius); border-radius: var(--border-radius);
@@ -1937,42 +1933,11 @@ tbody.commit-list {
.commit-status-item { .commit-status-item {
height: 40px; height: 40px;
padding: 0 10px;
display: flex; display: flex;
gap: 8px; gap: var(--gap-block);
align-items: center; align-items: center;
} justify-content: space-between;
flex-wrap: wrap;
.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 */
} }
.username-display { .username-display {
+9 -8
View File
@@ -10,10 +10,12 @@
} }
/* items have dividers between them, the dividers align with items (use parent padding) */ /* items have dividers between them, the dividers align with items (use parent padding) */
.flex-divided-list { .flex-divided-list,
list-style: none; .flex-divided-list > .item.flex-divided-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch;
gap: 0;
} }
.flex-divided-list > .item { .flex-divided-list > .item {
@@ -99,22 +101,21 @@
} }
/* special rules to make the list work with existing UI elements */ /* 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-left: 1em;
padding-right: 1em; padding-right: 1em;
} }
.container-divided > .flex-divided-list > .item.flex-divided-list {
.ui.segment.fitted > .flex-divided-list > .item { padding: 0;
padding: 1em;
} }
.container-padded > .flex-divided-list > .item:first-child, .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; padding-top: 0;
} }
.container-padded > .flex-divided-list > .item:last-child, .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; padding-bottom: 0;
} }
+7 -10
View File
@@ -2,6 +2,7 @@ import {createApp} from 'vue';
import {GET, POST} from '../modules/fetch.ts'; import {GET, POST} from '../modules/fetch.ts';
import {fomanticQuery} from '../modules/fomantic/base.ts'; import {fomanticQuery} from '../modules/fomantic/base.ts';
import {createElementFromHTML} from '../utils/dom.ts'; import {createElementFromHTML} from '../utils/dom.ts';
import {registerGlobalEventFunc} from '../modules/observer.ts';
function initRepoPullRequestUpdate(el: HTMLElement) { function initRepoPullRequestUpdate(el: HTMLElement) {
const prUpdateButtonContainer = el.querySelector('#update-pr-branch-with-base'); const prUpdateButtonContainer = el.querySelector('#update-pr-branch-with-base');
@@ -48,15 +49,11 @@ function initRepoPullRequestUpdate(el: HTMLElement) {
}); });
} }
function initRepoPullRequestCommitStatus(el: HTMLElement) { function onCommitStatusChecksToggle(btn: HTMLElement) {
for (const btn of el.querySelectorAll('.commit-status-hide-checks')) { const panel = btn.closest('.commit-status-toggle')!.parentElement!;
const panel = btn.closest('.commit-status-panel')!; const list = panel.querySelector<HTMLElement>('.commit-status-list')!;
const list = panel.querySelector<HTMLElement>('.commit-status-list')!; list.style.maxHeight = list.style.maxHeight ? '' : '0px'; // toggle
btn.addEventListener('click', () => { btn.textContent = btn.getAttribute(list.style.maxHeight ? 'data-show-all' : 'data-hide-all');
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) { async function initRepoPullRequestMergeForm(box: HTMLElement) {
@@ -70,7 +67,7 @@ async function initRepoPullRequestMergeForm(box: HTMLElement) {
} }
export function initRepoPullMergeBox(el: HTMLElement) { export function initRepoPullMergeBox(el: HTMLElement) {
initRepoPullRequestCommitStatus(el); registerGlobalEventFunc('click', 'onCommitStatusChecksToggle', onCommitStatusChecksToggle);
initRepoPullRequestUpdate(el); initRepoPullRequestUpdate(el);
initRepoPullRequestMergeForm(el); initRepoPullRequestMergeForm(el);