From f26f71f1b298a62697fa38ed7026ac1bba3991da Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 4 May 2026 02:53:24 +0800 Subject: [PATCH] Refactor pull request view (5) (#37517) Clean up templates, remove various CSS patches. By the way, fix incorrect NewRequest URLs in tests. --- templates/base/footer.tmpl | 2 +- templates/devtest/flex-list.tmpl | 21 +++++-- templates/repo/commit_statuses.tmpl | 6 +- .../issue/view_content/pull_merge_box.tmpl | 62 ++++++++++--------- .../view_content/pull_merge_instruction.tmpl | 1 - .../view_content/update_branch_by_merge.tmpl | 1 - templates/repo/pulls/status.tmpl | 42 ++++++------- .../integration/api_actions_artifact_test.go | 8 +-- tests/integration/api_branch_test.go | 2 +- tests/integration/attachment_test.go | 12 ++-- tests/integration/editor_test.go | 24 +++---- tests/integration/integration_test.go | 8 ++- tests/integration/issue_test.go | 6 +- tests/integration/org_profile_test.go | 4 +- tests/integration/pull_create_test.go | 2 +- tests/integration/pull_merge_test.go | 9 +-- tests/integration/pull_review_test.go | 4 +- tests/integration/pull_status_test.go | 6 +- tests/integration/repo_branch_test.go | 4 +- tests/integration/timetracking_test.go | 4 +- web_src/css/repo.css | 49 +++------------ web_src/css/shared/flex-list.css | 17 ++--- web_src/js/features/repo-issue-pull.ts | 17 +++-- 23 files changed, 144 insertions(+), 167 deletions(-) diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl index b7443345ada..81bb4ad3ce7 100644 --- a/templates/base/footer.tmpl +++ b/templates/base/footer.tmpl @@ -12,7 +12,7 @@ {{ctx.ScriptImport "js/index.js" "module"}} {{template "custom/footer" .}} diff --git a/templates/devtest/flex-list.tmpl b/templates/devtest/flex-list.tmpl index de59473a703..02f0df9ff92 100644 --- a/templates/devtest/flex-list.tmpl +++ b/templates/devtest/flex-list.tmpl @@ -101,21 +101,30 @@
item 2
-

Flex List (with "ui segment fitted")

-
-
+

Flex List (with "ui segment fitted", items have their own padding)

+
+
item 1
item 2
+
+
item nested 1
+
item nested 2
+
+
item 3
-

If parent provides border or padding:

-
+

If parent provides padding or items need their own flex and/or padding:

+
before divider
-
+
item 1
item 2
+
+
item nested 1
+
item nested 2
+
after divider
diff --git a/templates/repo/commit_statuses.tmpl b/templates/repo/commit_statuses.tmpl index 1bbfb331051..2f9f44fabe4 100644 --- a/templates/repo/commit_statuses.tmpl +++ b/templates/repo/commit_statuses.tmpl @@ -9,6 +9,10 @@ {{end}}
- {{template "repo/pulls/status" (dict "CommitStatuses" .Statuses "CommitStatus" .Status)}} +
+
+ {{template "repo/pulls/status" (dict "CommitStatuses" .Statuses "CommitStatus" .Status)}} +
+
{{end}} diff --git a/templates/repo/issue/view_content/pull_merge_box.tmpl b/templates/repo/issue/view_content/pull_merge_box.tmpl index 768d3b31194..2bda4ad83f6 100644 --- a/templates/repo/issue/view_content/pull_merge_box.tmpl +++ b/templates/repo/issue/view_content/pull_merge_box.tmpl @@ -27,18 +27,18 @@ {{- else if .Issue.PullRequest.IsStatusMergeable}}tw-text-green {{- else}}tw-text-red{{end}}">{{svg "octicon-git-merge" 40}}
- {{if .LatestCommitStatus}} -
- {{template "repo/pulls/status" (dict - "CommitStatus" .LatestCommitStatus - "CommitStatuses" .LatestCommitStatuses - "ShowHideChecks" true - "StatusCheckData" $statusCheckData - )}} -
- {{end}} - {{$showGeneralMergeForm := false}} -
+
+
+ {{if .LatestCommitStatus}} + {{template "repo/pulls/status" (dict + "CommitStatus" .LatestCommitStatus + "CommitStatuses" .LatestCommitStatuses + "ShowHideChecks" true + "StatusCheckData" $statusCheckData + )}} + {{end}} + + {{$showGeneralMergeForm := false}} {{if .Issue.PullRequest.HasMerged}} {{if .IsPullBranchDeletable}}
@@ -78,7 +78,7 @@ {{svg "octicon-x"}} {{ctx.Locale.Tr "repo.pulls.files_conflicted"}}
-
    +
      {{range .ConflictedFiles}}
    • {{.}}
    • {{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"}}
-
    +
      {{range .ChangedProtectedFiles}}
    • {{.}}
    • {{end}} @@ -200,7 +200,6 @@ {{template "repo/issue/view_content/update_branch_by_merge" $}} {{if .Issue.PullRequest.IsEmpty}} -
      {{svg "octicon-alert"}} {{ctx.Locale.Tr "repo.pulls.is_empty"}} @@ -209,13 +208,13 @@ {{if .AllowMerge}} {{/* user is allowed to merge */}} {{if $data.MergeFormProps}} -
      {{$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 */}} -
      +
      +
      +
      {{else}} {{/* no merge style was set in repo setting: not or ($prUnit.PullRequestsConfig.AllowMerge ...) */}} -
      {{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 */}} -
      {{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"}}
      -
        +
          {{range .ChangedProtectedFiles}}
        • {{.}}
        • {{end}} @@ -296,20 +294,24 @@ * Then the Manually Merged form will be shown in the merge form */}} {{if and $.StillCanManualMerge (not $showGeneralMergeForm)}} -
          -
          {{/* another similar form is in PullRequestMergeForm.vue*/}} -
          - -
          - -
          +
          +
          {{/* another similar form is in PullRequestMergeForm.vue*/}} +
          + +
          + +
          +
          {{end}} {{if $data.ShowPullCommands}} - {{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "MergeBoxData" $data}} +
          + {{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "MergeBoxData" $data}} +
          {{end}} +
diff --git a/templates/repo/issue/view_content/pull_merge_instruction.tmpl b/templates/repo/issue/view_content/pull_merge_instruction.tmpl index ad85c004505..0f24b1b3eaf 100644 --- a/templates/repo/issue/view_content/pull_merge_instruction.tmpl +++ b/templates/repo/issue/view_content/pull_merge_instruction.tmpl @@ -1,6 +1,5 @@ {{$data := $.MergeBoxData}} {{$pull := $.PullRequest}} -
{{ctx.Locale.Tr "repo.pulls.cmd_instruction_hint"}}
diff --git a/templates/repo/issue/view_content/update_branch_by_merge.tmpl b/templates/repo/issue/view_content/update_branch_by_merge.tmpl index f6fa66eba76..940da17db19 100644 --- a/templates/repo/issue/view_content/update_branch_by_merge.tmpl +++ b/templates/repo/issue/view_content/update_branch_by_merge.tmpl @@ -1,5 +1,4 @@ {{if and (gt $.Issue.PullRequest.CommitsBehind 0) (not $.Issue.IsClosed) (not $.Issue.PullRequest.IsChecking) (not $.IsPullFilesConflicted) (not $.IsPullRequestBroken)}} -
{{svg "octicon-alert"}} diff --git a/templates/repo/pulls/status.tmpl b/templates/repo/pulls/status.tmpl index 9f972be9d35..3a6c261423c 100644 --- a/templates/repo/pulls/status.tmpl +++ b/templates/repo/pulls/status.tmpl @@ -6,22 +6,19 @@ */}} {{$statusCheckData := .StatusCheckData}} {{if .CommitStatus}} -
-
- {{$statusCheckData.CommitStatusCheckPrompt ctx.Locale}} - + {{if $statusCheckData}} +
+
{{$statusCheckData.CommitStatusCheckPrompt ctx.Locale}}
{{if .ShowHideChecks}} -
- -
+ data-hide-all="{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}}" + >{{ctx.Locale.Tr "repo.pulls.status_checks_hide_all"}} {{end}}
- + {{end}} {{if and $statusCheckData $statusCheckData.RequireApprovalRunCount}} -
+
{{ctx.Locale.Tr "repo.pulls.status_checks_need_approvals" $statusCheckData.RequireApprovalRunCount}} @@ -36,28 +33,31 @@
{{end}} -
+
{{range .CommitStatuses}} -
- {{template "repo/commit_status" .}} -
{{.Context}} {{.Description}}
-
+
+
+ {{template "repo/commit_status" .}} +
{{.Context}} {{.Description}}
+
+
{{if and $statusCheckData $statusCheckData.IsContextRequired}} {{if (call $statusCheckData.IsContextRequired .Context)}}
{{ctx.Locale.Tr "repo.pulls.status_checks_requested"}}
{{end}} {{end}} - {{if .TargetURL}}{{ctx.Locale.Tr "repo.pulls.status_checks_details"}}{{end}} + {{if .TargetURL}}{{ctx.Locale.Tr "repo.pulls.status_checks_details"}}{{end}}
{{end}} {{if $statusCheckData}} {{range $statusCheckData.MissingRequiredChecks}} -
- {{svg "octicon-dot-fill" 18 "commit-status icon tw-text-yellow"}} -
{{.}}
+
+
+ {{svg "octicon-dot-fill" 16 "commit-status icon tw-text-yellow"}} +
{{.}}
+
{{ctx.Locale.Tr "repo.pulls.status_checks_requested"}}
{{end}} {{end}}
-
{{end}} diff --git a/tests/integration/api_actions_artifact_test.go b/tests/integration/api_actions_artifact_test.go index 0a4a63c551a..4670bb07045 100644 --- a/tests/integration/api_actions_artifact_test.go +++ b/tests/integration/api_actions_artifact_test.go @@ -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) diff --git a/tests/integration/api_branch_test.go b/tests/integration/api_branch_test.go index 5bf53605498..d67ba98f7c0 100644 --- a/tests/integration/api_branch_test.go +++ b/tests/integration/api_branch_test.go @@ -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) diff --git a/tests/integration/attachment_test.go b/tests/integration/attachment_test.go index db6928beac2..a00ba98b960 100644 --- a/tests/integration/attachment_test.go +++ b/tests/integration/attachment_test.go @@ -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) } diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go index 18b3a9400d7..4a061596907 100644 --- a/tests/integration/editor_test.go +++ b/tests/integration/editor_test.go @@ -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) }) } diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index 62aea184f36..72157458b90 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -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} } diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index 29a1d665af5..09475bad206 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -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) diff --git a/tests/integration/org_profile_test.go b/tests/integration/org_profile_test.go index 73cafd85c2b..69d7999bb9e 100644 --- a/tests/integration/org_profile_test.go +++ b/tests/integration/org_profile_test.go @@ -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) diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index fa10158a57c..48e8c96d38e 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -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 diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index 3d24c4c3264..83cf1d76052 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -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) }) } diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go index 7edbd0b9ce7..b38a037870b 100644 --- a/tests/integration/pull_review_test.go +++ b/tests/integration/pull_review_test.go @@ -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", diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index 3b8924b6e6d..b2e6273bad6 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -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", diff --git a/tests/integration/repo_branch_test.go b/tests/integration/repo_branch_test.go index 6cf9990d2ea..792ffb6011c 100644 --- a/tests/integration/repo_branch_test.go +++ b/tests/integration/repo_branch_test.go @@ -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) { diff --git a/tests/integration/timetracking_test.go b/tests/integration/timetracking_test.go index 3dec6db2e84..e4d8927856c 100644 --- a/tests/integration/timetracking_test.go +++ b/tests/integration/timetracking_test.go @@ -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) diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 26ef377e623..d2407c898de 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -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 { diff --git a/web_src/css/shared/flex-list.css b/web_src/css/shared/flex-list.css index 93a3a1b3f90..ea4314290ac 100644 --- a/web_src/css/shared/flex-list.css +++ b/web_src/css/shared/flex-list.css @@ -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; } diff --git a/web_src/js/features/repo-issue-pull.ts b/web_src/js/features/repo-issue-pull.ts index 33e072a1a5e..05aaf577967 100644 --- a/web_src/js/features/repo-issue-pull.ts +++ b/web_src/js/features/repo-issue-pull.ts @@ -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('.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('.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);