From f796548225c4fbfb2066ff013b5d77a1eb46c15b Mon Sep 17 00:00:00 2001 From: 6543 <m.huber@kithara.com> Date: Mon, 19 Feb 2024 14:42:18 +0100 Subject: [PATCH 01/64] Workaround to clean up old reviews on creating a new one (#28554) close #28542 blocks #28544 --- *Sponsored by Kithara Software GmbH* (cherry picked from commit 217d71c48a10265e08b95cc961656b921f61f9ff) Conflicts: tests/integration/api_pull_review_test.go context --- models/issues/review.go | 40 ++++++- models/unittest/unit_tests.go | 8 +- tests/integration/api_pull_review_test.go | 126 ++++++++++++++++++++++ 3 files changed, 165 insertions(+), 9 deletions(-) diff --git a/models/issues/review.go b/models/issues/review.go index 3aa9d3e2a8..fc110630e0 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -292,8 +292,14 @@ func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio // CreateReview creates a new review based on opts func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error) { + ctx, committer, err := db.TxContext(ctx) + if err != nil { + return nil, err + } + defer committer.Close() + sess := db.GetEngine(ctx) + review := &Review{ - Type: opts.Type, Issue: opts.Issue, IssueID: opts.Issue.ID, Reviewer: opts.Reviewer, @@ -303,15 +309,39 @@ func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error CommitID: opts.CommitID, Stale: opts.Stale, } + if opts.Reviewer != nil { + review.Type = opts.Type review.ReviewerID = opts.Reviewer.ID - } else { - if review.Type != ReviewTypeRequest { - review.Type = ReviewTypeRequest + + reviewCond := builder.Eq{"reviewer_id": opts.Reviewer.ID, "issue_id": opts.Issue.ID} + // make sure user review requests are cleared + if opts.Type != ReviewTypePending { + if _, err := sess.Where(reviewCond.And(builder.Eq{"type": ReviewTypeRequest})).Delete(new(Review)); err != nil { + return nil, err + } } + // make sure if the created review gets dismissed no old review surface + // other types can be ignored, as they don't affect branch protection + if opts.Type == ReviewTypeApprove || opts.Type == ReviewTypeReject { + if _, err := sess.Where(reviewCond.And(builder.In("type", ReviewTypeApprove, ReviewTypeReject))). + Cols("dismissed").Update(&Review{Dismissed: true}); err != nil { + return nil, err + } + } + + } else if opts.ReviewerTeam != nil { + review.Type = ReviewTypeRequest review.ReviewerTeamID = opts.ReviewerTeam.ID + + } else { + return nil, fmt.Errorf("provide either reviewer or reviewer team") } - return review, db.Insert(ctx, review) + + if _, err := sess.Insert(review); err != nil { + return nil, err + } + return review, committer.Commit() } // GetCurrentReview returns the current pending review of reviewer for given issue diff --git a/models/unittest/unit_tests.go b/models/unittest/unit_tests.go index d47bceea1e..75898436fc 100644 --- a/models/unittest/unit_tests.go +++ b/models/unittest/unit_tests.go @@ -131,8 +131,8 @@ func AssertSuccessfulInsert(t assert.TestingT, beans ...any) { } // AssertCount assert the count of a bean -func AssertCount(t assert.TestingT, bean, expected any) { - assert.EqualValues(t, expected, GetCount(t, bean)) +func AssertCount(t assert.TestingT, bean, expected any) bool { + return assert.EqualValues(t, expected, GetCount(t, bean)) } // AssertInt64InRange assert value is in range [low, high] @@ -150,7 +150,7 @@ func GetCountByCond(t assert.TestingT, tableName string, cond builder.Cond) int6 } // AssertCountByCond test the count of database entries matching bean -func AssertCountByCond(t assert.TestingT, tableName string, cond builder.Cond, expected int) { - assert.EqualValues(t, expected, GetCountByCond(t, tableName, cond), +func AssertCountByCond(t assert.TestingT, tableName string, cond builder.Cond, expected int) bool { + return assert.EqualValues(t, expected, GetCountByCond(t, tableName, cond), "Failed consistency test, the counted bean (of table %s) was %+v", tableName, cond) } diff --git a/tests/integration/api_pull_review_test.go b/tests/integration/api_pull_review_test.go index c66c7d752d..cb02baa083 100644 --- a/tests/integration/api_pull_review_test.go +++ b/tests/integration/api_pull_review_test.go @@ -13,12 +13,15 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" + issue_service "code.gitea.io/gitea/services/issue" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "xorm.io/builder" ) func TestAPIPullReviewCreateDeleteComment(t *testing.T) { @@ -436,3 +439,126 @@ func TestAPIPullReviewRequest(t *testing.T) { AddTokenAuth(token) MakeRequest(t, req, http.StatusNoContent) } + +func TestAPIPullReviewStayDismissed(t *testing.T) { + // This test against issue https://github.com/go-gitea/gitea/issues/28542 + // where old reviews surface after a review request got dismissed. + defer tests.PrepareTestEnv(t)() + pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}) + assert.NoError(t, pullIssue.LoadAttributes(db.DefaultContext)) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session2 := loginUser(t, user2.LoginName) + token2 := getTokenForLoggedInUser(t, session2, auth_model.AccessTokenScopeWriteRepository) + user8 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 8}) + session8 := loginUser(t, user8.LoginName) + token8 := getTokenForLoggedInUser(t, session8, auth_model.AccessTokenScopeWriteRepository) + + // user2 request user8 + req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers", repo.OwnerName, repo.Name, pullIssue.Index), &api.PullReviewRequestOptions{ + Reviewers: []string{user8.LoginName}, + }).AddTokenAuth(token2) + MakeRequest(t, req, http.StatusCreated) + + reviewsCountCheck(t, + "check we have only one review request", + pullIssue.ID, user8.ID, 0, 1, 1, false) + + // user2 request user8 again, it is expected to be ignored + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers", repo.OwnerName, repo.Name, pullIssue.Index), &api.PullReviewRequestOptions{ + Reviewers: []string{user8.LoginName}, + }).AddTokenAuth(token2) + MakeRequest(t, req, http.StatusCreated) + + reviewsCountCheck(t, + "check we have only one review request, even after re-request it again", + pullIssue.ID, user8.ID, 0, 1, 1, false) + + // user8 reviews it as accept + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews", repo.OwnerName, repo.Name, pullIssue.Index), &api.CreatePullReviewOptions{ + Event: "APPROVED", + Body: "lgtm", + }).AddTokenAuth(token8) + MakeRequest(t, req, http.StatusOK) + + reviewsCountCheck(t, + "check we have one valid approval", + pullIssue.ID, user8.ID, 0, 0, 1, true) + + // emulate of auto-dismiss lgtm on a protected branch that where a pull just got an update + _, err := db.GetEngine(db.DefaultContext).Where("issue_id = ? AND reviewer_id = ?", pullIssue.ID, user8.ID). + Cols("dismissed").Update(&issues_model.Review{Dismissed: true}) + assert.NoError(t, err) + + // user2 request user8 again + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers", repo.OwnerName, repo.Name, pullIssue.Index), &api.PullReviewRequestOptions{ + Reviewers: []string{user8.LoginName}, + }).AddTokenAuth(token2) + MakeRequest(t, req, http.StatusCreated) + + reviewsCountCheck(t, + "check we have no valid approval and one review request", + pullIssue.ID, user8.ID, 1, 1, 2, false) + + // user8 dismiss review + _, err = issue_service.ReviewRequest(db.DefaultContext, pullIssue, user8, user8, false) + assert.NoError(t, err) + + reviewsCountCheck(t, + "check new review request is now dismissed", + pullIssue.ID, user8.ID, 1, 0, 1, false) + + // add a new valid approval + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews", repo.OwnerName, repo.Name, pullIssue.Index), &api.CreatePullReviewOptions{ + Event: "APPROVED", + Body: "lgtm", + }).AddTokenAuth(token8) + MakeRequest(t, req, http.StatusOK) + + reviewsCountCheck(t, + "check that old reviews requests are deleted", + pullIssue.ID, user8.ID, 1, 0, 2, true) + + // now add a change request witch should dismiss the approval + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews", repo.OwnerName, repo.Name, pullIssue.Index), &api.CreatePullReviewOptions{ + Event: "REQUEST_CHANGES", + Body: "please change XYZ", + }).AddTokenAuth(token8) + MakeRequest(t, req, http.StatusOK) + + reviewsCountCheck(t, + "check that old reviews are dismissed", + pullIssue.ID, user8.ID, 2, 0, 3, false) +} + +func reviewsCountCheck(t *testing.T, name string, issueID, reviewerID int64, expectedDismissed, expectedRequested, expectedTotal int, expectApproval bool) { + t.Run(name, func(t *testing.T) { + unittest.AssertCountByCond(t, "review", builder.Eq{ + "issue_id": issueID, + "reviewer_id": reviewerID, + "dismissed": true, + }, expectedDismissed) + + unittest.AssertCountByCond(t, "review", builder.Eq{ + "issue_id": issueID, + "reviewer_id": reviewerID, + }, expectedTotal) + + unittest.AssertCountByCond(t, "review", builder.Eq{ + "issue_id": issueID, + "reviewer_id": reviewerID, + "type": issues_model.ReviewTypeRequest, + }, expectedRequested) + + approvalCount := 0 + if expectApproval { + approvalCount = 1 + } + unittest.AssertCountByCond(t, "review", builder.Eq{ + "issue_id": issueID, + "reviewer_id": reviewerID, + "type": issues_model.ReviewTypeApprove, + "dismissed": false, + }, approvalCount) + }) +} From fb137d1e49c0436f1db093e2dc0a2350d63e1e29 Mon Sep 17 00:00:00 2001 From: vincent <pulltheflower@163.com> Date: Mon, 19 Feb 2024 22:50:03 +0800 Subject: [PATCH 02/64] Fix content size does not match error when uploading lfs file (#29259)  When we update an lfs file by API `api/v1/repos/{owner}/{repo}/contents/{filepath}`, there will show an error ```json { "message": "Put \"http://localhost:9000/gitea/lfs/38/92/05904d6c7bb83fc676513911226f2be25bf1465616bb9b29587100ab1414\": readfrom tcp [::1]:57300->[::1]:9000: content size does not match", "url": "http://localhost:3000/api/swagger" } ``` The reason of this error is https://github.com/go-gitea/gitea/blob/main/services/repository/files/update.go, in this file, the `file.ContentReader` been used twice. So when use `file.ContentReader` in the second time, the `i` of this Reader has been updated to the length of the content. it will return 0 and an `io.EOF` error when we try to read cotent from this Reader. (cherry picked from commit 35d5e4aea4bb02a0b4c7b38ecb2acf612151e891) --- routers/api/v1/repo/file.go | 2 +- services/repository/files/update.go | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 49d85bf914..94a6381e25 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -425,7 +425,7 @@ func canReadFiles(r *context.Repository) bool { return r.Permission.CanRead(unit.TypeCode) } -func base64Reader(s string) (io.Reader, error) { +func base64Reader(s string) (io.ReadSeeker, error) { b, err := base64.StdEncoding.DecodeString(s) if err != nil { return nil, err diff --git a/services/repository/files/update.go b/services/repository/files/update.go index f223daf3a9..4f7178184b 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -40,7 +40,7 @@ type ChangeRepoFile struct { Operation string TreePath string FromTreePath string - ContentReader io.Reader + ContentReader io.ReadSeeker SHA string Options *RepoFileOptions } @@ -448,6 +448,10 @@ func CreateOrUpdateFile(ctx context.Context, t *TemporaryUploadRepository, file return err } if !exist { + _, err := file.ContentReader.Seek(0, io.SeekStart) + if err != nil { + return err + } if err := contentStore.Put(lfsMetaObject.Pointer, file.ContentReader); err != nil { if _, err2 := git_model.RemoveLFSMetaObjectByOid(ctx, repoID, lfsMetaObject.Oid); err2 != nil { return fmt.Errorf("unable to remove failed inserted LFS object %s: %v (Prev Error: %w)", lfsMetaObject.Oid, err2, err) From 58699d21e77ce233466f6e21ca9c0411c3f3894a Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Tue, 20 Feb 2024 00:34:35 +0200 Subject: [PATCH 03/64] Remove jQuery from the repo migration form (#29229) - Switched to plain JavaScript - Tested the repo migration form functionality and it works as before # Demo using JavaScript without jQuery  --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: silverwind <me@silverwind.io> (cherry picked from commit 100031f5f143a15c79ebbe1b77c86091e3b6d489) --- web_src/js/features/repo-migration.js | 72 +++++++++++++++------------ 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/web_src/js/features/repo-migration.js b/web_src/js/features/repo-migration.js index 3bd0e6d72c..59e282e4e7 100644 --- a/web_src/js/features/repo-migration.js +++ b/web_src/js/features/repo-migration.js @@ -1,38 +1,42 @@ -import $ from 'jquery'; import {hideElem, showElem, toggleElem} from '../utils/dom.js'; -const $service = $('#service_type'); -const $user = $('#auth_username'); -const $pass = $('#auth_password'); -const $token = $('#auth_token'); -const $mirror = $('#mirror'); -const $lfs = $('#lfs'); -const $lfsSettings = $('#lfs_settings'); -const $lfsEndpoint = $('#lfs_endpoint'); -const $items = $('#migrate_items').find('input[type=checkbox]'); +const service = document.getElementById('service_type'); +const user = document.getElementById('auth_username'); +const pass = document.getElementById('auth_password'); +const token = document.getElementById('auth_token'); +const mirror = document.getElementById('mirror'); +const lfs = document.getElementById('lfs'); +const lfsSettings = document.getElementById('lfs_settings'); +const lfsEndpoint = document.getElementById('lfs_endpoint'); +const items = document.querySelectorAll('#migrate_items input[type=checkbox]'); export function initRepoMigration() { checkAuth(); setLFSSettingsVisibility(); - $user.on('input', () => {checkItems(false)}); - $pass.on('input', () => {checkItems(false)}); - $token.on('input', () => {checkItems(true)}); - $mirror.on('change', () => {checkItems(true)}); - $('#lfs_settings_show').on('click', () => { showElem($lfsEndpoint); return false }); - $lfs.on('change', setLFSSettingsVisibility); + user?.addEventListener('input', () => {checkItems(false)}); + pass?.addEventListener('input', () => {checkItems(false)}); + token?.addEventListener('input', () => {checkItems(true)}); + mirror?.addEventListener('change', () => {checkItems(true)}); + document.getElementById('lfs_settings_show')?.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + showElem(lfsEndpoint); + }); + lfs?.addEventListener('change', setLFSSettingsVisibility); - const $cloneAddr = $('#clone_addr'); - $cloneAddr.on('change', () => { - const $repoName = $('#repo_name'); - if ($cloneAddr.val().length > 0 && $repoName.val().length === 0) { // Only modify if repo_name input is blank - $repoName.val($cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3]); + const cloneAddr = document.getElementById('clone_addr'); + cloneAddr?.addEventListener('change', () => { + const repoName = document.getElementById('repo_name'); + if (cloneAddr.value && !repoName?.value) { // Only modify if repo_name input is blank + repoName.value = cloneAddr.value.match(/^(.*\/)?((.+?)(\.git)?)$/)[3]; } }); } function checkAuth() { - const serviceType = $service.val(); + if (!service) return; + const serviceType = Number(service.value); checkItems(serviceType !== 1); } @@ -40,24 +44,26 @@ function checkAuth() { function checkItems(tokenAuth) { let enableItems; if (tokenAuth) { - enableItems = $token.val() !== ''; + enableItems = token?.value !== ''; } else { - enableItems = $user.val() !== '' || $pass.val() !== ''; + enableItems = user?.value !== '' || pass?.value !== ''; } - if (enableItems && $service.val() > 1) { - if ($mirror.is(':checked')) { - $items.not('[name="wiki"]').attr('disabled', true); - $items.filter('[name="wiki"]').attr('disabled', false); + if (enableItems && Number(service?.value) > 1) { + if (mirror?.checked) { + for (const item of items) { + item.disabled = item.name !== 'wiki'; + } return; } - $items.attr('disabled', false); + for (const item of items) item.disabled = false; } else { - $items.attr('disabled', true); + for (const item of items) item.disabled = true; } } function setLFSSettingsVisibility() { - const visible = $lfs.is(':checked'); - toggleElem($lfsSettings, visible); - hideElem($lfsEndpoint); + if (!lfs) return; + const visible = lfs.checked; + toggleElem(lfsSettings, visible); + hideElem(lfsEndpoint); } From 445c78e09fba5f96c3f1194922b5e7d2a748b3d1 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Tue, 20 Feb 2024 00:23:17 +0000 Subject: [PATCH 04/64] [skip ci] Updated translations via Crowdin (cherry picked from commit d9268369473965fce1464325d9f4b15ed9d38046) --- options/locale/locale_lv-LV.ini | 46 ++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 3057b871c7..b69199e953 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -110,6 +110,7 @@ loading=Notiek ielāde… error=Kļūda error404=Lapa, ko vēlaties atvērt, <strong>neeksistē</strong> vai arī <strong>Jums nav tiesības</strong> to aplūkot. +go_back=Atgriezties never=Nekad unknown=Nezināms @@ -590,6 +591,8 @@ user_bio=Biogrāfija disabled_public_activity=Šis lietotājs ir atslēdzies iespēju aplūkot tā aktivitāti. email_visibility.limited=E-pasta adrese ir redzama visiem autentificētajiem lietotājiem email_visibility.private=E-pasta adrese ir redzama tikai administratoriem +show_on_map=Rādīt šo vietu kartē +settings=Lietotāja iestatījumi form.name_reserved=Lietotājvārdu "%s" nedrīkst izmantot. form.name_pattern_not_allowed=Lietotājvārds "%s" nav atļauts. @@ -611,9 +614,12 @@ delete=Dzēst kontu twofa=Divfaktoru autentifikācija account_link=Saistītie konti organization=Organizācijas +uid=UID webauthn=Drošības atslēgas public_profile=Publiskais profils +biography_placeholder=Pastāsti mums mazliet par sevi! (Var izmantot Markdown) +location_placeholder=Kopīgot savu aptuveno atrašanās vietu ar citiem password_username_disabled=Ne-lokāliem lietotājiem nav atļauts mainīt savu lietotāja vārdu. Sazinieties ar sistēmas administratoru, lai uzzinātu sīkāk. full_name=Pilns vārds website=Mājas lapa @@ -697,6 +703,7 @@ add_email_success=Jūsu jaunā e-pasta adrese tika veiksmīgi pievienota. email_preference_set_success=E-pasta izvēle tika veiksmīgi saglabāta. add_openid_success=Jūsu jaunā OpenID adrese tika veiksmīgi pievienota. keep_email_private=Paslēpt e-pasta adresi +keep_email_private_popup=Šis profilā paslēps e-pasta adresi, kā arī tad, kad tiks veikts izmaiņu pieprasījums vai tīmekļa saskarnē labota datne. Aizgādātie iesūtījumi netiks pārveidoti. Revīzijās jāizmanto %s, lai sasaistītu tos ar kontu. openid_desc=Jūsu OpenID adreses ļauj autorizēties, izmantojot, Jūsu izvēlēto pakalpojumu sniedzēju. manage_ssh_keys=Pārvaldīt SSH atslēgas @@ -823,6 +830,7 @@ authorized_oauth2_applications=Autorizētās OAuth2 lietotnes revoke_key=Atsaukt revoke_oauth2_grant=Atsaukt piekļuvi revoke_oauth2_grant_description=Atsaucot piekļuvi šai trešas puses lietotnei tiks liegta piekļuve Jūsu datiem. Vai turpināt? +revoke_oauth2_grant_success=Piekļuve veiksmīgi atsaukta. twofa_desc=Divfaktoru autentifikācija uzlabo konta drošību. twofa_is_enrolled=Kontam ir <strong>ieslēgta</strong> divfaktoru autentifikācija. @@ -875,6 +883,7 @@ visibility=Lietotāja redzamība visibility.public=Publisks visibility.public_tooltip=Redzams ikvienam visibility.limited=Ierobežota +visibility.limited_tooltip=Redzams tikai autentificētiem lietotājiem visibility.private=Privāts [repo] @@ -889,6 +898,7 @@ template_helper=Padarīt repozitoriju par sagatavi template_description=Sagatavju repozitoriji tiek izmantoti, lai balstoties uz tiem veidotu jaunus repozitorijus saglabājot direktoriju un failu struktūru. visibility=Redzamība visibility_description=Tikai organizācijas īpašnieks vai tās biedri, kam ir tiesības, varēs piekļūt šim repozitorijam. +visibility_helper=Padarīt repozitoriju privātu visibility_helper_forced=Jūsu sistēmas administrators ir noteicis, ka visiem no jauna izveidotajiem repozitorijiem ir jābūt privātiem. visibility_fork_helper=(Šīs vērtības maiņa ietekmēs arī visus atdalītos repozitorijus.) clone_helper=Nepieciešama palīdzība klonēšanā? Apmeklē <a target="_blank" rel="noopener noreferrer" href="%s">palīdzības</a> sadaļu. @@ -897,6 +907,7 @@ fork_from=Atdalīt no already_forked=Repozitorijs %s jau ir atdalīts fork_to_different_account=Atdalīt uz citu kontu fork_visibility_helper=Atdalītam repozitorijam nav iespējams mainīt tā redzamību. +all_branches=Visi atzari use_template=Izmantot šo sagatavi clone_in_vsc=Atvērt VS Code download_zip=Lejupielādēt ZIP @@ -924,7 +935,8 @@ trust_model_helper_committer=Revīzijas iesūtītāja: Uzticēties parakstiem, k trust_model_helper_collaborator_committer=Līdzstrādnieka un revīzijas iesūtītāja: Uzticēties līdzstrādnieku parakstiem, kas atbilst revīzijas iesūtītājam trust_model_helper_default=Noklusētais: Izmantojiet šī servera noklusēto uzticamības modeli create_repo=Izveidot repozitoriju -default_branch=Noklusējuma atzars +default_branch=Noklusētais atzars +default_branch_label=noklusējuma default_branch_helper=Noklusētais atzars nosaka pamata atzaru uz kuru tiks veidoti izmaiņu pieprasījumi un koda revīziju iesūtīšana. mirror_prune=Izmest mirror_prune_desc=Izdzēst visas ārējās atsauces, kas ārējā repozitorijā vairs neeksistē @@ -960,6 +972,7 @@ delete_preexisting_success=Dzēst nepārņemtos failus direktorijā %s blame_prior=Aplūkot vainīgo par izmaiņām pirms šīs revīzijas author_search_tooltip=Tiks attēloti ne vairāk kā 30 lietotāji +tree_path_not_found_commit=Revīzijā %[2]s neeksistē ceļš %[1]s transfer.accept=Apstiprināt īpašnieka maiņu transfer.accept_desc=`Mainīt īpašnieku uz "%s"` @@ -1118,6 +1131,9 @@ commit_graph.select=Izvēlieties atzarus commit_graph.hide_pr_refs=Paslēpt izmaiņu pieprasījumus commit_graph.monochrome=Melnbalts commit_graph.color=Krāsa +commit.contained_in=Šī revīzija ir iekļauta: +commit.contained_in_default_branch=Šī revīzija ir daļa no noklusētā atzara +commit.load_referencing_branches_and_tags=Ielādēt atzarus un tagus, kas atsaucas uz šo revīziju blame=Vainot download_file=Lejupielādēt failu normal_view=Parastais skats @@ -1210,6 +1226,7 @@ commits.signed_by_untrusted_user=Parakstījis neuzticams lietotājs commits.signed_by_untrusted_user_unmatched=Parakstījis neuzticams lietotājs, kas neatbilst izmaiņu autoram commits.gpg_key_id=GPG atslēgas ID commits.ssh_key_fingerprint=SSH atslēgas identificējošā zīmju virkne +commits.view_path=Skatīt šajā vēstures punktā commit.operations=Darbības commit.revert=Atgriezt @@ -1220,7 +1237,7 @@ commit.cherry-pick-header=Izlasīt: %s commit.cherry-pick-content=Norādiet atzaru uz kuru izlasīt: commitstatus.error=Kļūda -commitstatus.failure=Neveiksmīgs +commitstatus.failure=Kļūme commitstatus.pending=Nav iesūtīts commitstatus.success=Pabeigts @@ -1418,6 +1435,7 @@ issues.ref_from=`no %[1]s` issues.author=Autors issues.role.owner=Īpašnieks issues.role.member=Biedri +issues.role.contributor_helper=Šis lietotājs repozitorijā ir iepriekš veicis labojumus. issues.re_request_review=Pieprasīt atkārtotu recenziju issues.is_stale=Šajā izmaiņu pieprasījumā ir notikušas izmaiņās, kopš veicāt tā recenziju issues.remove_request_review=Noņemt recenzijas pieprasījumu @@ -1603,6 +1621,11 @@ pulls.switch_comparison_type=Mainīt salīdzināšanas tipu pulls.switch_head_and_base=Mainīt galvas un pamata atzarus pulls.filter_branch=Filtrēt atzarus pulls.no_results=Nekas netika atrasts. +pulls.show_all_commits=Rādīt visas revīzijas +pulls.showing_only_single_commit=Rāda tikai revīzijas %[1]s izmaiņas +pulls.showing_specified_commit_range=Rāda tikai izmaiņas starp %[1]s..%[2]s +pulls.select_commit_hold_shift_for_range=Atlasīt revīziju. Jātur Shift + klikšķis, lai atlasītu vairākas +pulls.filter_changes_by_commit=Atlasīt pēc revīzijas pulls.nothing_to_compare=Nav ko salīdzināt, jo bāzes un salīdzināmie atzari ir vienādi. pulls.nothing_to_compare_and_allow_empty_pr=Šie atzari ir vienādi. Izveidotais izmaiņu pieprasījums būs tukšs. pulls.has_pull_request=`Izmaiņu pieprasījums starp šiem atzariem jau eksistē: <a href="%[1]s">%[2]s#%[3]d</a>` @@ -1706,6 +1729,7 @@ pulls.delete.title=Dzēst šo izmaiņu pieprasījumu? pulls.delete.text=Vai patiešām vēlaties dzēst šo izmaiņu pieprasījumu? (Neatgriezeniski tiks izdzēsts viss saturs. Apsveriet iespēju to aizvērt, ja vēlaties informāciju saglabāt vēsturei) +pull.deleted_branch=(izdzēsts):%s milestones.new=Jauns atskaites punkts milestones.closed=Aizvērts %s @@ -1734,7 +1758,17 @@ milestones.filter_sort.most_complete=Visvairāk pabeigtais milestones.filter_sort.most_issues=Visvairāk problēmu milestones.filter_sort.least_issues=Vismazāk problēmu +signing.will_sign=Šī revīzija tiks parakstīta ar atslēgu "%s". signing.wont_sign.error=Notika kļūda pārbaudot vai revīzija var tikt parakstīta. +signing.wont_sign.nokey=Nav pieejamas atslēgas, ar ko parakstīt šo revīziju. +signing.wont_sign.never=Revīzijas nekad netiek parakstītas. +signing.wont_sign.always=Revīzijas vienmēr tiek parakstītas. +signing.wont_sign.pubkey=Revīzija netiks parakstīta, jo kontam nav piesaistīta publiskā atslēga. +signing.wont_sign.twofa=Jābūt iespējotai divfaktoru autentifikācijai, lai parakstītu revīzijas. +signing.wont_sign.parentsigned=Revīzija netiks parakstīta, jo nav parakstīta vecāka revīzija. +signing.wont_sign.basesigned=Sapludināšanas revīzija netiks parakstīta, jo pamata revīzija nav parakstīta. +signing.wont_sign.headsigned=Sapludināšanas revīzija netiks parakstīta, jo galvenā revīzija nav parakstīta. +signing.wont_sign.commitssigned=Sapludināšana netiks parakstīta, jo visas saistītās revīzijas nav parakstītas. signing.wont_sign.not_signed_in=Jūs neesat pieteicies. ext_wiki=Piekļuve ārējai vikivietnei @@ -2176,6 +2210,7 @@ settings.dismiss_stale_approvals_desc=Kad tiek iesūtītas jaunas revīzijas, ka settings.require_signed_commits=Pieprasīt parakstītas revīzijas settings.require_signed_commits_desc=Noraidīt iesūtītās izmaiņas šim atzaram, ja tās nav parakstītas vai nav iespējams pārbaudīt. settings.protect_branch_name_pattern=Aizsargātā zara šablons +settings.protect_branch_name_pattern_desc=Aizsargāto atzaru nosaukumu šabloni. Šablonu pierakstu skatīt <a href="https://github.com/gobwas/glob">dokumentācijā</a>. Piemēri: main, release/** settings.protect_patterns=Šabloni settings.protect_protected_file_patterns=Aizsargāto failu šablons (vairākus var norādīt atdalot ar semikolu ';'): settings.protect_protected_file_patterns_desc=Aizsargātie faili, ko nevar mainīt, pat ja lietotājam ir tiesības veidot jaunus, labot vai dzēst failus šajā atzarā. Vairākus šablons ir iespējams norādīt atdalot tos ar semikolu (';'). Sīkāka informācija par šabloniem pieejama <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> dokumentācijā. Piemēram, <code>.drone.yml</code>, <code>/docs/**/*.txt</code>. @@ -2212,6 +2247,7 @@ settings.tags.protection.allowed.teams=Atļauts komandām settings.tags.protection.allowed.noone=Nevienam settings.tags.protection.create=Aizsargāt tagus settings.tags.protection.none=Nav uzstādīta tagu aizsargāšana. +settings.tags.protection.pattern.description=Var izmantot vienkāršu nosaukumu vai glob šablonu, vai regulāro izteiksmi, lai atbilstu vairākiem tagiem. Vairāk ir lasāms <a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/protected-tags">aizsargāto tagu šablonu dokumentācijā</a>. settings.bot_token=Bota pilnvara settings.chat_id=Tērzēšanas ID settings.matrix.homeserver_url=Mājas servera URL @@ -2382,13 +2418,14 @@ branch.default_deletion_failed=Atzars "%s" ir noklusētais atzars un to nevar dz branch.restore=`Atjaunot atzaru "%s"` branch.download=`Lejupielādēt atzaru "%s"` branch.rename=`Pārsaukt atzaru "%s"` +branch.search=Meklēt atzarā branch.included_desc=Šis atzars ir daļa no noklusēta atzara branch.included=Iekļauts branch.create_new_branch=Izveidot jaunu atzaru no atzara: branch.confirm_create_branch=Izveidot atzaru branch.warning_rename_default_branch=Tiks pārsaukts noklusētais atzars. branch.rename_branch_to=Pārsaukt "%s" uz: -branch.confirm_rename_branch=Pārsaukt atzaru +branch.confirm_rename_branch=Pārdēvēt atzaru branch.create_branch_operation=Izveidot atzaru branch.new_branch=Izveidot jaunu atzaru branch.new_branch_from=`Izveidot jaunu atzaru no "%s"` @@ -2624,6 +2661,7 @@ dashboard.gc_lfs=Veikt atkritumu uzkopšanas darbus LFS meta objektiem dashboard.stop_zombie_tasks=Apturēt zombija uzdevumus dashboard.stop_endless_tasks=Apturēt nepārtrauktus uzdevumus dashboard.cancel_abandoned_jobs=Atcelt pamestus darbus +dashboard.sync_branch.started=Sākta atzaru sinhronizācija users.user_manage_panel=Lietotāju kontu pārvaldība users.new_account=Izveidot lietotāja kontu @@ -3332,10 +3370,12 @@ runs.all_workflows=Visas darbaplūsmas runs.commit=Revīzija runs.invalid_workflow_helper=Darbaplūsmas konfigurācijas fails ir kļūdains. Pārbaudiet konfiugrācijas failu: %s runs.status=Statuss +runs.empty_commit_message=(tukšs revīzijas ziņojums) need_approval_desc=Nepieciešams apstiprinājums, lai izpildītu izmaiņu pieprasījumu darbaplūsmas no atdalītiem repozitorijiem. +variables.id_not_exist=Mainīgais ar identifikatoru %d neeksistē. [projects] type-1.display_name=Individuālais projekts From 89eca88643042952716a46285fe9818293dbd2d6 Mon Sep 17 00:00:00 2001 From: Rafael Heard <rafael.heard@gmail.com> Date: Mon, 19 Feb 2024 20:01:48 -0500 Subject: [PATCH 05/64] Left align the input labels for the link account page (#29255) In a previous [PR](https://github.com/go-gitea/gitea/pull/28753) we moved the labels to be above the inputs. The PR ensures that the alignment is also on both tabs of the link account page (`/user/link_account`). Before <img width="1094" alt="before" src="https://github.com/go-gitea/gitea/assets/6152817/ac1e86bd-c4d6-4e45-87d1-87bb8a736149"> After <img width="1094" alt="after" src="https://github.com/go-gitea/gitea/assets/6152817/1b5fc109-f4d2-43ee-b924-0a9e53a0e391"> --------- Co-authored-by: rafh <rafaelheard@gmail.com> (cherry picked from commit e4e5d76932e9d5ba1f8c63213aefae1493012a81) --- web_src/css/form.css | 2 -- 1 file changed, 2 deletions(-) diff --git a/web_src/css/form.css b/web_src/css/form.css index c0de4978dd..a5288c9309 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -242,7 +242,6 @@ textarea:focus, .user.activate form, .user.forgot.password form, .user.reset.password form, -.user.link-account form, .user.signup form { margin: auto; width: 700px !important; @@ -277,7 +276,6 @@ textarea:focus, .user.activate form .inline.field > label, .user.forgot.password form .inline.field > label, .user.reset.password form .inline.field > label, - .user.link-account form .inline.field > label, .user.signup form .inline.field > label { text-align: right; width: 250px !important; From eefc4bf6f00b99c7813d8441ddb82fb5acedbadd Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Tue, 20 Feb 2024 09:39:44 +0800 Subject: [PATCH 06/64] Do not show delete button when time tracker is disabled (#29257) Fix #29233 The delete button of time logs won't be shown when the time tracker is disabled.  (cherry picked from commit 8c21bc0d51ab22c0d05d8ce2ea8bc80d6f893800) --- templates/repo/issue/view_content/comments_delete_time.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/issue/view_content/comments_delete_time.tmpl b/templates/repo/issue/view_content/comments_delete_time.tmpl index 7c01bb4228..95121b0dc7 100644 --- a/templates/repo/issue/view_content/comments_delete_time.tmpl +++ b/templates/repo/issue/view_content/comments_delete_time.tmpl @@ -1,4 +1,4 @@ -{{if .comment.Time}} {{/* compatibility with time comments made before v1.14 */}} +{{if and .comment.Time (.ctxData.Repository.IsTimetrackerEnabled ctx)}} {{/* compatibility with time comments made before v1.14 */}} {{if (not .comment.Time.Deleted)}} {{if (or .ctxData.IsAdmin (and .ctxData.IsSigned (eq .ctxData.SignedUserID .comment.PosterID)))}} <span class="gt-float-right"> From 0d61f3decc3683155e1a237820401df6f49cc88a Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Tue, 20 Feb 2024 12:37:37 +0200 Subject: [PATCH 07/64] Remove jQuery from repo wiki creation page (#29271) - Switched to plain JavaScript - Tested the wiki creation form functionality and it works as before # Demo using JavaScript without jQuery  --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: silverwind <me@silverwind.io> (cherry picked from commit ade1110e8b7d94dc142a259854e2b73845eab8b9) --- .../js/features/comp/ComboMarkdownEditor.js | 16 +++--- web_src/js/features/repo-diff.js | 4 +- web_src/js/features/repo-wiki.js | 56 ++++++++++--------- web_src/js/utils/dom.js | 12 ++++ 4 files changed, 51 insertions(+), 37 deletions(-) diff --git a/web_src/js/features/comp/ComboMarkdownEditor.js b/web_src/js/features/comp/ComboMarkdownEditor.js index d486c5830a..d209f11ab2 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.js +++ b/web_src/js/features/comp/ComboMarkdownEditor.js @@ -2,7 +2,7 @@ import '@github/markdown-toolbar-element'; import '@github/text-expander-element'; import $ from 'jquery'; import {attachTribute} from '../tribute.js'; -import {hideElem, showElem, autosize} from '../../utils/dom.js'; +import {hideElem, showElem, autosize, isElemVisible} from '../../utils/dom.js'; import {initEasyMDEImagePaste, initTextareaImagePaste} from './ImagePaste.js'; import {handleGlobalEnterQuickSubmit} from './QuickSubmit.js'; import {renderPreviewPanelContent} from '../repo-editor.js'; @@ -14,17 +14,17 @@ let elementIdCounter = 0; /** * validate if the given textarea is non-empty. - * @param {jQuery} $textarea + * @param {HTMLElement} textarea - The textarea element to be validated. * @returns {boolean} returns true if validation succeeded. */ -export function validateTextareaNonEmpty($textarea) { +export function validateTextareaNonEmpty(textarea) { // When using EasyMDE, the original edit area HTML element is hidden, breaking HTML5 input validation. // The workaround (https://github.com/sparksuite/simplemde-markdown-editor/issues/324) doesn't work with contenteditable, so we just show an alert. - if (!$textarea.val()) { - if ($textarea.is(':visible')) { - $textarea.prop('required', true); - const $form = $textarea.parents('form'); - $form[0]?.reportValidity(); + if (!textarea.value) { + if (isElemVisible(textarea)) { + textarea.required = true; + const form = textarea.closest('form'); + form?.reportValidity(); } else { // The alert won't hurt users too much, because we are dropping the EasyMDE and the check only occurs in a few places. showErrorToast('Require non-empty content'); diff --git a/web_src/js/features/repo-diff.js b/web_src/js/features/repo-diff.js index 04dd153df2..85cb66c728 100644 --- a/web_src/js/features/repo-diff.js +++ b/web_src/js/features/repo-diff.js @@ -47,8 +47,8 @@ function initRepoDiffConversationForm() { e.preventDefault(); const $form = $(e.target); - const $textArea = $form.find('textarea'); - if (!validateTextareaNonEmpty($textArea)) { + const textArea = e.target.querySelector('textarea'); + if (!validateTextareaNonEmpty(textArea)) { return; } diff --git a/web_src/js/features/repo-wiki.js b/web_src/js/features/repo-wiki.js index 58036fde37..d51bf35c81 100644 --- a/web_src/js/features/repo-wiki.js +++ b/web_src/js/features/repo-wiki.js @@ -1,50 +1,51 @@ -import $ from 'jquery'; import {initMarkupContent} from '../markup/content.js'; import {validateTextareaNonEmpty, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js'; import {fomanticMobileScreen} from '../modules/fomantic.js'; - -const {csrfToken} = window.config; +import {POST} from '../modules/fetch.js'; async function initRepoWikiFormEditor() { - const $editArea = $('.repository.wiki .combo-markdown-editor textarea'); - if (!$editArea.length) return; + const editArea = document.querySelector('.repository.wiki .combo-markdown-editor textarea'); + if (!editArea) return; - const $form = $('.repository.wiki.new .ui.form'); - const $editorContainer = $form.find('.combo-markdown-editor'); + const form = document.querySelector('.repository.wiki.new .ui.form'); + const editorContainer = form.querySelector('.combo-markdown-editor'); let editor; let renderRequesting = false; let lastContent; - const renderEasyMDEPreview = function () { + const renderEasyMDEPreview = async function () { if (renderRequesting) return; - const $previewFull = $editorContainer.find('.EasyMDEContainer .editor-preview-active'); - const $previewSide = $editorContainer.find('.EasyMDEContainer .editor-preview-active-side'); - const $previewTarget = $previewSide.length ? $previewSide : $previewFull; - const newContent = $editArea.val(); - if (editor && $previewTarget.length && lastContent !== newContent) { + const previewFull = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active'); + const previewSide = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active-side'); + const previewTarget = previewSide || previewFull; + const newContent = editArea.value; + if (editor && previewTarget && lastContent !== newContent) { renderRequesting = true; - $.post(editor.previewUrl, { - _csrf: csrfToken, - mode: editor.previewMode, - context: editor.previewContext, - text: newContent, - wiki: editor.previewWiki, - }).done((data) => { + const formData = new FormData(); + formData.append('mode', editor.previewMode); + formData.append('context', editor.previewContext); + formData.append('text', newContent); + formData.append('wiki', editor.previewWiki); + try { + const response = await POST(editor.previewUrl, {data: formData}); + const data = await response.text(); lastContent = newContent; - $previewTarget.html(`<div class="markup ui segment">${data}</div>`); + previewTarget.innerHTML = `<div class="markup ui segment">${data}</div>`; initMarkupContent(); - }).always(() => { + } catch (error) { + console.error('Error rendering preview:', error); + } finally { renderRequesting = false; setTimeout(renderEasyMDEPreview, 1000); - }); + } } else { setTimeout(renderEasyMDEPreview, 1000); } }; renderEasyMDEPreview(); - editor = await initComboMarkdownEditor($editorContainer, { + editor = await initComboMarkdownEditor(editorContainer, { useScene: 'wiki', // EasyMDE has some problems of height definition, it has inline style height 300px by default, so we also use inline styles to override it. // And another benefit is that we only need to write the style once for both editors. @@ -64,9 +65,10 @@ async function initRepoWikiFormEditor() { }, }); - $form.on('submit', () => { - if (!validateTextareaNonEmpty($editArea)) { - return false; + form.addEventListener('submit', (e) => { + if (!validateTextareaNonEmpty(editArea)) { + e.preventDefault(); + e.stopPropagation(); } }); } diff --git a/web_src/js/utils/dom.js b/web_src/js/utils/dom.js index 4dc55a518a..1f6066acab 100644 --- a/web_src/js/utils/dom.js +++ b/web_src/js/utils/dom.js @@ -226,3 +226,15 @@ export function initSubmitEventPolyfill() { document.body.addEventListener('click', submitEventPolyfillListener); document.body.addEventListener('focus', submitEventPolyfillListener); } + +/** + * Check if an element is visible, equivalent to jQuery's `:visible` pseudo. + * Note: This function doesn't account for all possible visibility scenarios. + * @param {HTMLElement} element The element to check. + * @returns {boolean} True if the element is visible. + */ +export function isElemVisible(element) { + if (!element) return false; + + return Boolean(element.offsetWidth || element.offsetHeight || element.getClientRects().length); +} From 6068537f8acc9cb410cd72b2c5b109292c2082ec Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Wed, 21 Feb 2024 01:05:17 +0100 Subject: [PATCH 08/64] Remove jQuery .map() and enable eslint rules for it (#29272) - Use case in `repo-commit` was tested until the point where the POST request was sent with the same payload. - Use case in `repo-legacy` was tested completely with comment editing. - `jquery/no-fade` was disabled as well to stay in sync with `no-jquery/no-fade`, had no violations. (cherry picked from commit a5c570c1e02302212a5d8f7cf7d91f24ab0578d5) --- .eslintrc.yaml | 6 +++--- web_src/js/features/repo-commit.js | 18 ++++++++---------- web_src/js/features/repo-legacy.js | 9 +++------ 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index ab9c218849..e9991c02ba 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -296,7 +296,7 @@ rules: jquery/no-delegate: [2] jquery/no-each: [0] jquery/no-extend: [2] - jquery/no-fade: [0] + jquery/no-fade: [2] jquery/no-filter: [0] jquery/no-find: [0] jquery/no-global-eval: [2] @@ -309,7 +309,7 @@ rules: jquery/no-is-function: [2] jquery/no-is: [0] jquery/no-load: [2] - jquery/no-map: [0] + jquery/no-map: [2] jquery/no-merge: [2] jquery/no-param: [2] jquery/no-parent: [0] @@ -451,7 +451,7 @@ rules: no-jquery/no-load: [2] no-jquery/no-map-collection: [0] no-jquery/no-map-util: [2] - no-jquery/no-map: [0] + no-jquery/no-map: [2] no-jquery/no-merge: [2] no-jquery/no-node-name: [2] no-jquery/no-noop: [2] diff --git a/web_src/js/features/repo-commit.js b/web_src/js/features/repo-commit.js index 76b34d2077..fc70ba41e4 100644 --- a/web_src/js/features/repo-commit.js +++ b/web_src/js/features/repo-commit.js @@ -14,17 +14,15 @@ export function initRepoEllipsisButton() { } export function initRepoCommitLastCommitLoader() { + const notReadyEls = document.querySelectorAll('table#repo-files-table tr.notready'); + if (!notReadyEls.length) return; + const entryMap = {}; - - const entries = $('table#repo-files-table tr.notready') - .map((_, v) => { - entryMap[$(v).attr('data-entryname')] = $(v); - return $(v).attr('data-entryname'); - }) - .get(); - - if (entries.length === 0) { - return; + const entries = []; + for (const el of notReadyEls) { + const entryname = el.getAttribute('data-entryname'); + entryMap[entryname] = $(el); + entries.push(entryname); } const lastCommitLoaderURL = $('table#repo-files-table').data('lastCommitLoaderUrl'); diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index ce1bff11a2..10ad836797 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -398,17 +398,14 @@ async function onEditContent(event) { } }; - const saveAndRefresh = (dz, $dropzone) => { + const saveAndRefresh = (dz) => { showElem($renderContent); hideElem($editContentZone); - const $attachments = $dropzone.find('.files').find('[name=files]').map(function () { - return $(this).val(); - }).get(); $.post($editContentZone.attr('data-update-url'), { _csrf: csrfToken, content: comboMarkdownEditor.value(), context: $editContentZone.attr('data-context'), - files: $attachments, + files: dz.files.map((file) => file.uuid), }, (data) => { if (!data.content) { $renderContent.html($('#no-content').html()); @@ -452,7 +449,7 @@ async function onEditContent(event) { }); $editContentZone.find('.save.button').on('click', (e) => { e.preventDefault(); - saveAndRefresh(dz, $dropzone); + saveAndRefresh(dz); }); } else { comboMarkdownEditor = getComboMarkdownEditor($editContentZone.find('.combo-markdown-editor')); From 1410079b98e8eedd7fae8a7ba33d5547e2a32ac8 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Wed, 21 Feb 2024 00:23:41 +0000 Subject: [PATCH 09/64] [skip ci] Updated translations via Crowdin (cherry picked from commit 69dbfbe4e52845a807302a15e8d79d183acf683b) --- options/locale/locale_lv-LV.ini | 233 +++++++++++++++++++++++++++++--- 1 file changed, 212 insertions(+), 21 deletions(-) diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index b69199e953..7dd7220b7a 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -18,10 +18,11 @@ template=Sagatave language=Valoda notifications=Paziņojumi active_stopwatch=Aktīvā laika uzskaite +tracked_time_summary=Izsekojamā laika apkopojums, kas ir balstīts uz pieteikumu saraksta atlasi create_new=Izveidot… user_profile_and_more=Profils un iestatījumi… signed_in_as=Pieteicies kā -enable_javascript=Šai lapas darbībai ir nepieciešams JavaScript. +enable_javascript=Šai tīmekļvietnei ir nepieciešams JavaScript. toc=Satura rādītājs licenses=Licences return_to_gitea=Atgriezties Forgejo @@ -41,12 +42,12 @@ webauthn_sign_in=Nospiediet pogu uz drošības atslēgas. Ja tai nav pogas, izņ webauthn_press_button=Nospiediet drošības atslēgas pogu… webauthn_use_twofa=Izmantot divfaktoru kodu no tālruņa webauthn_error=Nevar nolasīt drošības atslēgu. -webauthn_unsupported_browser=Jūsu pārlūkprogramma neatbalsta WebAuthn standartu. +webauthn_unsupported_browser=Jūsu pārlūks neatbalsta WebAuthn standartu. webauthn_error_unknown=Notikusi nezināma kļūda. Atkārtojiet darbību vēlreiz. -webauthn_error_insecure=WebAuthn atbalsta tikai drošus savienojumus ar serveri -webauthn_error_unable_to_process=Serveris nevar apstrādāt Jūsu pieprasījumu. +webauthn_error_insecure=`WebAuthn atbalsta tikai drošus savienojumus. Pārbaudīšanai ar HTTP var izmantot izcelsmi "localhost" vai "127.0.0.1"` +webauthn_error_unable_to_process=Serveris nevarēja apstrādāt pieprasījumu. webauthn_error_duplicated=Drošības atslēga nav atļauta šim pieprasījumam. Pārliecinieties, ka šī atslēga jau nav reģistrēta. -webauthn_error_empty=Norādiet atslēgas nosaukumu. +webauthn_error_empty=Jānorāda šīs atslēgas nosaukums. webauthn_error_timeout=Iestājusies noildze, mēģinot, nolasīt atslēgu. Pārlādējiet lapu un mēģiniet vēlreiz. webauthn_reload=Pārlādēt @@ -61,11 +62,11 @@ new_org=Jauna organizācija new_project=Jauns projekts new_project_column=Jauna kolonna manage_org=Pārvaldīt organizācijas -admin_panel=Lapas administrēšana +admin_panel=Vietnes administrēšana account_settings=Konta iestatījumi settings=Iestatījumi your_profile=Profils -your_starred=Atzīmēts ar zvaigznīti +your_starred=Pievienots izlasē your_settings=Iestatījumi all=Visi @@ -91,9 +92,11 @@ remove=Noņemt remove_all=Noņemt visus remove_label_str=`Noņemt ierakstu "%s"` edit=Labot +view=Skatīt enabled=Iespējots disabled=Atspējots +locked=Slēgts copy=Kopēt copy_url=Kopēt saiti @@ -132,6 +135,7 @@ concept_user_organization=Organizācija show_timestamps=Rādīt laika zīmogus show_log_seconds=Rādīt sekundes show_full_screen=Atvērt pilnā logā +download_logs=Lejupielādēt žurnālus confirm_delete_selected=Apstiprināt, lai izdzēstu visus atlasītos vienumus? @@ -172,6 +176,7 @@ string.desc=Z - A [error] occurred=Radusies kļūda +report_message=Ja ir pārliecība, ka šī ir Gitea nepilnība, lūgums pārbaudīt <a href="https://github.com/go-gitea/gitea/issues" target="_blank">GitHub</a>, vai tā jau nav zināma, vai izveidot jaunu pieteikumu, ja nepieciešams. missing_csrf=Kļūdains pieprasījums: netika iesūtīta drošības pilnvara invalid_csrf=Kļūdains pieprasījums: iesūtīta kļūdaina drošības pilnvara not_found=Pieprasītie dati netika atrasti. @@ -180,6 +185,7 @@ network_error=Tīkla kļūda [startpage] app_desc=Viegli uzstādāms Git serviss install=Vienkārši instalējams +install_desc=Vienkārši <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.com/installation/install-from-binary">jāpalaiž izpildāmais fails</a> vajadzīgajai platformai, jāizmanto <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>, vai jāiegūst <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.com/installation/install-from-package">pakotne</a>. platform=Pieejama dažādām platformām platform_desc=Forgejo iespējams uzstādīt jebkur, kam <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> var nokompilēt: Windows, macOS, Linux, ARM utt. Izvēlies to, kas tev patīk! lightweight=Viegla @@ -224,6 +230,7 @@ repo_path_helper=Git repozitoriji tiks glabāti šajā direktorijā. lfs_path=Git LFS glabāšanas vieta lfs_path_helper=Faili, kas pievienoti Git LFS, tiks glabāti šajā direktorijā. Atstājiet tukšu, lai atspējotu. run_user=Izpildes lietotājs +run_user_helper=Operētājsistēms lietotājs, ar kuru tiks palaists Gitea. Jāņem vērā, ka šim lietotājam ir jābūt piekļuvei repozitorija atrašanās vietai. domain=Servera domēns domain_helper=Domēns vai servera adrese. ssh_port=SSH servera ports @@ -295,6 +302,8 @@ invalid_password_algorithm=Kļūdaina paroles jaucējfunkcija password_algorithm_helper=Norādiet paroles jaucējalgoritmu. Algoritmi atšķirās pēc prasībām pret resursiem un stipruma. Argon2 algoritms ir drošs, bet tam nepieciešams daudz operatīvās atmiņas, līdz ar ko tas var nebūt piemērots sistēmām ar maz pieejamajiem resursiem. enable_update_checker=Iespējot jaunu versiju paziņojumus enable_update_checker_helper=Periodiski pārbaudīt jaunu version pieejamību, izgūstot datus no gitea.io. +env_config_keys=Vides konfigurācija +env_config_keys_prompt=Šie vides mainīgie tiks pielietoti arī konfigurācijas failā: [home] uname_holder=Lietotājvārds vai e-pasts @@ -353,9 +362,11 @@ disable_register_prompt=Reģistrācija ir atspējota. Lūdzu, sazinieties ar vie disable_register_mail=Reģistrācijas e-pasta apstiprināšana ir atspējota. manual_activation_only=Sazinieties ar lapas administratoru, lai pabeigtu konta aktivizāciju. remember_me=Atcerēties šo ierīci +remember_me.compromised=Pieteikšanās pilnvara vairs nav derīga, kas var norādīt uz ļaunprātīgām darbībām kontā. Lūgums pārbaudīt, vai kontā nav neparastu darbību. forgot_password_title=Aizmirsu paroli forgot_password=Aizmirsi paroli? sign_up_now=Nepieciešams konts? Reģistrējies tagad. +sign_up_successful=Konts tika veiksmīgi izveidots. Laipni lūdzam! confirmation_mail_sent_prompt=Jauns apstiprināšanas e-pasts ir nosūtīts uz <b>%s</b>, pārbaudies savu e-pasta kontu tuvāko %s laikā, lai pabeigtu reģistrācijas procesu. must_change_password=Mainīt paroli allow_password_change=Pieprasīt lietotājam mainīt paroli (ieteicams) @@ -371,6 +382,7 @@ email_not_associate=Šī e-pasta adrese nav saistīta ar nevienu kontu. send_reset_mail=Nosūtīt paroles atjaunošanas e-pastu reset_password=Paroles atjaunošana invalid_code=Jūsu apstiprināšanas kodam ir beidzies derīguma termiņš vai arī tas ir nepareizs. +invalid_code_forgot_password=Apliecinājuma kods ir nederīgs vai tā derīgums ir beidzies. Nospiediet <a href="%s">šeit</a>, lai uzsāktu jaunu sesiju. invalid_password=Jūsu parole neatbilst parolei, kas tika ievadīta veidojot so kontu. reset_password_helper=Atjaunot paroli reset_password_wrong_user=Jūs esat pieteicies kā %s, bet konta atkopšanas saite ir paredzēta lietotājam %s @@ -398,6 +410,7 @@ openid_connect_title=Pievienoties jau esošam kontam openid_connect_desc=Izvēlētais OpenID konts sistēmā netika atpazīts, bet Jūs to varat piesaistīt esošam kontam. openid_register_title=Izveidot jaunu kontu openid_register_desc=Izvēlētais OpenID konts sistēmā netika atpazīts, bet Jūs to varat piesaistīt esošam kontam. +openid_signin_desc=Jāievada OpenID URI. Piemēram, anna.openid.example.org vai https://openid.example.org/anna. disable_forgot_password_mail=Konta atjaunošana ir atspējota, jo nav uzstādīti e-pasta servera iestatījumi. Sazinieties ar lapas administratoru. disable_forgot_password_mail_admin=Kontu atjaunošana ir pieejama tikai, ja ir veikta e-pasta servera iestatījumu konfigurēšana. Norādiet e-pasta servera iestatījumus, lai iespējotu kontu atjaunošanu. email_domain_blacklisted=Nav atļauts reģistrēties ar šādu e-pasta adresi. @@ -407,7 +420,9 @@ authorize_application_created_by=Šo lietotni izveidoja %s. authorize_application_description=Ja piešķirsiet tiesības, tā varēs piekļūt un mainīt Jūsu konta informāciju, ieskaitot privātos repozitorijus un organizācijas. authorize_title=Autorizēt "%s" piekļuvi jūsu kontam? authorization_failed=Autorizācija neizdevās +authorization_failed_desc=Autentifikācija neizdevās, jo tika veikts kļūdains pieprasījums. Sazinieties ar lietojumprogrammas, ar kuru mēģinājāt autentificēties, uzturētāju. sspi_auth_failed=SSPI autentifikācija neizdevās +password_pwned=Izvēlētā parole ir <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">nozagto paroļu sarakstā</a>, kas iepriekš ir atklāts publiskās datu noplūdēs. Lūgums mēģināt vēlreiz ar citu paroli un apsvērt to nomainīt arī citur. password_pwned_err=Neizdevās pabeigt pieprasījumu uz HaveIBeenPwned [mail] @@ -422,6 +437,7 @@ activate_account.text_1=Sveiki <b>%[1]s</b>, esat reģistrējies %[2]s! activate_account.text_2=Nospiediet uz saites, lai aktivizētu savu kontu lapā <b>%s</b>: activate_email=Apstipriniet savu e-pasta adresi +activate_email.title=%s, apstipriniet savu e-pasta adresi activate_email.text=Nospiediet uz saites, lai apstiprinātu savu e-pasta adresi lapā <b>%s</b>: register_notify=Laipni lūdzam Forgejo @@ -620,6 +636,7 @@ webauthn=Drošības atslēgas public_profile=Publiskais profils biography_placeholder=Pastāsti mums mazliet par sevi! (Var izmantot Markdown) location_placeholder=Kopīgot savu aptuveno atrašanās vietu ar citiem +profile_desc=Norādīt, kā profils tiek attēlots citiem lietotājiem. Primārā e-pasta adrese tiks izmantota paziņojumiem, paroles atjaunošanai un Git tīmekļa darbībām. password_username_disabled=Ne-lokāliem lietotājiem nav atļauts mainīt savu lietotāja vārdu. Sazinieties ar sistēmas administratoru, lai uzzinātu sīkāk. full_name=Pilns vārds website=Mājas lapa @@ -631,6 +648,8 @@ update_language_not_found=Valoda "%s" nav pieejama. update_language_success=Valoda tika nomainīta. update_profile_success=Jūsu profila informācija tika saglabāta. change_username=Lietotājvārds mainīts. +change_username_prompt=Piezīme: lietotājvārda mainīšana maina arī konta URL. +change_username_redirect_prompt=Iepriekšējais lietotājvārds tiks pārvirzīts, kamēr neviens cits to neizmanto. continue=Turpināt cancel=Atcelt language=Valoda @@ -655,6 +674,7 @@ comment_type_group_project=Projektus comment_type_group_issue_ref=Problēmu atsauces saved_successfully=Iestatījumi tika veiksmīgi saglabati. privacy=Privātums +keep_activity_private=Profila lapā paslēpt notikumus keep_activity_private_popup=Savu aktivitāti redzēsiet tikai Jūs un administratori lookup_avatar_by_mail=Meklēt profila bildes pēc e-pasta @@ -664,12 +684,14 @@ choose_new_avatar=Izvēlēties jaunu profila attēlu update_avatar=Saglabāt profila bildi delete_current_avatar=Dzēst pašreizējo profila bildi uploaded_avatar_not_a_image=Augšupielādētais fails nav attēls. +uploaded_avatar_is_too_big=Augšupielādētā faila izmērs (%d KiB) pārsniedz pieļaujamo izmēru (%d KiB). update_avatar_success=Profila attēls tika saglabāts. update_user_avatar_success=Lietotāja profila attēls tika atjaunots. update_password=Mainīt paroli old_password=Pašreizējā parole new_password=Jauna parole +retype_new_password=Apstiprināt jauno paroli password_incorrect=Ievadīta nepareiza pašreizējā parole. change_password_success=Parole tika veiksmīgi nomainīta. Tagad varat pieteikties ar jauno paroli. password_change_disabled=Ārējie konti nevar mainīt paroli, izmantojot, Forgejo saskarni. @@ -678,6 +700,7 @@ emails=E-pasta adreses manage_emails=Pārvaldīt e-pasta adreses manage_themes=Izvēlieties noklusējuma motīvu manage_openid=Pārvaldīt OpenID adreses +email_desc=Primārā e-pasta adrese tiks izmantota paziņojumiem, paroļu atjaunošanai un, ja tā nav paslēpta, Git tīmekļa darbībām. theme_desc=Šis būs noklusējuma motīvs visiem lietotājiem. primary=Primārā activated=Aktivizēts @@ -685,6 +708,7 @@ requires_activation=Nepieciešams aktivizēt primary_email=Uzstādīt kā primāro activate_email=Nosūtīt aktivizācijas e-pastu activations_pending=Gaida aktivizāciju +can_not_add_email_activations_pending=Ir nepabeigta aktivizācija. Pēc dažām minūtēm mēģiniet vēlreiz, ja ir vēlme pievienot jaunu e-pasta adresi. delete_email=Noņemt email_deletion=Dzēst e-pasta adresi email_deletion_desc=E-pasta adrese un ar to saistītā informācija tiks dzēsta no šī konta. Git revīzijas ar šo e-pasta adresi netiks mainītas. Vai turpināt? @@ -784,6 +808,7 @@ ssh_externally_managed=Šim lietotājam SSH atslēga tiek pāvaldīta attālinā manage_social=Pārvaldīt piesaistītos sociālos kontus social_desc=Šie sociālo tīklu konti var tikt izmantoti, lai pieteiktos. Pārliecinieties, ka visi ir atpazīstami. unbind=Atsaistīt +unbind_success=Sociālā tīkla konts tika veiksmīgi noņemts. manage_access_token=Pārvaldīt piekļuves pilnvaras generate_new_token=Izveidot jaunu pilnvaru @@ -803,7 +828,9 @@ permissions_public_only=Tikai publiskie permissions_access_all=Visi (publiskie, privātie un ierobežotie) select_permissions=Norādiet tiesības permission_no_access=Nav piekļuves -permission_read=Izlasītie +permission_read=Skatīšanās +permission_write=Skatīšanās un raksīšanas +access_token_desc=Atzīmētie pilnvaras apgabali ierobežo autentifikāciju tikai atbilstošiem <a %s>API</a> izsaukumiem. Sīkāka informācija pieejama <a %s>dokumentācijā</a>. at_least_one_permission=Nepieciešams norādīt vismaz vienu tiesību, lai izveidotu pilnvaru permissions_list=Tiesības: @@ -815,6 +842,8 @@ remove_oauth2_application_desc=Noņemot OAuth2 lietotni, tiks noņemta piekļuve remove_oauth2_application_success=Lietotne tika dzēsta. create_oauth2_application=Izveidot jaunu OAuth2 lietotni create_oauth2_application_button=Izveidot lietotni +create_oauth2_application_success=Ir veiksmīgi izveidota jauna OAuth2 lietotne. +update_oauth2_application_success=Ir veiksmīgi atjaunota OAuth2 lietotne. oauth2_application_name=Lietotnes nosaukums oauth2_confidential_client=Konfidenciāls klients. Norādiet lietotēm, kas glabā noslēpumu slepenībā, piemēram, tīmekļa lietotnēm. Nenorādiet instalējamām lietotnēm, tai skaitā darbavirsmas vai mobilajām lietotnēm. oauth2_redirect_uris=Pārsūtīšanas URI. Norādiet katru URI savā rindā. @@ -823,20 +852,26 @@ oauth2_client_id=Klienta ID oauth2_client_secret=Klienta noslēpums oauth2_regenerate_secret=Pārģenerēt noslēpumus oauth2_regenerate_secret_hint=Pazaudēts noslēpums? +oauth2_client_secret_hint=Pēc šīs lapas pamešanas vai atsvaidzināšanas noslēpums vairs netiks parādīts. Lūgums pārliecināties, ka tas ir saglabāts. oauth2_application_edit=Labot oauth2_application_create_description=OAuth2 lietotnes ļauj trešas puses lietotnēm piekļūt lietotāja kontiem šajā instancē. +oauth2_application_remove_description=OAuth2 lietotnes noņemšana liegs tai piekļūt pilnvarotiem lietotāju kontiem šajā instancē. Vai turpināt? +oauth2_application_locked=Gitea sāknēšanas brīdī reģistrē dažas OAuth2 lietotnes, ja tas ir iespējots konfigurācijā. Lai novērstu negaidītu uzvedību, tās nevar ne labot, ne noņemt. Lūgums vērsties OAuth2 dokumentācijā pēc vairāk informācijas. authorized_oauth2_applications=Autorizētās OAuth2 lietotnes +authorized_oauth2_applications_description=Ir ļauta piekļuve savam Gitea kontam šīm trešo pušu lietotnēm. Lūgums atsaukt piekļuvi lietotnēm, kas vairs nav nepieciešamas. revoke_key=Atsaukt revoke_oauth2_grant=Atsaukt piekļuvi revoke_oauth2_grant_description=Atsaucot piekļuvi šai trešas puses lietotnei tiks liegta piekļuve Jūsu datiem. Vai turpināt? revoke_oauth2_grant_success=Piekļuve veiksmīgi atsaukta. twofa_desc=Divfaktoru autentifikācija uzlabo konta drošību. +twofa_recovery_tip=Ja ierīce tiek pazaudēta, iespējams izmantot vienreiz izmantojamo atkopšanas atslēgu, lai atgūtu piekļuvi savam kontam. twofa_is_enrolled=Kontam ir <strong>ieslēgta</strong> divfaktoru autentifikācija. twofa_not_enrolled=Kontam šobrīd nav ieslēgta divfaktoru autentifikācija. twofa_disable=Atslēgt divfaktoru autentifikāciju twofa_scratch_token_regenerate=Ģenerēt jaunu vienreizējo kodu +twofa_scratch_token_regenerated=Vienreizējā pilnvara tagad ir %s. Tā ir jāglabā drošā vietā, tā vairs nekad netiks rādīta. twofa_enroll=Ieslēgt divfaktoru autentifikāciju twofa_disable_note=Nepieciešamības gadījumā divfaktoru autentifikāciju ir iespējams atslēgt. twofa_disable_desc=Atslēdzot divfaktoru autentifikāciju, konts vairs nebūs tik drošs. Vai turpināt? @@ -854,6 +889,8 @@ webauthn_register_key=Pievienot drošības atslēgu webauthn_nickname=Segvārds webauthn_delete_key=Noņemt drošības atslēgu webauthn_delete_key_desc=Noņemot drošības atslēgu ar to vairs nebūs iespējams pieteikties. Vai turpināt? +webauthn_key_loss_warning=Ja tiek pazaudētas drošības atslēgas, tiks zaudēta piekļuve kontam. +webauthn_alternative_tip=Ir vēlams uzstādīt papildu autentifikācijas veidu. manage_account_links=Pārvaldīt saistītos kontus manage_account_links_desc=Šādi ārējie konti ir piesaistīti Jūsu Forgejo kontam. @@ -863,8 +900,10 @@ remove_account_link=Noņemt saistīto kontu remove_account_link_desc=Noņemot saistīto kontu, tam tiks liegta piekļuve Jūsu Forgejo kontam. Vai turpināt? remove_account_link_success=Saistītais konts tika noņemts. +hooks.desc=Pievienot tīmekļa āķus, kas izpildīsies <strong>visos repozitorijos</strong>, kas jums pieder. orgs_none=Jūs neesat nevienas organizācijas biedrs. +repos_none=Jums nepieder neviens repozitorijs. delete_account=Dzēst savu kontu delete_prompt=Šī darbība pilnībā izdzēsīs Jūsu kontu, kā arī tā ir <strong>NEATGRIEZENISKA</strong>. @@ -885,8 +924,10 @@ visibility.public_tooltip=Redzams ikvienam visibility.limited=Ierobežota visibility.limited_tooltip=Redzams tikai autentificētiem lietotājiem visibility.private=Privāts +visibility.private_tooltip=Redzams tikai organizāciju, kurām esi pievienojies, dalībniekiem [repo] +new_repo_helper=Repozitorijs satur visus projekta failus, tajā skaitā izmaiņu vēsturi. Jau tiek glabāts kaut kur citur? <a href="%s">Pārnest repozitoriju.</a> owner=Īpašnieks owner_helper=Ņemot vērā maksimālā repozitoriju skaita ierobežojumu, ne visas organizācijas var tikt parādītas sarakstā. repo_name=Repozitorija nosaukums @@ -907,7 +948,9 @@ fork_from=Atdalīt no already_forked=Repozitorijs %s jau ir atdalīts fork_to_different_account=Atdalīt uz citu kontu fork_visibility_helper=Atdalītam repozitorijam nav iespējams mainīt tā redzamību. +fork_branch=Atzars, ko klonēt atdalītajā repozitorijā all_branches=Visi atzari +fork_no_valid_owners=Šim repozitorijam nevar izveidot atdalītu repozitoriju, jo tam nav spēkā esošu īpašnieku. use_template=Izmantot šo sagatavi clone_in_vsc=Atvērt VS Code download_zip=Lejupielādēt ZIP @@ -945,6 +988,8 @@ mirror_interval_invalid=Nekorekts spoguļošanas intervāls. mirror_sync_on_commit=Sinhronizēt, kad revīzijas tiek iesūtītas mirror_address=Spoguļa adrese mirror_address_desc=Pieslēgšanās rekvizītus norādiet autorizācijas sadaļā. +mirror_address_url_invalid=Norādītais URL ir nederīgs. Visas URL daļas ir jānorāda pareizi. +mirror_address_protocol_invalid=Norādītais URL ir nederīgs. Var spoguļot tikai no http(s):// vai git:// adresēm. mirror_lfs=Lielu failu glabātuve (LFS) mirror_lfs_desc=Aktivizēt LFS datu spoguļošanu. mirror_lfs_endpoint=LFS galapunkts @@ -955,7 +1000,7 @@ mirror_password_blank_placeholder=(nav uzstādīts) mirror_password_help=Nomainiet lietotāju, lai izdzēstu saglabāto paroli. watchers=Novērotāji stargazers=Zvaigžņdevēji -stars_remove_warning=Tiks noņemtas visas atzīmētās zvaigznes šim repozitorijam. +stars_remove_warning=Šis repozitorijs tiks noņemts no visām izlasēm. forks=Atdalītie repozitoriji reactions_more=un vēl %d unit_disabled=Administrators ir atspējojies šo repozitorija sadaļu. @@ -970,14 +1015,20 @@ delete_preexisting=Dzēst jau eksistējošos failus delete_preexisting_content=Dzēst failus direktorijā %s delete_preexisting_success=Dzēst nepārņemtos failus direktorijā %s blame_prior=Aplūkot vainīgo par izmaiņām pirms šīs revīzijas +blame.ignore_revs=Neņem vērā izmaiņas no <a href="%s">.git-blame-ignore-revs</a>. Nospiediet <a href="%s">šeit, lai to apietu</a> un redzētu visu izmaiņu skatu. +blame.ignore_revs.failed=Neizdevās neņemt vērā izmaiņas no <a href="%s">.git-blam-ignore-revs</a>. author_search_tooltip=Tiks attēloti ne vairāk kā 30 lietotāji tree_path_not_found_commit=Revīzijā %[2]s neeksistē ceļš %[1]s +tree_path_not_found_branch=Atzarā %[2]s nepastāv ceļš %[1]s +tree_path_not_found_tag=Tagā %[2]s nepastāv ceļš %[1]s transfer.accept=Apstiprināt īpašnieka maiņu transfer.accept_desc=`Mainīt īpašnieku uz "%s"` transfer.reject=Noraidīt īpašnieka maiņu transfer.reject_desc=`Atcelt īpašnieka maiņu uz "%s"` +transfer.no_permission_to_accept=Nav atļaujas pieņemt šo pārsūtīšanu. +transfer.no_permission_to_reject=Nav atļaujas noraidīt šo pārsūtīšanu. desc.private=Privāts desc.public=Publisks @@ -996,6 +1047,8 @@ template.issue_labels=Problēmu etiķetes template.one_item=Norādiet vismaz vienu sagataves vienību template.invalid=Norādiet sagataves repozitoriju +archive.title=Šis repozitorijs ir arhivēts. Ir iespējams aplūkot tā failus un to konēt, bet nav iespējams iesūtīt izmaiņas, kā arī izveidot jaunas problēmas vai izmaiņu pieprasījumus. +archive.title_date=Šis repozitorijs tika arhivēts %s. Ir iespējams aplūkot tā failus un to konēt, bet nav iespējams iesūtīt izmaiņas, kā arī izveidot jaunas problēmas vai izmaiņu pieprasījumus. archive.issue.nocomment=Repozitorijs ir arhivēts. Problēmām nevar pievienot jaunus komentārus. archive.pull.nocomment=Repozitorijs ir arhivēts. Izmaiņu pieprasījumiem nevar pievienot jaunus komentārus. @@ -1012,6 +1065,7 @@ migrate_options_lfs=Migrēt LFS failus migrate_options_lfs_endpoint.label=LFS galapunkts migrate_options_lfs_endpoint.description=Migrācija mēģinās izmantot attālināto URL, lai <a target="_blank" rel="noopener noreferrer" href="%s">noteiktu LFS serveri</a>. Var norādīt arī citu galapunktu, ja repozitorija LFS dati ir izvietoti citā vietā. migrate_options_lfs_endpoint.description.local=Iespējams norādīt arī servera ceļu. +migrate_options_lfs_endpoint.placeholder=Ja nav norādīts, galamērķis tiks atvasināts no klonēšanas URL migrate_items=Vienības, ko pārņemt migrate_items_wiki=Vikivietni migrate_items_milestones=Atskaites punktus @@ -1062,11 +1116,11 @@ generated_from=ģenerēts no fork_from_self=Nav iespējams atdalīt repozitoriju, kuram esat īpašnieks. fork_guest_user=Piesakieties, lai atdalītu repozitoriju. watch_guest_user=Piesakieties, lai sekotu šim repozitorijam. -star_guest_user=Piesakieties, lai atzīmētu šo repozitoriju ar zvaigznīti. +star_guest_user=Piesakieties, lai pievienotu šo repozitoriju izlasei. unwatch=Nevērot watch=Vērot unstar=Noņemt zvaigznīti -star=Pievienot zvaigznīti +star=Pievienot izlasei fork=Atdalīts download_archive=Lejupielādēt repozitoriju more_operations=Vairāk darbību @@ -1114,6 +1168,10 @@ file_view_rendered=Skatīt rezultātu file_view_raw=Rādīt neapstrādātu file_permalink=Patstāvīgā saite file_too_large=Šis fails ir par lielu, lai to parādītu. +invisible_runes_header=`Šīs fails satur neredzamus unikoda simbolus` +invisible_runes_description=`Šis fails satur neredzamus unikoda simbolus, kas ir neatšķirami cilvēkiem, bet dators tās var atstrādāt atšķirīgi. Ja šķiet, ka tas ir ar nolūku, šo brīdinājumu var droši neņemt vērā. Jāizmanto atsoļa taustiņš (Esc), lai atklātu tās.` +ambiguous_runes_header=`Šis fails satur neviennozīmīgus unikoda simbolus` +ambiguous_runes_description=`Šis fails satur unikoda simbolus, kas var tikt sajauktas ar citām rakstzīmēm. Ja šķiet, ka tas ir ar nolūku, šo brīdinājumu var droši neņemt vērā. Jāizmanto atsoļa taustiņš (Esc), lai atklātu tās.` invisible_runes_line=`Šī līnija satur neredzamus unikoda simbolus` ambiguous_runes_line=`Šī līnija satur neviennozīmīgus unikoda simbolus` ambiguous_character=`%[1]c [U+%04[1]X] var tikt sajaukts ar %[2]c [U+%04[2]X]` @@ -1126,6 +1184,7 @@ video_not_supported_in_browser=Jūsu pārlūks neatbalsta HTML5 video. audio_not_supported_in_browser=Jūsu pārlūks neatbalsta HTML5 audio. stored_lfs=Saglabāts Git LFS symbolic_link=Simboliska saite +executable_file=Izpildāmais fails commit_graph=Revīziju grafs commit_graph.select=Izvēlieties atzarus commit_graph.hide_pr_refs=Paslēpt izmaiņu pieprasījumus @@ -1354,14 +1413,15 @@ issues.delete_branch_at=`izdzēsa atzaru <b>%s</b> %s` issues.filter_label=Etiķete issues.filter_label_exclude=`Izmantojiet <code>alt</code> + <code>peles klikšķis vai enter</code>, lai neiekļautu etiķeti` issues.filter_label_no_select=Visas etiķetes +issues.filter_label_select_no_label=Nav etiķetes issues.filter_milestone=Atskaites punkts issues.filter_milestone_all=Visi atskaites punkti issues.filter_milestone_none=Nav atskaites punkta issues.filter_milestone_open=Atvērtie atskaites punkti issues.filter_milestone_closed=Aizvērtie atskaites punkti -issues.filter_project=Projektus +issues.filter_project=Projekts issues.filter_project_all=Visi projekti -issues.filter_project_none=Nav projektu +issues.filter_project_none=Nav projekta issues.filter_assignee=Atbildīgais issues.filter_assginee_no_select=Visi atbildīgie issues.filter_assginee_no_assignee=Nav atbildīgā @@ -1387,6 +1447,7 @@ issues.filter_sort.moststars=Visvairāk atzīmētie issues.filter_sort.feweststars=Vismazāk atzīmētie issues.filter_sort.mostforks=Visvairāk atdalītie issues.filter_sort.fewestforks=Vismazāk atdalītie +issues.keyword_search_unavailable=Meklēšana pēc atslēgvārda pašreiz nav pieejama. Lūgums sazināties ar vietnes administratoru. issues.action_open=Atvērt issues.action_close=Aizvērt issues.action_label=Etiķete @@ -1407,6 +1468,7 @@ issues.next=Nākamā issues.open_title=Atvērta issues.closed_title=Slēgta issues.draft_title=Melnraksts +issues.num_comments_1=%d komentārs issues.num_comments=%d komentāri issues.commented_at=`komentēja <a href="#%s">%s</a>` issues.delete_comment_confirm=Vai patiešām vēlaties dzēst šo komentāru? @@ -1415,6 +1477,7 @@ issues.context.quote_reply=Atbildēt citējot issues.context.reference_issue=Atsaukties uz šo jaunā problēmā issues.context.edit=Labot issues.context.delete=Dzēst +issues.no_content=Nav sniegts apraksts. issues.close=Slēgt problēmu issues.comment_pull_merged_at=saplidināta revīzija %[1]s atzarā %[2]s %[3]s issues.comment_manually_pull_merged_at=manuāli saplidināta revīzija %[1]s atzarā %[2]s %[3]s @@ -1433,8 +1496,16 @@ issues.ref_closed_from=`<a href="%[3]s">aizvēra problēmu %[4]s</a> <a id="%[1] issues.ref_reopened_from=`<a href="%[3]s">atkārtoti atvēra problēmu %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.ref_from=`no %[1]s` issues.author=Autors +issues.author_helper=Šis lietotājs ir autors. issues.role.owner=Īpašnieks -issues.role.member=Biedri +issues.role.owner_helper=Šis lietotājs ir šī repozitorija īpašnieks. +issues.role.member=Dalībnieks +issues.role.member_helper=Šis lietotājs ir organizācijas, kurai pieder šis repozitorijs, dalībnieks. +issues.role.collaborator=Līdzstrādnieks +issues.role.collaborator_helper=Šis lietotājs ir uzaicināts līdzdarboties repozitorijā. +issues.role.first_time_contributor=Pirmreizējs līdzradītājs +issues.role.first_time_contributor_helper=Šis ir pirmais šī lietotāja ieguldījums šājā repozitorijā. +issues.role.contributor=Līdzradītājs issues.role.contributor_helper=Šis lietotājs repozitorijā ir iepriekš veicis labojumus. issues.re_request_review=Pieprasīt atkārtotu recenziju issues.is_stale=Šajā izmaiņu pieprasījumā ir notikušas izmaiņās, kopš veicāt tā recenziju @@ -1450,6 +1521,9 @@ issues.label_title=Etiķetes nosaukums issues.label_description=Etiķetes apraksts issues.label_color=Etiķetes krāsa issues.label_exclusive=Ekskluzīvs +issues.label_archive=Arhīvēt etiķeti +issues.label_archived_filter=Rādīt arhivētās etiķetes +issues.label_archive_tooltip=Arhivētās etiķetes pēc noklusējuma netiek iekļautas ieteikumos, kad meklē pēc nosaukuma. issues.label_exclusive_desc=Nosauciet etiķeti <code>grupa/nosaukums</code>, lai grupētu etiķētes un varētu norādīt tās kā ekskluzīvas ar citām <code>grupa/</code> etiķetēm. issues.label_exclusive_warning=Jebkura konfliktējoša ekskluzīvas grupas etiķete tiks noņemta, labojot pieteikumu vai izmaiņu pietikumu etiķetes. issues.label_count=%d etiķetes @@ -1504,6 +1578,7 @@ issues.tracking_already_started=`Jau ir uzsākta laika uzskaite par <a href="%s" issues.stop_tracking=Apturēt taimeri issues.stop_tracking_history=` beidza strādāt %s` issues.cancel_tracking=Atmest +issues.cancel_tracking_history=`atcēla laika uzskaiti %s` issues.add_time=Manuāli pievienot laiku issues.del_time=Dzēst šo laika žurnāla ierakstu issues.add_time_short=Pievienot laiku @@ -1527,6 +1602,7 @@ issues.due_date_form=dd.mm.yyyy issues.due_date_form_add=Pievienot izpildes termiņu issues.due_date_form_edit=Labot issues.due_date_form_remove=Noņemt +issues.due_date_not_writer=Ir nepieciešama rakstīšanas piekļuve šim repozitorijam, lai varētu mainīt problēmas plānoto izpildes datumu. issues.due_date_not_set=Izpildes termiņš nav uzstādīts. issues.due_date_added=pievienoja izpildes termiņu %s %s issues.due_date_modified=mainīja termiņa datumu no %[2]s uz %[1]s %[3]s @@ -1582,6 +1658,9 @@ issues.review.pending.tooltip=Šis komentārs nav redzams citiem lietotājiem. L issues.review.review=Recenzija issues.review.reviewers=Recenzenti issues.review.outdated=Novecojis +issues.review.outdated_description=Saturs ir mainījies kopš šī komentāra pievienošanas +issues.review.option.show_outdated_comments=Rādīt novecojušus komentārus +issues.review.option.hide_outdated_comments=Paslēpt novecojušus komentārus issues.review.show_outdated=Rādīt novecojušu issues.review.hide_outdated=Paslēpt novecojušu issues.review.show_resolved=Rādīt atrisināto @@ -1622,9 +1701,11 @@ pulls.switch_head_and_base=Mainīt galvas un pamata atzarus pulls.filter_branch=Filtrēt atzarus pulls.no_results=Nekas netika atrasts. pulls.show_all_commits=Rādīt visas revīzijas +pulls.show_changes_since_your_last_review=Rādīt izmaiņas kopš Tavas pēdējās recenzijas pulls.showing_only_single_commit=Rāda tikai revīzijas %[1]s izmaiņas pulls.showing_specified_commit_range=Rāda tikai izmaiņas starp %[1]s..%[2]s pulls.select_commit_hold_shift_for_range=Atlasīt revīziju. Jātur Shift + klikšķis, lai atlasītu vairākas +pulls.review_only_possible_for_full_diff=Recenzēšana ir iespējama tikai tad, kad tiek apskatīts pilns salīdzinājums pulls.filter_changes_by_commit=Atlasīt pēc revīzijas pulls.nothing_to_compare=Nav ko salīdzināt, jo bāzes un salīdzināmie atzari ir vienādi. pulls.nothing_to_compare_and_allow_empty_pr=Šie atzari ir vienādi. Izveidotais izmaiņu pieprasījums būs tukšs. @@ -1657,6 +1738,12 @@ pulls.is_empty=Mērķa atzars jau satur šī atzara izmaiņas. Šī revīzija b pulls.required_status_check_failed=Dažas no pārbaudēm nebija veiksmīgas. pulls.required_status_check_missing=Trūkst dažu obligāto pārbaužu. pulls.required_status_check_administrator=Kā administrators Jūs varat sapludināt šo izmaiņu pieprasījumu. +pulls.blocked_by_approvals=Šim izmaiņu pieprasījumam vēl nav pietiekami daudz apstiprinājumu. Nodrošināti %d no %d apstiprinājumiem. +pulls.blocked_by_rejection=Šim izmaiņu pieprasījumam oficiālais recenzents ir pieprasījis labojumus. +pulls.blocked_by_official_review_requests=Šim izmaiņu pieprasījumam ir oficiāli recenzijas pieprasījumi. +pulls.blocked_by_outdated_branch=Šis izmaiņu pieprasījums ir bloķēts, jo tas ir novecojis. +pulls.blocked_by_changed_protected_files_1=Šis izmaiņu pieprasījums ir bloķēts, jo tas izmaina aizsargāto failu: +pulls.blocked_by_changed_protected_files_n=Šis izmaiņu pieprasījums ir bloķēts, jo tas izmaina aizsargātos failus: pulls.can_auto_merge_desc=Šo izmaiņu pieprasījumu var automātiski sapludināt. pulls.cannot_auto_merge_desc=Šis izmaiņu pieprasījums nevar tikt automātiski sapludināts konfliktu dēļ. pulls.cannot_auto_merge_helper=Sapludiniet manuāli, lai atrisinātu konfliktus. @@ -1691,6 +1778,7 @@ pulls.rebase_conflict_summary=Kļūdas paziņojums pulls.unrelated_histories=Sapludināšana neizdevās: mērķa un bāzes atzariem nav kopējas vēstures. Ieteikums: izvēlieties citu sapludināšanas stratēģiju pulls.merge_out_of_date=Sapludināšana neizdevās: sapludināšanas laikā, bāzes atzarā tika iesūtītas izmaiņas. Ieteikums: mēģiniet atkārtoti. pulls.head_out_of_date=Sapludināšana neizdevās: sapludināšanas laikā, bāzes atzarā tika iesūtītas izmaiņas. Ieteikums: mēģiniet atkārtoti. +pulls.has_merged=Neizdevās: izmaiņu pieprasījums jau ir sapludināts, nevar to darīt atkārtoti vai mainīt mērķa atzaru. pulls.push_rejected=Sapludināšana neizdevās: iesūtīšana tika noraidīta. Pārbaudiet git āķus šim repozitorijam. pulls.push_rejected_summary=Pilns noraidīšanas ziņojums pulls.push_rejected_no_message=Sapludināšana neizdevās: Izmaiņu iesūtīšana tika noraidīta, bet serveris neatgrieza paziņojumu.<br>Pārbaudiet git āķus šim repozitorijam @@ -1702,6 +1790,8 @@ pulls.status_checks_failure=Dažas pārbaudes neizdevās izpildīt pulls.status_checks_error=Dažu pārbaužu izpildes laikā, radās kļūdas pulls.status_checks_requested=Obligāts pulls.status_checks_details=Papildu informācija +pulls.status_checks_hide_all=Paslēpt visas pārbaudes +pulls.status_checks_show_all=Parādīt visas pārbaudes pulls.update_branch=Atjaunot atzaru, izmantojot, sapludināšanu pulls.update_branch_rebase=Atjaunot atzaru, izmantojot, pārbāzēšanu pulls.update_branch_success=Atzara atjaunināšana veiksmīgi pabeigta @@ -1710,6 +1800,11 @@ pulls.outdated_with_base_branch=Atzars ir novecojis salīdzinot ar bāzes atzaru pulls.close=Aizvērt izmaiņu pieprasījumu pulls.closed_at=`aizvēra šo izmaiņu pieprasījumu <a id="%[1]s" href="#%[1]s">%[2]s</a>` pulls.reopened_at=`atkārtoti atvēra šo izmaiņu pieprasījumu <a id="%[1]s" href="#%[1]s">%[2]s</a>` +pulls.cmd_instruction_hint=`Apskatīt <a class="show-instruction">komandrindas izmantošanas norādes</a>.` +pulls.cmd_instruction_checkout_title=Paņemt +pulls.cmd_instruction_checkout_desc=Projekta repozitorijā jāizveido jauns atzars un jāpārbauda izmaiņas. +pulls.cmd_instruction_merge_title=Sapludināt +pulls.cmd_instruction_merge_desc=Sapludināt izmaiņas un atjaunot tās Gitea. pulls.clear_merge_message=Notīrīt sapludināšanas ziņojumu pulls.clear_merge_message_hint=Notīrot sapludināšanas ziņojumu tiks noņemts tikai pats ziņojums, bet tiks paturēti ģenerētie git ziņojumu, kā "Co-Authored-By …". @@ -1728,6 +1823,7 @@ pulls.auto_merge_canceled_schedule_comment=`atcēla automātisko sapludināšanu pulls.delete.title=Dzēst šo izmaiņu pieprasījumu? pulls.delete.text=Vai patiešām vēlaties dzēst šo izmaiņu pieprasījumu? (Neatgriezeniski tiks izdzēsts viss saturs. Apsveriet iespēju to aizvērt, ja vēlaties informāciju saglabāt vēsturei) +pulls.recently_pushed_new_branches=Tu iesūtīji izmaiņas atzarā <strong>%[1]s</strong> %[2]s pull.deleted_branch=(izdzēsts):%s @@ -1737,6 +1833,7 @@ milestones.update_ago=Atjaunots %s milestones.no_due_date=Bez termiņa milestones.open=Atvērta milestones.close=Aizvērt +milestones.new_subheader=Atskaites punkti var palīdzēt pārvaldīt problēmas un sekot to virzībai. milestones.completeness=%d%% pabeigti milestones.create=Izveidot atskaites punktu milestones.title=Virsraksts @@ -1753,6 +1850,8 @@ milestones.edit_success=Izmaiņas atskaites punktā "%s" tika veiksmīgi saglab milestones.deletion=Dzēst atskaites punktu milestones.deletion_desc=Dzēšot šo atskaites punktu, tas tiks noņemts no visām saistītajām problēmām un izmaiņu pieprasījumiem. Vai turpināt? milestones.deletion_success=Atskaites punkts tika veiksmīgi izdzēsts. +milestones.filter_sort.earliest_due_data=Agrākais izpildes laiks +milestones.filter_sort.latest_due_date=Vēlākais izpildes laiks milestones.filter_sort.least_complete=Vismazāk pabeigtais milestones.filter_sort.most_complete=Visvairāk pabeigtais milestones.filter_sort.most_issues=Visvairāk problēmu @@ -1769,6 +1868,7 @@ signing.wont_sign.parentsigned=Revīzija netiks parakstīta, jo nav parakstīta signing.wont_sign.basesigned=Sapludināšanas revīzija netiks parakstīta, jo pamata revīzija nav parakstīta. signing.wont_sign.headsigned=Sapludināšanas revīzija netiks parakstīta, jo galvenā revīzija nav parakstīta. signing.wont_sign.commitssigned=Sapludināšana netiks parakstīta, jo visas saistītās revīzijas nav parakstītas. +signing.wont_sign.approved=Sapludināšana netiks parakstīta, jo izmaiņu pieprasījums nav apstiprināts. signing.wont_sign.not_signed_in=Jūs neesat pieteicies. ext_wiki=Piekļuve ārējai vikivietnei @@ -1899,6 +1999,7 @@ settings.mirror_settings.docs.disabled_push_mirror.info=Iesūtīšanas spoguļus settings.mirror_settings.docs.no_new_mirrors=Šis repozitorijs spoguļo izmaiņas uz vai no cita repozitorija. Pašlaik vairāk nav iespējams izveidot jaunus spoguļa repozitorijus. settings.mirror_settings.docs.can_still_use=Lai arī nav iespējams mainīt esošos vai izveidot jaunus spoguļa repozitorijus, esošie turpinās strādāt. settings.mirror_settings.docs.pull_mirror_instructions=Lai ietatītu atvilkšanas spoguli, sekojiet instrukcijām: +settings.mirror_settings.docs.more_information_if_disabled=Vairāk par piegādāšanas un saņemšanas spoguļiem var uzzināt šeit: settings.mirror_settings.docs.doc_link_title=Kā spoguļot repozitorijus? settings.mirror_settings.docs.doc_link_pull_section=dokumentācijas nodaļā "Pulling from a remote repository". settings.mirror_settings.docs.pulling_remote_title=Atvilkt no attāla repozitorija @@ -1910,8 +2011,11 @@ settings.mirror_settings.last_update=Pēdējās izmaiņas settings.mirror_settings.push_mirror.none=Nav konfigurēts iesūtīšanas spogulis settings.mirror_settings.push_mirror.remote_url=Git attālinātā repozitorija URL settings.mirror_settings.push_mirror.add=Pievienot iesūtīšanas spoguli +settings.mirror_settings.push_mirror.edit_sync_time=Labot spoguļa sinhronizācijas intervālu settings.sync_mirror=Sinhronizēt tagad +settings.pull_mirror_sync_in_progress=Pašlaik tiek saņemtas izmaiņas no attālā %s. +settings.push_mirror_sync_in_progress=Pašlaik tiek piegādātas izmaiņas uz attālo %s. settings.site=Mājas lapa settings.update_settings=Mainīt iestatījumus settings.update_mirror_settings=Atjaunot spoguļa iestatījumus @@ -1978,6 +2082,7 @@ settings.transfer.rejected=Repozitorija īpašnieka maiņas pieprasījums tika n settings.transfer.success=Repozitorija īpašnieka maiņa veiksmīga. settings.transfer_abort=Atcelt īpašnieka maiņu settings.transfer_abort_invalid=Nevar atcelt neeksistējoša repozitorija īpašnieka maiņu. +settings.transfer_abort_success=Repozitorija īpašnieka maiņa uz %s tika veiksmīgi atcelta. settings.transfer_desc=Mainīt šī repozitorija īpašnieku uz citu lietotāju vai organizāciju, kurai Jums ir administratora tiesības. settings.transfer_form_title=Ievadiet repozitorija nosaukumu, lai apstiprinātu: settings.transfer_in_progress=Pašlaik jau tiek veikta repozitorija īpašnieka maiņa. Atceliet iepriekšējo īpašnieka maiņu, ja vēlaties mainīt uz citu. @@ -2002,12 +2107,12 @@ settings.trust_model.collaboratorcommitter=Līdzstrādnieka un revīzijas iesūt settings.trust_model.collaboratorcommitter.long=Līdzstrādnieka un revīzijas iesūtītāja: Uzticēties līdzstrādnieku parakstiem, kas atbilst revīzijas iesūtītājam settings.trust_model.collaboratorcommitter.desc=Derīgi līdzstrādnieku paraksti tiks atzīmēti kā "uzticami", ja tie atbilst revīzijas iesūtītājam, citos gadījumos tie tiks atzīmēti kā "neuzticami", ja paraksts atbilst revīzijas iesūtītajam, vai "nesakrītoši", ja neatbilst. Šis nozīmē, ka Forgejo būs kā revīzijas iesūtītājs parakstītām revīzijām, kur īstais revīzijas iesūtītājs tiks atīzmēts revīzijas komentāra beigās ar tekstu Co-Authored-By: un Co-Committed-By:. Noklusētajai Forgejo atslēgai ir jāatbilst lietotājam datubāzē. settings.wiki_delete=Dzēst vikivietnes datus -settings.wiki_delete_desc=Vikivietnes repozitorija dzēšana ir <strong>NEATGRIEZENISKA</strong>. Vai turpināt? +settings.wiki_delete_desc=Vikivietnes repozitorija dzēšana ir neatgriezeniska un nav atsaucama. settings.wiki_delete_notices_1=- Šī darbība dzēsīs un atspējos repozitorija %s vikivietni. settings.confirm_wiki_delete=Dzēst vikivietnes datus settings.wiki_deletion_success=Repozitorija vikivietnes dati tika izdzēsti. settings.delete=Dzēst šo repozitoriju -settings.delete_desc=Repozitorija dzēšana ir <strong>NEATGRIEZENISKA</strong>. Vai turpināt? +settings.delete_desc=Repozitorija dzēšana ir neatgriezeniska un nav atsaucama. settings.delete_notices_1=- Šī darbība ir <strong>NEATGRIEZENISKA</strong>. settings.delete_notices_2=- Šī darbība neatgriezeniski izdzēsīs visu repozitorijā <strong>%s</strong>, tai skaitā problēmas, komentārus, vikivietni un līdzstrādnieku piesaisti. settings.delete_notices_fork_1=- Visi atdalītie repozitoriju pēc dzēšanas kļūs neatkarīgi. @@ -2044,12 +2149,14 @@ settings.webhook_deletion_desc=Noņemot tīmekļa āķi, tiks dzēsti visi tā i settings.webhook_deletion_success=Tīmekļa āķis tika noņemts. settings.webhook.test_delivery=Testa piegāde settings.webhook.test_delivery_desc=Veikt viltus push-notikuma piegādi, lai notestētu Jūsu tīmekļa āķa iestatījumus. +settings.webhook.test_delivery_desc_disabled=Lai pārbaudītu šo tīmekļa āķi ar neīstu notikumu, tas ir jāiespējo. settings.webhook.request=Pieprasījums settings.webhook.response=Atbilde settings.webhook.headers=Galvenes settings.webhook.payload=Saturs settings.webhook.body=Saturs settings.webhook.replay.description=Izpildīt atkārtoti šo tīmekļa āķi. +settings.webhook.replay.description_disabled=Lai atkārtoti izpildītu šo tīmekļa āķi, tas ir jāiespējo. settings.webhook.delivery.success=Notikums tika veiksmīgi pievienots piegādes rindai. Var paiet vairākas sekundes līdz tas parādās piegādes vēsturē. settings.githooks_desc=Git āķus apstrādā pats Git. Jūs varat labot atbalstīto āku failus sarakstā zemāk, lai veiktu pielāgotas darbības. settings.githook_edit_desc=Ja āķis nav aktīvs, tiks attēlots piemērs kā to izmantot. Atstājot āķa saturu tukšu, tas tiks atspējots. @@ -2250,16 +2357,23 @@ settings.tags.protection.none=Nav uzstādīta tagu aizsargāšana. settings.tags.protection.pattern.description=Var izmantot vienkāršu nosaukumu vai glob šablonu, vai regulāro izteiksmi, lai atbilstu vairākiem tagiem. Vairāk ir lasāms <a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/protected-tags">aizsargāto tagu šablonu dokumentācijā</a>. settings.bot_token=Bota pilnvara settings.chat_id=Tērzēšanas ID +settings.thread_id=Pavediena ID settings.matrix.homeserver_url=Mājas servera URL settings.matrix.room_id=Istabas ID settings.matrix.message_type=Ziņas veids settings.archive.button=Arhivēt settings.archive.header=Arhivēt repozitoriju +settings.archive.text=Repozitorija arhivēšana padarīs to tikai lasāmu. Tas nebūs redzams infopanelī. Neviens nevarēs izveidot jaunas revīzijas vai atvērt jaunus problēmu pieteikumus vai izmaiņu pieprasījumus. settings.archive.success=Repozitorijs veiksmīgi arhivēts. settings.archive.error=Arhivējot repozitoriju radās neparedzēta kļūda. Pārbaudiet kļūdu žurnālu, lai uzzinātu sīkāk. settings.archive.error_ismirror=Nav iespējams arhivēt spoguļotus repozitorijus. settings.archive.branchsettings_unavailable=Atzaru iestatījumi nav pieejami, ja repozitorijs ir arhivēts. settings.archive.tagsettings_unavailable=Tagu iestatījumi nav pieejami, ja repozitorijs ir arhivēts. +settings.unarchive.button=Atcelt repozitorija arhivēšanu +settings.unarchive.header=Atcelt šī repozitorija arhivēšanu +settings.unarchive.text=Repozitorija arhivēšanas atcelšana atjaunos tā spēju saņemt izmaiņas, kā arī jaunus problēmu pieteikumus un izmaiņu pieprasījumus. +settings.unarchive.success=Repozitorijam veiksmīgi atcelta arhivācija. +settings.unarchive.error=Repozitorija arhivēšanas atcelšanas laikā atgadījās kļūda. Vairāk ir redzams žurnālā. settings.update_avatar_success=Repozitorija attēls tika atjaunināts. settings.lfs=LFS settings.lfs_filelist=LFS faili, kas saglabāti šajā repozitorijā @@ -2326,6 +2440,7 @@ diff.show_more=Rādīt vairāk diff.load=Ielādēt izmaiņas diff.generated=ģenerēts diff.vendored=ārējs +diff.comment.add_line_comment=Pievienot rindas komentāru diff.comment.placeholder=Ievadiet komentāru diff.comment.markdown_info=Tiek atbalstīta formatēšana ar Markdown. diff.comment.add_single_comment=Pievienot vienu komentāru @@ -2382,6 +2497,7 @@ release.edit_release=Labot laidienu release.delete_release=Dzēst laidienu release.delete_tag=Dzēst tagu release.deletion=Dzēst laidienu +release.deletion_desc=Laidiena izdzēšana tikai noņem to no Gitea. Tā neietekmēs Git tagu, repozitorija saturu vai vēsturi. Vai turpināt? release.deletion_success=Laidiens tika izdzēsts. release.deletion_tag_desc=Tiks izdzēsts tags no repozitorija. Repozitorija saturs un vēsture netiks mainīta. Vai turpināt? release.deletion_tag_success=Tags tika izdzēsts. @@ -2401,6 +2517,7 @@ branch.already_exists=Atzars ar nosaukumu "%s" jau eksistē. branch.delete_head=Dzēst branch.delete=`Dzēst atzaru "%s"` branch.delete_html=Dzēst atzaru +branch.delete_desc=Atzara dzēšana ir neatgriezeniska. Kaut arī izdzēstais zars neilgu laiku var turpināt pastāvēt, pirms tas tiešām tiek noņemts, to vairumā gadījumu NEVAR atsaukt. Vai turpināt? branch.deletion_success=Atzars "%s" tika izdzēsts. branch.deletion_failed=Neizdevās izdzēst atzaru "%s". branch.delete_branch_has_new_commits=Atzars "%s" nevar tik dzēsts, jo pēc sapludināšanas, tam ir pievienotas jaunas revīzijas. @@ -2441,6 +2558,7 @@ tag.create_success=Tags "%s" tika izveidots. topic.manage_topics=Pārvaldīt tēmas topic.done=Gatavs topic.count_prompt=Nevar pievienot vairāk kā 25 tēmas +topic.format_prompt=Tēmai jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un punktus ('.') un var būt līdz 35 rakstzīmēm gara. Burtiem jābūt mazajiem. find_file.go_to_file=Iet uz failu find_file.no_matching=Atbilstošs fails netika atrasts @@ -2479,6 +2597,7 @@ form.create_org_not_allowed=Jums nav tiesību veidot jauno organizāciju. settings=Iestatījumi settings.options=Organizācija settings.full_name=Pilns vārds, uzvārds +settings.email=E-pasta adrese saziņai settings.website=Mājas lapa settings.location=Atrašanās vieta settings.permission=Tiesības @@ -2492,6 +2611,7 @@ settings.visibility.private_shortname=Privāta settings.update_settings=Mainīt iestatījumus settings.update_setting_success=Organizācijas iestatījumi tika saglabāti. +settings.change_orgname_prompt=Piezīme: organizācijas nosaukuma maiņa izmainīs arī organizācijas URL un atbrīvos veco nosaukumu. settings.change_orgname_redirect_prompt=Vecais vārds pārsūtīs uz jauno, kamēr vien tas nebūs izmantots. settings.update_avatar_success=Organizācijas attēls tika saglabāts. settings.delete=Dzēst organizāciju @@ -2511,7 +2631,7 @@ members.private=Slēpts members.private_helper=padarīt redzemu members.member_role=Dalībnieka loma: members.owner=Īpašnieks -members.member=Biedri +members.member=Dalībnieks members.remove=Noņemt members.remove.detail=Noņemt lietotāju %[1]s no organizācijas %[2]s? members.leave=Atstāt @@ -2567,15 +2687,19 @@ teams.all_repositories_helper=Šai komandai ir piekļuve visiem repozitorijiem. teams.all_repositories_read_permission_desc=Šī komanda piešķirt <strong>skatīšanās</strong> tiesības <strong>visiem repozitorijiem</strong>: komandas biedri var skatīties un klonēt visus organizācijas repozitorijus. teams.all_repositories_write_permission_desc=Šī komanda piešķirt <strong>labošanas</strong> tiesības <strong>visiem repozitorijiem</strong>: komandas biedri var skatīties un nosūtīt izmaiņas visiem organizācijas repozitorijiem. teams.all_repositories_admin_permission_desc=Šī komanda piešķirt <strong>administratora</strong> tiesības <strong>visiem repozitorijiem</strong>: komandas biedri var skatīties, nosūtīt izmaiņas un mainīt iestatījumus visiem organizācijas repozitorijiem. +teams.invite.title=Tu esi uzaicināts pievienoties organizācijas <strong>%[2]s</strong> komandai <strong>%[1]s</strong>. teams.invite.by=Uzaicināja %s teams.invite.description=Nospiediet pogu zemāk, lai pievienotos komandai. [admin] dashboard=Infopanelis +identity_access=Identitāte un piekļuve users=Lietotāju konti organizations=Organizācijas +assets=Koda aktīvi repositories=Repozitoriji hooks=Tīmekļa āķi +integrations=Integrācijas authentication=Autentificēšanas avoti emails=Lietotāja e-pasts config=Konfigurācija @@ -2584,6 +2708,7 @@ monitor=Uzraudzība first_page=Pirmā last_page=Pēdējā total=Kopā: %d +settings=Administratora iestatījumi dashboard.new_version_hint=Ir pieejama Forgejo versija %s, pašreizējā versija %s. Papildus informācija par jauno versiju ir pieejama <a target="_blank" rel="noreferrer" href="https://forgejo.org/news">mājas lapā</a>. dashboard.statistic=Kopsavilkums @@ -2596,11 +2721,13 @@ dashboard.clean_unbind_oauth=Notīrīt nepiesaistītos OAuth savienojumus dashboard.clean_unbind_oauth_success=Visi nepiesaistītie OAuth savienojumu tika izdzēsti. dashboard.task.started=Uzsākts uzdevums: %[1]s dashboard.task.process=Uzdevums: %[1]s +dashboard.task.cancelled=Uzdevums: %[1]s atcelts: %[3]s dashboard.task.error=Kļūda uzdevuma izpildē: %[1]s: %[3]s dashboard.task.finished=Uzdevums: %[1]s, ko iniciēja %[2]s ir izpildīts dashboard.task.unknown=Nezināms uzdevums: %[1]s dashboard.cron.started=Uzsākts Cron: %[1]s dashboard.cron.process=Cron: %[1]s +dashboard.cron.cancelled=Cron: %[1]s atcelts: %[3]s dashboard.cron.error=Kļūda Cron: %s: %[3]s dashboard.cron.finished=Cron: %[1]s pabeigts dashboard.delete_inactive_accounts=Dzēst visus neaktivizētos kontus @@ -2610,6 +2737,7 @@ dashboard.delete_repo_archives.started=Uzdevums visu repozitoriju arhīvu dzēš dashboard.delete_missing_repos=Dzēst visus repozitorijus, kam trūkst Git failu dashboard.delete_missing_repos.started=Uzdevums visu repozitoriju dzēšanai, kam trūkst git failu, uzsākts. dashboard.delete_generated_repository_avatars=Dzēst ģenerētos repozitoriju attēlus +dashboard.sync_repo_branches=Sinhronizācija ar dabubāzi izlaida atzarus no git datiem dashboard.update_mirrors=Atjaunot spoguļus dashboard.repo_health_check=Pārbaudīt visu repozitoriju veselību dashboard.check_repo_stats=Pārbaudīt visu repozitoriju statistiku @@ -2624,6 +2752,7 @@ dashboard.reinit_missing_repos=Atkārtoti inicializēt visus pazaudētos Git rep dashboard.sync_external_users=Sinhronizēt ārējo lietotāju datus dashboard.cleanup_hook_task_table=Iztīrīt tīmekļa āķu vēsturi dashboard.cleanup_packages=Notīrīt novecojušās pakotnes +dashboard.cleanup_actions=Notīrīt darbību izbeigušos žurnālus un artefaktus dashboard.server_uptime=Servera darbības laiks dashboard.current_goroutine=Izmantotās Gorutīnas dashboard.current_memory_usage=Pašreiz izmantotā atmiņa @@ -2661,7 +2790,9 @@ dashboard.gc_lfs=Veikt atkritumu uzkopšanas darbus LFS meta objektiem dashboard.stop_zombie_tasks=Apturēt zombija uzdevumus dashboard.stop_endless_tasks=Apturēt nepārtrauktus uzdevumus dashboard.cancel_abandoned_jobs=Atcelt pamestus darbus +dashboard.start_schedule_tasks=Sākt plānotos uzdevumus dashboard.sync_branch.started=Sākta atzaru sinhronizācija +dashboard.rebuild_issue_indexer=Pārbūvēt problēmu indeksu users.user_manage_panel=Lietotāju kontu pārvaldība users.new_account=Izveidot lietotāja kontu @@ -2670,6 +2801,9 @@ users.full_name=Vārds, uzvārds users.activated=Aktivizēts users.admin=Administrators users.restricted=Ierobežots +users.reserved=Aizņemts +users.bot=Bots +users.remote=Attāls users.2fa=2FA users.repos=Repozitoriji users.created=Izveidots @@ -2716,6 +2850,7 @@ users.list_status_filter.is_prohibit_login=Nav atļauta autorizēšanās users.list_status_filter.not_prohibit_login=Atļaut autorizāciju users.list_status_filter.is_2fa_enabled=2FA iespējots users.list_status_filter.not_2fa_enabled=2FA nav iespējots +users.details=Lietotāja informācija emails.email_manage_panel=Lietotāju e-pastu pārvaldība emails.primary=Primārais @@ -2728,6 +2863,7 @@ emails.updated=E-pasts atjaunots emails.not_updated=Neizdevās atjaunot pieprasīto e-pasta adresi: %v emails.duplicate_active=E-pasta adrese jau ir aktīva citam lietotājam. emails.change_email_header=Atjaunot e-pasta rekvizītus +emails.change_email_text=Vai patiešām vēlaties atjaunot šo e-pasta adresi? orgs.org_manage_panel=Organizāciju pārvaldība orgs.name=Nosaukums @@ -2742,14 +2878,17 @@ repos.owner=Īpašnieks repos.name=Nosaukums repos.private=Privāts repos.watches=Vērošana -repos.stars=Atzīmētās zvaigznītes +repos.stars=Zvaigznes repos.forks=Atdalītie repos.issues=Problēmas repos.size=Izmērs +repos.lfs_size=LFS izmērs packages.package_manage_panel=Pakotņu pārvaldība packages.total_size=Kopējais izmērs: %s packages.unreferenced_size=Izmērs bez atsauces: %s +packages.cleanup=Notīrīt novecojušos datus +packages.cleanup.success=Novecojuši dati veiksmīgi notīrīti packages.owner=Īpašnieks packages.creator=Izveidotājs packages.name=Nosaukums @@ -2760,10 +2899,12 @@ packages.size=Izmērs packages.published=Publicēts defaulthooks=Noklusētie tīmekļa āķi +defaulthooks.desc=Tīmekļa āķi automātiski nosūta HTTP POST pieprasījumus serverim, kad iestājas noteikti Gitea notikumi. Šeit pievienotie tīmekļa āķi ir noklusējuma, un tie tiks pievienoti visiem jaunajiem repozitorijiem. Vairāk ir lasāms <a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/webhooks">tīmekļa āķu dokumentācijā</a>. defaulthooks.add_webhook=Pievienot noklusēto tīmekļa āķi defaulthooks.update_webhook=Mainīt noklusēto tīmekļa āķi systemhooks=Sistēmas tīmekļa āķi +systemhooks.desc=Tīmekļa āķi automātiski nosūta HTTP POST pieprasījumus serverim, kad iestājas noteikti Gitea notikumi. Šeit pievienotie tīmekļa āķi tiks izsaukti visiem sistēmas repozitorijiem, tādēļ lūgums apsvērt to iespējamo ietekmi uz veiktspēju. Vairāk ir lasāms <a target="_blank" rel="noopener" href="https://docs.gitea.com/usage/webhooks">tīmekļa āķu dokumentācijā</a>. systemhooks.add_webhook=Pievienot sistēmas tīmekļa āķi systemhooks.update_webhook=Mainīt sistēmas tīmekļa āķi @@ -2856,6 +2997,7 @@ auths.sspi_default_language=Noklusētā lietotāja valoda auths.sspi_default_language_helper=Noklusētā valoda, ko uzstādīt automātiski izveidotajiem lietotājiem, kas izmanto SSPI autentifikācijas veidu. Atstājiet tukšu, ja vēlaties, lai valoda tiktu noteikta automātiski. auths.tips=Padomi auths.tips.oauth2.general=OAuth2 autentifikācija +auths.tips.oauth2.general.tip=Kad tiek reģistrēta jauna OAuth2 autentifikācija, atzvanīšanas/pārvirzīšanas URL vajadzētu būt: auths.tip.oauth2_provider=OAuth2 pakalpojuma sniedzējs auths.tip.bitbucket=Reģistrējiet jaunu OAuth klientu adresē https://bitbucket.org/account/user/<jūsu lietotājvārds>/oauth-consumers/new un piešķiriet tam "Account" - "Read" tiesības auths.tip.nextcloud=`Reģistrējiet jaunu OAuth klientu jūsu instances sadāļā "Settings -> Security -> OAuth 2.0 client"` @@ -2867,6 +3009,7 @@ auths.tip.google_plus=Iegūstiet OAuth2 klienta pilnvaru no Google API konsoles auths.tip.openid_connect=Izmantojiet OpenID pieslēgšanās atklāšanas URL (<serveris>/.well-known/openid-configuration), lai norādītu galapunktus auths.tip.twitter=Dodieties uz adresi https://dev.twitter.com/apps, izveidojiet lietotni un pārliecinieties, ka ir atzīmēts “Allow this application to be used to Sign in with Twitter” auths.tip.discord=Reģistrējiet jaunu aplikāciju adresē https://discordapp.com/developers/applications/me +auths.tip.gitea=Pievienot jaunu OAuth2 lietojumprogrammu. Dokumentācija ir pieejama https://docs.gitea.com/development/oauth2-provider auths.tip.yandex=`Izveidojiet jaunu lietotni adresē https://oauth.yandex.com/client/new. Izvēlieties sekojošas tiesības "Yandex.Passport API" sadaļā: "Access to email address", "Access to user avatar" un "Access to username, first name and surname, gender"` auths.tip.mastodon=Norādiet pielāgotu mastodon instances URL, ar kuru vēlaties autorizēties (vai izmantojiet noklusēto) auths.edit=Labot autentifikācijas avotu @@ -2896,6 +3039,7 @@ config.disable_router_log=Atspējot maršrutētāja žurnalizēšanu config.run_user=Izpildes lietotājs config.run_mode=Izpildes režīms config.git_version=Git versija +config.app_data_path=Lietotnes datu ceļš config.repo_root_path=Repozitoriju glabāšanas vieta config.lfs_root_path=LFS saknes ceļš config.log_file_root_path=Žurnalizēšanas ceļš @@ -3045,8 +3189,10 @@ monitor.queue.name=Nosaukums monitor.queue.type=Veids monitor.queue.exemplar=Eksemplāra veids monitor.queue.numberworkers=Strādņu skaits +monitor.queue.activeworkers=Darbojošies strādņi monitor.queue.maxnumberworkers=Maksimālais strādņu skaits monitor.queue.numberinqueue=Skaits rindā +monitor.queue.review_add=Pārskatīt/pievienot strādņus monitor.queue.settings.title=Pūla iestatījumi monitor.queue.settings.desc=Pūls dinamiski tiek palielināts atkarībā no bloķētiem darbiem rindā. monitor.queue.settings.maxnumberworkers=Maksimālais strādņu skaits @@ -3102,7 +3248,7 @@ publish_release=`izveidoja versiju <a href="%[2]s"> "%[4]s" </a> repozitorijā < review_dismissed=`noraidīja lietotāja <b>%[4]s</b> recenziju izmaiņu pieprasījumam <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason=Iemesls: create_branch=izveidoja atzaru <a href="%[2]s">%[3]s</a> repozitorijā <a href="%[1]s">%[4]s</a> -starred_repo=atzīmēja ar zvaigznīti <a href="%[1]s">%[2]s</a> +starred_repo=pievienoja izlasē <a href="%[1]s">%[2]s</a> watched_repo=sāka sekot <a href="%[1]s">%[2]s</a> [tool] @@ -3167,6 +3313,7 @@ desc=Pārvaldīt repozitorija pakotnes. empty=Pašlaik šeit nav nevienas pakotnes. empty.documentation=Papildus informācija par pakotņu reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="%s">dokumentācijā</a>. empty.repo=Neparādās augšupielādēta pakotne? Apmeklējiet <a href="%[1]s">pakotņu iestatījumus</a>, lai sasaistītu ar repozitoriju. +registry.documentation=Vairāk informācija par %s reģistru ir pieejama <a target="_blank" rel="noopener noreferrer" href="%s">dokumentācijā</a>. filter.type=Veids filter.type.all=Visas filter.no_result=Pēc norādītajiem kritērijiem nekas netika atrasts. @@ -3252,6 +3399,8 @@ pub.install=Lai instalētu Dart pakotni, izpildiet sekojošu komandu: pypi.requires=Nepieciešams Python pypi.install=Lai instalētu pip pakotni, izpildiet sekojošu komandu: rpm.registry=Konfigurējiet šo reģistru no komandrindas: +rpm.distros.redhat=uz RedHat balstītās operētājsistēmās +rpm.distros.suse=uz SUSE balstītās operētājsistēmās rpm.install=Lai uzstādītu pakotni, ir jāizpilda šī komanda: rubygems.install=Lai instalētu gem pakotni, izpildiet sekojošu komandu: rubygems.install2=vai pievienojiet Gemfile: @@ -3276,14 +3425,17 @@ settings.delete.success=Pakotne tika izdzēsta. settings.delete.error=Neizdevās izdzēst pakotni. owner.settings.cargo.title=Cargo reģistra inkdess owner.settings.cargo.initialize=Inicializēt indeksu +owner.settings.cargo.initialize.description=Ir nepieciešams īpašs indeksa Git repozitorijs, lai izmantotu Cargo reģistru. Šīs iespējas izmantošana (atkārtoti) izveidos repozitoriju un automātiski to iestatīs. owner.settings.cargo.initialize.error=Neizdevās inicializēt Cargo indeksu: %v owner.settings.cargo.initialize.success=Cargo indekss tika veiksmīgi inicializēts. owner.settings.cargo.rebuild=Pārbūvēt indeksu +owner.settings.cargo.rebuild.description=Pārbūvēšana var būt noderīga, ja indekss nav sinhronizēts ar saglabātajām Cargo pakotnēm. owner.settings.cargo.rebuild.error=Neizdevās pārbūvēt Cargo indeksu: %v owner.settings.cargo.rebuild.success=Cargo indekss tika veiksmīgi pārbūvēts. owner.settings.cleanuprules.title=Pārvaldīt notīrīšanas noteikumus owner.settings.cleanuprules.add=Pievienot notīrīšanas noteikumu owner.settings.cleanuprules.edit=Labot notīrīšanas noteikumu +owner.settings.cleanuprules.none=Nav pievienoti tīrīšanas noteikumi. Sīkāku informāciju iespējams iegūt dokumentācijā. owner.settings.cleanuprules.preview=Notīrīšānas noteikuma priekšskatījums owner.settings.cleanuprules.preview.overview=Ir ieplānota %d paku dzēšana. owner.settings.cleanuprules.preview.none=Notīrīšanas noteikumam neatbilst neviena pakotne. @@ -3302,6 +3454,7 @@ owner.settings.cleanuprules.success.update=Notīrīšanas noteikumi tika atjauno owner.settings.cleanuprules.success.delete=Notīrīšanas noteikumi tika izdzēsti. owner.settings.chef.title=Chef reģistrs owner.settings.chef.keypair=Ģenerēt atslēgu pāri +owner.settings.chef.keypair.description=Atslēgu pāris ir nepieciešams, lai autentificētos Chef reģistrā. Ja iepriekš ir izveidots atslēgu pāris, jauna pāra izveidošana veco atslēgu pāri padarīs nederīgu. [secrets] secrets=Noslēpumi @@ -3328,6 +3481,7 @@ status.waiting=Gaida status.running=Izpildās status.success=Pabeigts status.failure=Neveiksmīgs +status.cancelled=Atcelts status.skipped=Izlaists status.blocked=Bloķēts @@ -3340,11 +3494,12 @@ runners.id=ID runners.name=Nosaukums runners.owner_type=Veids runners.description=Apraksts -runners.labels=Etiķetes +runners.labels=Iezīmes runners.last_online=Pēdējo reizi tiešsaistē runners.runner_title=Izpildītājs runners.task_list=Pēdējās darbības, kas izpildītas -runners.task_list.run=Palaist +runners.task_list.no_tasks=Vēl nav uzdevumu. +runners.task_list.run=Izpildīt runners.task_list.status=Statuss runners.task_list.repository=Repozitorijs runners.task_list.commit=Revīzija @@ -3364,18 +3519,49 @@ runners.status.idle=Dīkstāvē runners.status.active=Aktīvs runners.status.offline=Bezsaistē runners.version=Versija +runners.reset_registration_token=Atiestatīt reģistrācijas pilnvaru runners.reset_registration_token_success=Izpildītāja reģistrācijas pilnvara tika veiksmīgi atiestatīta runs.all_workflows=Visas darbaplūsmas runs.commit=Revīzija +runs.scheduled=Ieplānots +runs.pushed_by=iesūtīja runs.invalid_workflow_helper=Darbaplūsmas konfigurācijas fails ir kļūdains. Pārbaudiet konfiugrācijas failu: %s +runs.no_matching_online_runner_helper=Nav pieejami izpildītāji, kas atbilstu šai iezīmei: %s +runs.actor=Aktors runs.status=Statuss +runs.actors_no_select=Visi aktori +runs.status_no_select=Visi stāvokļi +runs.no_results=Netika atrasts nekas atbilstošs. +runs.no_workflows=Vēl nav nevienas darbplūsmas. +runs.no_workflows.quick_start=Nav skaidrs, kā sākt izmantot Gitea darbības? Skatīt <a target="_blank" rel="noopener noreferrer" href="%s">ātrās sākšanas norādes</a>. +runs.no_workflows.documentation=Vairāk informācijas par Gitea darbībām ir skatāma <a target="_blank" rel="noopener noreferrer" href="%s">dokumentācijā</a>. +runs.no_runs=Darbplūsmai vēl nav nevienas izpildes. runs.empty_commit_message=(tukšs revīzijas ziņojums) +workflow.disable=Atspējot darbplūsmu +workflow.disable_success=Darbplūsma '%s' ir veiksmīgi atspējota. +workflow.enable=Iespējot darbplūsmu +workflow.enable_success=Darbplūsma '%s' ir veiksmīgi iespējota. +workflow.disabled=Darbplūsma ir atspējota. need_approval_desc=Nepieciešams apstiprinājums, lai izpildītu izmaiņu pieprasījumu darbaplūsmas no atdalītiem repozitorijiem. +variables=Mainīgie +variables.management=Mainīgo pārvaldība +variables.creation=Pievienot mainīgo +variables.none=Vēl nav neviena mainīgā. +variables.deletion=Noņemt mainīgo +variables.deletion.description=Mainīgā noņemšana ir neatgriezeniska un nav atsaucama. Vai turpināt? +variables.description=Mainīgie tiks padoti noteiktām darbībām, un citādāk tos nevar nolasīt. variables.id_not_exist=Mainīgais ar identifikatoru %d neeksistē. +variables.edit=Labot mainīgo +variables.deletion.failed=Neizdevās noņemt mainīgo. +variables.deletion.success=Mainīgais tika noņemts. +variables.creation.failed=Neizdevās pievienot mainīgo. +variables.creation.success=Mainīgais "%s" tika pievienots. +variables.update.failed=Neizdevās labot mainīgo. +variables.update.success=Mainīgais tika labots. [projects] type-1.display_name=Individuālais projekts @@ -3383,6 +3569,11 @@ type-2.display_name=Repozitorija projekts type-3.display_name=Organizācijas projekts [git.filemode] +changed_filemode=%[1]s → %[2]s ; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", … +directory=Direktorija +normal_file=Parasts fails +executable_file=Izpildāmais fails symbolic_link=Simboliska saite +submodule=Apakšmodulis From f803c5c0f41d74bd30c1543c31a4b144adb8f1ae Mon Sep 17 00:00:00 2001 From: DC <106393991+DanielMatiasCarvalho@users.noreply.github.com> Date: Wed, 21 Feb 2024 01:55:26 +0000 Subject: [PATCH 10/64] Update Discord logo (#29285) Fixes #27057 by changing the discord .svg file and running `make svg`. Before: <img width="637" src="https://private-user-images.githubusercontent.com/85847352/267667100-1eaf5d20-b4e9-4736-bb55-7f1da04bbde7.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MDg0NzAwNDUsIm5iZiI6MTcwODQ2OTc0NSwicGF0aCI6Ii84NTg0NzM1Mi8yNjc2NjcxMDAtMWVhZjVkMjAtYjRlOS00NzM2LWJiNTUtN2YxZGEwNGJiZGU3LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDAyMjAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwMjIwVDIyNTU0NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTIwN2Y2ODc5N2MzZDU5NzgzODRhNDIzZWY3MDk3ODhiYmIzZDU4NWVlYmFmZjc2OTIyZjE3MWM4ZDg0ODZjNTYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.C6jVQLFPfq4fhGV8wiY9D-P21PUNTDMkX2d2-kU17Ug"> After: <img width="637" src="https://github.com/go-gitea/gitea/assets/106393991/45b197ae-e422-42f4-999e-25dc8f6b7a92"> (cherry picked from commit 3d3c3d9ee5e934c515370d98f1c552ca8ef10f8a) --- public/assets/img/svg/gitea-discord.svg | 2 +- web_src/svg/gitea-discord.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/assets/img/svg/gitea-discord.svg b/public/assets/img/svg/gitea-discord.svg index 6ebbdcdcc3..2edcb4fed7 100644 --- a/public/assets/img/svg/gitea-discord.svg +++ b/public/assets/img/svg/gitea-discord.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="gitea-discord__svg gitea-discord__gitea-discord svg gitea-discord" preserveAspectRatio="xMidYMid" viewBox="0 0 256 293" width="16" height="16"><path fill="#7289DA" d="M226.011 0H29.99C13.459 0 0 13.458 0 30.135v197.778c0 16.677 13.458 30.135 29.989 30.135h165.888l-7.754-27.063 18.725 17.408 17.7 16.384L256 292.571V30.135C256 13.458 242.542 0 226.011 0m-56.466 191.05s-5.266-6.291-9.655-11.85c19.164-5.413 26.478-17.408 26.478-17.408-5.998 3.95-11.703 6.73-16.823 8.63-7.314 3.073-14.336 5.12-21.211 6.291-14.044 2.633-26.917 1.902-37.888-.146-8.339-1.61-15.507-3.95-21.504-6.29-3.365-1.317-7.022-2.926-10.68-4.974-.438-.293-.877-.439-1.316-.732a2 2 0 0 1-.585-.438c-2.633-1.463-4.096-2.487-4.096-2.487s7.022 11.703 25.6 17.261c-4.388 5.56-9.801 12.142-9.801 12.142-32.33-1.024-44.617-22.235-44.617-22.235 0-47.104 21.065-85.285 21.065-85.285 21.065-15.799 41.106-15.36 41.106-15.36l1.463 1.756C80.75 77.53 68.608 89.088 68.608 89.088s3.218-1.755 8.63-4.242c15.653-6.876 28.088-8.777 33.208-9.216.877-.147 1.609-.293 2.487-.293a123.8 123.8 0 0 1 29.55-.292c13.896 1.609 28.818 5.705 44.031 14.043 0 0-11.556-10.971-36.425-18.578l2.048-2.34s20.041-.44 41.106 15.36c0 0 21.066 38.18 21.066 85.284 0 0-12.435 21.211-44.764 22.235zm-68.023-68.316c-8.338 0-14.92 7.314-14.92 16.237 0 8.924 6.728 16.238 14.92 16.238 8.339 0 14.921-7.314 14.921-16.238.147-8.923-6.582-16.237-14.92-16.237m53.394 0c-8.339 0-14.922 7.314-14.922 16.237 0 8.924 6.73 16.238 14.922 16.238 8.338 0 14.92-7.314 14.92-16.238s-6.582-16.237-14.92-16.237"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36" class="svg gitea-discord" width="16" height="16" aria-hidden="true"><path fill="#5865f2" d="M107.7 8.07A105.2 105.2 0 0 0 81.47 0a72 72 0 0 0-3.36 6.83 97.7 97.7 0 0 0-29.11 0A72 72 0 0 0 45.64 0a106 106 0 0 0-26.25 8.09C2.79 32.65-1.71 56.6.54 80.21a105.7 105.7 0 0 0 32.17 16.15 77.7 77.7 0 0 0 6.89-11.11 68.4 68.4 0 0 1-10.85-5.18c.91-.66 1.8-1.34 2.66-2a75.57 75.57 0 0 0 64.32 0c.87.71 1.76 1.39 2.66 2a68.7 68.7 0 0 1-10.87 5.19 77 77 0 0 0 6.89 11.1 105.3 105.3 0 0 0 32.19-16.14c2.64-27.38-4.51-51.11-18.9-72.15M42.45 65.69C36.18 65.69 31 60 31 53s5-12.74 11.43-12.74S54 46 53.89 53s-5.05 12.69-11.44 12.69m42.24 0C78.41 65.69 73.25 60 73.25 53s5-12.74 11.44-12.74S96.23 46 96.12 53s-5.04 12.69-11.43 12.69"/></svg> \ No newline at end of file diff --git a/web_src/svg/gitea-discord.svg b/web_src/svg/gitea-discord.svg index ea64a39f6e..4cadbc7f7e 100644 --- a/web_src/svg/gitea-discord.svg +++ b/web_src/svg/gitea-discord.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" viewBox="0 0 256 293" class="svg gitea-discord" width="16" height="16" aria-hidden="true"><path fill="#7289DA" d="M226.011 0H29.99C13.459 0 0 13.458 0 30.135v197.778c0 16.677 13.458 30.135 29.989 30.135h165.888l-7.754-27.063 18.725 17.408 17.7 16.384L256 292.571V30.135C256 13.458 242.542 0 226.011 0zm-56.466 191.05s-5.266-6.291-9.655-11.85c19.164-5.413 26.478-17.408 26.478-17.408-5.998 3.95-11.703 6.73-16.823 8.63-7.314 3.073-14.336 5.12-21.211 6.291-14.044 2.633-26.917 1.902-37.888-.146-8.339-1.61-15.507-3.95-21.504-6.29-3.365-1.317-7.022-2.926-10.68-4.974-.438-.293-.877-.439-1.316-.732a2.022 2.022 0 0 1-.585-.438c-2.633-1.463-4.096-2.487-4.096-2.487s7.022 11.703 25.6 17.261c-4.388 5.56-9.801 12.142-9.801 12.142-32.33-1.024-44.617-22.235-44.617-22.235 0-47.104 21.065-85.285 21.065-85.285 21.065-15.799 41.106-15.36 41.106-15.36l1.463 1.756C80.75 77.53 68.608 89.088 68.608 89.088s3.218-1.755 8.63-4.242c15.653-6.876 28.088-8.777 33.208-9.216.877-.147 1.609-.293 2.487-.293a123.776 123.776 0 0 1 29.55-.292c13.896 1.609 28.818 5.705 44.031 14.043 0 0-11.556-10.971-36.425-18.578l2.048-2.34s20.041-.44 41.106 15.36c0 0 21.066 38.18 21.066 85.284 0 0-12.435 21.211-44.764 22.235zm-68.023-68.316c-8.338 0-14.92 7.314-14.92 16.237 0 8.924 6.728 16.238 14.92 16.238 8.339 0 14.921-7.314 14.921-16.238.147-8.923-6.582-16.237-14.92-16.237m53.394 0c-8.339 0-14.922 7.314-14.922 16.237 0 8.924 6.73 16.238 14.922 16.238 8.338 0 14.92-7.314 14.92-16.238 0-8.923-6.582-16.237-14.92-16.237"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36"><path fill="#5865f2" d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z"/></svg> \ No newline at end of file From 52bf6bf60c863f425aa951b52fbca6dfd0c5646d Mon Sep 17 00:00:00 2001 From: Jason Song <i@wolfogre.com> Date: Wed, 21 Feb 2024 12:57:22 +0800 Subject: [PATCH 11/64] Do not use `ctx.Doer` when reset password (#29289) Fix #29278. Caused by a small typo in #28733 (cherry picked from commit 22b8de85ddda50725480b21c5bf6ef9c0202b5e9) --- routers/web/auth/password.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index c23379b87a..1f2d133282 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -204,7 +204,7 @@ func ResetPasswdPost(ctx *context.Context) { Password: optional.Some(ctx.FormString("password")), MustChangePassword: optional.Some(false), } - if err := user_service.UpdateAuth(ctx, ctx.Doer, opts); err != nil { + if err := user_service.UpdateAuth(ctx, u, opts); err != nil { ctx.Data["IsResetForm"] = true ctx.Data["Err_Password"] = true switch { From d3a642a7e03650521644a18ba6986c75d2872b9e Mon Sep 17 00:00:00 2001 From: Earl Warren <contact@earl-warren.org> Date: Mon, 26 Feb 2024 21:39:12 +0100 Subject: [PATCH 12/64] Revert "[BUG] Initalize Git for hook regeneration" This reverts commit 815abad84c68da1722f87c97a47b0e96a29f3967. Redundant with: Always write proc-receive hook for all git versions (#29287) --- cmd/admin_regenerate.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cmd/admin_regenerate.go b/cmd/admin_regenerate.go index efdfc8e5e4..0db505ff9c 100644 --- a/cmd/admin_regenerate.go +++ b/cmd/admin_regenerate.go @@ -5,7 +5,6 @@ package cmd import ( asymkey_model "code.gitea.io/gitea/models/asymkey" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/graceful" repo_service "code.gitea.io/gitea/services/repository" @@ -33,12 +32,6 @@ func runRegenerateHooks(_ *cli.Context) error { if err := initDB(ctx); err != nil { return err } - - // Detection of ProcReceive support relies on Git module being initalized. - if err := git.InitFull(ctx); err != nil { - return err - } - return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext()) } From 2c8f112c1c2268d48c7c28aa91e7b0c631e272b4 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Wed, 21 Feb 2024 15:01:48 +0800 Subject: [PATCH 13/64] Always write proc-receive hook for all git versions (#29287) (cherry picked from commit 7f45dfb030f30a3ada58e636e3b8bfde391224bd) --- modules/repository/hooks.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/modules/repository/hooks.go b/modules/repository/hooks.go index daab7c3091..95849789ab 100644 --- a/modules/repository/hooks.go +++ b/modules/repository/hooks.go @@ -9,7 +9,6 @@ import ( "path/filepath" "runtime" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -94,15 +93,14 @@ done `, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf)), } - if git.SupportProcReceive { - hookNames = append(hookNames, "proc-receive") - hookTpls = append(hookTpls, - fmt.Sprintf(`#!/usr/bin/env %s + // although only new git (>=2.29) supports proc-receive, it's still good to create its hook, in case the user upgrades git + hookNames = append(hookNames, "proc-receive") + hookTpls = append(hookTpls, + fmt.Sprintf(`#!/usr/bin/env %s # AUTO GENERATED BY GITEA, DO NOT MODIFY %s hook --config=%s proc-receive `, setting.ScriptType, util.ShellEscape(setting.AppPath), util.ShellEscape(setting.CustomConf))) - giteaHookTpls = append(giteaHookTpls, "") - } + giteaHookTpls = append(giteaHookTpls, "") return hookNames, hookTpls, giteaHookTpls } From 769db26c5a5545d082b90baa558d9455f5371b7e Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Wed, 21 Feb 2024 10:13:48 +0200 Subject: [PATCH 14/64] Remove jQuery from the installation page (#29284) - Switched to plain JavaScript - Tested the installation page functionality and it works as before # Demo using JavaScript without jQuery  Signed-off-by: Yarden Shoham <git@yardenshoham.com> (cherry picked from commit 4e536edaead97d61a64508db0e93cf781a889472) --- web_src/js/features/install.js | 101 ++++++++++++++++----------------- 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/web_src/js/features/install.js b/web_src/js/features/install.js index bb83dd1ff4..1826ff7cde 100644 --- a/web_src/js/features/install.js +++ b/web_src/js/features/install.js @@ -1,19 +1,17 @@ -import $ from 'jquery'; import {hideElem, showElem} from '../utils/dom.js'; import {GET} from '../modules/fetch.js'; export function initInstall() { - const $page = $('.page-content.install'); - if ($page.length === 0) { + const page = document.querySelector('.page-content.install'); + if (!page) { return; } - if ($page.is('.post-install')) { + if (page.classList.contains('post-install')) { initPostInstall(); } else { initPreInstall(); } } - function initPreInstall() { const defaultDbUser = 'forgejo'; const defaultDbName = 'forgejo'; @@ -24,83 +22,82 @@ function initPreInstall() { mssql: '127.0.0.1:1433' }; - const $dbHost = $('#db_host'); - const $dbUser = $('#db_user'); - const $dbName = $('#db_name'); + const dbHost = document.getElementById('db_host'); + const dbUser = document.getElementById('db_user'); + const dbName = document.getElementById('db_name'); // Database type change detection. - $('#db_type').on('change', function () { - const dbType = $(this).val(); - hideElem($('div[data-db-setting-for]')); - showElem($(`div[data-db-setting-for=${dbType}]`)); + document.getElementById('db_type').addEventListener('change', function () { + const dbType = this.value; + hideElem('div[data-db-setting-for]'); + showElem(`div[data-db-setting-for=${dbType}]`); if (dbType !== 'sqlite3') { // for most remote database servers - showElem($(`div[data-db-setting-for=common-host]`)); - const lastDbHost = $dbHost.val(); + showElem('div[data-db-setting-for=common-host]'); + const lastDbHost = dbHost.value; const isDbHostDefault = !lastDbHost || Object.values(defaultDbHosts).includes(lastDbHost); if (isDbHostDefault) { - $dbHost.val(defaultDbHosts[dbType] ?? ''); + dbHost.value = defaultDbHosts[dbType] ?? ''; } - if (!$dbUser.val() && !$dbName.val()) { - $dbUser.val(defaultDbUser); - $dbName.val(defaultDbName); + if (!dbUser.value && !dbName.value) { + dbUser.value = defaultDbUser; + dbName.value = defaultDbName; } } // else: for SQLite3, the default path is always prepared by backend code (setting) - }).trigger('change'); + }); + document.getElementById('db_type').dispatchEvent(new Event('change')); - const $appUrl = $('#app_url'); - const configAppUrl = $appUrl.val(); - if (configAppUrl.includes('://localhost')) { - $appUrl.val(window.location.href); + const appUrl = document.getElementById('app_url'); + if (appUrl.value.includes('://localhost')) { + appUrl.value = window.location.href; } - const $domain = $('#domain'); - const configDomain = $domain.val().trim(); - if (configDomain === 'localhost') { - $domain.val(window.location.hostname); + const domain = document.getElementById('domain'); + if (domain.value.trim() === 'localhost') { + domain.value = window.location.hostname; } // TODO: better handling of exclusive relations. - $('#offline-mode input').on('change', function () { - if ($(this).is(':checked')) { - $('#disable-gravatar').checkbox('check'); - $('#federated-avatar-lookup').checkbox('uncheck'); + document.querySelector('#offline-mode input').addEventListener('change', function () { + if (this.checked) { + document.querySelector('#disable-gravatar input').checked = true; + document.querySelector('#federated-avatar-lookup input').checked = false; } }); - $('#disable-gravatar input').on('change', function () { - if ($(this).is(':checked')) { - $('#federated-avatar-lookup').checkbox('uncheck'); + document.querySelector('#disable-gravatar input').addEventListener('change', function () { + if (this.checked) { + document.querySelector('#federated-avatar-lookup input').checked = false; } else { - $('#offline-mode').checkbox('uncheck'); + document.querySelector('#offline-mode input').checked = false; } }); - $('#federated-avatar-lookup input').on('change', function () { - if ($(this).is(':checked')) { - $('#disable-gravatar').checkbox('uncheck'); - $('#offline-mode').checkbox('uncheck'); + document.querySelector('#federated-avatar-lookup input').addEventListener('change', function () { + if (this.checked) { + document.querySelector('#disable-gravatar input').checked = false; + document.querySelector('#offline-mode input').checked = false; } }); - $('#enable-openid-signin input').on('change', function () { - if ($(this).is(':checked')) { - if (!$('#disable-registration input').is(':checked')) { - $('#enable-openid-signup').checkbox('check'); + document.querySelector('#enable-openid-signin input').addEventListener('change', function () { + if (this.checked) { + if (!document.querySelector('#disable-registration input').checked) { + document.querySelector('#enable-openid-signup input').checked = true; } } else { - $('#enable-openid-signup').checkbox('uncheck'); + document.querySelector('#enable-openid-signup input').checked = false; } }); - $('#disable-registration input').on('change', function () { - if ($(this).is(':checked')) { - $('#enable-captcha').checkbox('uncheck'); - $('#enable-openid-signup').checkbox('uncheck'); + document.querySelector('#disable-registration input').addEventListener('change', function () { + if (this.checked) { + document.querySelector('#enable-captcha input').checked = false; + document.querySelector('#enable-openid-signup input').checked = false; } else { - $('#enable-openid-signup').checkbox('check'); + document.querySelector('#enable-openid-signup input').checked = true; } }); - $('#enable-captcha input').on('change', function () { - if ($(this).is(':checked')) { - $('#disable-registration').checkbox('uncheck'); + document.querySelector('#enable-captcha input').addEventListener('change', function () { + if (this.checked) { + document.querySelector('#disable-registration input').checked = false; } }); } From 321aaedc4ee16e925d56eedf357ad53c2f40de26 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Wed, 21 Feb 2024 19:40:46 +0800 Subject: [PATCH 15/64] Fix error display when merging PRs (#29288) Partially fix #29071, regression of Modernize merge button #28140 Fix some missing `Redirect` -> `JSONRedirect`. Thanks @yp05327 for the help in https://github.com/go-gitea/gitea/issues/29071#issuecomment-1931261075 (cherry picked from commit 79217ea63c1f77de7ca79813ae45950724e63d02) --- routers/web/repo/pull.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index ac244b1551..fd7e902225 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1311,19 +1311,19 @@ func MergePullRequest(ctx *context.Context) { return } ctx.Flash.Error(flashError) - ctx.Redirect(issue.Link()) + ctx.JSONRedirect(issue.Link()) } else if models.IsErrMergeUnrelatedHistories(err) { log.Debug("MergeUnrelatedHistories error: %v", err) ctx.Flash.Error(ctx.Tr("repo.pulls.unrelated_histories")) - ctx.Redirect(issue.Link()) + ctx.JSONRedirect(issue.Link()) } else if git.IsErrPushOutOfDate(err) { log.Debug("MergePushOutOfDate error: %v", err) ctx.Flash.Error(ctx.Tr("repo.pulls.merge_out_of_date")) - ctx.Redirect(issue.Link()) + ctx.JSONRedirect(issue.Link()) } else if models.IsErrSHADoesNotMatch(err) { log.Debug("MergeHeadOutOfDate error: %v", err) ctx.Flash.Error(ctx.Tr("repo.pulls.head_out_of_date")) - ctx.Redirect(issue.Link()) + ctx.JSONRedirect(issue.Link()) } else if git.IsErrPushRejected(err) { log.Debug("MergePushRejected error: %v", err) pushrejErr := err.(*git.ErrPushRejected) From c88ae2e38254b4ee17be2b055065d5d0b0110bc7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Wed, 21 Feb 2024 22:14:37 +0800 Subject: [PATCH 16/64] Revert #28753 because UI broken. (#29293) Revert #29255 Revert #28753 (cherry picked from commit e6e50696b83164805bec83a1b20c95a85a4dd7e5) --- templates/user/auth/signin_inner.tmpl | 11 +++++++---- templates/user/auth/signin_openid.tmpl | 6 ++++-- templates/user/auth/signup_inner.tmpl | 14 ++++++++------ web_src/css/form.css | 4 ++++ web_src/css/helpers.css | 1 - 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index a0aea5cb9b..40e54ec8fa 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -9,20 +9,21 @@ {{end}} </h4> <div class="ui attached segment"> - <form class="ui form gt-max-width-36rem gt-m-auto" action="{{.SignInLink}}" method="post"> + <form class="ui form" action="{{.SignInLink}}" method="post"> {{.CsrfTokenHtml}} <div class="required inline field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}"> <label for="user_name">{{ctx.Locale.Tr "home.uname_holder"}}</label> - <input id="user_name" class="gt-w-full" type="text" name="user_name" value="{{.user_name}}" autofocus required> + <input id="user_name" type="text" name="user_name" value="{{.user_name}}" autofocus required> </div> {{if or (not .DisablePassword) .LinkAccountMode}} <div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}"> <label for="password">{{ctx.Locale.Tr "password"}}</label> - <input id="password" class="gt-w-full" name="password" type="password" value="{{.password}}" autocomplete="current-password" required> + <input id="password" name="password" type="password" value="{{.password}}" autocomplete="current-password" required> </div> {{end}} {{if not .LinkAccountMode}} <div class="inline field"> + <label></label> <div class="ui checkbox"> <label>{{ctx.Locale.Tr "auth.remember_me"}}</label> <input name="remember" type="checkbox"> @@ -33,6 +34,7 @@ {{template "user/auth/captcha" .}} <div class="inline field"> + <label></label> <button class="ui primary button"> {{if .LinkAccountMode}} {{ctx.Locale.Tr "auth.oauth_signin_submit"}} @@ -45,6 +47,7 @@ {{if .ShowRegistrationButton}} <div class="inline field"> + <label></label> <a href="{{AppSubUrl}}/user/sign_up">{{ctx.Locale.Tr "auth.sign_up_now" | Str2html}}</a> </div> {{end}} @@ -57,7 +60,7 @@ <div class="gt-df gt-fc gt-jc"> <div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3"> {{range $provider := .OAuth2Providers}} - <a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 gt-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}"> + <a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}"> {{$provider.IconHTML 28}} {{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}} </a> diff --git a/templates/user/auth/signin_openid.tmpl b/templates/user/auth/signin_openid.tmpl index a138ea0b8d..0428026aa8 100644 --- a/templates/user/auth/signin_openid.tmpl +++ b/templates/user/auth/signin_openid.tmpl @@ -8,7 +8,7 @@ OpenID </h4> <div class="ui attached segment"> - <form class="ui form gt-m-auto" action="{{.Link}}" method="post"> + <form class="ui form" action="{{.Link}}" method="post"> {{.CsrfTokenHtml}} <div class="inline field"> {{ctx.Locale.Tr "auth.openid_signin_desc"}} @@ -18,15 +18,17 @@ {{svg "fontawesome-openid"}} OpenID URI </label> - <input id="openid" class="gt-w-full" name="openid" value="{{.openid}}" autofocus required> + <input id="openid" name="openid" value="{{.openid}}" autofocus required> </div> <div class="inline field"> + <label></label> <div class="ui checkbox"> <label>{{ctx.Locale.Tr "auth.remember_me"}}</label> <input name="remember" type="checkbox"> </div> </div> <div class="inline field"> + <label></label> <button class="ui primary button">{{ctx.Locale.Tr "sign_in"}}</button> </div> </form> diff --git a/templates/user/auth/signup_inner.tmpl b/templates/user/auth/signup_inner.tmpl index 65ce98c31a..e930bd3d15 100644 --- a/templates/user/auth/signup_inner.tmpl +++ b/templates/user/auth/signup_inner.tmpl @@ -7,7 +7,7 @@ {{end}} </h4> <div class="ui attached segment"> - <form class="ui form gt-max-width-36rem gt-m-auto" action="{{.SignUpLink}}" method="post"> + <form class="ui form" action="{{.SignUpLink}}" method="post"> {{.CsrfTokenHtml}} {{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister)}} {{template "base/alert" .}} @@ -17,27 +17,28 @@ {{else}} <div class="required inline field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}"> <label for="user_name">{{ctx.Locale.Tr "username"}}</label> - <input id="user_name" class="gt-w-full" type="text" name="user_name" value="{{.user_name}}" autofocus required> + <input id="user_name" type="text" name="user_name" value="{{.user_name}}" autofocus required> </div> <div class="required inline field {{if .Err_Email}}error{{end}}"> <label for="email">{{ctx.Locale.Tr "email"}}</label> - <input id="email" class="gt-w-full" name="email" type="email" value="{{.email}}" required> + <input id="email" name="email" type="email" value="{{.email}}" required> </div> {{if not .DisablePassword}} <div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}"> <label for="password">{{ctx.Locale.Tr "password"}}</label> - <input id="password" class="gt-w-full" name="password" type="password" value="{{.password}}" autocomplete="new-password" required> + <input id="password" name="password" type="password" value="{{.password}}" autocomplete="new-password" required> </div> <div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}"> <label for="retype">{{ctx.Locale.Tr "re_type"}}</label> - <input id="retype" class="gt-w-full" name="retype" type="password" value="{{.retype}}" autocomplete="new-password" required> + <input id="retype" name="retype" type="password" value="{{.retype}}" autocomplete="new-password" required> </div> {{end}} {{template "user/auth/captcha" .}} <div class="inline field"> + <label></label> <button class="ui primary button"> {{if .LinkAccountMode}} {{ctx.Locale.Tr "auth.oauth_signup_submit"}} @@ -49,6 +50,7 @@ {{if not .LinkAccountMode}} <div class="inline field"> + <label></label> <a href="{{AppSubUrl}}/user/login">{{ctx.Locale.Tr "auth.register_helper_msg"}}</a> </div> {{end}} @@ -62,7 +64,7 @@ <div class="gt-df gt-fc gt-jc"> <div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3"> {{range $provider := .OAuth2Providers}} - <a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 gt-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}"> + <a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}"> {{$provider.IconHTML 28}} {{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}} </a> diff --git a/web_src/css/form.css b/web_src/css/form.css index a5288c9309..e4efa34948 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -242,6 +242,8 @@ textarea:focus, .user.activate form, .user.forgot.password form, .user.reset.password form, +.user.link-account form, +.user.signin form, .user.signup form { margin: auto; width: 700px !important; @@ -276,6 +278,8 @@ textarea:focus, .user.activate form .inline.field > label, .user.forgot.password form .inline.field > label, .user.reset.password form .inline.field > label, + .user.link-account form .inline.field > label, + .user.signin form .inline.field > label, .user.signup form .inline.field > label { text-align: right; width: 250px !important; diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index c7d8abb1d4..da94ebb486 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -48,7 +48,6 @@ Gitea's private styles use `g-` prefix. .gt-max-width-12rem { max-width: 12rem !important; } .gt-max-width-24rem { max-width: 24rem !important; } -.gt-max-width-36rem { max-width: 36rem !important; } /* below class names match Tailwind CSS */ .gt-break-all { word-break: break-all !important; } From 5f79550a0dade6a6cebdf8cf62f55ffa6df30b30 Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Wed, 21 Feb 2024 19:54:17 +0100 Subject: [PATCH 17/64] Prevent double use of `git cat-file` session. (#29298) Fixes the reason why #29101 is hard to replicate. Related #29297 Create a repo with a file with minimum size 4097 bytes (I use 10000) and execute the following code: ```go gitRepo, err := gitrepo.OpenRepository(db.DefaultContext, <repo>) assert.NoError(t, err) commit, err := gitRepo.GetCommit(<sha>) assert.NoError(t, err) entry, err := commit.GetTreeEntryByPath(<file>) assert.NoError(t, err) b := entry.Blob() // Create a reader r, err := b.DataAsync() assert.NoError(t, err) defer r.Close() // Create a second reader r2, err := b.DataAsync() assert.NoError(t, err) // Should be no error but is ErrNotExist defer r2.Close() ``` The problem is the check in `CatFileBatch`: https://github.com/go-gitea/gitea/blob/79217ea63c1f77de7ca79813ae45950724e63d02/modules/git/repo_base_nogogit.go#L81-L87 `Buffered() > 0` is used to check if there is a "operation" in progress at the moment. This is a problem because we can't control the internal buffer in the `bufio.Reader`. The code above demonstrates a sequence which initiates an operation for which the code thinks there is no active processing. The second call to `DataAsync()` therefore reuses the existing instances instead of creating a new batch reader. (cherry picked from commit f74c869221624092999097af38b6f7fae4701420) --- modules/git/repo_base_nogogit.go | 21 ++++++++++----- tests/integration/git_test.go | 44 ++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/modules/git/repo_base_nogogit.go b/modules/git/repo_base_nogogit.go index d5a350a926..8c6eae5897 100644 --- a/modules/git/repo_base_nogogit.go +++ b/modules/git/repo_base_nogogit.go @@ -27,10 +27,12 @@ type Repository struct { gpgSettings *GPGSettings + batchInUse bool batchCancel context.CancelFunc batchReader *bufio.Reader batchWriter WriteCloserError + checkInUse bool checkCancel context.CancelFunc checkReader *bufio.Reader checkWriter WriteCloserError @@ -79,23 +81,28 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) { // CatFileBatch obtains a CatFileBatch for this repository func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) { - if repo.batchCancel == nil || repo.batchReader.Buffered() > 0 { + if repo.batchCancel == nil || repo.batchInUse { log.Debug("Opening temporary cat file batch for: %s", repo.Path) return CatFileBatch(ctx, repo.Path) } - return repo.batchWriter, repo.batchReader, func() {} + repo.batchInUse = true + return repo.batchWriter, repo.batchReader, func() { + repo.batchInUse = false + } } // CatFileBatchCheck obtains a CatFileBatchCheck for this repository func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) { - if repo.checkCancel == nil || repo.checkReader.Buffered() > 0 { - log.Debug("Opening temporary cat file batch-check: %s", repo.Path) + if repo.checkCancel == nil || repo.checkInUse { + log.Debug("Opening temporary cat file batch-check for: %s", repo.Path) return CatFileBatchCheck(ctx, repo.Path) } - return repo.checkWriter, repo.checkReader, func() {} + repo.checkInUse = true + return repo.checkWriter, repo.checkReader, func() { + repo.checkInUse = false + } } -// Close this repository, in particular close the underlying gogitStorage if this is not nil func (repo *Repository) Close() (err error) { if repo == nil { return nil @@ -105,12 +112,14 @@ func (repo *Repository) Close() (err error) { repo.batchReader = nil repo.batchWriter = nil repo.batchCancel = nil + repo.batchInUse = false } if repo.checkCancel != nil { repo.checkCancel() repo.checkCancel = nil repo.checkReader = nil repo.checkWriter = nil + repo.checkInUse = false } repo.LastCommitCache = nil repo.tagCache = nil diff --git a/tests/integration/git_test.go b/tests/integration/git_test.go index 365e7f91b1..ff5421d93a 100644 --- a/tests/integration/git_test.go +++ b/tests/integration/git_test.go @@ -4,6 +4,7 @@ package integration import ( + "bytes" "encoding/hex" "fmt" "math/rand" @@ -26,9 +27,11 @@ import ( user_model "code.gitea.io/gitea/models/user" gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + files_service "code.gitea.io/gitea/services/repository/files" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" @@ -1034,3 +1037,44 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB t.Run("CheckoutMasterAgain", doGitCheckoutBranch(dstPath, "master")) } } + +func TestDataAsync_Issue29101(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + + resp, err := files_service.ChangeRepoFiles(db.DefaultContext, repo, user, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: "test.txt", + ContentReader: bytes.NewReader(make([]byte, 10000)), + }, + }, + OldBranch: repo.DefaultBranch, + NewBranch: repo.DefaultBranch, + }) + assert.NoError(t, err) + + sha := resp.Commit.SHA + + gitRepo, err := gitrepo.OpenRepository(db.DefaultContext, repo) + assert.NoError(t, err) + + commit, err := gitRepo.GetCommit(sha) + assert.NoError(t, err) + + entry, err := commit.GetTreeEntryByPath("test.txt") + assert.NoError(t, err) + + b := entry.Blob() + + r, err := b.DataAsync() + assert.NoError(t, err) + defer r.Close() + + r2, err := b.DataAsync() + assert.NoError(t, err) + defer r2.Close() + }) +} From 0f793ef6b9fd4b728e7691b7b8c4cc8d434aa190 Mon Sep 17 00:00:00 2001 From: GiteaBot <teabot@gitea.io> Date: Thu, 22 Feb 2024 00:23:48 +0000 Subject: [PATCH 18/64] [skip ci] Updated translations via Crowdin (cherry picked from commit 2bd999a28b472f2909f6856740cdc712eb0ad136) Conflicts: options/locale/locale_fr-FR.ini options/locale/locale_ja-JP.ini options/locale/locale_pt-PT.ini options/locale/locale_ru-RU.ini options/locale/locale_zh-CN.ini removal of runs.no_workflows.quick_start= runs.no_workflows.documentation= --- options/locale/locale_cs-CZ.ini | 11 ++++++-- options/locale/locale_de-DE.ini | 9 +++++- options/locale/locale_el-GR.ini | 11 ++++++-- options/locale/locale_es-ES.ini | 9 +++++- options/locale/locale_fa-IR.ini | 6 ++++ options/locale/locale_fi-FI.ini | 6 ++++ options/locale/locale_fr-FR.ini | 11 ++++++-- options/locale/locale_hu-HU.ini | 6 ++++ options/locale/locale_id-ID.ini | 6 ++++ options/locale/locale_is-IS.ini | 6 ++++ options/locale/locale_it-IT.ini | 6 ++++ options/locale/locale_ja-JP.ini | 11 ++++++-- options/locale/locale_ko-KR.ini | 6 ++++ options/locale/locale_lv-LV.ini | 11 ++++++-- options/locale/locale_nl-NL.ini | 6 ++++ options/locale/locale_pl-PL.ini | 6 ++++ options/locale/locale_pt-BR.ini | 8 ++++++ options/locale/locale_pt-PT.ini | 47 +++++++++++++++++++++++++++++-- options/locale/locale_ru-RU.ini | 11 ++++++-- options/locale/locale_si-LK.ini | 6 ++++ options/locale/locale_sk-SK.ini | 6 ++++ options/locale/locale_sv-SE.ini | 6 ++++ options/locale/locale_tr-TR.ini | 11 ++++++-- options/locale/locale_uk-UA.ini | 6 ++++ options/locale/locale_zh-CN.ini | 49 ++++++++++++++++++++++++++++----- options/locale/locale_zh-HK.ini | 6 ++++ options/locale/locale_zh-TW.ini | 8 ++++++ 27 files changed, 258 insertions(+), 33 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 88cfc04020..954295b5cd 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -590,6 +590,7 @@ org_still_own_packages=Organizace stále vlastní jeden nebo více balíčků. N target_branch_not_exist=Cílová větev neexistuje. + [user] change_avatar=Změnit váš avatar… joined_on=Přidal/a se %s @@ -1956,6 +1957,8 @@ activity.git_stats_and_deletions=a activity.git_stats_deletion_1=%d odebrání activity.git_stats_deletion_n=%d odebrání +contributors.contribution_type.commits=Commity + search=Vyhledat search.search_repo=Hledat repozitář search.type.tooltip=Druh vyhledávání @@ -2544,6 +2547,8 @@ error.csv.too_large=Tento soubor nelze vykreslit, protože je příliš velký. error.csv.unexpected=Tento soubor nelze vykreslit, protože obsahuje neočekávaný znak na řádku %d ve sloupci %d. error.csv.invalid_field_count=Soubor nelze vykreslit, protože má nesprávný počet polí na řádku %d. +[graphs] + [org] org_name_holder=Název organizace org_full_name_holder=Celý název organizace @@ -3182,6 +3187,7 @@ notices.desc=Popis notices.op=Akce notices.delete_success=Systémové upozornění bylo smazáno. + [action] create_repo=vytvořil/a repozitář <a href="%s">%s</a> rename_repo=přejmenoval/a repozitář z <code>%[1]s</code> na <a href="%[2]s">%[3]s</a> @@ -3366,6 +3372,8 @@ rpm.registry=Nastavte tento registr z příkazového řádku: rpm.distros.redhat=na distribuce založené na RedHat rpm.distros.suse=na distribuce založené na SUSE rpm.install=Pro instalaci balíčku spusťte následující příkaz: +rpm.repository=Informace o repozitáři +rpm.repository.architectures=Architektury rubygems.install=Pro instalaci balíčku pomocí gem spusťte následující příkaz: rubygems.install2=nebo ho přidejte do Gemfie: rubygems.dependencies.runtime=Běhové závislosti @@ -3493,8 +3501,6 @@ runs.actors_no_select=Všichni aktéři runs.status_no_select=Všechny stavy runs.no_results=Nebyly nalezeny žádné výsledky. runs.no_workflows=Zatím neexistují žádné pracovní postupy. -runs.no_workflows.quick_start=Nevíte jak začít s Gitea Action? Podívejte se na <a target="_blank" rel="noopener noreferrer" href="%s">průvodce rychlým startem</a>. -runs.no_workflows.documentation=Další informace o Gitea Action, viz <a target="_blank" rel="noopener noreferrer" href="%s">dokumentace</a>. runs.no_runs=Pracovní postup zatím nebyl spuštěn. runs.empty_commit_message=(prázdná zpráva commitu) @@ -3512,7 +3518,6 @@ variables.none=Zatím nejsou žádné proměnné. variables.deletion=Odstranit proměnnou variables.deletion.description=Odstranění proměnné je trvalé a nelze jej vrátit zpět. Pokračovat? variables.description=Proměnné budou předány určitým akcím a nelze je přečíst jinak. -variables.id_not_exist=Proměnná s id %d neexistuje. variables.edit=Upravit proměnnou variables.deletion.failed=Nepodařilo se odstranit proměnnou. variables.deletion.success=Proměnná byla odstraněna. diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 796bd41adf..fb2bb337a1 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -601,6 +601,7 @@ target_branch_not_exist=Der Ziel-Branch existiert nicht. username_error_no_dots = ` darf nur alphanumerische Zeichen („0-9“, „a-z“, „A-Z“), Bindestriche („-“), Unterstriche („_“) enthalten. Es kann nicht mit nicht-alphanumerischen Zeichen beginnen oder enden und aufeinanderfolgende nicht-alphanumerische Zeichen sind ebenfalls verboten.` admin_cannot_delete_self = Du kannst dich nicht selbst löschen, wenn du ein Admin bist. Bitte entferne zuerst deine Adminrechte. + [user] change_avatar=Profilbild ändern … joined_on=Beigetreten am %s @@ -1985,6 +1986,8 @@ activity.git_stats_and_deletions=und activity.git_stats_deletion_1=%d Löschung activity.git_stats_deletion_n=%d Löschungen +contributors.contribution_type.commits=Commits + search=Suchen search.search_repo=Repository durchsuchen search.type.tooltip=Suchmodus @@ -2645,6 +2648,8 @@ vendored = Vendored activity.navbar.pulse = Puls pulls.made_using_agit = AGit +[graphs] + [org] org_name_holder=Name der Organisation org_full_name_holder=Vollständiger Name der Organisation @@ -3306,6 +3311,7 @@ self_check.no_problem_found = Noch kein Problem gefunden. self_check.database_inconsistent_collation_columns = Datenbank benutzt Collation %s, aber diese Spalten benutzen Collations, die nicht zusammenpassen. Das könnte ein paar unerwartete Probleme verursachen. self_check.database_collation_mismatch = Erwarte von Datenbank, folgende Collation zu verwenden: %s + [action] create_repo=hat das Repository <a href="%s">%s</a> erstellt rename_repo=hat das Repository von <code>%[1]s</code> zu <a href="%[2]s">%[3]s</a> umbenannt @@ -3490,6 +3496,8 @@ rpm.registry=Diese Registry über die Kommandozeile einrichten: rpm.distros.redhat=auf RedHat-basierten Distributionen rpm.distros.suse=auf SUSE-basierten Distributionen rpm.install=Nutze folgenden Befehl, um das Paket zu installieren: +rpm.repository=Repository-Informationen +rpm.repository.architectures=Architekturen rubygems.install=Um das Paket mit gem zu installieren, führe den folgenden Befehl aus: rubygems.install2=oder füg es zum Gemfile hinzu: rubygems.dependencies.runtime=Laufzeitabhängigkeiten @@ -3640,7 +3648,6 @@ variables.none=Es gibt noch keine Variablen. variables.deletion=Variable entfernen variables.deletion.description=Das Entfernen einer Variable ist dauerhaft und kann nicht rückgängig gemacht werden. Fortfahren? variables.description=Variablen werden an bestimmte Aktionen übergeben und können nicht anderweitig gelesen werden. -variables.id_not_exist=Variable mit ID %d existiert nicht. variables.edit=Variable bearbeiten variables.deletion.failed=Fehler beim Entfernen der Variable. variables.deletion.success=Die Variable wurde entfernt. diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 212cb3f918..578846eb4d 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -589,6 +589,7 @@ org_still_own_packages=Αυτός ο οργανισμός κατέχει ακό target_branch_not_exist=Ο κλάδος προορισμού δεν υπάρχει. + [user] change_avatar=Αλλαγή του avatar σας… joined_on=Εγγράφηκε την %s @@ -1967,6 +1968,8 @@ activity.git_stats_and_deletions=και activity.git_stats_deletion_1=%d διαγραφή activity.git_stats_deletion_n=%d διαγραφές +contributors.contribution_type.commits=Υποβολές + search=Αναζήτηση search.search_repo=Αναζήτηση αποθετηρίου search.type.tooltip=Τύπος αναζήτησης @@ -2567,6 +2570,8 @@ error.csv.too_large=Δεν είναι δυνατή η απόδοση αυτού error.csv.unexpected=Δεν είναι δυνατή η απόδοση αυτού του αρχείου, επειδή περιέχει έναν μη αναμενόμενο χαρακτήρα στη γραμμή %d και στη στήλη %d. error.csv.invalid_field_count=Δεν είναι δυνατή η απόδοση αυτού του αρχείου, επειδή έχει λάθος αριθμό πεδίων στη γραμμή %d. +[graphs] + [org] org_name_holder=Όνομα Οργανισμού org_full_name_holder=Πλήρες Όνομα Οργανισμού @@ -3218,6 +3223,7 @@ notices.desc=Περιγραφή notices.op=Λειτ. notices.delete_success=Οι ειδοποιήσεις του συστήματος έχουν διαγραφεί. + [action] create_repo=δημιούργησε το αποθετήριο <a href="%s">%s</a> rename_repo=μετονόμασε το αποθετήριο από <code>%[1]s</code> σε <a href="%[2]s">%[3]s</a> @@ -3402,6 +3408,8 @@ rpm.registry=Ρυθμίστε αυτό το μητρώο από τη γραμμ rpm.distros.redhat=σε διανομές βασισμένες στο RedHat rpm.distros.suse=σε διανομές με βάση το SUSE rpm.install=Για να εγκαταστήσετε το πακέτο, εκτελέστε την ακόλουθη εντολή: +rpm.repository=Πληροφορίες Αποθετηρίου +rpm.repository.architectures=Αρχιτεκτονικές rubygems.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το gem, εκτελέστε την ακόλουθη εντολή: rubygems.install2=ή προσθέστε το στο Gemfile: rubygems.dependencies.runtime=Εξαρτήσεις Εκτέλεσης @@ -3534,8 +3542,6 @@ runs.actors_no_select=Όλοι οι φορείς runs.status_no_select=Όλες οι καταστάσεις runs.no_results=Δεν βρέθηκαν αποτελέσματα. runs.no_workflows=Δεν υπάρχουν ροές εργασίας ακόμα. -runs.no_workflows.quick_start=Δεν ξέρετε πώς να ξεκινήσετε με τις Δράσεις Gitea; Συμβουλευτείτε <a target="_blank" rel="noopener noreferrer" href="%s">τον οδηγό για γρήγορη αρχή</a>. -runs.no_workflows.documentation=Για περισσότερες πληροφορίες σχετικά με τη Δράση Gitea, ανατρέξτε <a target="_blank" rel="noopener noreferrer" href="%s">στην τεκμηρίωση</a>. runs.no_runs=Η ροή εργασίας δεν έχει τρέξει ακόμα. runs.empty_commit_message=(κενό μήνυμα υποβολής) @@ -3554,7 +3560,6 @@ variables.none=Δεν υπάρχουν μεταβλητές ακόμα. variables.deletion=Αφαίρεση μεταβλητής variables.deletion.description=Η αφαίρεση μιας μεταβλητής είναι μόνιμη και δεν μπορεί να αναιρεθεί. Συνέχεια; variables.description=Η μεταβλητές θα δίνονται σε ορισμένες δράσεις και δεν μπορούν να διαβαστούν αλλιώς. -variables.id_not_exist=Η μεταβλητή με id %d δεν υπάρχει. variables.edit=Επεξεργασία Μεταβλητής variables.deletion.failed=Αποτυχία αφαίρεσης της μεταβλητής. variables.deletion.success=Η μεταβλητή έχει αφαιρεθεί. diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 9230b937cd..7bd2cdad4b 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -599,6 +599,7 @@ target_branch_not_exist=La rama de destino no existe admin_cannot_delete_self = No puedes eliminarte a ti mismo cuando eres un admin (administrador). Por favor, elimina primero tus privilegios de administrador. username_error_no_dots = ` solo puede contener carácteres alfanuméricos ('0-9','a-z','A-Z'), guiones ('-') y guiones bajos ('_'). No puede empezar o terminar con carácteres no alfanuméricos y también están prohibidos los carácteres no alfanuméricos consecutivos.` + [user] change_avatar=Cambiar su avatar… joined_on=Se unió el %s @@ -1982,6 +1983,8 @@ activity.git_stats_and_deletions=y activity.git_stats_deletion_1=%d eliminación activity.git_stats_deletion_n=%d eliminaciones +contributors.contribution_type.commits=Commits + search=Buscar search.search_repo=Buscar repositorio search.type.tooltip=Tipo de búsqueda @@ -2582,6 +2585,8 @@ error.csv.unexpected=No se puede procesar este archivo porque contiene un carác error.csv.invalid_field_count=No se puede procesar este archivo porque tiene un número incorrecto de campos en la línea %d. rss.must_be_on_branch = Debes estar en una rama para tener un feed RSS. +[graphs] + [org] org_name_holder=Nombre de la organización org_full_name_holder=Nombre completo de la organización @@ -3231,6 +3236,7 @@ notices.desc=Descripción notices.op=Operación notices.delete_success=Los avisos del sistema se han eliminado. + [action] create_repo=creó el repositorio <a href="%s">%s</a> rename_repo=repositorio renombrado de <code>%[1]s</code> a <a href="%[2]s">%[3]s</a> @@ -3415,6 +3421,8 @@ rpm.registry=Configurar este registro desde la línea de comandos: rpm.distros.redhat=en distribuciones basadas en RedHat rpm.distros.suse=en distribuciones basadas en SUSE rpm.install=Para instalar el paquete, ejecute el siguiente comando: +rpm.repository=Información del repositorio +rpm.repository.architectures=Arquitecturas rubygems.install=Para instalar el paquete usando gem, ejecute el siguiente comando: rubygems.install2=o añádelo al archivo Gemfile: rubygems.dependencies.runtime=Dependencias en tiempo de ejecución @@ -3562,7 +3570,6 @@ variables.none=Aún no hay variables. variables.deletion=Eliminar variable variables.deletion.description=Eliminar una variable es permanente y no se puede deshacer. ¿Continuar? variables.description=Las variables se pasarán a ciertas acciones y no se podrán leer de otro modo. -variables.id_not_exist=Variable con id %d no existe. variables.edit=Editar variable variables.deletion.failed=No se pudo eliminar la variable. variables.deletion.success=La variable ha sido eliminada. diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 4b4ecd4a0a..64d29cbda7 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -464,6 +464,7 @@ auth_failed=تشخیص هویت ناموفق: %v target_branch_not_exist=شاخه مورد نظر وجود ندارد. + [user] change_avatar=تغییر آواتار… repositories=مخازن @@ -1499,6 +1500,8 @@ activity.git_stats_and_deletions=و activity.git_stats_deletion_1=%d مذحوف activity.git_stats_deletion_n=%d مذحوف +contributors.contribution_type.commits=کامیتها + search=جستجو search.search_repo=جستجوی مخزن search.fuzzy=درهم @@ -1952,6 +1955,8 @@ error.csv.too_large=نمی توان این فایل را رندر کرد زیر error.csv.unexpected=نمی توان این فایل را رندر کرد زیرا حاوی یک کاراکتر غیرمنتظره در خط %d و ستون %d است. error.csv.invalid_field_count=نمی توان این فایل را رندر کرد زیرا تعداد فیلدهای آن در خط %d اشتباه است. +[graphs] + [org] org_name_holder=نام سازمان org_full_name_holder=نام کامل سازمان @@ -2502,6 +2507,7 @@ notices.desc=توضیحات notices.op=عملیات. notices.delete_success=گزارش سیستم حذف شده است. + [action] create_repo=مخزن ایجاد شده <a href="%s"> %s</a> rename_repo=مخزن تغییر نام داد از <code>%[1]s</code> به <a href="%[2]s">%[3]s</a> diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index c0710f2cd8..ad45e55ade 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -426,6 +426,7 @@ auth_failed=Todennus epäonnistui: %v target_branch_not_exist=Kohde branchia ei ole olemassa. + [user] change_avatar=Vaihda profiilikuvasi… repositories=Repot @@ -1075,6 +1076,8 @@ activity.git_stats_and_deletions=ja activity.git_stats_deletion_1=%d poisto activity.git_stats_deletion_n=%d poistoa +contributors.contribution_type.commits=Commitit + search=Haku search.match=Osuma search.code_no_results=Hakuehtoasi vastaavaa lähdekoodia ei löytynyt. @@ -1316,6 +1319,8 @@ topic.done=Valmis +[graphs] + [org] org_name_holder=Organisaatio org_full_name_holder=Organisaation täydellinen nimi @@ -1661,6 +1666,7 @@ notices.type_1=Repo notices.desc=Kuvaus notices.op=Toiminta + [action] create_repo=luotu repo <a href="%s">%s</a> rename_repo=uudelleennimetty repo <code>%[1]s</code> nimelle <a href="%[2]s">%[3]s</a> diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 90e1a062a8..e547810320 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -600,6 +600,7 @@ target_branch_not_exist=La branche cible n'existe pas. username_error_no_dots = ` peut uniquement contenir des caractères alphanumériques ('0-9','a-z','A-Z'), tiret ('-') et souligné ('_'). Ne peut commencer ou terminer avec un caractère non-alphanumérique, et l'utilisation de caractères non-alphanumériques consécutifs n'est pas permise.` admin_cannot_delete_self = Vous ne pouvez supprimer votre compte lorsque vous disposez de droits d'administration. Veuillez d'abord renoncer à vos droits d'administration. + [user] change_avatar=Changer votre avatar… joined_on=Inscrit le %s @@ -1991,6 +1992,8 @@ activity.git_stats_and_deletions=et activity.git_stats_deletion_1=%d suppression activity.git_stats_deletion_n=%d suppressions +contributors.contribution_type.commits=Révisions + search=Chercher search.search_repo=Rechercher dans le dépôt search.type.tooltip=Type de recherche @@ -2642,6 +2645,8 @@ contributors.contribution_type.additions = Ajouts contributors.contribution_type.filter_label = Type de contributeur : contributors.contribution_type.deletions = Suppressions +[graphs] + [org] org_name_holder=Nom de l'organisation org_full_name_holder=Nom complet de l'organisation @@ -3303,6 +3308,7 @@ self_check.database_inconsistent_collation_columns = La base de donnée utilise self_check.database_fix_mysql = Les utilisateurs de MySQL/MariaDB peuvent utiliser la commande "forgejo doctor convert" pour corriger les problèmes de collation, ou bien manuellement avec la commande SQL "ALTER ... COLLATE ...". self_check.database_fix_mssql = Les utilisateurs de MSSQL sont pour l'instant contraint d'utiliser la commande SQL "ALTER ... COLLATE ..." pour corriger ce problème. + [action] create_repo=a créé le dépôt <a href="%s">%s</a> rename_repo=a rebaptisé le dépôt <s><code>%[1]s</code></s> en <a href="%[2]s">%[3]s</a> @@ -3487,6 +3493,8 @@ rpm.registry=Configurez ce registre à partir d'un terminal : rpm.distros.redhat=sur les distributions basées sur RedHat rpm.distros.suse=sur les distributions basées sur SUSE rpm.install=Pour installer le paquet, exécutez la commande suivante : +rpm.repository=Informations sur le Dépôt +rpm.repository.architectures=Architectures rubygems.install=Pour installer le paquet en utilisant gem, exécutez la commande suivante : rubygems.install2=ou ajoutez-le au Gemfile : rubygems.dependencies.runtime=Dépendances d'exécution @@ -3622,8 +3630,6 @@ runs.actors_no_select=Tous les acteurs runs.status_no_select=Touts les statuts runs.no_results=Aucun résultat correspondant. runs.no_workflows=Il n'y a pas encore de workflows. -runs.no_workflows.quick_start=Vous ne savez pas comment commencer avec Forgejo Action ? Consultez <a target="_blank" rel="noopener noreferrer" href="%s">le guide de démarrage rapide</a>. -runs.no_workflows.documentation=Pour plus d’informations sur les Actions Forgejo, voir <a target="_blank" rel="noopener noreferrer" href="%s">la documentation</a>. runs.no_runs=Le flux de travail n'a pas encore d'exécution. runs.empty_commit_message=(message de révision vide) @@ -3642,7 +3648,6 @@ variables.none=Il n'y a pas encore de variables. variables.deletion=Retirer la variable variables.deletion.description=La suppression d’une variable est permanente et ne peut être défaite. Continuer ? variables.description=Les variables sont passées aux actions et ne peuvent être lues autrement. -variables.id_not_exist=La variable numéro %d n’existe pas. variables.edit=Modifier la variable variables.deletion.failed=Impossible de retirer la variable. variables.deletion.success=La variable a bien été retirée. diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index d61c40671c..17f5310276 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -370,6 +370,7 @@ auth_failed=A hitelesítés sikertelen: %v target_branch_not_exist=Cél ág nem létezik. + [user] change_avatar=Profilkép megváltoztatása… repositories=Tárolók @@ -1054,6 +1055,8 @@ activity.git_stats_and_deletions=és activity.git_stats_deletion_1=%d törlés activity.git_stats_deletion_n=%d törlés +contributors.contribution_type.commits=Commit-ok + search=Keresés search.search_repo=Tároló keresés search.results=`"%s" találatok keresése itt: <a href="%s">%s</a>` @@ -1169,6 +1172,8 @@ topic.done=Kész +[graphs] + [org] org_name_holder=Szervezet neve org_full_name_holder=Szervezet teljes neve @@ -1581,6 +1586,7 @@ config.domain = Kiszolgálótartomány config.cache_item_ttl = Gyorsítótárelem TTL értéke config.app_data_path = Alkalmazásadatok elérési útja + [action] create_repo=létrehozott tárolót: <a href="%s"> %s</a> rename_repo=átnevezte a(z) <code>%[1]s</code> tárolót <a href="%[2]s">%[3]s</a>-ra/re diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 9e1065756d..5c5632474a 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -294,6 +294,7 @@ auth_failed=Otentikasi gagal: %v target_branch_not_exist=Target cabang tidak ada. + [user] change_avatar=Ganti avatar anda… repositories=Repositori @@ -839,6 +840,8 @@ activity.title.releases_n=%d Rilis activity.title.releases_published_by=%s dikeluarkan oleh %s activity.published_release_label=Dikeluarkan +contributors.contribution_type.commits=Melakukan + search=Cari search.search_repo=Cari repositori search.results=Cari hasil untuk "%s" dalam <a href="%s">%s</a> @@ -954,6 +957,8 @@ branch.deleted_by=Dihapus oleh %s +[graphs] + [org] org_name_holder=Nama Organisasi org_full_name_holder=Organisasi Nama Lengkap @@ -1263,6 +1268,7 @@ notices.desc=Deskripsi notices.op=Op. notices.delete_success=Laporan sistem telah dihapus. + [action] create_repo=repositori dibuat <a href="%s">%s</a> rename_repo=ganti nama gudang penyimpanan dari <code>%[1]s</code> ke <a href="%[2]s">%[3]s</a> diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index a51b8c0a44..fb39bfbf3d 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -402,6 +402,7 @@ team_not_exist=Liðið er ekki til. + [user] change_avatar=Breyttu notandamyndinni þinni… repositories=Hugbúnaðarsöfn @@ -990,6 +991,8 @@ activity.git_stats_and_deletions=og activity.git_stats_deletion_1=%d eyðing activity.git_stats_deletion_n=%d eyðingar +contributors.contribution_type.commits=Framlög + search=Leita search.fuzzy=Óljóst search.code_no_results=Enginn samsvarandi frumkóði fannst eftur þínum leitarorðum. @@ -1114,6 +1117,8 @@ topic.done=Í lagi +[graphs] + [org] repo_updated=Uppfært members=Meðlimar @@ -1280,6 +1285,7 @@ notices.type_1=Hugbúnaðarsafn notices.type_2=Verkefni notices.desc=Lýsing + [action] create_issue=`opnaði vandamál <a href="%[1]s">%[3]s#%[2]s</a>` reopen_issue=`enduropnaði vandamál <a href="%[1]s">%[3]s#%[2]s</a>` diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 191242731c..49f4288b7d 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -491,6 +491,7 @@ auth_failed=Autenticazione non riuscita: %v target_branch_not_exist=Il ramo (branch) di destinazione non esiste. + [user] change_avatar=Modifica il tuo avatar… repositories=Repository @@ -1624,6 +1625,8 @@ activity.git_stats_and_deletions=e activity.git_stats_deletion_1=%d cancellazione activity.git_stats_deletion_n=%d cancellazioni +contributors.contribution_type.commits=Commit + search=Ricerca search.search_repo=Ricerca repository search.fuzzy=Fuzzy @@ -2119,6 +2122,8 @@ error.csv.too_large=Impossibile visualizzare questo file perché è troppo grand error.csv.unexpected=Impossibile visualizzare questo file perché contiene un carattere inatteso alla riga %d e alla colonna %d. error.csv.invalid_field_count=Impossibile visualizzare questo file perché ha un numero errato di campi alla riga %d. +[graphs] + [org] org_name_holder=Nome dell'Organizzazione org_full_name_holder=Nome completo dell'organizzazione @@ -2705,6 +2710,7 @@ notices.desc=Descrizione notices.op=Op. notices.delete_success=Gli avvisi di sistema sono stati eliminati. + [action] create_repo=ha creato il repository <a href="%s">%s</a> rename_repo=repository rinominato da <code>%[1]s</code> a <a href="%[2]s">[3]s</a> diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index ba0813ace4..8b8cb352ff 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -599,6 +599,7 @@ target_branch_not_exist=ターゲットのブランチが存在していませ admin_cannot_delete_self = 管理者である場合、自分自身を削除することはできません。最初に管理者権限を削除してください。 username_error_no_dots = `英数字 (「0-9」、「a-z」、「A-Z」)、ダッシュ (「-」)、およびアンダースコア (「_」) のみを含めることができます。英数字以外の文字で開始または終了することはできず、連続した英数字以外の文字も禁止されています。` + [user] change_avatar=アバターを変更… joined_on=%sに登録 @@ -1986,6 +1987,8 @@ activity.git_stats_and_deletions=、 activity.git_stats_deletion_1=%d行削除 activity.git_stats_deletion_n=%d行削除 +contributors.contribution_type.commits=コミット + search=検索 search.search_repo=リポジトリを検索 search.type.tooltip=検索タイプ @@ -2589,6 +2592,8 @@ admin.enabled_flags = このリポジトリで有効になっているフラグ clone_in_vscodium = VSCodiumでcloneする desc.sha256 = SHA256 +[graphs] + [org] org_name_holder=組織名 org_full_name_holder=組織のフルネーム @@ -3240,6 +3245,7 @@ notices.desc=説明 notices.op=操作 notices.delete_success=システム通知を削除しました。 + [action] create_repo=がリポジトリ <a href="%s">%s</a> を作成しました rename_repo=がリポジトリ名を <code>%[1]s</code> から <a href="%[2]s">%[3]s</a> へ変更しました @@ -3424,6 +3430,8 @@ rpm.registry=このレジストリをコマンドラインからセットアッ rpm.distros.redhat=RedHat系ディストリビューションの場合 rpm.distros.suse=SUSE系ディストリビューションの場合 rpm.install=パッケージをインストールするには、次のコマンドを実行します: +rpm.repository=リポジトリ情報 +rpm.repository.architectures=Architectures rubygems.install=gem を使用してパッケージをインストールするには、次のコマンドを実行します: rubygems.install2=または Gemfile に追加します: rubygems.dependencies.runtime=実行用依存関係 @@ -3556,8 +3564,6 @@ runs.actors_no_select=すべてのアクター runs.status_no_select=すべてのステータス runs.no_results=一致する結果はありません。 runs.no_workflows=ワークフローはまだありません。 -runs.no_workflows.quick_start=Forgejo Action の始め方がわからない? <a target="_blank" rel="noopener noreferrer" href="%s">クイックスタートガイド</a>をご覧ください。 -runs.no_workflows.documentation=Forgejo Action の詳細については、<a target="_blank" rel="noopener noreferrer" href="%s">ドキュメント</a>を参照してください。 runs.no_runs=ワークフローはまだ実行されていません。 runs.empty_commit_message=(空のコミットメッセージ) @@ -3576,7 +3582,6 @@ variables.none=変数はまだありません。 variables.deletion=変数を削除 variables.deletion.description=変数の削除は恒久的で元に戻すことはできません。 続行しますか? variables.description=変数は特定のActionsに渡されます。 それ以外で読み出されることはありません。 -variables.id_not_exist=idが%dの変数は存在しません。 variables.edit=変数の編集 variables.deletion.failed=変数を削除できませんでした。 variables.deletion.success=変数を削除しました。 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index b10f146759..89ea2f3335 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -350,6 +350,7 @@ auth_failed=인증 실패: %v target_branch_not_exist=대상 브랜치가 존재하지 않습니다. + [user] change_avatar=아바타 변경 repositories=저장소 @@ -950,6 +951,8 @@ activity.title.releases_n=%d 개의 릴리즈 activity.title.releases_published_by=%s 가 %s 에 의하여 배포되었습니다. activity.published_release_label=배포됨 +contributors.contribution_type.commits=커밋 + search=검색 search.search_repo=저장소 검색 search.results="<a href=\"%s\">%s</a> 에서 \"%s\" 에 대한 검색 결과" @@ -1162,6 +1165,8 @@ topic.count_prompt=25개 이상의 토픽을 선택하실 수 없습니다. +[graphs] + [org] org_name_holder=조직 이름 org_full_name_holder=조직 전체 이름 @@ -1522,6 +1527,7 @@ notices.desc=설명 notices.op=일. notices.delete_success=시스템 알림이 삭제되었습니다. + [action] create_repo=저장소를 만들었습니다. <a href="%s">%s</a> rename_repo=<code>%[1]s에서</code>에서 <a href="%[2]s"> %[3]s</a>으로 저장소 이름을 바꾸었습니다. diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 7dd7220b7a..15d24558df 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -589,6 +589,7 @@ org_still_own_packages=Šai organizācijai pieder viena vai vārākas pakotnes, target_branch_not_exist=Mērķa atzars neeksistē + [user] change_avatar=Mainīt profila attēlu… joined_on=Pievienojās %s @@ -1967,6 +1968,8 @@ activity.git_stats_and_deletions=un activity.git_stats_deletion_1=%d dzēšana activity.git_stats_deletion_n=%d dzēšanas +contributors.contribution_type.commits=Revīzijas + search=Meklēt search.search_repo=Meklēšana repozitorijā search.type.tooltip=Meklēšanas veids @@ -2567,6 +2570,8 @@ error.csv.too_large=Nevar attēlot šo failu, jo tas ir pārāk liels. error.csv.unexpected=Nevar attēlot šo failu, jo tas satur neparedzētu simbolu %d. līnijas %d. kolonnā. error.csv.invalid_field_count=Nevar attēlot šo failu, jo tas satur nepareizu skaitu ar laukiem %d. līnijā. +[graphs] + [org] org_name_holder=Organizācijas nosaukums org_full_name_holder=Organizācijas pilnais nosaukums @@ -3218,6 +3223,7 @@ notices.desc=Apraksts notices.op=Op. notices.delete_success=Sistēmas paziņojumi ir dzēsti. + [action] create_repo=izveidoja repozitoriju <a href="%s">%s</a> rename_repo=pārsauca repozitoriju no <code>%[1]s</code> uz <a href="%[2]s">%[3]s</a> @@ -3402,6 +3408,8 @@ rpm.registry=Konfigurējiet šo reģistru no komandrindas: rpm.distros.redhat=uz RedHat balstītās operētājsistēmās rpm.distros.suse=uz SUSE balstītās operētājsistēmās rpm.install=Lai uzstādītu pakotni, ir jāizpilda šī komanda: +rpm.repository=Repozitorija informācija +rpm.repository.architectures=Arhitektūras rubygems.install=Lai instalētu gem pakotni, izpildiet sekojošu komandu: rubygems.install2=vai pievienojiet Gemfile: rubygems.dependencies.runtime=Izpildlaika atkarības @@ -3534,8 +3542,6 @@ runs.actors_no_select=Visi aktori runs.status_no_select=Visi stāvokļi runs.no_results=Netika atrasts nekas atbilstošs. runs.no_workflows=Vēl nav nevienas darbplūsmas. -runs.no_workflows.quick_start=Nav skaidrs, kā sākt izmantot Gitea darbības? Skatīt <a target="_blank" rel="noopener noreferrer" href="%s">ātrās sākšanas norādes</a>. -runs.no_workflows.documentation=Vairāk informācijas par Gitea darbībām ir skatāma <a target="_blank" rel="noopener noreferrer" href="%s">dokumentācijā</a>. runs.no_runs=Darbplūsmai vēl nav nevienas izpildes. runs.empty_commit_message=(tukšs revīzijas ziņojums) @@ -3554,7 +3560,6 @@ variables.none=Vēl nav neviena mainīgā. variables.deletion=Noņemt mainīgo variables.deletion.description=Mainīgā noņemšana ir neatgriezeniska un nav atsaucama. Vai turpināt? variables.description=Mainīgie tiks padoti noteiktām darbībām, un citādāk tos nevar nolasīt. -variables.id_not_exist=Mainīgais ar identifikatoru %d neeksistē. variables.edit=Labot mainīgo variables.deletion.failed=Neizdevās noņemt mainīgo. variables.deletion.success=Mainīgais tika noņemts. diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 27f1273fe8..cf16f3dd17 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -601,6 +601,7 @@ invalid_group_team_map_error = ` mapping is ongeldig: %s" org_still_own_repo = Deze organisatie is eigenaar van één of meer repositories, verwijder of draag deze eerst over. org_still_own_packages = Deze organisatie is eigenaar van één of meer pakketten, verwijder deze eerst. + [user] change_avatar=Wijzig je profielfoto… repositories=repositories @@ -1807,6 +1808,8 @@ activity.git_stats_and_deletions=en activity.git_stats_deletion_1=%d verwijdering activity.git_stats_deletion_n=%d verwijderingen +contributors.contribution_type.commits=Commits + search=Zoek search.search_repo=Zoek repository search.fuzzy=Vergelijkbaar @@ -2643,6 +2646,8 @@ settings.convert_notices_1 = Deze bewerking zet de mirror om in een reguliere re +[graphs] + [org] org_name_holder=Organisatienaam org_full_name_holder=Volledige naam organisatie @@ -3304,6 +3309,7 @@ config.mailer_enable_helo = HELO inschakelen auths.oauth2_map_group_to_team_removal = Verwijder gebruikers uit gesynchroniseerde teams als de gebruiker niet tot de overeenkomstige groep behoort. config.mailer_config = Mailer configuratie + [action] create_repo=repository aangemaakt in <a href="%s">%s</a> rename_repo=hernoemde repository van <code>%[1]s</code> naar <a href="%[2]s">%[3]s</a> diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index c26a19d9e3..3b2fcd9ec0 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -492,6 +492,7 @@ auth_failed=Uwierzytelnienie się nie powiodło: %v target_branch_not_exist=Gałąź docelowa nie istnieje. + [user] change_avatar=Zmień swój awatar… repositories=Repozytoria @@ -1485,6 +1486,8 @@ activity.git_stats_and_deletions=i activity.git_stats_deletion_1=%d usunięcie activity.git_stats_deletion_n=%d usunięć +contributors.contribution_type.commits=Commity + search=Szukaj search.search_repo=Przeszukaj repozytorium search.fuzzy=Fuzzy @@ -1917,6 +1920,8 @@ error.csv.too_large=Nie można wyświetlić tego pliku, ponieważ jest on zbyt d error.csv.unexpected=Nie można renderować tego pliku, ponieważ zawiera nieoczekiwany znak w wierszu %d i kolumnie %d. error.csv.invalid_field_count=Nie można renderować tego pliku, ponieważ ma nieprawidłową liczbę pól w wierszu %d. +[graphs] + [org] org_name_holder=Nazwa organizacji org_full_name_holder=Pełna nazwa organizacji @@ -2443,6 +2448,7 @@ notices.desc=Opis notices.op=Operacja notices.delete_success=Powiadomienia systemu zostały usunięte. + [action] create_repo=tworzy repozytorium <a href="%s">%s</a> rename_repo=zmienia nazwę repozytorium <code>%[1]s</code> na <a href="%[2]s">%[3]s</a> diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 0eec655460..f9651e89b7 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -599,6 +599,7 @@ target_branch_not_exist=O branch de destino não existe. username_error_no_dots = ` pode conter apenas caracteres alfanuméricos ("0-9, "a-z", "A-Z"), hífens ("-") e traços inferiores ("_"). Não é permitido conter caracteres não alfanuméricos no início ou fim e caracteres não alfanuméricos consecutivos.` admin_cannot_delete_self = Você não pode excluir a si mesmo quando você é um administrador. Por favor, remova suas permissões de administrador primeiro. + [user] change_avatar=Altere seu avatar... joined_on=Inscreveu-se em %s @@ -1960,6 +1961,8 @@ activity.git_stats_and_deletions=e activity.git_stats_deletion_1=%d exclusão activity.git_stats_deletion_n=%d exclusões +contributors.contribution_type.commits=Commits + search=Pesquisar search.search_repo=Pesquisar no repositório... search.type.tooltip=Tipo de pesquisa @@ -2566,6 +2569,8 @@ editor.invalid_commit_mail = E-mail inválido para criar um commit. issues.role.contributor_helper = Este usuário fez commits para o repositório anteriormente. issues.choose.invalid_config = A configuração de issue contém erros: +[graphs] + [org] org_name_holder=Nome da organização org_full_name_holder=Nome completo da organização @@ -3202,6 +3207,7 @@ emails.change_email_text = Tem certeza de que deseja atualizar este endereço de self_check = Autodiagnóstico auths.tip.gitea = Registre um novo aplicativo OAuth2. A documentação pode ser encontrada em https://forgejo.org/docs/latest/user/oauth2-provider/ + [action] create_repo=criou o repositório <a href="%s">%s</a> rename_repo=renomeou o repositório <code>%[1]s</code> para <a href="%[2]s">%[3]s</a> @@ -3385,6 +3391,8 @@ rpm.registry=Configure este registro pela linha de comando: rpm.distros.redhat=em distribuições baseadas no RedHat rpm.distros.suse=em distribuições baseadas no SUSE rpm.install=Para instalar o pacote, execute o seguinte comando: +rpm.repository=Informações do repositório +rpm.repository.architectures=Arquiteturas rubygems.install=Para instalar o pacote usando gem, execute o seguinte comando: rubygems.install2=ou adicione-o ao Gemfile: rubygems.dependencies.runtime=Dependências de Execução diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 0a6eb11365..1d2335dbab 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -124,6 +124,7 @@ pin=Fixar unpin=Desafixar artifacts=Artefactos +confirm_delete_artifact=Tem a certeza que quer eliminar este artefacto "%s"? archived=Arquivado @@ -424,6 +425,7 @@ authorization_failed_desc=A autorização falhou porque encontrámos um pedido i sspi_auth_failed=Falhou a autenticação SSPI password_pwned=A senha utilizada está numa <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">lista de senhas roubadas</a> anteriormente expostas em fugas de dados públicas. Tente novamente com uma senha diferente e considere também mudar esta senha nos outros sítios. password_pwned_err=Não foi possível completar o pedido ao HaveIBeenPwned +last_admin=Não pode remover o último administrador. Tem que existir pelo menos um administrador. [mail] view_it_on=Ver em %s @@ -589,6 +591,8 @@ org_still_own_packages=Esta organização ainda possui um ou mais pacotes, elimi target_branch_not_exist=O ramo de destino não existe. +admin_cannot_delete_self=Não se pode auto-remover quando tem privilégios de administração. Remova esses privilégios primeiro. + [user] change_avatar=Mude o seu avatar… joined_on=Inscreveu-se em %s @@ -968,6 +972,8 @@ issue_labels_helper=Escolha um conjunto de rótulos para as questões. license=Licença license_helper=Escolha um ficheiro de licença. license_helper_desc=Uma licença rege o que os outros podem, ou não, fazer com o seu código fonte. Não tem a certeza sobre qual a mais indicada para o seu trabalho? Veja: <a target="_blank" rel="noopener noreferrer" href="%s">Escolher uma licença.</a> +object_format=Formato dos elementos +object_format_helper=Formato dos elementos do repositório. Não poderá ser alterado mais tarde. SHA1 é o mais compatível. readme=README readme_helper=Escolha um modelo de ficheiro README. readme_helper_desc=Este é o sítio onde pode escrever uma descrição completa do seu trabalho. @@ -985,6 +991,7 @@ mirror_prune=Podar mirror_prune_desc=Remover referências obsoletas de seguimento remoto mirror_interval=Intervalo entre sincronizações (as unidades de tempo válidas são 'h', 'm' e 's'). O valor zero desabilita a sincronização periódica. (Intervalo mínimo: %s) mirror_interval_invalid=O intervalo entre sincronizações não é válido. +mirror_sync=sincronizado mirror_sync_on_commit=Sincronizar quando forem enviados cometimentos mirror_address=Clonar a partir do URL mirror_address_desc=Coloque, na secção de autorização, as credenciais que, eventualmente, sejam necessárias. @@ -1035,6 +1042,7 @@ desc.public=Público desc.template=Modelo desc.internal=Interno desc.archived=Arquivado +desc.sha256=SHA256 template.items=Itens do modelo template.git_content=Conteúdo Git (ramo principal) @@ -1185,6 +1193,8 @@ audio_not_supported_in_browser=O seu navegador não suporta a etiqueta 'audio' d stored_lfs=Armazenado com Git LFS symbolic_link=Ligação simbólica executable_file=Ficheiro executável +vendored=Externo +generated=Gerado commit_graph=Gráfico de cometimentos commit_graph.select=Escolher ramos commit_graph.hide_pr_refs=Ocultar pedidos de integração @@ -1708,6 +1718,7 @@ pulls.select_commit_hold_shift_for_range=Escolha o comentimento. Mantenha premid pulls.review_only_possible_for_full_diff=A revisão só é possível ao visualizar o diff completo pulls.filter_changes_by_commit=Filtrar por cometimento pulls.nothing_to_compare=Estes ramos são iguais. Não há necessidade de criar um pedido de integração. +pulls.nothing_to_compare_have_tag=O ramo/etiqueta escolhidos são iguais. pulls.nothing_to_compare_and_allow_empty_pr=Estes ramos são iguais. Este pedido de integração ficará vazio. pulls.has_pull_request=`Já existe um pedido de integração entre estes ramos: <a href="%[1]s">%[2]s#%[3]d</a>` pulls.create=Criar um pedido de integração @@ -1766,6 +1777,7 @@ pulls.merge_pull_request=Criar um cometimento de integração pulls.rebase_merge_pull_request=Mudar a base e avançar rapidamente pulls.rebase_merge_commit_pull_request=Mudar a base e criar um cometimento de integração pulls.squash_merge_pull_request=Criar cometimento de compactação +pulls.fast_forward_only_merge_pull_request=Avançar rapidamente apenas pulls.merge_manually=Integrado manualmente pulls.merge_commit_id=O ID de cometimento da integração pulls.require_signed_wont_sign=O ramo requer que os cometimentos sejam assinados mas esta integração não vai ser assinada @@ -1902,6 +1914,8 @@ wiki.page_name_desc=Insira um nome para esta página Wiki. Alguns dos nomes espe wiki.original_git_entry_tooltip=Ver o ficheiro Git original, ao invés de usar uma ligação amigável. activity=Trabalho +activity.navbar.pulse=Pulso +activity.navbar.contributors=Contribuidores activity.period.filter_label=Período: activity.period.daily=1 dia activity.period.halfweekly=3 dias @@ -1967,6 +1981,11 @@ activity.git_stats_and_deletions=e activity.git_stats_deletion_1=%d eliminação activity.git_stats_deletion_n=%d eliminações +contributors.contribution_type.filter_label=Tipo de contribuição: +contributors.contribution_type.commits=Cometimentos +contributors.contribution_type.additions=Adições +contributors.contribution_type.deletions=Eliminações + search=Procurar search.search_repo=Procurar repositório search.type.tooltip=Tipo de pesquisa @@ -2004,6 +2023,7 @@ settings.mirror_settings.docs.doc_link_title=Como é que eu replico repositório settings.mirror_settings.docs.doc_link_pull_section=a parte "Puxar de um repositório remoto" da documentação. settings.mirror_settings.docs.pulling_remote_title=Puxando a partir de um repositório remoto settings.mirror_settings.mirrored_repository=Repositório replicado +settings.mirror_settings.pushed_repository=Repositório enviado settings.mirror_settings.direction=Sentido settings.mirror_settings.direction.pull=Puxada settings.mirror_settings.direction.push=Envio @@ -2314,6 +2334,8 @@ settings.protect_approvals_whitelist_users=Revisores com permissão: settings.protect_approvals_whitelist_teams=Equipas com permissão para rever: settings.dismiss_stale_approvals=Descartar aprovações obsoletas settings.dismiss_stale_approvals_desc=Quando novos cometimentos que mudam o conteúdo do pedido de integração forem enviados para o ramo, as aprovações antigas serão descartadas. +settings.ignore_stale_approvals=Ignorar aprovações obsoletas +settings.ignore_stale_approvals_desc=Não contar as aprovações feitas em cometimentos mais antigos (revisões obsoletas) para o número de aprovações do pedido de integração. É irrelevante se as revisões obsoletas já forem descartadas. settings.require_signed_commits=Exigir cometimentos assinados settings.require_signed_commits_desc=Rejeitar envios para este ramo que não estejam assinados ou que não sejam validáveis. settings.protect_branch_name_pattern=Padrão do nome do ramo protegido @@ -2369,6 +2391,7 @@ settings.archive.error=Ocorreu um erro enquanto decorria o processo de arquivo d settings.archive.error_ismirror=Não pode arquivar um repositório que tenha sido replicado. settings.archive.branchsettings_unavailable=As configurações dos ramos não estão disponíveis quando o repositório está arquivado. settings.archive.tagsettings_unavailable=As configurações sobre etiquetas não estão disponíveis quando o repositório está arquivado. +settings.archive.mirrors_unavailable=As réplicas não estão disponíveis se o repositório estiver arquivado. settings.unarchive.button=Desarquivar repositório settings.unarchive.header=Desarquivar este repositório settings.unarchive.text=Desarquivar o repositório irá restaurar a capacidade de receber cometimentos e envios, assim como novas questões e pedidos de integração. @@ -2567,6 +2590,13 @@ error.csv.too_large=Não é possível apresentar este ficheiro por ser demasiado error.csv.unexpected=Não é possível apresentar este ficheiro porque contém um caractere inesperado na linha %d e coluna %d. error.csv.invalid_field_count=Não é possível apresentar este ficheiro porque tem um número errado de campos na linha %d. +[graphs] +component_loading=A carregar %s... +component_loading_failed=Não foi possível carregar %s +component_loading_info=Isto pode demorar um pouco… +component_failed_to_load=Ocorreu um erro inesperado. +contributors.what=contribuições + [org] org_name_holder=Nome da organização org_full_name_holder=Nome completo da organização @@ -2693,6 +2723,7 @@ teams.invite.description=Clique no botão abaixo para se juntar à equipa. [admin] dashboard=Painel de controlo +self_check=Auto-verificação identity_access=Identidade e acesso users=Contas de utilizador organizations=Organizações @@ -2738,6 +2769,7 @@ dashboard.delete_missing_repos=Eliminar todos os repositórios que não tenham o dashboard.delete_missing_repos.started=Foi iniciada a tarefa de eliminação de todos os repositórios que não têm ficheiros git. dashboard.delete_generated_repository_avatars=Eliminar avatares gerados do repositório dashboard.sync_repo_branches=Sincronizar ramos perdidos de dados do git para bases de dados +dashboard.sync_repo_tags=Sincronizar etiquetas dos dados do git para a base de dados dashboard.update_mirrors=Sincronizar réplicas dashboard.repo_health_check=Verificar a saúde de todos os repositórios dashboard.check_repo_stats=Verificar as estatísticas de todos os repositórios @@ -2792,6 +2824,7 @@ dashboard.stop_endless_tasks=Parar tarefas intermináveis dashboard.cancel_abandoned_jobs=Cancelar trabalhos abandonados dashboard.start_schedule_tasks=Iniciar tarefas de agendamento dashboard.sync_branch.started=Sincronização de ramos iniciada +dashboard.sync_tag.started=Sincronização de etiquetas iniciada dashboard.rebuild_issue_indexer=Reconstruir indexador de questões users.user_manage_panel=Gestão das contas de utilizadores @@ -3218,6 +3251,13 @@ notices.desc=Descrição notices.op=Op. notices.delete_success=As notificações do sistema foram eliminadas. +self_check.no_problem_found=Nenhum problema encontrado até agora. +self_check.database_collation_mismatch=Supor que a base de dados usa a colação: %s +self_check.database_collation_case_insensitive=A base de dados está a usar a colação %s, que é insensível à diferença entre maiúsculas e minúsculas. Embora o Gitea possa trabalhar com ela, pode haver alguns casos raros que não funcionem como esperado. +self_check.database_inconsistent_collation_columns=A base de dados está a usar a colação %s, mas estas colunas estão a usar colações diferentes. Isso poderá causar alguns problemas inesperados. +self_check.database_fix_mysql=Para utilizadores do MySQL/MariaDB, pode usar o comando "gitea doctor convert" para resolver os problemas de colação. Também pode resolver o problema com comandos SQL "ALTER ... COLLATE ..." aplicados manualmente. +self_check.database_fix_mssql=Para utilizadores do MSSQL só pode resolver o problema aplicando comandos SQL "ALTER ... COLLATE ..." manualmente, por enquanto. + [action] create_repo=criou o repositório <a href="%s">%s</a> rename_repo=renomeou o repositório de <code>%[1]s</code> para <a href="%[2]s">%[3]s</a> @@ -3402,6 +3442,9 @@ rpm.registry=Configurar este registo usando a linha de comandos: rpm.distros.redhat=em distribuições baseadas no RedHat rpm.distros.suse=em distribuições baseadas no SUSE rpm.install=Para instalar o pacote, execute o seguinte comando: +rpm.repository=Informação do repositório +rpm.repository.architectures=Arquitecturas +rpm.repository.multiple_groups=Este pacote está disponível em vários grupos. rubygems.install=Para instalar o pacote usando o gem, execute o seguinte comando: rubygems.install2=ou adicione-o ao ficheiro <code>Gemfile</code>: rubygems.dependencies.runtime=Dependências do tempo de execução (runtime) @@ -3534,8 +3577,6 @@ runs.actors_no_select=Todos os intervenientes runs.status_no_select=Todos os estados runs.no_results=Nenhum resultado obtido. runs.no_workflows=Ainda não há sequências de trabalho. -runs.no_workflows.quick_start=Não sabe como começar com o Forgejo Action? Veja o <a target="_blank" rel="noopener noreferrer" href="%s">guia de iniciação rápida</a>. -runs.no_workflows.documentation=Para mais informação sobre o Forgejo Action, veja <a target="_blank" rel="noopener noreferrer" href="%s">a documentação</a>. runs.no_runs=A sequência de trabalho ainda não foi executada. runs.empty_commit_message=(mensagem de cometimento vazia) @@ -3554,7 +3595,7 @@ variables.none=Ainda não há variáveis. variables.deletion=Remover variável variables.deletion.description=Remover uma variável é permanente e não pode ser revertido. Quer continuar? variables.description=As variáveis serão transmitidas a certas operações e não poderão ser lidas de outra forma. -variables.id_not_exist=A variável com o id %d não existe. +variables.id_not_exist=A variável com o ID %d não existe. variables.edit=Editar variável variables.deletion.failed=Falha ao remover a variável. variables.deletion.success=A variável foi removida. diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 301dfce750..a7234f958c 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -601,6 +601,7 @@ target_branch_not_exist=Целевая ветка не существует. admin_cannot_delete_self = Вы не можете удалить свою учётную запись, будучи администратором. Сперва снимите с себя роль администратора. username_error_no_dots = ` может состоять только из латинских букв ('a-z','A-Z'), цифр ('0-9'), знаков минуса ('-') и нижнего подчёркивания ('_'). Знаки не могут стоять в начале или в конце, а также идти подряд.` + [user] change_avatar=Изменить свой аватар… joined_on=Зарегистрирован(а) с %s @@ -1961,6 +1962,8 @@ activity.git_stats_and_deletions=и activity.git_stats_deletion_1=%d удаление activity.git_stats_deletion_n=%d удалений +contributors.contribution_type.commits=коммитов + search=Поиск search.search_repo=Поиск по репозиторию search.type.tooltip=Тип поиска @@ -2632,6 +2635,8 @@ pulls.commit_ref_at = `сослался(ась) на этот запрос сл settings.thread_id = ИД обсуждения pulls.made_using_agit = AGit +[graphs] + [org] org_name_holder=Название организации org_full_name_holder=Полное название организации @@ -3287,6 +3292,7 @@ dashboard.sync_repo_tags = Синхронизировать теги из git в self_check.database_collation_mismatch = Ожидается, что БД использует сопоставление: %s self_check = Самопроверка + [action] create_repo=создал(а) репозиторий <a href="%s"> %s</a> rename_repo=переименовал(а) репозиторий из <code>%[1]s</code> на <a href="%[2]s">%[3]s</a> @@ -3471,6 +3477,8 @@ rpm.registry=Настроить реестр из командной строк rpm.distros.redhat=на дистрибутивах семейства RedHat rpm.distros.suse=на дистрибутивах семейства SUSE rpm.install=Чтобы установить пакет, выполните следующую команду: +rpm.repository=О репозитории +rpm.repository.architectures=Архитектуры rubygems.install=Чтобы установить пакет с помощью gem, выполните следующую команду: rubygems.install2=или добавьте его в Gemfile: rubygems.dependencies.runtime=Зависимости времени выполнения @@ -3603,8 +3611,6 @@ runs.status=Статус runs.actors_no_select=Все акторы runs.no_results=Ничего не найдено. runs.no_workflows=Пока нет рабочих процессов. -runs.no_workflows.quick_start=Не знаете, как начать использовать Действия Forgejo? Читайте <a target="_blank" rel="noopener noreferrer" href="%s">руководство по быстрому старту</a>. -runs.no_workflows.documentation=Чтобы узнать больше о Действиях Forgejo, читайте <a target="_blank" rel="noopener noreferrer" href="%s">документацию</a>. runs.no_runs=Рабочий поток ещё не запускался. runs.empty_commit_message=(пустое сообщение коммита) @@ -3623,7 +3629,6 @@ variables.none=Переменных пока нет. variables.deletion=Удалить переменную variables.deletion.description=Удаление переменной необратимо, его нельзя отменить. Продолжить? variables.description=Переменные будут передаваться определенным действиям и не могут быть прочитаны иначе. -variables.id_not_exist=Переменная с идентификатором %d не существует. variables.edit=Изменить переменную variables.deletion.failed=Не удалось удалить переменную. variables.deletion.success=Переменная удалена. diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index 885907df15..318eb24df8 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -451,6 +451,7 @@ auth_failed=සත්යාපන අසමත් විය: %v target_branch_not_exist=ඉලක්කගත ශාඛාව නොපවතී. + [user] change_avatar=ඔබගේ අවතාරය වෙනස් කරන්න… repositories=කෝෂ්ඨ @@ -1460,6 +1461,8 @@ activity.git_stats_and_deletions=සහ activity.git_stats_deletion_1=%d මකාදැමීම activity.git_stats_deletion_n=%d මකාදැමීම් +contributors.contribution_type.commits=විවරයන් + search=සොයන්න search.search_repo=කෝෂ්ඨය සොයන්න search.fuzzy=සිනිඳු @@ -1911,6 +1914,8 @@ error.csv.too_large=එය ඉතා විශාල නිසා මෙම ග error.csv.unexpected=%d පේළියේ සහ %dතීරුවේ අනපේක්ෂිත චරිතයක් අඩංගු බැවින් මෙම ගොනුව විදැහුම්කරණය කළ නොහැක. error.csv.invalid_field_count=මෙම ගොනුව රේඛාවේ වැරදි ක්ෂේත්ර සංඛ්යාවක් ඇති බැවින් එය විදැහුම්කරණය කළ නොහැක %d. +[graphs] + [org] org_name_holder=සංවිධානයේ නම org_full_name_holder=සංවිධානයේ සම්පූර්ණ නම @@ -2457,6 +2462,7 @@ notices.desc=සවිස්තරය notices.op=ඔප්. notices.delete_success=පද්ධති දැන්වීම් මකා දමා ඇත. + [action] create_repo=නිර්මිත ගබඩාව <a href="%s">%s</a> rename_repo=<code>%[1]s</code> සිට <a href="%[2]s">%[3]s</a>දක්වා නම් කරන ලද ගබඩාව diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini index c8fe29e56d..758b01573d 100644 --- a/options/locale/locale_sk-SK.ini +++ b/options/locale/locale_sk-SK.ini @@ -564,6 +564,7 @@ auth_failed=Overenie zlyhalo: %v target_branch_not_exist=Cieľová vetva neexistuje. + [user] change_avatar=Zmeniť svoj avatar… joined_on=Pripojil/a sa %s @@ -1145,6 +1146,8 @@ activity.unresolved_conv_label=Otvoriť activity.git_stats_commit_1=%d commit activity.git_stats_commit_n=%d commity +contributors.contribution_type.commits=Commitov + search=Hľadať search.type.tooltip=Typ vyhľadávania search.fuzzy=Fuzzy @@ -1248,6 +1251,8 @@ release.cancel=Zrušiť +[graphs] + [org] code=Kód lower_repositories=repozitáre @@ -1330,6 +1335,7 @@ monitor.process.cancel=Zrušiť proces + [action] compare_commits=Porovnať %d commitov compare_commits_general=Porovnať commity diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 2e520b3b84..5c5736013c 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -391,6 +391,7 @@ auth_failed=Autentisering misslyckades: %v target_branch_not_exist=Målgrenen finns inte. + [user] change_avatar=Byt din avatar… repositories=Utvecklingskataloger @@ -1228,6 +1229,8 @@ activity.git_stats_and_deletions=och activity.git_stats_deletion_1=%d borttagen activity.git_stats_deletion_n=%d borttagningar +contributors.contribution_type.commits=Incheckningar + search=Sök search.search_repo=Sök utvecklingskatalog search.results=Sökresultat för ”%s” i <a href="%s"> %s</a> @@ -1536,6 +1539,8 @@ topic.count_prompt=Du kan inte välja fler än 25 ämnen +[graphs] + [org] org_name_holder=Organisationsnamn org_full_name_holder=Organisationens Fullständiga Namn @@ -1972,6 +1977,7 @@ notices.desc=Beskrivning notices.op=Op. notices.delete_success=Systemnotifikationer har blivit raderade. + [action] create_repo=skapade utvecklingskatalog <a href="%s"> %s</a> rename_repo=döpte om utvecklingskalatogen från <code>%[1]s</code> till <a href="%[2]s">%[3]s</a> diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 6edc30d1f8..27accb4e03 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -589,6 +589,7 @@ org_still_own_packages=Bu organizasyon hala bir veya daha fazla pakete sahip, ö target_branch_not_exist=Hedef dal mevcut değil. + [user] change_avatar=Profil resmini değiştir… joined_on=%s tarihinde katıldı @@ -1967,6 +1968,8 @@ activity.git_stats_and_deletions=ve activity.git_stats_deletion_1=%d silme oldu activity.git_stats_deletion_n=%d silme oldu +contributors.contribution_type.commits=İşleme + search=Ara search.search_repo=Depo ara search.type.tooltip=Arama türü @@ -2567,6 +2570,8 @@ error.csv.too_large=Bu dosya çok büyük olduğu için işlenemiyor. error.csv.unexpected=%d satırı ve %d sütununda beklenmeyen bir karakter içerdiğinden bu dosya işlenemiyor. error.csv.invalid_field_count=%d satırında yanlış sayıda alan olduğundan bu dosya işlenemiyor. +[graphs] + [org] org_name_holder=Organizasyon Adı org_full_name_holder=Organizasyon Tam Adı @@ -3218,6 +3223,7 @@ notices.desc=Açıklama notices.op=İşlem notices.delete_success=Sistem bildirimleri silindi. + [action] create_repo=depo <a href="%s">%s</a> oluşturuldu rename_repo=<code>%[1]s</code> olan depo adını <a href="%[2]s">%[3]s</a> buna çevirdi @@ -3402,6 +3408,8 @@ rpm.registry=Bu kütüğü komut satırını kullanarak kurun: rpm.distros.redhat=RedHat tabanlı dağıtımlarda rpm.distros.suse=SUSE tabanlı dağıtımlarda rpm.install=Paketi kurmak için, aşağıdaki komutu çalıştırın: +rpm.repository=Depo Bilgisi +rpm.repository.architectures=Mimariler rubygems.install=Paketi gem ile kurmak için, şu komutu çalıştırın: rubygems.install2=veya paketi Gemfile dosyasına ekleyin: rubygems.dependencies.runtime=Çalışma Zamanı Bağımlılıkları @@ -3534,8 +3542,6 @@ runs.actors_no_select=Tüm aktörler runs.status_no_select=Tüm durumlar runs.no_results=Eşleşen sonuç yok. runs.no_workflows=Henüz hiç bir iş akışı yok. -runs.no_workflows.quick_start=Gitea İşlem'i nasıl başlatacağınızı bilmiyor musunuz? <a target="_blank" rel="noopener noreferrer" href="%s">Hızlı başlangıç rehberine</a> bakabilirsiniz. -runs.no_workflows.documentation=Gitea İşlem'i hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="%s">belgeye</a> bakabilirsiniz. runs.no_runs=İş akışı henüz hiç çalıştırılmadı. runs.empty_commit_message=(boş işleme iletisi) @@ -3554,7 +3560,6 @@ variables.none=Henüz hiçbir değişken yok. variables.deletion=Değişkeni kaldır variables.deletion.description=Bir değişkeni kaldırma kalıcıdır ve geri alınamaz. Devam edilsin mi? variables.description=Değişkenler belirli işlemlere aktarılacaktır, bunun dışında okunamaz. -variables.id_not_exist=%d kimlikli değişken mevcut değil. variables.edit=Değişkeni Düzenle variables.deletion.failed=Değişken kaldırılamadı. variables.deletion.success=Değişken kaldırıldı. diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 376e7efb9e..a5a2050577 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -518,6 +518,7 @@ auth_failed=Помилка автентифікації: %v target_branch_not_exist=Цільової гілки не існує. + [user] change_avatar=Змінити свій аватар… repositories=Репозиторії @@ -1577,6 +1578,8 @@ activity.git_stats_and_deletions=та activity.git_stats_deletion_1=%d видалений activity.git_stats_deletion_n=%d видалені +contributors.contribution_type.commits=Коміти + search=Пошук search.search_repo=Пошук репозиторію search.fuzzy=Неточний @@ -2068,6 +2071,8 @@ commit.cherry-pick-content = Оберіть гілку, на яку висмик pulls.expand_files = Розгорнути всі файли pulls.collapse_files = Згорнути всі файли +[graphs] + [org] org_name_holder=Назва організації org_full_name_holder=Повна назва організації @@ -2626,6 +2631,7 @@ packages.package_manage_panel = Менеджмент Пакунків packages.published = Опубліковано notices.operations = Дії + [action] create_repo=створив(ла) репозиторій <a href="%s">%s</a> rename_repo=репозиторій перейменовано з <code>%[1]s</code> на <a href="%[2]s">%[3]s</a> diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 47bcf2639a..2265611004 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -124,6 +124,7 @@ pin=固定 unpin=取消置顶 artifacts=制品 +confirm_delete_artifact=您确定要删除制品'%s'吗? archived=已归档 @@ -426,10 +427,7 @@ authorization_failed_desc=因为检测到无效请求,授权失败。请尝试 sspi_auth_failed=SSPI 认证失败 password_pwned=此密码出现在 <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">被盗密码</a> 列表上并且曾经被公开。 请使用另一个密码再试一次。 password_pwned_err=无法完成对 HaveIBeenPwned 的请求 -change_unconfirmed_email_summary = 修改用来接收激活邮件的邮箱地址。 -change_unconfirmed_email_error = 无法修改邮箱地址: %v -change_unconfirmed_email = 如果您在注册时提供了错误的邮箱地址,您可以在下方修改,激活邮件会发送到修改后的邮箱地址。 -last_admin = 您无法删除唯一的管理员。您至少需要有一个管理员。 +last_admin=您不能删除最后一个管理员。必须至少保留一个管理员。 [mail] view_it_on=在 %s 上查看 @@ -600,6 +598,8 @@ target_branch_not_exist=目标分支不存在。 username_error_no_dots = ` 只能包含英文字母与数字 ('0-9','a-z','A-Z'), 连字符 ('-') 与下划线 ('_')。 开头与结尾的字符只能使用英文字母或数字,且不能包含连续的非字母非数字字符。` admin_cannot_delete_self = 您无法以管理员的身份删除自己。请先移除您的管理员权限。 +admin_cannot_delete_self=当您是管理员时,您不能删除自己。请先移除您的管理员权限 + [user] change_avatar=修改头像 joined_on=加入于 %s @@ -992,6 +992,8 @@ issue_labels_helper=选择一个工单标签集 license=授权许可 license_helper=选择授权许可文件。 license_helper_desc=许可证说明了其他人可以和不可以用您的代码做什么。不确定哪一个适合你的项目?见 <a target="_blank" rel="noopener noreferrer" href="%s">选择一个许可证</a> +object_format=对象格式 +object_format_helper=仓库的对象格式。之后无法更改。SHA1 是最兼容的。 readme=自述 readme_helper=选择自述文件模板。 readme_helper_desc=这是您可以为您的项目撰写完整描述的地方。 @@ -1009,6 +1011,7 @@ mirror_prune=修剪 mirror_prune_desc=删除过时的远程跟踪引用 mirror_interval=镜像间隔 (有效的时间单位是 'h', 'm', 's')。0 禁用自动定期同步 (最短间隔: %s) mirror_interval_invalid=镜像间隔无效。 +mirror_sync=已同步 mirror_sync_on_commit=推送提交时同步 mirror_address=从 URL 克隆 mirror_address_desc=在授权框中输入必要的凭据。 @@ -1059,6 +1062,7 @@ desc.public=公开 desc.template=模板 desc.internal=内部 desc.archived=已存档 +desc.sha256=SHA256 template.items=模板选项 template.git_content=Git数据(默认分支) @@ -1209,6 +1213,8 @@ audio_not_supported_in_browser=您的浏览器不支持使用 HTML5 'video' 标 stored_lfs=存储到Git LFS symbolic_link=符号链接 executable_file=可执行文件 +vendored=被供应的 +generated=已生成的 commit_graph=提交图 commit_graph.select=选择分支 commit_graph.hide_pr_refs=隐藏合并请求 @@ -1732,6 +1738,7 @@ pulls.select_commit_hold_shift_for_range=选择提交。按住 Shift + 单击选 pulls.review_only_possible_for_full_diff=只有在查看全部差异时才能进行审核 pulls.filter_changes_by_commit=按提交筛选 pulls.nothing_to_compare=分支内容相同,无需创建合并请求。 +pulls.nothing_to_compare_have_tag=所选分支/标签相同。 pulls.nothing_to_compare_and_allow_empty_pr=这些分支是相等的,此合并请求将为空。 pulls.has_pull_request=这些分支之间的合并请求已存在: <a href="%[1]s">%[2]s#%[3]d</a> pulls.create=创建合并请求 @@ -1926,6 +1933,7 @@ wiki.page_name_desc=输入此 Wiki 页面的名称。特殊名称有:'Home', ' wiki.original_git_entry_tooltip=查看原始的 Git 文件而不是使用友好链接。 activity=动态 +activity.navbar.contributors=贡献者 activity.period.filter_label=周期: activity.period.daily=1 天 activity.period.halfweekly=3 天 @@ -1991,6 +1999,11 @@ activity.git_stats_and_deletions=和 activity.git_stats_deletion_1=删除 %d 行 activity.git_stats_deletion_n=删除 %d 行 +contributors.contribution_type.filter_label=贡献类型: +contributors.contribution_type.commits=提交 +contributors.contribution_type.additions=更多 +contributors.contribution_type.deletions=删除 + search=搜索 search.search_repo=搜索仓库... search.type.tooltip=搜索类型 @@ -2028,6 +2041,7 @@ settings.mirror_settings.docs.doc_link_title=如何镜像仓库? settings.mirror_settings.docs.doc_link_pull_section=文档中的 “从远程仓库拉取” 部分。 settings.mirror_settings.docs.pulling_remote_title=从远程仓库拉取代码 settings.mirror_settings.mirrored_repository=镜像库 +settings.mirror_settings.pushed_repository=推送仓库 settings.mirror_settings.direction=方向 settings.mirror_settings.direction.pull=拉取 settings.mirror_settings.direction.push=推送 @@ -2338,6 +2352,8 @@ settings.protect_approvals_whitelist_users=审查者白名单: settings.protect_approvals_whitelist_teams=审查团队白名单: settings.dismiss_stale_approvals=取消过时的批准 settings.dismiss_stale_approvals_desc=当新的提交更改合并请求内容被推送到分支时,旧的批准将被撤销。 +settings.ignore_stale_approvals=忽略过期批准 +settings.ignore_stale_approvals_desc=对旧提交(过期审核)的批准将不计入 PR 的批准数。如果过期审查已被驳回,则与此无关。 settings.require_signed_commits=需要签名提交 settings.require_signed_commits_desc=拒绝推送未签名或无法验证的提交到分支 settings.protect_branch_name_pattern=受保护的分支名称模式 @@ -2393,6 +2409,7 @@ settings.archive.error=仓库在归档时出现异常。请通过日志获取详 settings.archive.error_ismirror=请不要对镜像仓库归档,谢谢! settings.archive.branchsettings_unavailable=已归档仓库无法进行分支设置。 settings.archive.tagsettings_unavailable=已归档仓库的Git标签设置不可用。 +settings.archive.mirrors_unavailable=如果仓库已被归档,镜像将不可用。 settings.unarchive.button=撤销仓库归档 settings.unarchive.header=撤销此仓库归档 settings.unarchive.text=撤销归档将恢复仓库接收提交、推送,以及新工单和合并请求的能力。 @@ -2634,6 +2651,13 @@ pulls.fast_forward_only_merge_pull_request = 仅快速向前 settings.units.overview = 概览 settings.units.add_more = 添加更多 +[graphs] +component_loading=正在加载 %s... +component_loading_failed=无法加载 %s +component_loading_info=这可能需要一点… +component_failed_to_load=意外的错误发生了。 +contributors.what=贡献 + [org] org_name_holder=组织名称 org_full_name_holder=组织全名 @@ -2761,6 +2785,7 @@ follow_blocked_user = 你无法关注此组织,因为此组织已屏蔽你。 [admin] dashboard=管理面板 +self_check=自我检查 identity_access=身份及认证 users=帐户管理 organizations=组织管理 @@ -2806,6 +2831,7 @@ dashboard.delete_missing_repos=删除所有丢失 Git 文件的仓库 dashboard.delete_missing_repos.started=删除所有丢失 Git 文件的仓库任务已启动。 dashboard.delete_generated_repository_avatars=删除生成的仓库头像 dashboard.sync_repo_branches=将缺少的分支从 git 数据同步到数据库 +dashboard.sync_repo_tags=从 git 数据同步标签到数据库 dashboard.update_mirrors=更新镜像仓库 dashboard.repo_health_check=健康检查所有仓库 dashboard.check_repo_stats=检查所有仓库统计 @@ -2860,6 +2886,7 @@ dashboard.stop_endless_tasks=停止永不停止的任务 dashboard.cancel_abandoned_jobs=取消丢弃的任务 dashboard.start_schedule_tasks=开始调度任务 dashboard.sync_branch.started=分支同步已开始 +dashboard.sync_tag.started=标签同步已开始 dashboard.rebuild_issue_indexer=重建工单索引 users.user_manage_panel=用户帐户管理 @@ -3295,6 +3322,11 @@ self_check.database_inconsistent_collation_columns = 数据库正在使用 %s self_check.database_fix_mysql = 对于 MySQL/MariaDB 用户,您可以使用 "gitea doctor convert" 命令来修复排序规则问题,也可以通过SQL命令 "ALTER ... COLLATE ..." 来手动修复问题。 self_check.database_fix_mssql = 对于 MSSQL 用户,目前您只能通过SQL命令 "ALTER ... COLLATE ..." 来手动修复问题。 +self_check.no_problem_found=尚未发现问题。 +self_check.database_collation_mismatch=期望数据库使用的校验方式:%s +self_check.database_collation_case_insensitive=数据库正在使用一个校验 %s, 这是一个不敏感的校验. 虽然Gitea可以与它合作,但可能有一些罕见的情况不如预期的那样起作用。 +self_check.database_fix_mysql=对于MySQL/MariaDB用户,您可以使用“gitea doctor convert”命令来解决校验问题。 或者您也可以通过 "ALTER ... COLLATE ..." 这样的SQL 来手动解决这个问题。 + [action] create_repo=创建了仓库 <a href="%s">%s</a> rename_repo=重命名仓库 <code>%[1]s</code> 为 <a href="%[2]s">%[3]s</a> @@ -3479,6 +3511,9 @@ rpm.registry=从命令行设置此注册中心: rpm.distros.redhat=在基于 RedHat 的发行版 rpm.distros.suse=在基于 SUSE 的发行版 rpm.install=要安装包,请运行以下命令: +rpm.repository=仓库信息 +rpm.repository.architectures=架构 +rpm.repository.multiple_groups=此软件包可在多个组中使用。 rubygems.install=要使用 gem 安装软件包,请运行以下命令: rubygems.install2=或将它添加到 Gemfile: rubygems.dependencies.runtime=运行时依赖 @@ -3614,8 +3649,8 @@ runs.actors_no_select=所有操作者 runs.status_no_select=所有状态 runs.no_results=没有匹配的结果。 runs.no_workflows=目前还没有工作流。 -runs.no_workflows.quick_start=不知道如何启动Gitea Action?请参阅 <a target="_blank" rel="noopener noreferrer" href="%s">快速启动指南</a> -runs.no_workflows.documentation=更多有关 Gitea Action 的信息,请访问 <a target="_blank" rel="noopener noreferrer" href="%s">文档</a>。 +runs.no_workflows.quick_start=不知道如何使用 Gitea Actions吗?请查看 <a target="_blank" rel="noopener noreferrer" href="%s">快速启动指南</a>。 +runs.no_workflows.documentation=关于Gitea Actions的更多信息,请参阅 <a target="_blank" rel="noopener noreferrer" href="%s">文档</a>。 runs.no_runs=工作流尚未运行过。 runs.empty_commit_message=(空白的提交消息) @@ -3634,7 +3669,7 @@ variables.none=目前还没有变量。 variables.deletion=删除变量 variables.deletion.description=删除变量是永久性的,无法撤消。继续吗? variables.description=变量将被传给特定的 Actions,其它情况将不能读取 -variables.id_not_exist=ID %d 变量不存在。 +variables.id_not_exist=ID为 %d 的变量不存在。 variables.edit=编辑变量 variables.deletion.failed=删除变量失败。 variables.deletion.success=变量已被删除。 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index b00c6e6b3d..289a3e7b5d 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -196,6 +196,7 @@ auth_failed=授權驗證失敗:%v target_branch_not_exist=目標分支不存在 + [user] repositories=儲存庫列表 activity=公開活動 @@ -538,6 +539,8 @@ activity.merged_prs_label=已合併 activity.closed_issue_label=已關閉 activity.new_issues_count_1=建立問題 +contributors.contribution_type.commits=提交歷史 + search=搜尋 settings=儲存庫設定 @@ -640,6 +643,8 @@ release.downloads=下載附件 +[graphs] + [org] org_name_holder=組織名稱 org_full_name_holder=組織全名 @@ -916,6 +921,7 @@ notices.desc=描述 notices.op=操作 notices.delete_success=已刪除系統提示。 + [action] create_repo=建立了儲存庫 <a href="%s">%s</a> rename_repo=重新命名儲存庫 <code>%[1]s</code> 為 <a href="%[2]s">%[3]s</a> diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 0cdf8f3ceb..e49be30691 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -556,6 +556,7 @@ org_still_own_packages=此組織仍然擁有一個以上的套件,請先刪除 target_branch_not_exist=目標分支不存在 + [user] change_avatar=更改大頭貼... repositories=儲存庫 @@ -1777,6 +1778,8 @@ activity.git_stats_and_deletions=和 activity.git_stats_deletion_1=刪除 %d 行 activity.git_stats_deletion_n=刪除 %d 行 +contributors.contribution_type.commits=提交歷史 + search=搜尋 search.search_repo=搜尋儲存庫 search.type.tooltip=搜尋類型 @@ -2323,6 +2326,8 @@ error.csv.too_large=無法渲染此檔案,因為它太大了。 error.csv.unexpected=無法渲染此檔案,因為它包含了未預期的字元,於第 %d 行第 %d 列。 error.csv.invalid_field_count=無法渲染此檔案,因為它第 %d 行的欄位數量有誤。 +[graphs] + [org] org_name_holder=組織名稱 org_full_name_holder=組織全名 @@ -2935,6 +2940,7 @@ notices.desc=描述 notices.op=操作 notices.delete_success=已刪除系統提示。 + [action] create_repo=建立了儲存庫 <a href="%s">%s</a> rename_repo=重新命名儲存庫 <code>%[1]s</code> 為 <a href="%[2]s">%[3]s</a> @@ -3111,6 +3117,8 @@ pypi.requires=需要 Python pypi.install=執行下列命令以使用 pip 安裝此套件: rpm.registry=透過下列命令設定此註冊中心: rpm.install=執行下列命令安裝此套件: +rpm.repository=儲存庫資訊 +rpm.repository.architectures=架構 rubygems.install=執行下列命令以使用 gem 安裝此套件: rubygems.install2=或將它加到 Gemfile: rubygems.dependencies.runtime=執行階段相依性 From 3591d9bff925f55b5bbd1edaec4dd1e352db7a85 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 22 Feb 2024 04:19:13 +0100 Subject: [PATCH 19/64] Don't install playwright twice (#29302) 1. `playwright/test` is already installed as part of `deps-frontend` on CI which runs before, so it's better to not install it again (on a potentially different version), and just use the version from package.json and add the `deps-frontend` dependency. 2. `PLAYWRIGHT_DIR` is a undefined variable, so I removed it ```bash $ git show c8ded77680db7344c8dc1ccee76bce0b4e02e103 | grep PLAYWRIGHT_DIR +playwright: $(PLAYWRIGHT_DIR) ``` (cherry picked from commit c236e64aca42b9ab0743431bc505033a0cb78b93) --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 194da59ef0..72a48038f4 100644 --- a/Makefile +++ b/Makefile @@ -625,8 +625,7 @@ test-mssql\#%: integrations.mssql.test generate-ini-mssql test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test .PHONY: playwright -playwright: $(PLAYWRIGHT_DIR) - npm install --no-save @playwright/test +playwright: deps-frontend npx playwright install $(PLAYWRIGHT_FLAGS) .PHONY: test-e2e% From 9debff3b71b048b8e14e42711de0df3aba579481 Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Thu, 22 Feb 2024 04:48:19 +0100 Subject: [PATCH 20/64] Discard unread data of `git cat-file` (#29297) Fixes #29101 Related #29298 Discard all read data to prevent misinterpreting existing data. Some discard calls were missing in error cases. --------- Co-authored-by: yp05327 <576951401@qq.com> (cherry picked from commit d6811baf88ca6d58b92d4dc12b1f2a292198751f) --- modules/git/batch_reader.go | 40 +++++++++++----------- modules/git/blob_nogogit.go | 24 ++----------- modules/git/commit_info_nogogit.go | 3 ++ modules/git/pipeline/lfs_nogogit.go | 4 +++ modules/git/repo_commit_nogogit.go | 3 +- modules/git/repo_language_stats_nogogit.go | 23 +------------ modules/git/repo_tag_nogogit.go | 3 ++ modules/git/repo_tree_nogogit.go | 3 ++ modules/git/tree_nogogit.go | 16 ++------- modules/git/tree_test.go | 27 +++++++++++++++ 10 files changed, 66 insertions(+), 80 deletions(-) create mode 100644 modules/git/tree_test.go diff --git a/modules/git/batch_reader.go b/modules/git/batch_reader.go index 53a9393d5f..043dbb44bd 100644 --- a/modules/git/batch_reader.go +++ b/modules/git/batch_reader.go @@ -203,16 +203,7 @@ headerLoop: } // Discard the rest of the tag - discard := size - n + 1 - for discard > math.MaxInt32 { - _, err := rd.Discard(math.MaxInt32) - if err != nil { - return id, err - } - discard -= math.MaxInt32 - } - _, err := rd.Discard(int(discard)) - return id, err + return id, DiscardFull(rd, size-n+1) } // ReadTreeID reads a tree ID from a cat-file --batch stream, throwing away the rest of the stream. @@ -238,16 +229,7 @@ headerLoop: } // Discard the rest of the commit - discard := size - n + 1 - for discard > math.MaxInt32 { - _, err := rd.Discard(math.MaxInt32) - if err != nil { - return id, err - } - discard -= math.MaxInt32 - } - _, err := rd.Discard(int(discard)) - return id, err + return id, DiscardFull(rd, size-n+1) } // git tree files are a list: @@ -345,3 +327,21 @@ func init() { _, filename, _, _ := runtime.Caller(0) callerPrefix = strings.TrimSuffix(filename, "modules/git/batch_reader.go") } + +func DiscardFull(rd *bufio.Reader, discard int64) error { + if discard > math.MaxInt32 { + n, err := rd.Discard(math.MaxInt32) + discard -= int64(n) + if err != nil { + return err + } + } + for discard > 0 { + n, err := rd.Discard(int(discard)) + discard -= int64(n) + if err != nil { + return err + } + } + return nil +} diff --git a/modules/git/blob_nogogit.go b/modules/git/blob_nogogit.go index 6e8a48b1db..9e1c2a0376 100644 --- a/modules/git/blob_nogogit.go +++ b/modules/git/blob_nogogit.go @@ -9,7 +9,6 @@ import ( "bufio" "bytes" "io" - "math" "code.gitea.io/gitea/modules/log" ) @@ -104,25 +103,6 @@ func (b *blobReader) Read(p []byte) (n int, err error) { // Close implements io.Closer func (b *blobReader) Close() error { defer b.cancel() - if b.n > 0 { - for b.n > math.MaxInt32 { - n, err := b.rd.Discard(math.MaxInt32) - b.n -= int64(n) - if err != nil { - return err - } - b.n -= math.MaxInt32 - } - n, err := b.rd.Discard(int(b.n)) - b.n -= int64(n) - if err != nil { - return err - } - } - if b.n == 0 { - _, err := b.rd.Discard(1) - b.n-- - return err - } - return nil + + return DiscardFull(b.rd, b.n+1) } diff --git a/modules/git/commit_info_nogogit.go b/modules/git/commit_info_nogogit.go index e469d2cab6..a5d18694f7 100644 --- a/modules/git/commit_info_nogogit.go +++ b/modules/git/commit_info_nogogit.go @@ -151,6 +151,9 @@ func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string, return nil, err } if typ != "commit" { + if err := DiscardFull(batchReader, size+1); err != nil { + return nil, err + } return nil, fmt.Errorf("unexpected type: %s for commit id: %s", typ, commitID) } c, err = CommitFromReader(commit.repo, MustIDFromString(commitID), io.LimitReader(batchReader, size)) diff --git a/modules/git/pipeline/lfs_nogogit.go b/modules/git/pipeline/lfs_nogogit.go index a725f4799d..4c65249089 100644 --- a/modules/git/pipeline/lfs_nogogit.go +++ b/modules/git/pipeline/lfs_nogogit.go @@ -169,6 +169,10 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err } else { break commitReadingLoop } + default: + if err := git.DiscardFull(batchReader, size+1); err != nil { + return nil, err + } } } } diff --git a/modules/git/repo_commit_nogogit.go b/modules/git/repo_commit_nogogit.go index f0214e1ff8..a7031184e2 100644 --- a/modules/git/repo_commit_nogogit.go +++ b/modules/git/repo_commit_nogogit.go @@ -121,8 +121,7 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id ObjectID) return commit, nil default: log.Debug("Unknown typ: %s", typ) - _, err = rd.Discard(int(size) + 1) - if err != nil { + if err := DiscardFull(rd, size+1); err != nil { return nil, err } return nil, ErrNotExist{ diff --git a/modules/git/repo_language_stats_nogogit.go b/modules/git/repo_language_stats_nogogit.go index b313e2298f..1a3fdbb1f8 100644 --- a/modules/git/repo_language_stats_nogogit.go +++ b/modules/git/repo_language_stats_nogogit.go @@ -7,10 +7,8 @@ package git import ( - "bufio" "bytes" "io" - "math" "strings" "code.gitea.io/gitea/modules/analyze" @@ -174,8 +172,7 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err return nil, err } content = contentBuf.Bytes() - err = discardFull(batchReader, discard) - if err != nil { + if err := DiscardFull(batchReader, discard); err != nil { return nil, err } } @@ -224,21 +221,3 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err return mergeLanguageStats(sizes), nil } - -func discardFull(rd *bufio.Reader, discard int64) error { - if discard > math.MaxInt32 { - n, err := rd.Discard(math.MaxInt32) - discard -= int64(n) - if err != nil { - return err - } - } - for discard > 0 { - n, err := rd.Discard(int(discard)) - discard -= int64(n) - if err != nil { - return err - } - } - return nil -} diff --git a/modules/git/repo_tag_nogogit.go b/modules/git/repo_tag_nogogit.go index 5d98fadd54..cbab39f8c5 100644 --- a/modules/git/repo_tag_nogogit.go +++ b/modules/git/repo_tag_nogogit.go @@ -103,6 +103,9 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) { return nil, err } if typ != "tag" { + if err := DiscardFull(rd, size+1); err != nil { + return nil, err + } return nil, ErrNotExist{ID: tagID.String()} } diff --git a/modules/git/repo_tree_nogogit.go b/modules/git/repo_tree_nogogit.go index 20c92a79ed..582247b4a4 100644 --- a/modules/git/repo_tree_nogogit.go +++ b/modules/git/repo_tree_nogogit.go @@ -58,6 +58,9 @@ func (repo *Repository) getTree(id ObjectID) (*Tree, error) { tree.entriesParsed = true return tree, nil default: + if err := DiscardFull(rd, size+1); err != nil { + return nil, err + } return nil, ErrNotExist{ ID: id.String(), } diff --git a/modules/git/tree_nogogit.go b/modules/git/tree_nogogit.go index 89d3aebbc0..28d02c7e81 100644 --- a/modules/git/tree_nogogit.go +++ b/modules/git/tree_nogogit.go @@ -7,7 +7,6 @@ package git import ( "io" - "math" "strings" ) @@ -63,19 +62,8 @@ func (t *Tree) ListEntries() (Entries, error) { } // Not a tree just use ls-tree instead - for sz > math.MaxInt32 { - discarded, err := rd.Discard(math.MaxInt32) - sz -= int64(discarded) - if err != nil { - return nil, err - } - } - for sz > 0 { - discarded, err := rd.Discard(int(sz)) - sz -= int64(discarded) - if err != nil { - return nil, err - } + if err := DiscardFull(rd, sz+1); err != nil { + return nil, err } } diff --git a/modules/git/tree_test.go b/modules/git/tree_test.go new file mode 100644 index 0000000000..6d2b5c84d5 --- /dev/null +++ b/modules/git/tree_test.go @@ -0,0 +1,27 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSubTree_Issue29101(t *testing.T) { + repo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare")) + assert.NoError(t, err) + defer repo.Close() + + commit, err := repo.GetCommit("ce064814f4a0d337b333e646ece456cd39fab612") + assert.NoError(t, err) + + // old code could produce a different error if called multiple times + for i := 0; i < 10; i++ { + _, err = commit.SubTree("file1.txt") + assert.Error(t, err) + assert.True(t, IsErrNotExist(err)) + } +} From 7906838669a6e361d45d6c13439faba0d9d6ef6b Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Thu, 22 Feb 2024 15:04:30 +0800 Subject: [PATCH 21/64] Refactor cmd setup and remove deadcode (#29313) * use `setup(ctx, c.Bool("debug"))` like all other callers * `setting.RunMode = "dev"` is a no-op. * `if _, err := os.Stat(setting.RepoRootPath); err != nil` could be simplified (cherry picked from commit e9b13732f3d3b5536e43bdfdb5757dbbf484d694) --- cmd/keys.go | 2 +- cmd/serv.go | 13 +------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/cmd/keys.go b/cmd/keys.go index 28b20958b9..81425a5722 100644 --- a/cmd/keys.go +++ b/cmd/keys.go @@ -71,7 +71,7 @@ func runKeys(c *cli.Context) error { ctx, cancel := installSignals() defer cancel() - setup(ctx, false) + setup(ctx, c.Bool("debug")) authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content) // do not use handleCliResponseExtra or cli.NewExitError, if it exists immediately, it breaks some tests like Test_CmdKeys diff --git a/cmd/serv.go b/cmd/serv.go index ac754ee12f..9d26515254 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -63,21 +63,10 @@ func setup(ctx context.Context, debug bool) { setupConsoleLogger(log.FATAL, false, os.Stderr) } setting.MustInstalled() - if debug { - setting.RunMode = "dev" - } - - // Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when - // `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection. if _, err := os.Stat(setting.RepoRootPath); err != nil { - if os.IsNotExist(err) { - _ = fail(ctx, "Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath) - } else { - _ = fail(ctx, "Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err) - } + _ = fail(ctx, "Unable to access repository path", "Unable to access repository path %q, err: %v", setting.RepoRootPath, err) return } - if err := git.InitSimple(context.Background()); err != nil { _ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err) } From 542badbb76408c17ce6692e99fff680bee69face Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Br=C3=BCckner?= <code@nik.dev> Date: Thu, 22 Feb 2024 07:29:03 +0000 Subject: [PATCH 22/64] Properly migrate automatic merge GitLab comments (#27873) GitLab generates "system notes" whenever an event happens within the platform. Unlike Gitea, those events are stored and retrieved as text comments with no semantic details. The only way to tell whether a comment was generated in this manner is the `system` flag on the note type. This PR adds detection for two specific kinds of events: Scheduling and un-scheduling of automatic merges on a PR. When detected, they are downloaded using Gitea's type for these events, and eventually uploaded into Gitea in the expected format, i.e. with no text content in the comment. This PR also updates the template used to render comments to add support for migrated comments of these two types. ref: https://gitlab.com/gitlab-org/gitlab/-/blob/11bd6dc826e0bea2832324a1d7356949a9398884/app/services/system_notes/merge_requests_service.rb#L6-L17 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> (cherry picked from commit a70c00b80bcb5de8479e407f1b8f08dcf756019d) --- services/migrations/gitea_uploader.go | 2 + services/migrations/gitlab.go | 50 +++++++------- services/migrations/gitlab_test.go | 65 +++++++++++++++++++ .../repo/issue/view_content/comments.tmpl | 17 ++++- .../repo/issue/view_content/conversation.tmpl | 7 +- 5 files changed, 111 insertions(+), 30 deletions(-) diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index 0f0ca7e0f5..ebb1313c2b 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -487,6 +487,8 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { if comment.Meta["NewTitle"] != nil { cm.NewTitle = fmt.Sprintf("%s", comment.Meta["NewTitle"]) } + case issues_model.CommentTypePRScheduledToAutoMerge, issues_model.CommentTypePRUnScheduledToAutoMerge: + cm.Content = "" default: } diff --git a/services/migrations/gitlab.go b/services/migrations/gitlab.go index 3db10465fc..d08eaf0f84 100644 --- a/services/migrations/gitlab.go +++ b/services/migrations/gitlab.go @@ -14,6 +14,7 @@ import ( "strings" "time" + issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" base "code.gitea.io/gitea/modules/migration" @@ -506,30 +507,8 @@ func (g *GitlabDownloader) GetComments(commentable base.Commentable) ([]*base.Co return nil, false, fmt.Errorf("error while listing comments: %v %w", g.repoID, err) } for _, comment := range comments { - // Flatten comment threads - if !comment.IndividualNote { - for _, note := range comment.Notes { - allComments = append(allComments, &base.Comment{ - IssueIndex: commentable.GetLocalIndex(), - Index: int64(note.ID), - PosterID: int64(note.Author.ID), - PosterName: note.Author.Username, - PosterEmail: note.Author.Email, - Content: note.Body, - Created: *note.CreatedAt, - }) - } - } else { - c := comment.Notes[0] - allComments = append(allComments, &base.Comment{ - IssueIndex: commentable.GetLocalIndex(), - Index: int64(c.ID), - PosterID: int64(c.Author.ID), - PosterName: c.Author.Username, - PosterEmail: c.Author.Email, - Content: c.Body, - Created: *c.CreatedAt, - }) + for _, note := range comment.Notes { + allComments = append(allComments, g.convertNoteToComment(commentable.GetLocalIndex(), note)) } } if resp.NextPage == 0 { @@ -540,6 +519,29 @@ func (g *GitlabDownloader) GetComments(commentable base.Commentable) ([]*base.Co return allComments, true, nil } +func (g *GitlabDownloader) convertNoteToComment(localIndex int64, note *gitlab.Note) *base.Comment { + comment := &base.Comment{ + IssueIndex: localIndex, + Index: int64(note.ID), + PosterID: int64(note.Author.ID), + PosterName: note.Author.Username, + PosterEmail: note.Author.Email, + Content: note.Body, + Created: *note.CreatedAt, + } + + // Try to find the underlying event of system notes. + if note.System { + if strings.HasPrefix(note.Body, "enabled an automatic merge") { + comment.CommentType = issues_model.CommentTypePRScheduledToAutoMerge.String() + } else if note.Body == "canceled the automatic merge" { + comment.CommentType = issues_model.CommentTypePRUnScheduledToAutoMerge.String() + } + } + + return comment +} + // GetPullRequests returns pull requests according page and perPage func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) { if perPage > g.maxPerPage { diff --git a/services/migrations/gitlab_test.go b/services/migrations/gitlab_test.go index 25324a087f..d941cebd2c 100644 --- a/services/migrations/gitlab_test.go +++ b/services/migrations/gitlab_test.go @@ -558,6 +558,71 @@ func TestAwardsToReactions(t *testing.T) { }, reactions) } +func TestNoteToComment(t *testing.T) { + downloader := &GitlabDownloader{} + + now := time.Now() + makeTestNote := func(id int, body string, system bool) gitlab.Note { + return gitlab.Note{ + ID: id, + Author: struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + }{ + ID: 72, + Email: "test@example.com", + Username: "test", + }, + Body: body, + CreatedAt: &now, + System: system, + } + } + notes := []gitlab.Note{ + makeTestNote(1, "This is a regular comment", false), + makeTestNote(2, "enabled an automatic merge for abcd1234", true), + makeTestNote(3, "canceled the automatic merge", true), + } + comments := []base.Comment{{ + IssueIndex: 17, + Index: 1, + PosterID: 72, + PosterName: "test", + PosterEmail: "test@example.com", + CommentType: "", + Content: "This is a regular comment", + Created: now, + }, { + IssueIndex: 17, + Index: 2, + PosterID: 72, + PosterName: "test", + PosterEmail: "test@example.com", + CommentType: "pull_scheduled_merge", + Content: "enabled an automatic merge for abcd1234", + Created: now, + }, { + IssueIndex: 17, + Index: 3, + PosterID: 72, + PosterName: "test", + PosterEmail: "test@example.com", + CommentType: "pull_cancel_scheduled_merge", + Content: "canceled the automatic merge", + Created: now, + }} + + for i, note := range notes { + actualComment := *downloader.convertNoteToComment(17, ¬e) + assert.EqualValues(t, actualComment, comments[i]) + } +} + func TestGitlabIIDResolver(t *testing.T) { r := gitlabIIDResolver{} r.recordIssueIID(1) diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index a4fd97297f..43e059d6c1 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -385,8 +385,9 @@ {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} {{.OriginalAuthor}} </span> - <span class="text grey muted-links"> {{if $.Repository.OriginalURL}}</span> - <span class="text migrate">({{ctx.Locale.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape) | Safe}}){{end}}</span> + {{if $.Repository.OriginalURL}} + <span class="migrate">({{ctx.Locale.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname}})</span> + {{end}} {{else}} {{template "shared/user/authorlink" .Poster}} {{end}} @@ -667,7 +668,17 @@ <div class="timeline-item event" id="{{.HashTag}}"> <span class="badge">{{svg "octicon-git-merge" 16}}</span> <span class="text grey muted-links"> - {{template "shared/user/authorlink" .Poster}} + {{if .OriginalAuthor}} + <span class="text black"> + {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} + {{.OriginalAuthor}} + </span> + {{if $.Repository.OriginalURL}} + <span class="migrate">({{ctx.Locale.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname}})</span> + {{end}} + {{else}} + {{template "shared/user/authorlink" .Poster}} + {{end}} {{if eq .Type 34}}{{ctx.Locale.Tr "repo.pulls.auto_merge_newly_scheduled_comment" $createdStr | Safe}} {{else}}{{ctx.Locale.Tr "repo.pulls.auto_merge_canceled_schedule_comment" $createdStr | Safe}}{{end}} </span> diff --git a/templates/repo/issue/view_content/conversation.tmpl b/templates/repo/issue/view_content/conversation.tmpl index c9e5ee6275..fc1d9865f5 100644 --- a/templates/repo/issue/view_content/conversation.tmpl +++ b/templates/repo/issue/view_content/conversation.tmpl @@ -63,12 +63,13 @@ {{end}} <span class="text grey muted-links"> {{if .OriginalAuthor}} - <span class="text black gt-font-semibold"> + <span class="text black"> {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} {{.OriginalAuthor}} </span> - <span class="text grey muted-links"> {{if $.Repository.OriginalURL}}</span> - <span class="text migrate">({{ctx.Locale.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape) | Safe}}){{end}}</span> + {{if $.Repository.OriginalURL}} + <span class="migrate">({{ctx.Locale.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname}})</span> + {{end}} {{else}} {{template "shared/user/authorlink" .Poster}} {{end}} From ff5df5fc97463079915e0f43682dd747860dae61 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Thu, 22 Feb 2024 22:47:35 +0800 Subject: [PATCH 23/64] Improve the `issue_comment` workflow trigger event (#29277) Fix #29175 Replace #29207 This PR makes some improvements to the `issue_comment` workflow trigger event. 1. Fix the bug that pull requests cannot trigger `issue_comment` workflows 2. Previously the `issue_comment` event only supported the `created` activity type. This PR adds support for the missing `edited` and `deleted` activity types. 3. Some events (including `issue_comment`, `issues`, etc. ) only trigger workflows that belong to the workflow file on the default branch. This PR introduces the `IsDefaultBranchWorkflow` function to check for these events. (cherry picked from commit a4fe1cdf38f9a063e44b197ef07e4260f731c919) Conflicts: modules/actions/github.go context --- modules/actions/github.go | 44 +++++++++++++ modules/actions/github_test.go | 6 ++ services/actions/notifier.go | 96 ++++++++++++++++++++++------- services/actions/notifier_helper.go | 11 ++-- 4 files changed, 130 insertions(+), 27 deletions(-) diff --git a/modules/actions/github.go b/modules/actions/github.go index d4e559408b..cc04ca5c5c 100644 --- a/modules/actions/github.go +++ b/modules/actions/github.go @@ -25,6 +25,45 @@ const ( GithubEventSchedule = "schedule" ) +// IsDefaultBranchWorkflow returns true if the event only triggers workflows on the default branch +func IsDefaultBranchWorkflow(triggedEvent webhook_module.HookEventType) bool { + switch triggedEvent { + case webhook_module.HookEventDelete: + // GitHub "delete" event + // https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#delete + return true + case webhook_module.HookEventFork: + // GitHub "fork" event + // https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#fork + return true + case webhook_module.HookEventIssueComment: + // GitHub "issue_comment" event + // https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment + return true + case webhook_module.HookEventPullRequestComment: + // GitHub "pull_request_comment" event + // https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment + return true + case webhook_module.HookEventWiki: + // GitHub "gollum" event + // https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#gollum + return true + case webhook_module.HookEventSchedule: + // GitHub "schedule" event + // https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule + return true + case webhook_module.HookEventIssues, + webhook_module.HookEventIssueAssign, + webhook_module.HookEventIssueLabel, + webhook_module.HookEventIssueMilestone: + // Github "issues" event + // https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issues + return true + } + + return false +} + // canGithubEventMatch check if the input Github event can match any Gitea event. func canGithubEventMatch(eventName string, triggedEvent webhook_module.HookEventType) bool { switch eventName { @@ -75,6 +114,11 @@ func canGithubEventMatch(eventName string, triggedEvent webhook_module.HookEvent return false } + case GithubEventIssueComment: + // https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment + return triggedEvent == webhook_module.HookEventIssueComment || + triggedEvent == webhook_module.HookEventPullRequestComment + default: return eventName == string(triggedEvent) } diff --git a/modules/actions/github_test.go b/modules/actions/github_test.go index 4bf55ae03f..6652ff6eac 100644 --- a/modules/actions/github_test.go +++ b/modules/actions/github_test.go @@ -103,6 +103,12 @@ func TestCanGithubEventMatch(t *testing.T) { webhook_module.HookEventCreate, true, }, + { + "create pull request comment", + GithubEventIssueComment, + webhook_module.HookEventPullRequestComment, + true, + }, } for _, tc := range testCases { diff --git a/services/actions/notifier.go b/services/actions/notifier.go index 77848a3f58..e144484dab 100644 --- a/services/actions/notifier.go +++ b/services/actions/notifier.go @@ -224,37 +224,88 @@ func (n *actionsNotifier) CreateIssueComment(ctx context.Context, doer *user_mod ) { ctx = withMethod(ctx, "CreateIssueComment") - permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer) - if issue.IsPull { - if err := issue.LoadPullRequest(ctx); err != nil { + notifyIssueCommentChange(ctx, doer, comment, "", webhook_module.HookEventPullRequestComment, api.HookIssueCommentCreated) + return + } + notifyIssueCommentChange(ctx, doer, comment, "", webhook_module.HookEventIssueComment, api.HookIssueCommentCreated) +} + +func (n *actionsNotifier) UpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) { + ctx = withMethod(ctx, "UpdateComment") + + if err := c.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) + return + } + + if c.Issue.IsPull { + notifyIssueCommentChange(ctx, doer, c, oldContent, webhook_module.HookEventPullRequestComment, api.HookIssueCommentEdited) + return + } + notifyIssueCommentChange(ctx, doer, c, oldContent, webhook_module.HookEventIssueComment, api.HookIssueCommentEdited) +} + +func (n *actionsNotifier) DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) { + ctx = withMethod(ctx, "DeleteComment") + + if err := comment.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) + return + } + + if comment.Issue.IsPull { + notifyIssueCommentChange(ctx, doer, comment, "", webhook_module.HookEventPullRequestComment, api.HookIssueCommentDeleted) + return + } + notifyIssueCommentChange(ctx, doer, comment, "", webhook_module.HookEventIssueComment, api.HookIssueCommentDeleted) +} + +func notifyIssueCommentChange(ctx context.Context, doer *user_model.User, comment *issues_model.Comment, oldContent string, event webhook_module.HookEventType, action api.HookIssueCommentAction) { + if err := comment.LoadIssue(ctx); err != nil { + log.Error("LoadIssue: %v", err) + return + } + if err := comment.Issue.LoadAttributes(ctx); err != nil { + log.Error("LoadAttributes: %v", err) + return + } + + permission, _ := access_model.GetUserRepoPermission(ctx, comment.Issue.Repo, doer) + + payload := &api.IssueCommentPayload{ + Action: action, + Issue: convert.ToAPIIssue(ctx, comment.Issue), + Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment), + Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission), + Sender: convert.ToUser(ctx, doer, nil), + IsPull: comment.Issue.IsPull, + } + + if action == api.HookIssueCommentEdited { + payload.Changes = &api.ChangesPayload{ + Body: &api.ChangesFromPayload{ + From: oldContent, + }, + } + } + + if comment.Issue.IsPull { + if err := comment.Issue.LoadPullRequest(ctx); err != nil { log.Error("LoadPullRequest: %v", err) return } - newNotifyInputFromIssue(issue, webhook_module.HookEventPullRequestComment). + newNotifyInputFromIssue(comment.Issue, event). WithDoer(doer). - WithPayload(&api.IssueCommentPayload{ - Action: api.HookIssueCommentCreated, - Issue: convert.ToAPIIssue(ctx, issue), - Comment: convert.ToAPIComment(ctx, repo, comment), - Repository: convert.ToRepo(ctx, repo, permission), - Sender: convert.ToUser(ctx, doer, nil), - IsPull: true, - }). - WithPullRequest(issue.PullRequest). + WithPayload(payload). + WithPullRequest(comment.Issue.PullRequest). Notify(ctx) return } - newNotifyInputFromIssue(issue, webhook_module.HookEventIssueComment). + + newNotifyInputFromIssue(comment.Issue, event). WithDoer(doer). - WithPayload(&api.IssueCommentPayload{ - Action: api.HookIssueCommentCreated, - Issue: convert.ToAPIIssue(ctx, issue), - Comment: convert.ToAPIComment(ctx, repo, comment), - Repository: convert.ToRepo(ctx, repo, permission), - Sender: convert.ToUser(ctx, doer, nil), - IsPull: false, - }). + WithPayload(payload). Notify(ctx) } @@ -496,7 +547,6 @@ func (n *actionsNotifier) DeleteRef(ctx context.Context, pusher *user_model.User apiRepo := convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeNone}) newNotifyInput(repo, pusher, webhook_module.HookEventDelete). - WithRef(refFullName.ShortName()). // FIXME: should we use a full ref name WithPayload(&api.DeletePayload{ Ref: refFullName.ShortName(), RefType: refFullName.RefType(), diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 46be4ac0a7..2d138aaf33 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -133,12 +133,15 @@ func notify(ctx context.Context, input *notifyInput) error { defer gitRepo.Close() ref := input.Ref - if input.Event == webhook_module.HookEventDelete { - // The event is deleting a reference, so it will fail to get the commit for a deleted reference. - // Set ref to empty string to fall back to the default branch. - ref = "" + if ref != input.Repo.DefaultBranch && actions_module.IsDefaultBranchWorkflow(input.Event) { + if ref != "" { + log.Warn("Event %q should only trigger workflows on the default branch, but its ref is %q. Will fall back to the default branch", + input.Event, ref) + } + ref = input.Repo.DefaultBranch } if ref == "" { + log.Warn("Ref of event %q is empty, will fall back to the default branch", input.Event) ref = input.Repo.DefaultBranch } From 01fa6fbb97f0e6e2cf63f0d0e84957aace05d051 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Thu, 22 Feb 2024 18:35:58 +0200 Subject: [PATCH 24/64] Remove jQuery from the image pasting functionality (#29324) - Switched to plain JavaScript - Tested the image pasting functionality and it works as before # Demo using JavaScript without jQuery  Signed-off-by: Yarden Shoham <git@yardenshoham.com> (cherry picked from commit f390d5eb4f4db21eeacdf2e7a093f6bd4e87c96f) --- web_src/js/features/comp/ImagePaste.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index 444ab89150..b727880bc8 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -1,4 +1,3 @@ -import $ from 'jquery'; import {htmlEscape} from 'escape-goat'; import {POST} from '../../modules/fetch.js'; import {imageInfo} from '../../utils/image.js'; @@ -93,11 +92,10 @@ class CodeMirrorEditor { } const uploadClipboardImage = async (editor, dropzone, e) => { - const $dropzone = $(dropzone); - const uploadUrl = $dropzone.attr('data-upload-url'); - const $files = $dropzone.find('.files'); + const uploadUrl = dropzone.getAttribute('data-upload-url'); + const filesContainer = dropzone.querySelector('.files'); - if (!uploadUrl || !$files.length) return; + if (!uploadUrl || !filesContainer) return; const pastedImages = clipboardPastedImages(e); if (!pastedImages || pastedImages.length === 0) { @@ -126,8 +124,12 @@ const uploadClipboardImage = async (editor, dropzone, e) => { } editor.replacePlaceholder(placeholder, text); - const $input = $(`<input name="files" type="hidden">`).attr('id', uuid).val(uuid); - $files.append($input); + const input = document.createElement('input'); + input.setAttribute('name', 'files'); + input.setAttribute('type', 'hidden'); + input.setAttribute('id', uuid); + input.value = uuid; + filesContainer.append(input); } }; @@ -140,7 +142,7 @@ export function initEasyMDEImagePaste(easyMDE, dropzone) { export function initTextareaImagePaste(textarea, dropzone) { if (!dropzone) return; - $(textarea).on('paste', async (e) => { - return uploadClipboardImage(new TextareaEditor(textarea), dropzone, e.originalEvent); + textarea.addEventListener('paste', async (e) => { + return uploadClipboardImage(new TextareaEditor(textarea), dropzone, e); }); } From 60447a7097a9eb05eda237ea33d46e1bc7044004 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Fri, 23 Feb 2024 01:02:33 +0800 Subject: [PATCH 25/64] Remove unnecessary "Safe" modifier from templates (#29318) Follow #29165 (cherry picked from commit 7a1557d2cc893030ae900c4333eeb12d84b891dc) Conflicts: templates/package/content/alpine.tmpl templates/package/content/cargo.tmpl templates/package/content/chef.tmpl templates/package/content/composer.tmpl templates/package/content/conan.tmpl templates/package/content/conda.tmpl templates/package/content/container.tmpl templates/package/content/cran.tmpl templates/package/content/debian.tmpl templates/package/content/generic.tmpl templates/package/content/go.tmpl templates/package/content/helm.tmpl templates/package/content/maven.tmpl templates/package/content/npm.tmpl templates/package/content/nuget.tmpl templates/package/content/pub.tmpl templates/package/content/pypi.tmpl templates/package/content/rpm.tmpl templates/package/content/rubygems.tmpl templates/package/content/swift.tmpl templates/package/content/vagrant.tmpl templates/package/shared/cargo.tmpl templates/package/shared/list.tmpl templates/repo/code/recently_pushed_new_branches.tmpl templates/repo/issue/view_content/comments.tmpl templates/status/404.tmpl templates/user/settings/packages.tmpl context --- templates/explore/repo_search.tmpl | 2 +- templates/explore/user_list.tmpl | 2 +- templates/install.tmpl | 4 +- templates/package/content/alpine.tmpl | 8 +- templates/package/content/cargo.tmpl | 4 +- templates/package/content/chef.tmpl | 4 +- templates/package/content/composer.tmpl | 4 +- templates/package/content/conan.tmpl | 2 +- templates/package/content/conda.tmpl | 4 +- templates/package/content/container.tmpl | 2 +- templates/package/content/cran.tmpl | 4 +- templates/package/content/debian.tmpl | 4 +- templates/package/content/generic.tmpl | 2 +- templates/package/content/go.tmpl | 2 +- templates/package/content/helm.tmpl | 2 +- templates/package/content/maven.tmpl | 6 +- templates/package/content/npm.tmpl | 4 +- templates/package/content/nuget.tmpl | 2 +- templates/package/content/pub.tmpl | 2 +- templates/package/content/pypi.tmpl | 2 +- templates/package/content/rpm.tmpl | 2 +- templates/package/content/rubygems.tmpl | 4 +- templates/package/content/swift.tmpl | 4 +- templates/package/content/vagrant.tmpl | 2 +- templates/package/shared/cargo.tmpl | 2 +- .../package/shared/cleanup_rules/edit.tmpl | 2 +- templates/package/shared/list.tmpl | 8 +- templates/package/shared/versionlist.tmpl | 2 +- templates/package/view.tmpl | 4 +- templates/repo/actions/no_workflows.tmpl | 4 +- .../code/recently_pushed_new_branches.tmpl | 2 +- templates/repo/create.tmpl | 4 +- templates/repo/create_helper.tmpl | 2 +- templates/repo/diff/comments.tmpl | 6 +- templates/repo/diff/compare.tmpl | 4 +- templates/repo/editor/commit_form.tmpl | 6 +- templates/repo/empty.tmpl | 2 +- templates/repo/home.tmpl | 2 +- templates/repo/issue/card.tmpl | 6 +- templates/repo/issue/filter_list.tmpl | 2 +- .../repo/issue/labels/edit_delete_label.tmpl | 4 +- templates/repo/issue/labels/label_new.tmpl | 2 +- templates/repo/issue/milestone_issues.tmpl | 4 +- templates/repo/issue/milestones.tmpl | 4 +- templates/repo/issue/new_form.tmpl | 2 +- templates/repo/issue/view_content.tmpl | 8 +- .../repo/issue/view_content/comments.tmpl | 110 +++++++++--------- .../repo/issue/view_content/conversation.tmpl | 2 +- templates/repo/issue/view_content/pull.tmpl | 6 +- .../view_content/pull_merge_instruction.tmpl | 2 +- .../repo/issue/view_content/sidebar.tmpl | 8 +- templates/repo/issue/view_title.tmpl | 6 +- templates/repo/migrate/codebase.tmpl | 12 +- templates/repo/migrate/git.tmpl | 4 +- templates/repo/migrate/gitbucket.tmpl | 16 +-- templates/repo/migrate/gitea.tmpl | 16 +-- templates/repo/migrate/github.tmpl | 16 +-- templates/repo/migrate/gitlab.tmpl | 16 +-- templates/repo/migrate/gogs.tmpl | 16 +-- templates/repo/migrate/migrating.tmpl | 10 +- templates/repo/migrate/onedev.tmpl | 12 +- templates/repo/pulls/fork.tmpl | 2 +- templates/repo/pulse.tmpl | 4 +- templates/repo/settings/deploy_keys.tmpl | 2 +- templates/repo/settings/options.tmpl | 10 +- templates/repo/settings/protected_branch.tmpl | 6 +- templates/repo/settings/tags.tmpl | 2 +- templates/repo/user_cards.tmpl | 2 +- templates/repo/wiki/pages.tmpl | 2 +- templates/repo/wiki/revision.tmpl | 2 +- templates/repo/wiki/view.tmpl | 4 +- templates/shared/actions/runner_edit.tmpl | 2 +- templates/shared/issuelist.tmpl | 6 +- templates/shared/searchbottom.tmpl | 2 +- templates/shared/secrets/add_list.tmpl | 2 +- templates/shared/user/profile_big_avatar.tmpl | 2 +- templates/shared/variables/variable_list.tmpl | 2 +- templates/status/404.tmpl | 2 +- templates/user/dashboard/milestones.tmpl | 4 +- templates/user/settings/applications.tmpl | 2 +- templates/user/settings/grants_oauth2.tmpl | 2 +- templates/user/settings/keys_gpg.tmpl | 4 +- templates/user/settings/keys_principal.tmpl | 2 +- templates/user/settings/keys_ssh.tmpl | 2 +- templates/user/settings/packages.tmpl | 2 +- .../user/settings/security/webauthn.tmpl | 2 +- 86 files changed, 243 insertions(+), 243 deletions(-) diff --git a/templates/explore/repo_search.tmpl b/templates/explore/repo_search.tmpl index 573163d554..d8044767a2 100644 --- a/templates/explore/repo_search.tmpl +++ b/templates/explore/repo_search.tmpl @@ -38,7 +38,7 @@ </div> {{if and .PageIsExploreRepositories .OnlyShowRelevant}} <div class="ui message explore-relevancy-note"> - <span data-tooltip-content="{{ctx.Locale.Tr "explore.relevant_repositories_tooltip"}}">{{ctx.Locale.Tr "explore.relevant_repositories" ((printf "?only_show_relevant=0&sort=%s&q=%s&language=%s" $.SortType (QueryEscape $.Keyword) (QueryEscape $.Language))|Escape) | Safe}}</span> + <span data-tooltip-content="{{ctx.Locale.Tr "explore.relevant_repositories_tooltip"}}">{{ctx.Locale.Tr "explore.relevant_repositories" ((printf "?only_show_relevant=0&sort=%s&q=%s&language=%s" $.SortType (QueryEscape $.Keyword) (QueryEscape $.Language))|Escape)}}</span> </div> {{end}} <div class="divider"></div> diff --git a/templates/explore/user_list.tmpl b/templates/explore/user_list.tmpl index 9abbff6d9c..0d661d53cb 100644 --- a/templates/explore/user_list.tmpl +++ b/templates/explore/user_list.tmpl @@ -21,7 +21,7 @@ <a href="mailto:{{.Email}}">{{.Email}}</a> </span> {{end}} - <span class="flex-text-inline">{{svg "octicon-calendar"}}{{ctx.Locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}}</span> + <span class="flex-text-inline">{{svg "octicon-calendar"}}{{ctx.Locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix)}}</span> </div> </div> </div> diff --git a/templates/install.tmpl b/templates/install.tmpl index 42842084b7..c18f25f79c 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -8,7 +8,7 @@ <div class="ui attached segment"> {{template "base/alert" .}} - <p>{{ctx.Locale.Tr "install.docker_helper" "https://docs.gitea.com/installation/install-with-docker" | Safe}}</p> + <p>{{ctx.Locale.Tr "install.docker_helper" "https://docs.gitea.com/installation/install-with-docker"}}</p> <form class="ui form" action="{{AppSubUrl}}/" method="post"> <!-- Database Settings --> @@ -72,7 +72,7 @@ <div class="inline required field {{if or .Err_DbPath .Err_DbSetting}}error{{end}}"> <label for="db_path">{{ctx.Locale.Tr "install.path"}}</label> <input id="db_path" name="db_path" value="{{.db_path}}"> - <span class="help">{{ctx.Locale.Tr "install.sqlite_helper" | Safe}}</span> + <span class="help">{{ctx.Locale.Tr "install.sqlite_helper"}}</span> </div> </div> diff --git a/templates/package/content/alpine.tmpl b/templates/package/content/alpine.tmpl index 48e1dff939..496ffbc7b5 100644 --- a/templates/package/content/alpine.tmpl +++ b/templates/package/content/alpine.tmpl @@ -3,12 +3,12 @@ <div class="ui attached segment"> <div class="ui form"> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.alpine.registry" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.alpine.registry"}}</label> <div class="markup"><pre class="code-block"><code><gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/alpine"></gitea-origin-url>/$branch/$repository</code></pre></div> - <p>{{ctx.Locale.Tr "packages.alpine.registry.info" | Safe}}</p> + <p>{{ctx.Locale.Tr "packages.alpine.registry.info"}}</p> </div> <div class="field"> - <label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.alpine.registry.key" | Safe}}</label> + <label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.alpine.registry.key"}}</label> <div class="markup"><pre class="code-block"><code>curl -JO <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/alpine/key"></gitea-origin-url></code></pre></div> </div> <div class="field"> @@ -18,7 +18,7 @@ </div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Alpine" "https://forgejo.org/docs/latest/user/packages/alpine/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Alpine" "https://forgejo.org/docs/latest/user/packages/alpine/"}}</label> </div> </div> </div> diff --git a/templates/package/content/cargo.tmpl b/templates/package/content/cargo.tmpl index 5b4c809096..53b2ef1152 100644 --- a/templates/package/content/cargo.tmpl +++ b/templates/package/content/cargo.tmpl @@ -3,7 +3,7 @@ <div class="ui attached segment"> <div class="ui form"> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.cargo.registry" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.cargo.registry"}}</label> <div class="markup"><pre class="code-block"><code>[registry] default = "forgejo" @@ -19,7 +19,7 @@ git-fetch-with-cli = true</code></pre></div> <div class="markup"><pre class="code-block"><code>cargo add {{.PackageDescriptor.Package.Name}}@{{.PackageDescriptor.Version.Version}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Cargo" "https://forgejo.org/docs/latest/user/packages/cargo/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Cargo" "https://forgejo.org/docs/latest/user/packages/cargo/"}}</label> </div> </div> </div> diff --git a/templates/package/content/chef.tmpl b/templates/package/content/chef.tmpl index a2f69b8f84..0f7694edc8 100644 --- a/templates/package/content/chef.tmpl +++ b/templates/package/content/chef.tmpl @@ -3,7 +3,7 @@ <div class="ui attached segment"> <div class="ui form"> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.chef.registry" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.chef.registry"}}</label> <div class="markup"><pre class="code-block"><code>knife[:supermarket_site] = '<gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/chef"></gitea-origin-url>'</code></pre></div> </div> <div class="field"> @@ -11,7 +11,7 @@ <div class="markup"><pre class="code-block"><code>knife supermarket install {{.PackageDescriptor.Package.Name}} {{.PackageDescriptor.Version.Version}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Chef" "https://forgejo.org/docs/latest/user/packages/chef/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Chef" "https://forgejo.org/docs/latest/user/packages/chef/"}}</label> </div> </div> </div> diff --git a/templates/package/content/composer.tmpl b/templates/package/content/composer.tmpl index 3a4025fb33..7da94095dd 100644 --- a/templates/package/content/composer.tmpl +++ b/templates/package/content/composer.tmpl @@ -3,7 +3,7 @@ <div class="ui attached segment"> <div class="ui form"> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.composer.registry" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.composer.registry"}}</label> <div class="markup"><pre class="code-block"><code>{ "repositories": [{ "type": "composer", @@ -17,7 +17,7 @@ <div class="markup"><pre class="code-block"><code>composer require {{.PackageDescriptor.Package.Name}}:{{.PackageDescriptor.Version.Version}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Composer" "https://forgejo.org/docs/latest/user/packages/composer/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Composer" "https://forgejo.org/docs/latest/user/packages/composer/"}}</label> </div> </div> </div> diff --git a/templates/package/content/conan.tmpl b/templates/package/content/conan.tmpl index fbbb44d8b7..0a9f508dcc 100644 --- a/templates/package/content/conan.tmpl +++ b/templates/package/content/conan.tmpl @@ -11,7 +11,7 @@ <div class="markup"><pre class="code-block"><code>conan install --remote=forgejo {{.PackageDescriptor.Package.Name}}/{{.PackageDescriptor.Version.Version}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Conan" "https://forgejo.org/docs/latest/user/packages/conan/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Conan" "https://forgejo.org/docs/latest/user/packages/conan/"}}</label> </div> </div> </div> diff --git a/templates/package/content/conda.tmpl b/templates/package/content/conda.tmpl index d5905c76fb..313b05ffe9 100644 --- a/templates/package/content/conda.tmpl +++ b/templates/package/content/conda.tmpl @@ -3,7 +3,7 @@ <div class="ui attached segment"> <div class="ui form"> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.conda.registry" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.conda.registry"}}</label> <div class="markup"><pre class="code-block"><code>channel_alias: <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/conda"></gitea-origin-url> channels:   - <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/conda"></gitea-origin-url> @@ -16,7 +16,7 @@ default_channels: <div class="markup"><pre class="code-block"><code>conda install{{if $channel}} -c {{$channel}}{{end}} {{.PackageDescriptor.PackageProperties.GetByName "conda.name"}}={{.PackageDescriptor.Version.Version}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Conda" "https://forgejo.org/docs/latest/user/packages/conda/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Conda" "https://forgejo.org/docs/latest/user/packages/conda/"}}</label> </div> </div> </div> diff --git a/templates/package/content/container.tmpl b/templates/package/content/container.tmpl index b8d2768fa7..0d5f0f09d5 100644 --- a/templates/package/content/container.tmpl +++ b/templates/package/content/container.tmpl @@ -19,7 +19,7 @@ <div class="markup"><pre class="code-block"><code>{{range .PackageDescriptor.Files}}{{if eq .File.LowerName "manifest.json"}}{{.Properties.GetByName "container.digest"}}{{end}}{{end}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Container" "https://forgejo.org/docs/latest/user/packages/container/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Container" "https://forgejo.org/docs/latest/user/packages/container/"}}</label> </div> </div> </div> diff --git a/templates/package/content/cran.tmpl b/templates/package/content/cran.tmpl index 54ead877ba..766dd43a4c 100644 --- a/templates/package/content/cran.tmpl +++ b/templates/package/content/cran.tmpl @@ -3,7 +3,7 @@ <div class="ui attached segment"> <div class="ui form"> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.cran.registry" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.cran.registry"}}</label> <div class="markup"><pre class="code-block"><code>options("repos" = c(getOption("repos"), c(forgejo="<gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/cran"></gitea-origin-url>")))</code></pre></div> </div> <div class="field"> @@ -11,7 +11,7 @@ <div class="markup"><pre class="code-block"><code>install.packages("{{.PackageDescriptor.Package.Name}}")</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "CRAN" "https://forgejo.org/docs/latest/user/packages/cran/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "CRAN" "https://forgejo.org/docs/latest/user/packages/cran/"}}</label> </div> </div> </div> diff --git a/templates/package/content/debian.tmpl b/templates/package/content/debian.tmpl index 460e7cc3c5..3c03eec396 100644 --- a/templates/package/content/debian.tmpl +++ b/templates/package/content/debian.tmpl @@ -7,7 +7,7 @@ <div class="markup"><pre class="code-block"><code>sudo curl <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/debian/repository.key"></gitea-origin-url> -o /etc/apt/keyrings/forgejo-{{$.PackageDescriptor.Owner.Name}}.asc echo "deb [signed-by=/etc/apt/keyrings/forgejo-{{$.PackageDescriptor.Owner.Name}}.asc] <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/debian"></gitea-origin-url> $distribution $component" | sudo tee -a /etc/apt/sources.list.d/forgejo.list sudo apt update</code></pre></div> - <p>{{ctx.Locale.Tr "packages.debian.registry.info" | Safe}}</p> + <p>{{ctx.Locale.Tr "packages.debian.registry.info"}}</p> </div> <div class="field"> <label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.debian.install"}}</label> @@ -16,7 +16,7 @@ sudo apt update</code></pre></div> </div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Debian" "https://forgejo.org/docs/latest/user/packages/debian/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Debian" "https://forgejo.org/docs/latest/user/packages/debian/"}}</label> </div> </div> </div> diff --git a/templates/package/content/generic.tmpl b/templates/package/content/generic.tmpl index 70218ddf6b..aec8eb314e 100644 --- a/templates/package/content/generic.tmpl +++ b/templates/package/content/generic.tmpl @@ -11,7 +11,7 @@ curl -OJ <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescr </code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Generic" "https://forgejo.org/docs/latest/user/packages/generic/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Generic" "https://forgejo.org/docs/latest/user/packages/generic/"}}</label> </div> </div> </div> diff --git a/templates/package/content/go.tmpl b/templates/package/content/go.tmpl index 3b2b478e0c..853218e51c 100644 --- a/templates/package/content/go.tmpl +++ b/templates/package/content/go.tmpl @@ -7,7 +7,7 @@ <div class="markup"><pre class="code-block"><code>GOPROXY=<gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/go"></gitea-origin-url> go install {{$.PackageDescriptor.Package.Name}}@{{$.PackageDescriptor.Version.Version}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Go" "https://forgejo.org/docs/latest/user/packages/go/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Go" "https://forgejo.org/docs/latest/user/packages/go/"}}</label> </div> </div> </div> diff --git a/templates/package/content/helm.tmpl b/templates/package/content/helm.tmpl index 7f39a0e78f..59f89be637 100644 --- a/templates/package/content/helm.tmpl +++ b/templates/package/content/helm.tmpl @@ -12,7 +12,7 @@ helm repo update</code></pre></div> <div class="markup"><pre class="code-block"><code>helm install {{.PackageDescriptor.Package.Name}} {{AppDomain}}/{{.PackageDescriptor.Package.Name}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Helm" "https://forgejo.org/docs/latest/user/packages/helm/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Helm" "https://forgejo.org/docs/latest/user/packages/helm/"}}</label> </div> </div> </div> diff --git a/templates/package/content/maven.tmpl b/templates/package/content/maven.tmpl index 7880eb63d8..e764684595 100644 --- a/templates/package/content/maven.tmpl +++ b/templates/package/content/maven.tmpl @@ -3,7 +3,7 @@ <div class="ui attached segment"> <div class="ui form"> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.maven.registry" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.maven.registry"}}</label> <div class="markup"><pre class="code-block"><code><repositories> <repository> <id>gitea</id> @@ -24,7 +24,7 @@ </distributionManagement></code></pre></div> </div> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.maven.install" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.maven.install"}}</label> <div class="markup"><pre class="code-block"><code><dependency> <groupId>{{.PackageDescriptor.Metadata.GroupID}}</groupId> <artifactId>{{.PackageDescriptor.Metadata.ArtifactID}}</artifactId> @@ -40,7 +40,7 @@ <div class="markup"><pre class="code-block"><code>mvn dependency:get -DremoteRepositories=<gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/maven"></gitea-origin-url> -Dartifact={{.PackageDescriptor.Metadata.GroupID}}:{{.PackageDescriptor.Metadata.ArtifactID}}:{{.PackageDescriptor.Version.Version}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Maven" "https://forgejo.org/docs/latest/user/packages/maven/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Maven" "https://forgejo.org/docs/latest/user/packages/maven/"}}</label> </div> </div> </div> diff --git a/templates/package/content/npm.tmpl b/templates/package/content/npm.tmpl index 3c493d38e6..cfd7595bfc 100644 --- a/templates/package/content/npm.tmpl +++ b/templates/package/content/npm.tmpl @@ -3,7 +3,7 @@ <div class="ui attached segment"> <div class="ui form"> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.npm.registry" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.npm.registry"}}</label> <div class="markup"><pre class="code-block"><code>{{if .PackageDescriptor.Metadata.Scope}}{{.PackageDescriptor.Metadata.Scope}}:{{end}}registry=<gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/npm/"></gitea-origin-url></code></pre></div> </div> <div class="field"> @@ -15,7 +15,7 @@ <div class="markup"><pre class="code-block"><code>"{{.PackageDescriptor.Package.Name}}": "{{.PackageDescriptor.Version.Version}}"</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "npm" "https://forgejo.org/docs/latest/user/packages/npm/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "npm" "https://forgejo.org/docs/latest/user/packages/npm/"}}</label> </div> </div> </div> diff --git a/templates/package/content/nuget.tmpl b/templates/package/content/nuget.tmpl index 80c7917ae2..f4807b0ad9 100644 --- a/templates/package/content/nuget.tmpl +++ b/templates/package/content/nuget.tmpl @@ -11,7 +11,7 @@ <div class="markup"><pre class="code-block"><code>dotnet add package --source {{.PackageDescriptor.Owner.Name}} --version {{.PackageDescriptor.Version.Version}} {{.PackageDescriptor.Package.Name}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "NuGet" "https://forgejo.org/docs/latest/user/packages/nuget/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "NuGet" "https://forgejo.org/docs/latest/user/packages/nuget/"}}</label> </div> </div> </div> diff --git a/templates/package/content/pub.tmpl b/templates/package/content/pub.tmpl index 316001a961..e83b0d3570 100644 --- a/templates/package/content/pub.tmpl +++ b/templates/package/content/pub.tmpl @@ -7,7 +7,7 @@ <div class="markup"><pre class="code-block"><code>dart pub add {{.PackageDescriptor.Package.Name}}:{{.PackageDescriptor.Version.Version}} --hosted-url=<gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/pub/"></gitea-origin-url></code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Pub" "https://forgejo.org/docs/latest/user/packages/pub/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Pub" "https://forgejo.org/docs/latest/user/packages/pub/"}}</label> </div> </div> </div> diff --git a/templates/package/content/pypi.tmpl b/templates/package/content/pypi.tmpl index c4bfe487e0..e0353c91c6 100644 --- a/templates/package/content/pypi.tmpl +++ b/templates/package/content/pypi.tmpl @@ -7,7 +7,7 @@ <div class="markup"><pre class="code-block"><code>pip install --index-url <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/pypi/simple/"></gitea-origin-url> {{.PackageDescriptor.Package.Name}}</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "PyPI" "https://forgejo.org/docs/latest/user/packages/pypi/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "PyPI" "https://forgejo.org/docs/latest/user/packages/pypi/"}}</label> </div> </div> </div> diff --git a/templates/package/content/rpm.tmpl b/templates/package/content/rpm.tmpl index aedac6ca43..a7e2141ccd 100644 --- a/templates/package/content/rpm.tmpl +++ b/templates/package/content/rpm.tmpl @@ -31,7 +31,7 @@ zypper install {{$.PackageDescriptor.Package.Name}}</code></pre> </div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "RPM" "https://forgejo.org/docs/latest/user/packages/rpm/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "RPM" "https://forgejo.org/docs/latest/user/packages/rpm/"}}</label> </div> </div> </div> diff --git a/templates/package/content/rubygems.tmpl b/templates/package/content/rubygems.tmpl index bc99af4a70..412c3a2954 100644 --- a/templates/package/content/rubygems.tmpl +++ b/templates/package/content/rubygems.tmpl @@ -3,7 +3,7 @@ <div class="ui attached segment"> <div class="ui form"> <div class="field"> - <label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.rubygems.install" | Safe}}:</label> + <label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.rubygems.install"}}:</label> <div class="markup"><pre class="code-block"><code>gem install {{.PackageDescriptor.Package.Name}} --version "{{.PackageDescriptor.Version.Version}}" --source "<gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/rubygems"></gitea-origin-url>"</code></pre></div> </div> <div class="field"> @@ -13,7 +13,7 @@ end</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "RubyGems" "https://forgejo.org/docs/latest/user/packages/rubygems/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "RubyGems" "https://forgejo.org/docs/latest/user/packages/rubygems/"}}</label> </div> </div> </div> diff --git a/templates/package/content/swift.tmpl b/templates/package/content/swift.tmpl index 9c2e35ebae..471f5b5457 100644 --- a/templates/package/content/swift.tmpl +++ b/templates/package/content/swift.tmpl @@ -7,7 +7,7 @@ <div class="markup"><pre class="code-block"><code>swift package-registry set <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/swift"></gitea-origin-url></code></pre></div> </div> <div class="field"> - <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.swift.install" | Safe}}</label> + <label>{{svg "octicon-code"}} {{ctx.Locale.Tr "packages.swift.install"}}</label> <div class="markup"><pre class="code-block"><code>dependencies: [ .package(id: "{{.PackageDescriptor.Package.Name}}", from:"{{.PackageDescriptor.Version.Version}}") ]</code></pre></div> @@ -17,7 +17,7 @@ <div class="markup"><pre class="code-block"><code>swift package resolve</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Swift" "https://forgejo.org/docs/latest/user/packages/swift/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Swift" "https://forgejo.org/docs/latest/user/packages/swift/"}}</label> </div> </div> </div> diff --git a/templates/package/content/vagrant.tmpl b/templates/package/content/vagrant.tmpl index 61a4ae8b2d..79b4d2f054 100644 --- a/templates/package/content/vagrant.tmpl +++ b/templates/package/content/vagrant.tmpl @@ -7,7 +7,7 @@ <div class="markup"><pre class="code-block"><code>vagrant box add --box-version {{.PackageDescriptor.Version.Version}} "<gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{.PackageDescriptor.Owner.Name}}/vagrant/{{.PackageDescriptor.Package.Name}}"></gitea-origin-url>"</code></pre></div> </div> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Vagrant" "https://forgejo.org/docs/latest/user/packages/vagrant/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Vagrant" "https://forgejo.org/docs/latest/user/packages/vagrant/"}}</label> </div> </div> </div> diff --git a/templates/package/shared/cargo.tmpl b/templates/package/shared/cargo.tmpl index 9015bc6616..401d909002 100644 --- a/templates/package/shared/cargo.tmpl +++ b/templates/package/shared/cargo.tmpl @@ -18,7 +18,7 @@ <button class="ui primary button">{{ctx.Locale.Tr "packages.owner.settings.cargo.rebuild"}}</button> </form> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Cargo" "https://forgejo.org/docs/latest/user/packages/cargo/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Cargo" "https://forgejo.org/docs/latest/user/packages/cargo/"}}</label> </div> </div> </div> diff --git a/templates/package/shared/cleanup_rules/edit.tmpl b/templates/package/shared/cleanup_rules/edit.tmpl index 8729494412..138a90791c 100644 --- a/templates/package/shared/cleanup_rules/edit.tmpl +++ b/templates/package/shared/cleanup_rules/edit.tmpl @@ -40,7 +40,7 @@ <div class="field {{if .Err_KeepPattern}}error{{end}}"> <label>{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.keep.pattern"}}:</label> <input name="keep_pattern" type="text" value="{{.CleanupRule.KeepPattern}}"> - <p>{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.keep.pattern.container" | Safe}}</p> + <p>{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.keep.pattern.container"}}</p> </div> <div class="divider"></div> <p>{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.remove.title"}}</p> diff --git a/templates/package/shared/list.tmpl b/templates/package/shared/list.tmpl index 299c182dc9..78f9edea39 100644 --- a/templates/package/shared/list.tmpl +++ b/templates/package/shared/list.tmpl @@ -30,9 +30,9 @@ {{$hasRepositoryAccess = index $.RepositoryAccessMap .Repository.ID}} {{end}} {{if $hasRepositoryAccess}} - {{ctx.Locale.Tr "packages.published_by_in" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) .Repository.Link (.Repository.FullName | Escape) | Safe}} + {{ctx.Locale.Tr "packages.published_by_in" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) .Repository.Link (.Repository.FullName | Escape)}} {{else}} - {{ctx.Locale.Tr "packages.published_by" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) | Safe}} + {{ctx.Locale.Tr "packages.published_by" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape)}} {{end}} </div> </div> @@ -45,9 +45,9 @@ <h2>{{ctx.Locale.Tr "packages.empty"}}</h2> {{if and .Repository .CanWritePackages}} {{$packagesUrl := URLJoin .Owner.HomeLink "-" "packages"}} - <p>{{ctx.Locale.Tr "packages.empty.repo" $packagesUrl | Safe}}</p> + <p>{{ctx.Locale.Tr "packages.empty.repo" $packagesUrl}}</p> {{end}} - <p>{{ctx.Locale.Tr "packages.empty.documentation" "https://forgejo.org/docs/latest/user/packages/" | Safe}}</p> + <p>{{ctx.Locale.Tr "packages.empty.documentation" "https://forgejo.org/docs/latest/user/packages/"}}</p> </div> {{else}} <p class="gt-py-4">{{ctx.Locale.Tr "packages.filter.no_result"}}</p> diff --git a/templates/package/shared/versionlist.tmpl b/templates/package/shared/versionlist.tmpl index fcf3030fe6..4b22dc22b2 100644 --- a/templates/package/shared/versionlist.tmpl +++ b/templates/package/shared/versionlist.tmpl @@ -25,7 +25,7 @@ <div class="flex-item-main"> <a class="flex-item-title" href="{{.FullWebLink}}">{{.Version.LowerVersion}}</a> <div class="flex-item-body"> - {{ctx.Locale.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix ctx.Locale) .Creator.HomeLink (.Creator.GetDisplayName | Escape) | Safe}} + {{ctx.Locale.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix ctx.Locale) .Creator.HomeLink (.Creator.GetDisplayName | Escape)}} </div> </div> </div> diff --git a/templates/package/view.tmpl b/templates/package/view.tmpl index 553a46cfad..65502a6e4d 100644 --- a/templates/package/view.tmpl +++ b/templates/package/view.tmpl @@ -10,9 +10,9 @@ <div> {{$timeStr := TimeSinceUnix .PackageDescriptor.Version.CreatedUnix ctx.Locale}} {{if .HasRepositoryAccess}} - {{ctx.Locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) .PackageDescriptor.Repository.Link (.PackageDescriptor.Repository.FullName | Escape) | Safe}} + {{ctx.Locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) .PackageDescriptor.Repository.Link (.PackageDescriptor.Repository.FullName | Escape)}} {{else}} - {{ctx.Locale.Tr "packages.published_by" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) | Safe}} + {{ctx.Locale.Tr "packages.published_by" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape)}} {{end}} </div> </div> diff --git a/templates/repo/actions/no_workflows.tmpl b/templates/repo/actions/no_workflows.tmpl index af1f28e8cf..009313581e 100644 --- a/templates/repo/actions/no_workflows.tmpl +++ b/templates/repo/actions/no_workflows.tmpl @@ -2,7 +2,7 @@ {{svg "octicon-no-entry" 48}} <h2>{{ctx.Locale.Tr "actions.runs.no_workflows"}}</h2> {{if and .CanWriteCode .CanWriteActions}} - <p>{{ctx.Locale.Tr "actions.runs.no_workflows.quick_start" "https://docs.gitea.com/usage/actions/quickstart/" | Safe}}</p> + <p>{{ctx.Locale.Tr "actions.runs.no_workflows.quick_start" "https://docs.gitea.com/usage/actions/quickstart/"}}</p> {{end}} - <p>{{ctx.Locale.Tr "actions.runs.no_workflows.documentation" "https://docs.gitea.com/usage/actions/overview/" | Safe}}</p> + <p>{{ctx.Locale.Tr "actions.runs.no_workflows.documentation" "https://docs.gitea.com/usage/actions/overview/"}}</p> </div> diff --git a/templates/repo/code/recently_pushed_new_branches.tmpl b/templates/repo/code/recently_pushed_new_branches.tmpl index 176ae3df00..85b78118d5 100644 --- a/templates/repo/code/recently_pushed_new_branches.tmpl +++ b/templates/repo/code/recently_pushed_new_branches.tmpl @@ -8,7 +8,7 @@ {{$name = (print $repo.FullName ":" .Name)}} {{end}} {{$branchLink := (print ($repo.Link) "/src/branch/" (PathEscapeSegments .Name))}} - {{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" (Escape $name) $timeSince $branchLink | Safe}} + {{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" (Escape $name) $timeSince $branchLink}} </div> <a role="button" class="ui compact positive button gt-m-0" href="{{$.Repository.ComposeBranchCompareURL $.Repository.BaseRepo $name}}"> {{ctx.Locale.Tr "repo.pulls.compare_changes"}} diff --git a/templates/repo/create.tmpl b/templates/repo/create.tmpl index 66f73fb398..d6ff22b7ab 100644 --- a/templates/repo/create.tmpl +++ b/templates/repo/create.tmpl @@ -51,10 +51,10 @@ <div class="ui checkbox"> {{if .IsForcedPrivate}} <input name="private" type="checkbox" checked readonly> - <label>{{ctx.Locale.Tr "repo.visibility_helper_forced" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> {{end}} </div> <span class="help">{{ctx.Locale.Tr "repo.visibility_description"}}</span> diff --git a/templates/repo/create_helper.tmpl b/templates/repo/create_helper.tmpl index 653955efc9..6ca691592c 100644 --- a/templates/repo/create_helper.tmpl +++ b/templates/repo/create_helper.tmpl @@ -1,3 +1,3 @@ {{if not $.DisableMigrations}} - <p class="ui center">{{ctx.Locale.Tr "repo.new_repo_helper" ((print AppSubUrl "/repo/migrate")|Escape) | Safe}}</p> + <p class="ui center">{{ctx.Locale.Tr "repo.new_repo_helper" ((print AppSubUrl "/repo/migrate")|Escape)}}</p> {{end}} diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index 2fbfe2fd6a..b3d06ed6bc 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -16,17 +16,17 @@ {{.OriginalAuthor}} </span> <span class="text grey muted-links"> - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr}} </span> <span class="text migrate"> {{if $.root.Repository.OriginalURL}} - ({{ctx.Locale.Tr "repo.migrated_from" ($.root.Repository.OriginalURL | Escape) ($.root.Repository.GetOriginalURLHostname | Escape) | Safe}}) + ({{ctx.Locale.Tr "repo.migrated_from" ($.root.Repository.OriginalURL | Escape) ($.root.Repository.GetOriginalURLHostname | Escape)}}) {{end}} </span> {{else}} <span class="text grey muted-links"> {{template "shared/user/namelink" .Poster}} - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr}} </span> {{end}} </div> diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index c2a114ba4e..b18908577a 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -194,7 +194,7 @@ {{if .HasPullRequest}} <div class="ui segment grid title"> <div class="twelve wide column issue-title"> - {{ctx.Locale.Tr "repo.pulls.has_pull_request" (print (Escape $.RepoLink) "/pulls/" .PullRequest.Issue.Index) (Escape $.RepoRelPath) .PullRequest.Index | Safe}} + {{ctx.Locale.Tr "repo.pulls.has_pull_request" (print (Escape $.RepoLink) "/pulls/" .PullRequest.Issue.Index) (Escape $.RepoRelPath) .PullRequest.Index}} <h1> <span id="issue-title">{{RenderIssueTitle $.Context .PullRequest.Issue.Title ($.Repository.ComposeMetas ctx)}}</span> <span class="index">#{{.PullRequest.Issue.Index}}</span> @@ -220,7 +220,7 @@ {{if .Repository.ArchivedUnix.IsZero}} {{ctx.Locale.Tr "repo.archive.title"}} {{else}} - {{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix) | Safe}} + {{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix)}} {{end}} </div> {{end}} diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl index 6fd240da62..87b2286319 100644 --- a/templates/repo/editor/commit_form.tmpl +++ b/templates/repo/editor/commit_form.tmpl @@ -26,7 +26,7 @@ <input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="direct" button_text="{{ctx.Locale.Tr "repo.editor.commit_changes"}}" {{if eq .commit_choice "direct"}}checked{{end}}> <label> {{svg "octicon-git-commit"}} - {{ctx.Locale.Tr "repo.editor.commit_directly_to_this_branch" (.BranchName|Escape) | Safe}} + {{ctx.Locale.Tr "repo.editor.commit_directly_to_this_branch" (.BranchName|Escape)}} {{if not .CanCommitToBranch.CanCommitToBranch}} <div class="ui visible small warning message"> {{ctx.Locale.Tr "repo.editor.no_commit_to_branch"}} @@ -50,9 +50,9 @@ <label> {{svg "octicon-git-pull-request"}} {{if .CanCreatePullRequest}} - {{ctx.Locale.Tr "repo.editor.create_new_branch" | Safe}} + {{ctx.Locale.Tr "repo.editor.create_new_branch"}} {{else}} - {{ctx.Locale.Tr "repo.editor.create_new_branch_np" | Safe}} + {{ctx.Locale.Tr "repo.editor.create_new_branch_np"}} {{end}} </label> </div> diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl index c1ec483b77..62194abe50 100644 --- a/templates/repo/empty.tmpl +++ b/templates/repo/empty.tmpl @@ -10,7 +10,7 @@ {{if .Repository.ArchivedUnix.IsZero}} {{ctx.Locale.Tr "repo.archive.title"}} {{else}} - {{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix) | Safe}} + {{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix)}} {{end}} </div> {{end}} diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 9bac26ce1e..f9a4599b92 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -63,7 +63,7 @@ {{if .Repository.ArchivedUnix.IsZero}} {{ctx.Locale.Tr "repo.archive.title"}} {{else}} - {{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix) | Safe}} + {{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix)}} {{end}} </div> {{end}} diff --git a/templates/repo/issue/card.tmpl b/templates/repo/issue/card.tmpl index 14d08fc0ef..7b71bd724e 100644 --- a/templates/repo/issue/card.tmpl +++ b/templates/repo/issue/card.tmpl @@ -23,11 +23,11 @@ {{if not $.Page.Repository}}{{.Repo.FullName}}{{end}}#{{.Index}} {{$timeStr := TimeSinceUnix .GetLastEventTimestamp ctx.Locale}} {{if .OriginalAuthor}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape) | Safe}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape)}} {{else if gt .Poster.ID 0}} - {{ctx.Locale.Tr .GetLastEventLabel $timeStr (.Poster.HomeLink|Escape) (.Poster.GetDisplayName | Escape) | Safe}} + {{ctx.Locale.Tr .GetLastEventLabel $timeStr (.Poster.HomeLink|Escape) (.Poster.GetDisplayName | Escape)}} {{else}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape)}} {{end}} </span> </div> diff --git a/templates/repo/issue/filter_list.tmpl b/templates/repo/issue/filter_list.tmpl index 5aa9135efa..f9f635f7cd 100644 --- a/templates/repo/issue/filter_list.tmpl +++ b/templates/repo/issue/filter_list.tmpl @@ -21,7 +21,7 @@ </i> </label> </div> - <span class="info">{{ctx.Locale.Tr "repo.issues.filter_label_exclude" | Safe}}</span> + <span class="info">{{ctx.Locale.Tr "repo.issues.filter_label_exclude"}}</span> <div class="divider"></div> <a rel="nofollow" class="{{if .AllLabels}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_label_no_select"}}</a> <a rel="nofollow" class="{{if .NoLabel}}active selected {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels=0&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_label_select_no_label"}}</a> diff --git a/templates/repo/issue/labels/edit_delete_label.tmpl b/templates/repo/issue/labels/edit_delete_label.tmpl index f41b4ee2c6..7ddc38a387 100644 --- a/templates/repo/issue/labels/edit_delete_label.tmpl +++ b/templates/repo/issue/labels/edit_delete_label.tmpl @@ -29,9 +29,9 @@ <label>{{ctx.Locale.Tr "repo.issues.label_exclusive"}}</label> </div> <br> - <small class="desc">{{ctx.Locale.Tr "repo.issues.label_exclusive_desc" | Safe}}</small> + <small class="desc">{{ctx.Locale.Tr "repo.issues.label_exclusive_desc"}}</small> <div class="desc gt-ml-2 gt-mt-3 gt-hidden label-exclusive-warning"> - {{svg "octicon-alert"}} {{ctx.Locale.Tr "repo.issues.label_exclusive_warning" | Safe}} + {{svg "octicon-alert"}} {{ctx.Locale.Tr "repo.issues.label_exclusive_warning"}} </div> <br> </div> diff --git a/templates/repo/issue/labels/label_new.tmpl b/templates/repo/issue/labels/label_new.tmpl index e7fb1e5ff6..2b2b2336c4 100644 --- a/templates/repo/issue/labels/label_new.tmpl +++ b/templates/repo/issue/labels/label_new.tmpl @@ -17,7 +17,7 @@ <label>{{ctx.Locale.Tr "repo.issues.label_exclusive"}}</label> </div> <br> - <small class="desc">{{ctx.Locale.Tr "repo.issues.label_exclusive_desc" | Safe}}</small> + <small class="desc">{{ctx.Locale.Tr "repo.issues.label_exclusive_desc"}}</small> </div> <div class="field"> <label for="description">{{ctx.Locale.Tr "repo.issues.label_description"}}</label> diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index ea19518efa..d9495d9b77 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -31,7 +31,7 @@ <div classs="gt-df gt-ac"> {{$closedDate:= TimeSinceUnix .Milestone.ClosedDateUnix ctx.Locale}} {{if .IsClosed}} - {{svg "octicon-clock"}} {{ctx.Locale.Tr "repo.milestones.closed" $closedDate | Safe}} + {{svg "octicon-clock"}} {{ctx.Locale.Tr "repo.milestones.closed" $closedDate}} {{else}} {{if .Milestone.DeadlineString}} @@ -45,7 +45,7 @@ {{end}} {{end}} </div> - <div class="gt-mr-3">{{ctx.Locale.Tr "repo.milestones.completeness" .Milestone.Completeness | Safe}}</div> + <div class="gt-mr-3">{{ctx.Locale.Tr "repo.milestones.completeness" .Milestone.Completeness}}</div> {{if .TotalTrackedTime}} <div data-tooltip-content='{{ctx.Locale.Tr "tracked_time_summary"}}'> {{svg "octicon-clock"}} diff --git a/templates/repo/issue/milestones.tmpl b/templates/repo/issue/milestones.tmpl index 3d4bbfd8b1..698e3fffba 100644 --- a/templates/repo/issue/milestones.tmpl +++ b/templates/repo/issue/milestones.tmpl @@ -47,14 +47,14 @@ {{if .UpdatedUnix}} <div class="flex-text-block"> {{svg "octicon-clock"}} - {{ctx.Locale.Tr "repo.milestones.update_ago" (TimeSinceUnix .UpdatedUnix ctx.Locale) | Safe}} + {{ctx.Locale.Tr "repo.milestones.update_ago" (TimeSinceUnix .UpdatedUnix ctx.Locale)}} </div> {{end}} <div class="flex-text-block"> {{if .IsClosed}} {{$closedDate:= TimeSinceUnix .ClosedDateUnix ctx.Locale}} {{svg "octicon-clock" 14}} - {{ctx.Locale.Tr "repo.milestones.closed" $closedDate | Safe}} + {{ctx.Locale.Tr "repo.milestones.closed" $closedDate}} {{else}} {{if .DeadlineString}} <span class="flex-text-inline {{if .IsOverdue}}text red{{end}}"> diff --git a/templates/repo/issue/new_form.tmpl b/templates/repo/issue/new_form.tmpl index 04ae8456bb..d1cbba6873 100644 --- a/templates/repo/issue/new_form.tmpl +++ b/templates/repo/issue/new_form.tmpl @@ -13,7 +13,7 @@ <div class="field"> <input name="title" id="issue_title" placeholder="{{ctx.Locale.Tr "repo.milestones.title"}}" value="{{if .TitleQuery}}{{.TitleQuery}}{{else if .IssueTemplateTitle}}{{.IssueTemplateTitle}}{{else}}{{.title}}{{end}}" autofocus required maxlength="255" autocomplete="off"> {{if .PageIsComparePull}} - <div class="title_wip_desc" data-wip-prefixes="{{JsonUtils.EncodeToString .PullRequestWorkInProgressPrefixes}}">{{ctx.Locale.Tr "repo.pulls.title_wip_desc" (index .PullRequestWorkInProgressPrefixes 0| Escape) | Safe}}</div> + <div class="title_wip_desc" data-wip-prefixes="{{JsonUtils.EncodeToString .PullRequestWorkInProgressPrefixes}}">{{ctx.Locale.Tr "repo.pulls.title_wip_desc" (index .PullRequestWorkInProgressPrefixes 0| Escape)}}</div> {{end}} </div> {{if .Fields}} diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index ed444f6dce..793772ecd0 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -28,10 +28,10 @@ {{.Issue.OriginalAuthor}} </span> <span class="text grey muted-links"> - {{ctx.Locale.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr}} </span> <span class="text migrate"> - {{if .Repository.OriginalURL}} ({{ctx.Locale.Tr "repo.migrated_from" (.Repository.OriginalURL|Escape) (.Repository.GetOriginalURLHostname|Escape) | Safe}}){{end}} + {{if .Repository.OriginalURL}} ({{ctx.Locale.Tr "repo.migrated_from" (.Repository.OriginalURL|Escape) (.Repository.GetOriginalURLHostname|Escape)}}){{end}} </span> {{else}} <a class="inline-timeline-avatar" href="{{.Issue.Poster.HomeLink}}"> @@ -39,7 +39,7 @@ </a> <span class="text grey muted-links"> {{template "shared/user/authorlink" .Issue.Poster}} - {{ctx.Locale.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr}} </span> {{end}} </div> @@ -133,7 +133,7 @@ </div> {{else}} <div class="ui warning message"> - {{ctx.Locale.Tr "repo.issues.sign_in_require_desc" (.SignInLink|Escape) | Safe}} + {{ctx.Locale.Tr "repo.issues.sign_in_require_desc" (.SignInLink|Escape)}} </div> {{end}} {{end}}{{/* end if: .IsSigned */}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 43e059d6c1..cf9df4dbda 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -33,10 +33,10 @@ {{.OriginalAuthor}} </span> <span class="text grey muted-links"> - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr | Safe}} {{if $.Repository.OriginalURL}} + {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr}} {{if $.Repository.OriginalURL}} </span> <span class="text migrate"> - ({{ctx.Locale.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape) | Safe}}){{end}} + ({{ctx.Locale.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape)}}){{end}} </span> {{else}} {{if gt .Poster.ID 0}} @@ -46,7 +46,7 @@ {{end}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr}} </span> {{end}} </div> @@ -85,9 +85,9 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} {{if .Issue.IsPull}} - {{ctx.Locale.Tr "repo.pulls.reopened_at" .EventTag $createdStr | Safe}} + {{ctx.Locale.Tr "repo.pulls.reopened_at" .EventTag $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.reopened_at" .EventTag $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.reopened_at" .EventTag $createdStr}} {{end}} </span> </div> @@ -98,9 +98,9 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} {{if .Issue.IsPull}} - {{ctx.Locale.Tr "repo.pulls.closed_at" .EventTag $createdStr | Safe}} + {{ctx.Locale.Tr "repo.pulls.closed_at" .EventTag $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.closed_at" .EventTag $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.closed_at" .EventTag $createdStr}} {{end}} </span> </div> @@ -138,7 +138,7 @@ {{if eq .RefAction 3}}<del>{{end}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr $refTr (.EventTag|Escape) $createdStr ((.RefCommentLink ctx)|Escape) $refFrom | Safe}} + {{ctx.Locale.Tr $refTr (.EventTag|Escape) $createdStr ((.RefCommentLink ctx)|Escape) $refFrom}} </span> {{if eq .RefAction 3}}</del>{{end}} @@ -153,9 +153,9 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} {{if .Issue.IsPull}} - {{ctx.Locale.Tr "repo.pulls.commit_ref_at" .EventTag $createdStr | Safe}} + {{ctx.Locale.Tr "repo.pulls.commit_ref_at" .EventTag $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.commit_ref_at" .EventTag $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.commit_ref_at" .EventTag $createdStr}} {{end}} </span> <div class="detail"> @@ -171,11 +171,11 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} {{if and .AddedLabels (not .RemovedLabels)}} - {{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) $createdStr | Safe}} + {{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) $createdStr}} {{else if and (not .AddedLabels) .RemovedLabels}} - {{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr | Safe}} + {{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr}} {{end}} </span> </div> @@ -186,7 +186,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{if gt .OldMilestoneID 0}}{{if gt .MilestoneID 0}}{{ctx.Locale.Tr "repo.issues.change_milestone_at" (.OldMilestone.Name|Escape) (.Milestone.Name|Escape) $createdStr | Safe}}{{else}}{{ctx.Locale.Tr "repo.issues.remove_milestone_at" (.OldMilestone.Name|Escape) $createdStr | Safe}}{{end}}{{else if gt .MilestoneID 0}}{{ctx.Locale.Tr "repo.issues.add_milestone_at" (.Milestone.Name|Escape) $createdStr | Safe}}{{end}} + {{if gt .OldMilestoneID 0}}{{if gt .MilestoneID 0}}{{ctx.Locale.Tr "repo.issues.change_milestone_at" (.OldMilestone.Name|Escape) (.Milestone.Name|Escape) $createdStr}}{{else}}{{ctx.Locale.Tr "repo.issues.remove_milestone_at" (.OldMilestone.Name|Escape) $createdStr}}{{end}}{{else if gt .MilestoneID 0}}{{ctx.Locale.Tr "repo.issues.add_milestone_at" (.Milestone.Name|Escape) $createdStr}}{{end}} </span> </div> {{else if and (eq .Type 9) (gt .AssigneeID 0)}} @@ -197,9 +197,9 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Assignee}} {{if eq .Poster.ID .Assignee.ID}} - {{ctx.Locale.Tr "repo.issues.remove_self_assignment" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.remove_self_assignment" $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.remove_assignee_at" (.Poster.GetDisplayName|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.remove_assignee_at" (.Poster.GetDisplayName|Escape) $createdStr}} {{end}} </span> {{else}} @@ -207,9 +207,9 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Assignee}} {{if eq .Poster.ID .AssigneeID}} - {{ctx.Locale.Tr "repo.issues.self_assign_at" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.self_assign_at" $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.add_assignee_at" (.Poster.GetDisplayName|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.add_assignee_at" (.Poster.GetDisplayName|Escape) $createdStr}} {{end}} </span> {{end}} @@ -220,7 +220,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.change_title_at" (.OldTitle|RenderEmoji $.Context) (.NewTitle|RenderEmoji $.Context) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.change_title_at" (.OldTitle|RenderEmoji $.Context) (.NewTitle|RenderEmoji $.Context) $createdStr}} </span> </div> {{else if eq .Type 11}} @@ -229,7 +229,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.delete_branch_at" (.OldRef|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.delete_branch_at" (.OldRef|Escape) $createdStr}} </span> </div> {{else if eq .Type 12}} @@ -238,7 +238,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.start_tracking_history" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.start_tracking_history" $createdStr}} </span> </div> {{else if eq .Type 13}} @@ -247,7 +247,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.stop_tracking_history" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.stop_tracking_history" $createdStr}} </span> {{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}} <div class="detail"> @@ -266,7 +266,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.add_time_history" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.add_time_history" $createdStr}} </span> {{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}} <div class="detail"> @@ -285,7 +285,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.cancel_tracking_history" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.cancel_tracking_history" $createdStr}} </span> </div> {{else if eq .Type 16}} @@ -294,7 +294,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.due_date_added" (DateTime "long" .Content) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.due_date_added" (DateTime "long" .Content) $createdStr}} </span> </div> {{else if eq .Type 17}} @@ -307,7 +307,7 @@ {{if eq (len $parsedDeadline) 2}} {{$from := DateTime "long" (index $parsedDeadline 1)}} {{$to := DateTime "long" (index $parsedDeadline 0)}} - {{ctx.Locale.Tr "repo.issues.due_date_modified" $to $from $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.due_date_modified" $to $from $createdStr}} {{end}} </span> </div> @@ -317,7 +317,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.due_date_remove" (DateTime "long" .Content) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.due_date_remove" (DateTime "long" .Content) $createdStr}} </span> </div> {{else if eq .Type 19}} @@ -326,7 +326,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.dependency.added_dependency" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.dependency.added_dependency" $createdStr}} </span> {{if .DependentIssue}} <div class="detail"> @@ -349,7 +349,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.dependency.removed_dependency" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.dependency.removed_dependency" $createdStr}} </span> {{if .DependentIssue}} <div class="detail"> @@ -393,13 +393,13 @@ {{end}} {{if eq .Review.Type 1}} - {{ctx.Locale.Tr "repo.issues.review.approve" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.review.approve" $createdStr}} {{else if eq .Review.Type 2}} - {{ctx.Locale.Tr "repo.issues.review.comment" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.review.comment" $createdStr}} {{else if eq .Review.Type 3}} - {{ctx.Locale.Tr "repo.issues.review.reject" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.review.reject" $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.review.comment" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.review.comment" $createdStr}} {{end}} {{if .Review.Dismissed}} <div class="ui small label">{{ctx.Locale.Tr "repo.issues.review.dismissed_label"}}</div> @@ -423,12 +423,12 @@ {{.OriginalAuthor}} </span> <span class="text grey muted-links"> {{if $.Repository.OriginalURL}}</span> - <span class="text migrate">({{ctx.Locale.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape) | Safe}}){{end}}</span> + <span class="text migrate">({{ctx.Locale.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape)}}){{end}}</span> {{else}} {{template "shared/user/authorlink" .Poster}} {{end}} - {{ctx.Locale.Tr "repo.issues.review.left_comment" | Safe}} + {{ctx.Locale.Tr "repo.issues.review.left_comment"}} </span> </div> <div class="comment-header-right actions gt-df gt-ac"> @@ -478,12 +478,12 @@ {{if .Content}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.lock_with_reason" .Content $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.lock_with_reason" .Content $createdStr}} </span> {{else}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.lock_no_reason" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.lock_no_reason" $createdStr}} </span> {{end}} </div> @@ -493,7 +493,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.unlock_comment" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.unlock_comment" $createdStr}} </span> </div> {{else if eq .Type 25}} @@ -502,7 +502,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> <a{{if gt .Poster.ID 0}} href="{{.Poster.HomeLink}}"{{end}}>{{.Poster.Name}}</a> - {{ctx.Locale.Tr "repo.pulls.change_target_branch_at" (.OldRef|Escape) (.NewRef|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.pulls.change_target_branch_at" (.OldRef|Escape) (.NewRef|Escape) $createdStr}} </span> </div> {{else if eq .Type 26}} @@ -512,7 +512,7 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.del_time_history" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.del_time_history" $createdStr}} </span> <div class="detail"> {{svg "octicon-clock"}} @@ -533,12 +533,12 @@ {{if (gt .AssigneeID 0)}} {{if .RemovedAssignee}} {{if eq .PosterID .AssigneeID}} - {{ctx.Locale.Tr "repo.issues.review.remove_review_request_self" $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.review.remove_review_request_self" $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.review.remove_review_request" (.Assignee.GetDisplayName|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.review.remove_review_request" (.Assignee.GetDisplayName|Escape) $createdStr}} {{end}} {{else}} - {{ctx.Locale.Tr "repo.issues.review.add_review_request" (.Assignee.GetDisplayName|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.review.add_review_request" (.Assignee.GetDisplayName|Escape) $createdStr}} {{end}} {{else}} <!-- If the assigned team is deleted, just displaying "Ghost Team" in the comment --> @@ -547,9 +547,9 @@ {{$teamName = .AssigneeTeam.Name}} {{end}} {{if .RemovedAssignee}} - {{ctx.Locale.Tr "repo.issues.review.remove_review_request" ($teamName|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.review.remove_review_request" ($teamName|Escape) $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.review.add_review_request" ($teamName|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.review.add_review_request" ($teamName|Escape) $createdStr}} {{end}} {{end}} </span> @@ -564,9 +564,9 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} {{if .IsForcePush}} - {{ctx.Locale.Tr "repo.issues.force_push_codes" ($.Issue.PullRequest.HeadBranch|Escape) (ShortSha .OldCommit) (($.Issue.Repo.CommitLink .OldCommit)|Escape) (ShortSha .NewCommit) (($.Issue.Repo.CommitLink .NewCommit)|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.force_push_codes" ($.Issue.PullRequest.HeadBranch|Escape) (ShortSha .OldCommit) (($.Issue.Repo.CommitLink .OldCommit)|Escape) (ShortSha .NewCommit) (($.Issue.Repo.CommitLink .NewCommit)|Escape) $createdStr}} {{else}} - {{ctx.Locale.TrN (len .Commits) "repo.issues.push_commit_1" "repo.issues.push_commits_n" (len .Commits) $createdStr | Safe}} + {{ctx.Locale.TrN (len .Commits) "repo.issues.push_commit_1" "repo.issues.push_commits_n" (len .Commits) $createdStr}} {{end}} </span> {{if and .IsForcePush $.Issue.PullRequest.BaseRepo.Name}} @@ -620,7 +620,7 @@ {{else}} {{$reviewerName = .Review.OriginalAuthor}} {{end}} - <span class="dismissed-message">{{ctx.Locale.Tr "repo.issues.review.dismissed" $reviewerName $createdStr | Safe}}</span> + <span class="dismissed-message">{{ctx.Locale.Tr "repo.issues.review.dismissed" $reviewerName $createdStr}}</span> </span> </div> {{if .Content}} @@ -656,11 +656,11 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} {{if and .OldRef .NewRef}} - {{ctx.Locale.Tr "repo.issues.change_ref_at" (.OldRef|Escape) (.NewRef|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.change_ref_at" (.OldRef|Escape) (.NewRef|Escape) $createdStr}} {{else if .OldRef}} - {{ctx.Locale.Tr "repo.issues.remove_ref_at" (.OldRef|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.remove_ref_at" (.OldRef|Escape) $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.add_ref_at" (.NewRef|Escape) $createdStr | Safe}} + {{ctx.Locale.Tr "repo.issues.add_ref_at" (.NewRef|Escape) $createdStr}} {{end}} </span> </div> @@ -679,8 +679,8 @@ {{else}} {{template "shared/user/authorlink" .Poster}} {{end}} - {{if eq .Type 34}}{{ctx.Locale.Tr "repo.pulls.auto_merge_newly_scheduled_comment" $createdStr | Safe}} - {{else}}{{ctx.Locale.Tr "repo.pulls.auto_merge_canceled_schedule_comment" $createdStr | Safe}}{{end}} + {{if eq .Type 34}}{{ctx.Locale.Tr "repo.pulls.auto_merge_newly_scheduled_comment" $createdStr}} + {{else}}{{ctx.Locale.Tr "repo.pulls.auto_merge_canceled_schedule_comment" $createdStr}}{{end}} </span> </div> {{else if or (eq .Type 36) (eq .Type 37)}} @@ -689,8 +689,8 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{if eq .Type 36}}{{ctx.Locale.Tr "repo.issues.pin_comment" $createdStr | Safe}} - {{else}}{{ctx.Locale.Tr "repo.issues.unpin_comment" $createdStr | Safe}}{{end}} + {{if eq .Type 36}}{{ctx.Locale.Tr "repo.issues.pin_comment" $createdStr}} + {{else}}{{ctx.Locale.Tr "repo.issues.unpin_comment" $createdStr}}{{end}} </span> </div> {{end}} diff --git a/templates/repo/issue/view_content/conversation.tmpl b/templates/repo/issue/view_content/conversation.tmpl index fc1d9865f5..1bc850d8cf 100644 --- a/templates/repo/issue/view_content/conversation.tmpl +++ b/templates/repo/issue/view_content/conversation.tmpl @@ -73,7 +73,7 @@ {{else}} {{template "shared/user/authorlink" .Poster}} {{end}} - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdSubStr | Safe}} + {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdSubStr}} </span> </div> <div class="comment-header-right actions gt-df gt-ac"> diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index e86deb8915..13d49b61b7 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -88,7 +88,7 @@ </div> {{if or .HasIssuesOrPullsWritePermission .IsIssuePoster}} <button class="ui compact button"> - {{ctx.Locale.Tr "repo.pulls.remove_prefix" (.WorkInProgressPrefix|Escape) | Safe}} + {{ctx.Locale.Tr "repo.pulls.remove_prefix" (.WorkInProgressPrefix|Escape)}} </button> {{end}} </div> @@ -127,7 +127,7 @@ {{else if .IsBlockedByChangedProtectedFiles}} <div class="item"> {{svg "octicon-x"}} - {{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n" | Safe}} + {{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}} </div> <ul> {{range .ChangedProtectedFiles}} @@ -334,7 +334,7 @@ {{else if .IsBlockedByChangedProtectedFiles}} <div class="item text red"> {{svg "octicon-x"}} - {{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n" | Safe}} + {{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}} </div> <ul> {{range .ChangedProtectedFiles}} diff --git a/templates/repo/issue/view_content/pull_merge_instruction.tmpl b/templates/repo/issue/view_content/pull_merge_instruction.tmpl index a214f29786..a2269feeaf 100644 --- a/templates/repo/issue/view_content/pull_merge_instruction.tmpl +++ b/templates/repo/issue/view_content/pull_merge_instruction.tmpl @@ -1,5 +1,5 @@ <div class="divider"></div> -<div class="instruct-toggle"> {{ctx.Locale.Tr "repo.pulls.cmd_instruction_hint" | Safe}} </div> +<div class="instruct-toggle"> {{ctx.Locale.Tr "repo.pulls.cmd_instruction_hint"}} </div> <div class="instruct-content gt-mt-3 gt-hidden"> <div><h3>{{ctx.Locale.Tr "repo.pulls.cmd_instruction_checkout_title"}}</h3>{{ctx.Locale.Tr "repo.pulls.cmd_instruction_checkout_desc"}}</div> {{$localBranch := .PullRequest.HeadBranch}} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 22f67ade7b..bb45b07421 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -101,7 +101,7 @@ {{range .OriginalReviews}} <div class="item gt-df gt-ac gt-py-3"> <div class="gt-df gt-ac gt-f1"> - <a class="muted" href="{{$.Repository.OriginalURL}}" data-tooltip-content="{{ctx.Locale.Tr "repo.migrated_from_fake" ($.Repository.GetOriginalURLHostname|Escape) | Safe}}"> + <a class="muted" href="{{$.Repository.OriginalURL}}" data-tooltip-content="{{ctx.Locale.Tr "repo.migrated_from_fake" ($.Repository.GetOriginalURLHostname|Escape)}}"> {{svg (MigrationIcon $.Repository.GetOriginalURLHostname) 20 "gt-mr-3"}} {{.OriginalAuthor}} </a> @@ -116,7 +116,7 @@ {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .HasMerged) (not .Issue.IsClosed) (not .IsPullWorkInProgress)}} <div class="toggle-wip" data-title="{{.Issue.Title}}" data-wip-prefix="{{(index .PullRequestWorkInProgressPrefixes 0| Escape)}}" data-update-url="{{.Issue.Link}}/title"> <a class="muted"> - {{ctx.Locale.Tr "repo.pulls.still_in_progress"}} {{ctx.Locale.Tr "repo.pulls.add_prefix" (index .PullRequestWorkInProgressPrefixes 0| Escape) | Safe}} + {{ctx.Locale.Tr "repo.pulls.still_in_progress"}} {{ctx.Locale.Tr "repo.pulls.add_prefix" (index .PullRequestWorkInProgressPrefixes 0| Escape)}} </a> </div> {{end}} @@ -300,7 +300,7 @@ {{else}} {{if .HasUserStopwatch}} <div class="ui warning message"> - {{ctx.Locale.Tr "repo.issues.tracking_already_started" (.OtherStopwatchURL|Escape) | Safe}} + {{ctx.Locale.Tr "repo.issues.tracking_already_started" (.OtherStopwatchURL|Escape)}} </div> {{end}} <button class="ui fluid button issue-start-time" data-tooltip-content='{{ctx.Locale.Tr "repo.issues.start_tracking"}}'> @@ -332,7 +332,7 @@ {{if .WorkingUsers}} <div class="divider"></div> <div class="ui comments"> - <span class="text"><strong>{{ctx.Locale.Tr "repo.issues.time_spent_from_all_authors" ($.Issue.TotalTrackedTime | Sec2Time) | Safe}}</strong></span> + <span class="text"><strong>{{ctx.Locale.Tr "repo.issues.time_spent_from_all_authors" ($.Issue.TotalTrackedTime | Sec2Time)}}</strong></span> <div> {{range $user, $trackedtime := .WorkingUsers}} <div class="comment gt-mt-3"> diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index 8a5954681b..c6c86124a1 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -112,11 +112,11 @@ {{$createdStr:= TimeSinceUnix .Issue.CreatedUnix ctx.Locale}} <span class="time-desc"> {{if .Issue.OriginalAuthor}} - {{ctx.Locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.OriginalAuthor|Escape) | Safe}} + {{ctx.Locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.OriginalAuthor|Escape)}} {{else if gt .Issue.Poster.ID 0}} - {{ctx.Locale.Tr "repo.issues.opened_by" $createdStr (.Issue.Poster.HomeLink|Escape) (.Issue.Poster.GetDisplayName|Escape) | Safe}} + {{ctx.Locale.Tr "repo.issues.opened_by" $createdStr (.Issue.Poster.HomeLink|Escape) (.Issue.Poster.GetDisplayName|Escape)}} {{else}} - {{ctx.Locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.Poster.GetDisplayName|Escape) | Safe}} + {{ctx.Locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.Poster.GetDisplayName|Escape)}} {{end}} · {{ctx.Locale.TrN .Issue.NumComments "repo.issues.num_comments_1" "repo.issues.num_comments" .Issue.NumComments}} diff --git a/templates/repo/migrate/codebase.tmpl b/templates/repo/migrate/codebase.tmpl index a34a039f8f..439a883863 100644 --- a/templates/repo/migrate/codebase.tmpl +++ b/templates/repo/migrate/codebase.tmpl @@ -35,22 +35,22 @@ <label>{{ctx.Locale.Tr "repo.migrate_items"}}</label> <div class="ui checkbox"> <input name="milestones" type="checkbox" {{if .milestones}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_milestones" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_milestones"}}</label> </div> <div class="ui checkbox"> <input name="labels" type="checkbox" {{if .labels}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_labels" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_labels"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="issues" type="checkbox" {{if .issues}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_issues" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_issues"}}</label> </div> <div class="ui checkbox"> <input name="pull_requests" type="checkbox" {{if .pull_requests}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_merge_requests" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_merge_requests"}}</label> </div> </div> </div> @@ -90,10 +90,10 @@ <div class="ui checkbox"> {{if .IsForcedPrivate}} <input name="private" type="checkbox" checked readonly> - <label>{{ctx.Locale.Tr "repo.visibility_helper_forced" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> {{end}} </div> </div> diff --git a/templates/repo/migrate/git.tmpl b/templates/repo/migrate/git.tmpl index 7fe4fbc672..db01b8d858 100644 --- a/templates/repo/migrate/git.tmpl +++ b/templates/repo/migrate/git.tmpl @@ -64,10 +64,10 @@ <div class="ui checkbox"> {{if .IsForcedPrivate}} <input name="private" type="checkbox" checked readonly> - <label>{{ctx.Locale.Tr "repo.visibility_helper_forced" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> {{end}} </div> </div> diff --git a/templates/repo/migrate/gitbucket.tmpl b/templates/repo/migrate/gitbucket.tmpl index d07351e727..d1f1db99ba 100644 --- a/templates/repo/migrate/gitbucket.tmpl +++ b/templates/repo/migrate/gitbucket.tmpl @@ -34,7 +34,7 @@ <label>{{ctx.Locale.Tr "repo.migrate_items"}}</label> <div class="ui checkbox"> <input name="wiki" type="checkbox" {{if .wiki}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_wiki" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_wiki"}}</label> </div> </div> @@ -44,29 +44,29 @@ <label></label> <div class="ui checkbox"> <input name="labels" type="checkbox" {{if .labels}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_labels" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_labels"}}</label> </div> <div class="ui checkbox"> <input name="issues" type="checkbox" {{if .issues}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_issues" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_issues"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="pull_requests" type="checkbox" {{if .pull_requests}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_pullrequests" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_pullrequests"}}</label> </div> <div class="ui checkbox"> <input name="releases" type="checkbox" {{if .releases}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_releases" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_releases"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="milestones" type="checkbox" {{if .milestones}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_milestones" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_milestones"}}</label> </div> </div> </div> @@ -106,10 +106,10 @@ <div class="ui checkbox"> {{if .IsForcedPrivate}} <input name="private" type="checkbox" checked readonly> - <label>{{ctx.Locale.Tr "repo.visibility_helper_forced" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> {{end}} </div> </div> diff --git a/templates/repo/migrate/gitea.tmpl b/templates/repo/migrate/gitea.tmpl index a40886b7a5..143f220449 100644 --- a/templates/repo/migrate/gitea.tmpl +++ b/templates/repo/migrate/gitea.tmpl @@ -30,7 +30,7 @@ <label>{{ctx.Locale.Tr "repo.migrate_items"}}</label> <div class="ui checkbox"> <input name="wiki" type="checkbox" {{if .wiki}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_wiki" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_wiki"}}</label> </div> </div> @@ -40,29 +40,29 @@ <label></label> <div class="ui checkbox"> <input name="labels" type="checkbox" {{if .labels}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_labels" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_labels"}}</label> </div> <div class="ui checkbox"> <input name="issues" type="checkbox" {{if .issues}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_issues" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_issues"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="pull_requests" type="checkbox" {{if .pull_requests}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_pullrequests" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_pullrequests"}}</label> </div> <div class="ui checkbox"> <input name="releases" type="checkbox" {{if .releases}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_releases" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_releases"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="milestones" type="checkbox" {{if .milestones}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_milestones" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_milestones"}}</label> </div> </div> </div> @@ -102,10 +102,10 @@ <div class="ui checkbox"> {{if .IsForcedPrivate}} <input name="private" type="checkbox" checked readonly> - <label>{{ctx.Locale.Tr "repo.visibility_helper_forced" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> {{end}} </div> </div> diff --git a/templates/repo/migrate/github.tmpl b/templates/repo/migrate/github.tmpl index 07f8216fcb..dfb2b4bc46 100644 --- a/templates/repo/migrate/github.tmpl +++ b/templates/repo/migrate/github.tmpl @@ -33,7 +33,7 @@ <label>{{ctx.Locale.Tr "repo.migrate_items"}}</label> <div class="ui checkbox"> <input name="wiki" type="checkbox" {{if .wiki}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_wiki" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_wiki"}}</label> </div> </div> <div id="migrate_items"> @@ -42,29 +42,29 @@ <label></label> <div class="ui checkbox"> <input name="labels" type="checkbox" {{if .labels}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_labels" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_labels"}}</label> </div> <div class="ui checkbox"> <input name="issues" type="checkbox" {{if .issues}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_issues" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_issues"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="pull_requests" type="checkbox" {{if .pull_requests}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_pullrequests" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_pullrequests"}}</label> </div> <div class="ui checkbox"> <input name="releases" type="checkbox" {{if .releases}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_releases" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_releases"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="milestones" type="checkbox" {{if .milestones}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_milestones" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_milestones"}}</label> </div> </div> </div> @@ -104,10 +104,10 @@ <div class="ui checkbox"> {{if .IsForcedPrivate}} <input name="private" type="checkbox" checked readonly> - <label>{{ctx.Locale.Tr "repo.visibility_helper_forced" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> {{end}} </div> </div> diff --git a/templates/repo/migrate/gitlab.tmpl b/templates/repo/migrate/gitlab.tmpl index 623822df11..76c2828257 100644 --- a/templates/repo/migrate/gitlab.tmpl +++ b/templates/repo/migrate/gitlab.tmpl @@ -30,7 +30,7 @@ <label>{{ctx.Locale.Tr "repo.migrate_items"}}</label> <div class="ui checkbox"> <input name="wiki" type="checkbox" {{if .wiki}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_wiki" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_wiki"}}</label> </div> </div> <div id="migrate_items"> @@ -39,29 +39,29 @@ <label></label> <div class="ui checkbox"> <input name="labels" type="checkbox" {{if .labels}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_labels" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_labels"}}</label> </div> <div class="ui checkbox"> <input name="issues" type="checkbox" {{if .issues}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_issues" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_issues"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="pull_requests" type="checkbox" {{if .pull_requests}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_merge_requests" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_merge_requests"}}</label> </div> <div class="ui checkbox"> <input name="releases" type="checkbox" {{if .releases}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_releases" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_releases"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="milestones" type="checkbox" {{if .milestones}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_milestones" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_milestones"}}</label> </div> </div> </div> @@ -101,10 +101,10 @@ <div class="ui checkbox"> {{if .IsForcedPrivate}} <input name="private" type="checkbox" checked readonly> - <label>{{ctx.Locale.Tr "repo.visibility_helper_forced" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> {{end}} </div> </div> diff --git a/templates/repo/migrate/gogs.tmpl b/templates/repo/migrate/gogs.tmpl index 095efd5d60..b01d0eeb67 100644 --- a/templates/repo/migrate/gogs.tmpl +++ b/templates/repo/migrate/gogs.tmpl @@ -30,7 +30,7 @@ <label>{{ctx.Locale.Tr "repo.migrate_items"}}</label> <div class="ui checkbox"> <input name="wiki" type="checkbox" {{if .wiki}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_wiki" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_wiki"}}</label> </div> </div> @@ -40,18 +40,18 @@ <label></label> <div class="ui checkbox"> <input name="labels" type="checkbox" {{if .labels}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_labels" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_labels"}}</label> </div> <div class="ui checkbox"> <input name="issues" type="checkbox" {{if .issues}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_issues" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_issues"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="milestones" type="checkbox" {{if .milestones}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_milestones" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_milestones"}}</label> </div> </div> <!-- Gogs do not support it @@ -59,11 +59,11 @@ <label></label> <div class="ui checkbox"> <input name="pull_requests" type="checkbox" {{if .pull_requests}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_merge_requests" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_merge_requests"}}</label> </div> <div class="ui checkbox"> <input name="releases" type="checkbox" {{if .releases}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_releases" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_releases"}}</label> </div> </div> --> @@ -104,10 +104,10 @@ <div class="ui checkbox"> {{if .IsForcedPrivate}} <input name="private" type="checkbox" checked readonly> - <label>{{ctx.Locale.Tr "repo.visibility_helper_forced" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}} checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> {{end}} </div> </div> diff --git a/templates/repo/migrate/migrating.tmpl b/templates/repo/migrate/migrating.tmpl index 46cf997b68..bf8ea0ef7a 100644 --- a/templates/repo/migrate/migrating.tmpl +++ b/templates/repo/migrate/migrating.tmpl @@ -21,14 +21,14 @@ <div class="ui stackable middle very relaxed page grid"> <div class="sixteen wide center aligned centered column"> <div id="repo_migrating_progress"> - <p>{{ctx.Locale.Tr "repo.migrate.migrating" .CloneAddr | Safe}}</p> + <p>{{ctx.Locale.Tr "repo.migrate.migrating" .CloneAddr}}</p> <p id="repo_migrating_progress_message"></p> </div> <div id="repo_migrating_failed" class="gt-hidden"> {{if .CloneAddr}} - <p>{{ctx.Locale.Tr "repo.migrate.migrating_failed" .CloneAddr | Safe}}</p> + <p>{{ctx.Locale.Tr "repo.migrate.migrating_failed" .CloneAddr}}</p> {{else}} - <p>{{ctx.Locale.Tr "repo.migrate.migrating_failed_no_addr" | Safe}}</p> + <p>{{ctx.Locale.Tr "repo.migrate.migrating_failed_no_addr"}}</p> {{end}} <p id="repo_migrating_failed_error"></p> </div> @@ -57,8 +57,8 @@ </div> <div class="content"> <div class="ui warning message"> - {{ctx.Locale.Tr "repo.settings.delete_notices_1" | Safe}}<br> - {{ctx.Locale.Tr "repo.settings.delete_notices_2" .Repository.FullName | Safe}} + {{ctx.Locale.Tr "repo.settings.delete_notices_1"}}<br> + {{ctx.Locale.Tr "repo.settings.delete_notices_2" .Repository.FullName}} {{if .Repository.NumForks}}<br> {{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}} {{end}} diff --git a/templates/repo/migrate/onedev.tmpl b/templates/repo/migrate/onedev.tmpl index b06e6929a1..8b2a2d8730 100644 --- a/templates/repo/migrate/onedev.tmpl +++ b/templates/repo/migrate/onedev.tmpl @@ -35,22 +35,22 @@ <label>{{ctx.Locale.Tr "repo.migrate_items"}}</label> <div class="ui checkbox"> <input name="milestones" type="checkbox" {{if .milestones}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_milestones" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_milestones"}}</label> </div> <div class="ui checkbox"> <input name="labels" type="checkbox" {{if .labels}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_labels" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_labels"}}</label> </div> </div> <div class="inline field"> <label></label> <div class="ui checkbox"> <input name="issues" type="checkbox" {{if .issues}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_issues" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_issues"}}</label> </div> <div class="ui checkbox"> <input name="pull_requests" type="checkbox" {{if .pull_requests}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.migrate_items_pullrequests" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.migrate_items_pullrequests"}}</label> </div> </div> </div> @@ -90,10 +90,10 @@ <div class="ui checkbox"> {{if .IsForcedPrivate}} <input name="private" type="checkbox" checked readonly> - <label>{{ctx.Locale.Tr "repo.visibility_helper_forced" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label> {{else}} <input name="private" type="checkbox" {{if .private}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> {{end}} </div> </div> diff --git a/templates/repo/pulls/fork.tmpl b/templates/repo/pulls/fork.tmpl index 94de4d78eb..f0907f409b 100644 --- a/templates/repo/pulls/fork.tmpl +++ b/templates/repo/pulls/fork.tmpl @@ -47,7 +47,7 @@ <label>{{ctx.Locale.Tr "repo.visibility"}}</label> <div class="ui disabled checkbox"> <input type="checkbox" disabled {{if .IsPrivate}}checked{{end}}> - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}}</label> </div> <span class="help">{{ctx.Locale.Tr "repo.fork_visibility_helper"}}</span> </div> diff --git a/templates/repo/pulse.tmpl b/templates/repo/pulse.tmpl index ccd7ebf6b5..e6a59ea8c6 100644 --- a/templates/repo/pulse.tmpl +++ b/templates/repo/pulse.tmpl @@ -33,7 +33,7 @@ <a class="table-cell tiny background light grey"></a> </div> {{end}} - {{ctx.Locale.TrN .Activity.ActivePRCount "repo.activity.active_prs_count_1" "repo.activity.active_prs_count_n" .Activity.ActivePRCount | Safe}} + {{ctx.Locale.TrN .Activity.ActivePRCount "repo.activity.active_prs_count_1" "repo.activity.active_prs_count_n" .Activity.ActivePRCount}} </div> {{end}} {{if .Permission.CanRead $.UnitTypeIssues}} @@ -48,7 +48,7 @@ <a class="table-cell tiny background light grey"></a> </div> {{end}} - {{ctx.Locale.TrN .Activity.ActiveIssueCount "repo.activity.active_issues_count_1" "repo.activity.active_issues_count_n" .Activity.ActiveIssueCount | Safe}} + {{ctx.Locale.TrN .Activity.ActiveIssueCount "repo.activity.active_issues_count_1" "repo.activity.active_issues_count_n" .Activity.ActiveIssueCount}} </div> {{end}} </div> diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl index a283150c60..3ea854ef88 100644 --- a/templates/repo/settings/deploy_keys.tmpl +++ b/templates/repo/settings/deploy_keys.tmpl @@ -55,7 +55,7 @@ {{.Fingerprint}} </div> <div class="flex-item-body"> - <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}} - <span>{{ctx.Locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{ctx.Locale.Tr "settings.can_write_info"}} {{end}}</span></i> + <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}} - <span>{{ctx.Locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{ctx.Locale.Tr "settings.can_write_info"}} {{end}}</span></i> </div> </div> <div class="flex-item-trailing"> diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 6cfef31060..128f553d3d 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -32,7 +32,7 @@ {{else}} <input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} readonly{{end}}> {{end}} - <label>{{ctx.Locale.Tr "repo.visibility_helper" | Safe}} {{if .Repository.NumForks}}<span class="text red">{{ctx.Locale.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label> + <label>{{ctx.Locale.Tr "repo.visibility_helper"}} {{if .Repository.NumForks}}<span class="text red">{{ctx.Locale.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label> </div> </div> {{end}} @@ -624,8 +624,8 @@ </div> <div class="content"> <div class="ui warning message"> - {{ctx.Locale.Tr "repo.settings.delete_notices_1" | Safe}}<br> - {{ctx.Locale.Tr "repo.settings.delete_notices_2" .Repository.FullName | Safe}} + {{ctx.Locale.Tr "repo.settings.delete_notices_1"}}<br> + {{ctx.Locale.Tr "repo.settings.delete_notices_2" .Repository.FullName}} {{if .Repository.NumForks}}<br> {{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}} {{end}} @@ -659,8 +659,8 @@ </div> <div class="content"> <div class="ui warning message"> - {{ctx.Locale.Tr "repo.settings.delete_notices_1" | Safe}}<br> - {{ctx.Locale.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name | Safe}} + {{ctx.Locale.Tr "repo.settings.delete_notices_1"}}<br> + {{ctx.Locale.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name}} </div> <form class="ui form" action="{{.Link}}" method="post"> {{.CsrfTokenHtml}} diff --git a/templates/repo/settings/protected_branch.tmpl b/templates/repo/settings/protected_branch.tmpl index 9c0fbddf06..e2f841f758 100644 --- a/templates/repo/settings/protected_branch.tmpl +++ b/templates/repo/settings/protected_branch.tmpl @@ -10,17 +10,17 @@ <label>{{ctx.Locale.Tr "repo.settings.protect_branch_name_pattern"}}</label> <input name="rule_name" type="text" value="{{.Rule.RuleName}}"> <input name="rule_id" type="hidden" value="{{.Rule.ID}}"> - <p class="help gt-ml-0">{{ctx.Locale.Tr "repo.settings.protect_branch_name_pattern_desc" | Safe}}</p> + <p class="help gt-ml-0">{{ctx.Locale.Tr "repo.settings.protect_branch_name_pattern_desc"}}</p> </div> <div class="field"> <label>{{ctx.Locale.Tr "repo.settings.protect_protected_file_patterns"}}</label> <input name="protected_file_patterns" type="text" value="{{.Rule.ProtectedFilePatterns}}"> - <p class="help gt-ml-0">{{ctx.Locale.Tr "repo.settings.protect_protected_file_patterns_desc" | Safe}}</p> + <p class="help gt-ml-0">{{ctx.Locale.Tr "repo.settings.protect_protected_file_patterns_desc"}}</p> </div> <div class="field"> <label>{{ctx.Locale.Tr "repo.settings.protect_unprotected_file_patterns"}}</label> <input name="unprotected_file_patterns" type="text" value="{{.Rule.UnprotectedFilePatterns}}"> - <p class="help gt-ml-0">{{ctx.Locale.Tr "repo.settings.protect_unprotected_file_patterns_desc" | Safe}}</p> + <p class="help gt-ml-0">{{ctx.Locale.Tr "repo.settings.protect_unprotected_file_patterns_desc"}}</p> </div> {{.CsrfTokenHtml}} diff --git a/templates/repo/settings/tags.tmpl b/templates/repo/settings/tags.tmpl index ed7762acc5..e4fcf2ee6b 100644 --- a/templates/repo/settings/tags.tmpl +++ b/templates/repo/settings/tags.tmpl @@ -21,7 +21,7 @@ <div class="ui input"> <input class="prompt" name="name_pattern" autocomplete="off" value="{{.name_pattern}}" placeholder="v*" autofocus required> </div> - <div class="help">{{ctx.Locale.Tr "repo.settings.tags.protection.pattern.description" | Safe}}</div> + <div class="help">{{ctx.Locale.Tr "repo.settings.tags.protection.pattern.description"}}</div> </div> </div> <div class="whitelist field"> diff --git a/templates/repo/user_cards.tmpl b/templates/repo/user_cards.tmpl index 12fb23f067..5accc2c7af 100644 --- a/templates/repo/user_cards.tmpl +++ b/templates/repo/user_cards.tmpl @@ -18,7 +18,7 @@ {{else if .Location}} {{svg "octicon-location"}} {{.Location}} {{else}} - {{svg "octicon-calendar"}} {{ctx.Locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}} + {{svg "octicon-calendar"}} {{ctx.Locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix)}} {{end}} </div> </li> diff --git a/templates/repo/wiki/pages.tmpl b/templates/repo/wiki/pages.tmpl index a1bf13287c..22eb2619f9 100644 --- a/templates/repo/wiki/pages.tmpl +++ b/templates/repo/wiki/pages.tmpl @@ -20,7 +20,7 @@ <a class="wiki-git-entry" href="{{$.RepoLink}}/wiki/{{.GitEntryName | PathEscape}}" data-tooltip-content="{{ctx.Locale.Tr "repo.wiki.original_git_entry_tooltip"}}">{{svg "octicon-chevron-right"}}</a> </td> {{$timeSince := TimeSinceUnix .UpdatedUnix ctx.Locale}} - <td class="text right">{{ctx.Locale.Tr "repo.wiki.last_updated" $timeSince | Safe}}</td> + <td class="text right">{{ctx.Locale.Tr "repo.wiki.last_updated" $timeSince}}</td> </tr> {{end}} </tbody> diff --git a/templates/repo/wiki/revision.tmpl b/templates/repo/wiki/revision.tmpl index 95b3cd0920..647c331d55 100644 --- a/templates/repo/wiki/revision.tmpl +++ b/templates/repo/wiki/revision.tmpl @@ -10,7 +10,7 @@ {{$title}} <div class="ui sub header gt-word-break"> {{$timeSince := TimeSince .Author.When ctx.Locale}} - {{ctx.Locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}} + {{ctx.Locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince}} </div> </div> </div> diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index 039ff3f179..5b296dc2af 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -40,7 +40,7 @@ {{$title}} <div class="ui sub header"> {{$timeSince := TimeSince .Author.When ctx.Locale}} - {{ctx.Locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}} + {{ctx.Locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince}} </div> </div> <div class="eight wide right aligned column"> @@ -107,7 +107,7 @@ {{ctx.Locale.Tr "repo.wiki.delete_page_button"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "repo.wiki.delete_page_notice_1" ($title|Escape) | Safe}}</p> + <p>{{ctx.Locale.Tr "repo.wiki.delete_page_notice_1" ($title|Escape)}}</p> </div> {{template "base/modal_actions_confirm" .}} </div> diff --git a/templates/shared/actions/runner_edit.tmpl b/templates/shared/actions/runner_edit.tmpl index c10901501d..fbc730b288 100644 --- a/templates/shared/actions/runner_edit.tmpl +++ b/templates/shared/actions/runner_edit.tmpl @@ -89,7 +89,7 @@ {{ctx.Locale.Tr "actions.runners.delete_runner_header"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "actions.runners.delete_runner_notice" | Safe}}</p> + <p>{{ctx.Locale.Tr "actions.runners.delete_runner_notice"}}</p> </div> {{template "base/modal_actions_confirm" .}} </div> diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index 8fe5aadf2b..7940234ccc 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -62,11 +62,11 @@ </a> {{$timeStr := TimeSinceUnix .GetLastEventTimestamp ctx.Locale}} {{if .OriginalAuthor}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape) | Safe}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape)}} {{else if gt .Poster.ID 0}} - {{ctx.Locale.Tr .GetLastEventLabel $timeStr (.Poster.HomeLink|Escape) (.Poster.GetDisplayName | Escape) | Safe}} + {{ctx.Locale.Tr .GetLastEventLabel $timeStr (.Poster.HomeLink|Escape) (.Poster.GetDisplayName | Escape)}} {{else}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape)}} {{end}} {{if .IsPull}} <div class="branches flex-text-inline"> diff --git a/templates/shared/searchbottom.tmpl b/templates/shared/searchbottom.tmpl index 55b6cb2909..b123b497c7 100644 --- a/templates/shared/searchbottom.tmpl +++ b/templates/shared/searchbottom.tmpl @@ -6,7 +6,7 @@ </div> <div class="gt-mr-4"> {{if not .result.UpdatedUnix.IsZero}} - <span class="ui grey text">{{ctx.Locale.Tr "explore.code_last_indexed_at" (TimeSinceUnix .result.UpdatedUnix ctx.Locale) | Safe}}</span> + <span class="ui grey text">{{ctx.Locale.Tr "explore.code_last_indexed_at" (TimeSinceUnix .result.UpdatedUnix ctx.Locale)}}</span> {{end}} </div> </div> diff --git a/templates/shared/secrets/add_list.tmpl b/templates/shared/secrets/add_list.tmpl index 7192f31fb2..4fbd8ddcfd 100644 --- a/templates/shared/secrets/add_list.tmpl +++ b/templates/shared/secrets/add_list.tmpl @@ -28,7 +28,7 @@ </div> <div class="flex-item-trailing"> <span class="color-text-light-2"> - {{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}} + {{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}} </span> <button class="ui btn interact-bg link-action gt-p-3" data-url="{{$.Link}}/delete?id={{.ID}}" diff --git a/templates/shared/user/profile_big_avatar.tmpl b/templates/shared/user/profile_big_avatar.tmpl index e731cfe2e0..f1b0560b3b 100644 --- a/templates/shared/user/profile_big_avatar.tmpl +++ b/templates/shared/user/profile_big_avatar.tmpl @@ -81,7 +81,7 @@ </li> {{end}} {{end}} - <li>{{svg "octicon-calendar"}} <span>{{ctx.Locale.Tr "user.joined_on" (DateTime "short" .ContextUser.CreatedUnix) | Safe}}</span></li> + <li>{{svg "octicon-calendar"}} <span>{{ctx.Locale.Tr "user.joined_on" (DateTime "short" .ContextUser.CreatedUnix)}}</span></li> {{if and .Orgs .HasOrgsVisible}} <li> <ul class="user-orgs"> diff --git a/templates/shared/variables/variable_list.tmpl b/templates/shared/variables/variable_list.tmpl index fc5cd966fc..8e262d016c 100644 --- a/templates/shared/variables/variable_list.tmpl +++ b/templates/shared/variables/variable_list.tmpl @@ -30,7 +30,7 @@ </div> <div class="flex-item-trailing"> <span class="color-text-light-2"> - {{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}} + {{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}} </span> <button class="btn interact-bg gt-p-3 show-modal" data-tooltip-content="{{ctx.Locale.Tr "actions.variables.edit"}}" diff --git a/templates/status/404.tmpl b/templates/status/404.tmpl index c73ee34774..289b9ea654 100644 --- a/templates/status/404.tmpl +++ b/templates/status/404.tmpl @@ -3,7 +3,7 @@ {{if .IsRepo}}{{template "repo/header" .}}{{end}} <div class="ui container center"> <h1 style="margin-top: 100px" class="error-code">404</h1> - <p>{{if .NotFoundPrompt}}{{.NotFoundPrompt}}{{else}}{{ctx.Locale.Tr "error404" | Safe}}{{end}}</p> + <p>{{if .NotFoundPrompt}}{{.NotFoundPrompt}}{{else}}{{ctx.Locale.Tr "error404"}}{{end}}</p> {{if .NotFoundGoBackURL}}<a class="ui button green" href="{{.NotFoundGoBackURL}}">{{ctx.Locale.Tr "go_back"}}</a>{{end}} <div class="divider"></div> diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 390457a60a..1829021ff4 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -106,14 +106,14 @@ {{if .UpdatedUnix}} <div class="flex-text-block"> {{svg "octicon-clock"}} - {{ctx.Locale.Tr "repo.milestones.update_ago" (TimeSinceUnix .UpdatedUnix ctx.Locale) | Safe}} + {{ctx.Locale.Tr "repo.milestones.update_ago" (TimeSinceUnix .UpdatedUnix ctx.Locale)}} </div> {{end}} <div class="flex-text-block"> {{if .IsClosed}} {{$closedDate:= TimeSinceUnix .ClosedDateUnix ctx.Locale}} {{svg "octicon-clock" 14}} - {{ctx.Locale.Tr "repo.milestones.closed" $closedDate | Safe}} + {{ctx.Locale.Tr "repo.milestones.closed" $closedDate}} {{else}} {{if .DeadlineString}} <span{{if .IsOverdue}} class="text red"{{end}}> diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index 7553c798dc..e7eb6c8180 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -36,7 +36,7 @@ </ul> </details> <div class="flex-item-body"> - <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</i> + <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</i> </div> </div> <div class="flex-item-trailing"> diff --git a/templates/user/settings/grants_oauth2.tmpl b/templates/user/settings/grants_oauth2.tmpl index 3c4c6e80d4..92fea1306f 100644 --- a/templates/user/settings/grants_oauth2.tmpl +++ b/templates/user/settings/grants_oauth2.tmpl @@ -14,7 +14,7 @@ <div class="flex-item-main"> <div class="flex-item-title">{{.Application.Name}}</div> <div class="flex-item-body"> - <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}}</i> + <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}}</i> </div> </div> <div class="flex-item-trailing"> diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl index e8bba69f6d..981cfd8106 100644 --- a/templates/user/settings/keys_gpg.tmpl +++ b/templates/user/settings/keys_gpg.tmpl @@ -63,9 +63,9 @@ <b>{{ctx.Locale.Tr "settings.subkeys"}}:</b> {{range .SubsKey}} {{.PaddedKeyID}} {{end}} </div> <div class="flex-item-body"> - <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .AddedUnix) | Safe}}</i> + <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .AddedUnix)}}</i> - - <i>{{if not .ExpiredUnix.IsZero}}{{ctx.Locale.Tr "settings.valid_until_date" (DateTime "short" .ExpiredUnix) | Safe}}{{else}}{{ctx.Locale.Tr "settings.valid_forever"}}{{end}}</i> + <i>{{if not .ExpiredUnix.IsZero}}{{ctx.Locale.Tr "settings.valid_until_date" (DateTime "short" .ExpiredUnix)}}{{else}}{{ctx.Locale.Tr "settings.valid_forever"}}{{end}}</i> </div> </div> <div class="flex-item-trailing"> diff --git a/templates/user/settings/keys_principal.tmpl b/templates/user/settings/keys_principal.tmpl index a7ab12dd78..b6acb63c5e 100644 --- a/templates/user/settings/keys_principal.tmpl +++ b/templates/user/settings/keys_principal.tmpl @@ -22,7 +22,7 @@ <div class="flex-item-main"> <div class="flex-item-title">{{.Name}}</div> <div class="flex-item-body"> - <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}} — {{svg "octicon-info" 16}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</i> + <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}} — {{svg "octicon-info" 16}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</i> </div> </div> <div class="flex-item-trailing"> diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index 9a49cc4e8b..dc3179fdd0 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -53,7 +53,7 @@ {{.Fingerprint}} </div> <div class="flex-item-body"> - <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</i> + <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</i> </div> </div> <div class="flex-item-trailing"> diff --git a/templates/user/settings/packages.tmpl b/templates/user/settings/packages.tmpl index 43a0f9eca0..bd7d69b259 100644 --- a/templates/user/settings/packages.tmpl +++ b/templates/user/settings/packages.tmpl @@ -16,7 +16,7 @@ <button class="ui primary button">{{ctx.Locale.Tr "packages.owner.settings.chef.keypair"}}</button> </form> <div class="field"> - <label>{{ctx.Locale.Tr "packages.registry.documentation" "Chef" "https://forgejo.org/docs/latest/user/packages/chef/" | Safe}}</label> + <label>{{ctx.Locale.Tr "packages.registry.documentation" "Chef" "https://forgejo.org/docs/latest/user/packages/chef/"}}</label> </div> </div> </div> diff --git a/templates/user/settings/security/webauthn.tmpl b/templates/user/settings/security/webauthn.tmpl index da6e5977c6..e582b801da 100644 --- a/templates/user/settings/security/webauthn.tmpl +++ b/templates/user/settings/security/webauthn.tmpl @@ -12,7 +12,7 @@ <div class="flex-item-main"> <div class="flex-item-title">{{.Name}}</div> <div class="flex-item-body"> - <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}}</i> + <i>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}}</i> </div> </div> <div class="flex-item-trailing"> From 6db296f1cbd217067336d45a8ab38629f0c8ba83 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Thu, 22 Feb 2024 19:13:25 +0200 Subject: [PATCH 26/64] Remove jQuery from the repo commit functions (#29230) - Switched to plain JavaScript - Tested the commit ellipsis button functionality and it works as before - Tested the commits statuses tippy functionality and it works as before - Tested the last commit loader functionality and it works as before # Demo using JavaScript without jQuery   --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: silverwind <me@silverwind.io> (cherry picked from commit eaede2de98fbe0ac2156c9f4cd8b5899d2c7cbbf) --- web_src/js/features/repo-commit.js | 96 +++++++++++++++--------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/web_src/js/features/repo-commit.js b/web_src/js/features/repo-commit.js index fc70ba41e4..7e2f6fa58e 100644 --- a/web_src/js/features/repo-commit.js +++ b/web_src/js/features/repo-commit.js @@ -1,70 +1,70 @@ -import $ from 'jquery'; import {createTippy} from '../modules/tippy.js'; import {toggleElem} from '../utils/dom.js'; - -const {csrfToken} = window.config; +import {parseDom} from '../utils.js'; +import {POST} from '../modules/fetch.js'; export function initRepoEllipsisButton() { - $('.js-toggle-commit-body').on('click', function (e) { - e.preventDefault(); - const expanded = $(this).attr('aria-expanded') === 'true'; - toggleElem($(this).parent().find('.commit-body')); - $(this).attr('aria-expanded', String(!expanded)); - }); + for (const button of document.querySelectorAll('.js-toggle-commit-body')) { + button.addEventListener('click', function (e) { + e.preventDefault(); + const expanded = this.getAttribute('aria-expanded') === 'true'; + toggleElem(this.parentElement.querySelector('.commit-body')); + this.setAttribute('aria-expanded', String(!expanded)); + }); + } } -export function initRepoCommitLastCommitLoader() { - const notReadyEls = document.querySelectorAll('table#repo-files-table tr.notready'); - if (!notReadyEls.length) return; - +export async function initRepoCommitLastCommitLoader() { const entryMap = {}; - const entries = []; - for (const el of notReadyEls) { - const entryname = el.getAttribute('data-entryname'); - entryMap[entryname] = $(el); - entries.push(entryname); - } - const lastCommitLoaderURL = $('table#repo-files-table').data('lastCommitLoaderUrl'); + const entries = Array.from(document.querySelectorAll('table#repo-files-table tr.notready'), (el) => { + const entryName = el.getAttribute('data-entryname'); + entryMap[entryName] = el; + return entryName; + }); - if (entries.length > 200) { - $.post(lastCommitLoaderURL, { - _csrf: csrfToken, - }, (data) => { - $('table#repo-files-table').replaceWith(data); - }); + if (entries.length === 0) { return; } - $.post(lastCommitLoaderURL, { - _csrf: csrfToken, - 'f': entries, - }, (data) => { - $(data).find('tr').each((_, row) => { - if (row.className === 'commit-list') { - $('table#repo-files-table .commit-list').replaceWith(row); - return; - } - // there are other <tr> rows in response (eg: <tr class="has-parent">) - // at the moment only the "data-entryname" rows should be processed - const entryName = $(row).attr('data-entryname'); - if (entryName) { - entryMap[entryName].replaceWith(row); - } - }); - }); + const lastCommitLoaderURL = document.querySelector('table#repo-files-table').getAttribute('data-last-commit-loader-url'); + + if (entries.length > 200) { + // For more than 200 entries, replace the entire table + const response = await POST(lastCommitLoaderURL); + const data = await response.text(); + document.querySelector('table#repo-files-table').outerHTML = data; + return; + } + + // For fewer entries, update individual rows + const response = await POST(lastCommitLoaderURL, {data: {'f': entries}}); + const data = await response.text(); + const doc = parseDom(data, 'text/html'); + for (const row of doc.querySelectorAll('tr')) { + if (row.className === 'commit-list') { + document.querySelector('table#repo-files-table .commit-list')?.replaceWith(row); + continue; + } + // there are other <tr> rows in response (eg: <tr class="has-parent">) + // at the moment only the "data-entryname" rows should be processed + const entryName = row.getAttribute('data-entryname'); + if (entryName) { + entryMap[entryName]?.replaceWith(row); + } + } } export function initCommitStatuses() { - $('[data-tippy="commit-statuses"]').each(function () { - const top = $('.repository.file.list').length > 0 || $('.repository.diff').length > 0; + for (const element of document.querySelectorAll('[data-tippy="commit-statuses"]')) { + const top = document.querySelector('.repository.file.list') || document.querySelector('.repository.diff'); - createTippy(this, { - content: this.nextElementSibling, + createTippy(element, { + content: element.nextElementSibling, placement: top ? 'top-start' : 'bottom-start', interactive: true, role: 'dialog', theme: 'box-with-header', }); - }); + } } From 44f45d8b7210941bad9ede8707125a0f1eb63eca Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Fri, 23 Feb 2024 01:40:53 +0800 Subject: [PATCH 27/64] Ignore the linux anchor point to avoid linux migrate failure (#29295) Fix #28843 This PR will bypass the pushUpdateTag to database failure when syncAllTags. An error log will be recorded. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> (cherry picked from commit 5ed17d9895bf678374ef5227ca37870c1c170802) --- modules/repository/repo.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/repository/repo.go b/modules/repository/repo.go index 65b50b2e45..2f076c5286 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -376,7 +376,9 @@ func SyncReleasesWithTags(ctx context.Context, repo *repo_model.Repository, gitR } if err := PushUpdateAddTag(ctx, repo, gitRepo, tagName, sha1, refname); err != nil { - return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err) + // sometimes, some tags will be sync failed. i.e. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tag/?h=v2.6.11 + // this is a tree object, not a tag object which created before git + log.Error("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %v", tagName, repo.ID, repo.OwnerName, repo.Name, err) } return nil From c432f141bb78ea6eac1c7ee99ba7afc7a59fba23 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Thu, 22 Feb 2024 22:21:43 +0100 Subject: [PATCH 28/64] Don't show third-party JS errors in production builds (#29303) So we don't get issues like https://github.com/go-gitea/gitea/issues/29080 and https://github.com/go-gitea/gitea/issues/29273 any more. Only active in [production builds](https://webpack.js.org/guides/production/#specify-the-mode), in non-production the errors will still show. (cherry picked from commit 532da5ed5ee3edb45d2ee63c6ab0fad53473691f) --- web_src/js/bootstrap.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index f8d0c0cac0..e46c91e5e6 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -29,17 +29,26 @@ export function showGlobalErrorMessage(msg) { * @param {ErrorEvent} e */ function processWindowErrorEvent(e) { + const err = e.error ?? e.reason; + const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); + + // error is likely from browser extension or inline script. Do not show these in production builds. + if (!err.stack?.includes(assetBaseUrl) && window.config?.runModeIsProd) return; + + let message; if (e.type === 'unhandledrejection') { - showGlobalErrorMessage(`JavaScript promise rejection: ${e.reason}. Open browser console to see more details.`); - return; + message = `JavaScript promise rejection: ${err.message}.`; + } else { + message = `JavaScript error: ${e.message} (${e.filename} @ ${e.lineno}:${e.colno}).`; } + if (!e.error && e.lineno === 0 && e.colno === 0 && e.filename === '' && window.navigator.userAgent.includes('FxiOS/')) { // At the moment, Firefox (iOS) (10x) has an engine bug. See https://github.com/go-gitea/gitea/issues/20240 // If a script inserts a newly created (and content changed) element into DOM, there will be a nonsense error event reporting: Script error: line 0, col 0. return; // ignore such nonsense error event } - showGlobalErrorMessage(`JavaScript error: ${e.message} (${e.filename} @ ${e.lineno}:${e.colno}). Open browser console to see more details.`); + showGlobalErrorMessage(`${message} Open browser console to see more details.`); } function initGlobalErrorHandler() { From 643d66ee0efb2a88b4bf41ed1f042ba43f55bb60 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 23 Feb 2024 00:31:24 +0100 Subject: [PATCH 29/64] Upgrade to fabric 6 (#29334) Upgrade fabric to latest v6 beta. It works for our use case, even thought it does not fix the upstream issue https://github.com/fabricjs/fabric.js/issues/9679 that https://github.com/go-gitea/gitea/issues/29326 relates to. (cherry picked from commit c4b0cb4d0d527793296cf801e611f77666f86551) Conflicts: public/assets/img/favicon.svg public/assets/img/logo.svg --- Makefile | 2 +- build/generate-images.js | 29 +++++++++++------------------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 72a48038f4..602f42fe4b 100644 --- a/Makefile +++ b/Makefile @@ -1009,7 +1009,7 @@ generate-gitignore: .PHONY: generate-images generate-images: | node_modules - npm install --no-save --no-package-lock fabric@5 imagemin-zopfli@7 + npm install --no-save fabric@6.0.0-beta19 imagemin-zopfli@7 node build/generate-images.js $(TAGS) .PHONY: generate-manpage diff --git a/build/generate-images.js b/build/generate-images.js index 09e3e068af..db31d19e2a 100755 --- a/build/generate-images.js +++ b/build/generate-images.js @@ -1,20 +1,13 @@ #!/usr/bin/env node import imageminZopfli from 'imagemin-zopfli'; import {optimize} from 'svgo'; -import {fabric} from 'fabric'; +import {loadSVGFromString, Canvas, Rect, util} from 'fabric/node'; import {readFile, writeFile} from 'node:fs/promises'; +import {argv, exit} from 'node:process'; -function exit(err) { +function doExit(err) { if (err) console.error(err); - process.exit(err ? 1 : 0); -} - -function loadSvg(svg) { - return new Promise((resolve) => { - fabric.loadSVGFromString(svg, (objects, options) => { - resolve({objects, options}); - }); - }); + exit(err ? 1 : 0); } async function generate(svg, path, {size, bg}) { @@ -35,14 +28,14 @@ async function generate(svg, path, {size, bg}) { return; } - const {objects, options} = await loadSvg(svg); - const canvas = new fabric.Canvas(); + const {objects, options} = await loadSVGFromString(svg); + const canvas = new Canvas(); canvas.setDimensions({width: size, height: size}); const ctx = canvas.getContext('2d'); ctx.scale(options.width ? (size / options.width) : 1, options.height ? (size / options.height) : 1); if (bg) { - canvas.add(new fabric.Rect({ + canvas.add(new Rect({ left: 0, top: 0, height: size * (1 / (size / options.height)), @@ -51,7 +44,7 @@ async function generate(svg, path, {size, bg}) { })); } - canvas.add(fabric.util.groupSVGElements(objects, options)); + canvas.add(util.groupSVGElements(objects, options)); canvas.renderAll(); let png = Buffer.from([]); @@ -64,7 +57,7 @@ async function generate(svg, path, {size, bg}) { } async function main() { - const gitea = process.argv.slice(2).includes('gitea'); + const gitea = argv.slice(2).includes('gitea'); const logoSvg = await readFile(new URL('../assets/logo.svg', import.meta.url), 'utf8'); const faviconSvg = await readFile(new URL('../assets/favicon.svg', import.meta.url), 'utf8'); @@ -80,7 +73,7 @@ async function main() { } try { - exit(await main()); + doExit(await main()); } catch (err) { - exit(err); + doExit(err); } From 4b494d341f3142c066bc5b2b3cfd50f924d64fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Nicas=20Oelschl=C3=A4ger?= <72873130+zokkis@users.noreply.github.com> Date: Fri, 23 Feb 2024 01:24:57 +0100 Subject: [PATCH 30/64] Unify organizations header (#29248) Unify organizations header before:  after:  --------- Co-authored-by: silverwind <me@silverwind.io> (cherry picked from commit 532e422027c88a4a3dc0c2968857f8d5f94d861f) Conflicts: routers/web/shared/user/header.go templates/org/home.tmpl context --- modules/context/org.go | 15 +++++ routers/web/org/home.go | 18 ------ routers/web/shared/user/header.go | 15 ----- routers/web/user/profile.go | 1 + templates/org/header.tmpl | 42 +++++++++----- templates/org/home.tmpl | 33 +---------- templates/org/member/members.tmpl | 2 +- templates/org/menu.tmpl | 10 ++-- templates/org/projects/list.tmpl | 7 +-- templates/package/settings.tmpl | 12 +++- templates/user/code.tmpl | 5 +- templates/user/overview/header.tmpl | 57 ++++++------------- templates/user/overview/package_versions.tmpl | 7 +-- templates/user/overview/packages.tmpl | 7 +-- web_src/css/org.css | 18 +++--- 15 files changed, 95 insertions(+), 154 deletions(-) diff --git a/modules/context/org.go b/modules/context/org.go index d068646577..018b76de43 100644 --- a/modules/context/org.go +++ b/modules/context/org.go @@ -11,6 +11,8 @@ import ( "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" ) @@ -255,6 +257,19 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects) ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages) ctx.Data["CanReadCode"] = ctx.Org.CanReadUnit(ctx, unit.TypeCode) + + ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID) + if len(ctx.ContextUser.Description) != 0 { + content, err := markdown.RenderString(&markup.RenderContext{ + Metas: map[string]string{"mode": "document"}, + Ctx: ctx, + }, ctx.ContextUser.Description) + if err != nil { + ctx.ServerError("RenderString", err) + return + } + ctx.Data["RenderedDescription"] = content + } } // OrgAssignment returns a middleware to handle organization assignment diff --git a/routers/web/org/home.go b/routers/web/org/home.go index 8bf02b2c42..36f543dc45 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -11,7 +11,6 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" @@ -46,17 +45,6 @@ func Home(ctx *context.Context) { ctx.Data["PageIsUserProfile"] = true ctx.Data["Title"] = org.DisplayName() - if len(org.Description) != 0 { - desc, err := markdown.RenderString(&markup.RenderContext{ - Ctx: ctx, - Metas: map[string]string{"mode": "document"}, - }, org.Description) - if err != nil { - ctx.ServerError("RenderString", err) - return - } - ctx.Data["RenderedDescription"] = desc - } var orderBy db.SearchOrderBy ctx.Data["SortType"] = ctx.FormString("sort") @@ -131,18 +119,12 @@ func Home(ctx *context.Context) { return } - var isFollowing bool - if ctx.Doer != nil { - isFollowing = user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID) - } - ctx.Data["Repos"] = repos ctx.Data["Total"] = count ctx.Data["Members"] = members ctx.Data["Teams"] = ctx.Org.Teams ctx.Data["DisableNewPullMirrors"] = setting.Mirror.DisableNewPull ctx.Data["PageIsViewRepositories"] = true - ctx.Data["IsFollowing"] = isFollowing err = shared_user.LoadHeaderCount(ctx) if err != nil { diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go index 6830bdb8a9..07026e484f 100644 --- a/routers/web/shared/user/header.go +++ b/routers/web/shared/user/header.go @@ -17,8 +17,6 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/markup" - "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -36,7 +34,6 @@ func prepareContextForCommonProfile(ctx *context.Context) { func PrepareContextForProfileBigAvatar(ctx *context.Context) { prepareContextForCommonProfile(ctx) - ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID) ctx.Data["IsBlocked"] = ctx.Doer != nil && user_model.IsBlocked(ctx, ctx.Doer.ID, ctx.ContextUser.ID) ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate ctx.Data["ContextUserLocationMapURL"] = setting.Service.UserLocationMapURL + url.QueryEscape(ctx.ContextUser.Location) @@ -49,18 +46,6 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) { } ctx.Data["OpenIDs"] = openIDs - if len(ctx.ContextUser.Description) != 0 { - content, err := markdown.RenderString(&markup.RenderContext{ - Metas: map[string]string{"mode": "document"}, - Ctx: ctx, - }, ctx.ContextUser.Description) - if err != nil { - ctx.ServerError("RenderString", err) - return - } - ctx.Data["RenderedDescription"] = content - } - showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID) orgs, err := db.Find[organization.Organization](ctx, organization.FindOrgOptions{ UserID: ctx.ContextUser.ID, diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 1a9a9cf603..4eec0e9905 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -355,6 +355,7 @@ func Action(ctx *context.Context) { ctx.HTML(http.StatusOK, tplProfileBigAvatar) return } else if ctx.ContextUser.IsOrganization() { + ctx.Data["Org"] = ctx.ContextUser ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID) ctx.HTML(http.StatusOK, tplFollowUnfollow) return diff --git a/templates/org/header.tmpl b/templates/org/header.tmpl index 7b912c1c56..8423fd7d3b 100644 --- a/templates/org/header.tmpl +++ b/templates/org/header.tmpl @@ -1,18 +1,32 @@ -{{with .Org}} - <div class="ui container"> - <div class="ui vertically grid head"> - <div class="column"> - <div class="ui header gt-df gt-ac gt-word-break"> - {{ctx.AvatarUtils.Avatar . 100}} - <span class="text thin grey"><a href="{{.HomeLink}}">{{.DisplayName}}</a></span> - <span class="org-visibility"> - {{if .Visibility.IsLimited}}<div class="ui medium basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.limited_shortname"}}</div>{{end}} - {{if .Visibility.IsPrivate}}<div class="ui medium basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.private_shortname"}}</div>{{end}} - </span> - </div> - </div> +<div class="ui container gt-df"> + {{ctx.AvatarUtils.Avatar .Org 100 "org-avatar"}} + <div id="org-info" class="gt-df gt-fc"> + <div class="ui header"> + {{.Org.DisplayName}} + <span class="org-visibility"> + {{if .Org.Visibility.IsLimited}}<span class="ui large basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.limited_shortname"}}</span>{{end}} + {{if .Org.Visibility.IsPrivate}}<span class="ui large basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.private_shortname"}}</span>{{end}} + </span> + <span class="gt-df gt-ac gt-gap-2 gt-ml-auto gt-font-16 gt-whitespace-nowrap"> + {{if .EnableFeed}} + <a class="ui basic label button gt-mr-0" href="{{.Org.HomeLink}}.rss" data-tooltip-content="{{ctx.Locale.Tr "rss_feed"}}"> + {{svg "octicon-rss" 24}} + </a> + {{end}} + {{if .IsSigned}} + {{template "org/follow_unfollow" .}} + {{end}} + </span> + </div> + {{if .RenderedDescription}}<div class="render-content markup">{{.RenderedDescription | Str2html}}</div>{{end}} + <div class="text light meta gt-mt-2"> + {{if .Org.Location}}<div class="flex-text-block">{{svg "octicon-location"}} <span>{{.Org.Location}}</span></div>{{end}} + {{if .Org.Website}}<div class="flex-text-block">{{svg "octicon-link"}} <a class="muted" target="_blank" rel="noopener noreferrer me" href="{{.Org.Website}}">{{.Org.Website}}</a></div>{{end}} + {{if .IsSigned}} + {{if .Org.Email}}<div class="flex-text-block">{{svg "octicon-mail"}} <a class="muted" href="mailto:{{.Org.Email}}">{{.Org.Email}}</a></div>{{end}} + {{end}} </div> </div> -{{end}} +</div> {{template "org/menu" .}} diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl index fd2326ffd5..1c8a083aed 100644 --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -5,38 +5,7 @@ {{template "base/alert" .}} </div> {{end}} - <div class="ui container gt-df"> - {{ctx.AvatarUtils.Avatar .Org 140 "org-avatar"}} - <div id="org-info"> - <div class="ui header"> - {{.Org.DisplayName}} - <span class="org-visibility"> - {{if .Org.Visibility.IsLimited}}<span class="ui large basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.limited_shortname"}}</span>{{end}} - {{if .Org.Visibility.IsPrivate}}<span class="ui large basic horizontal label">{{ctx.Locale.Tr "org.settings.visibility.private_shortname"}}</span>{{end}} - </span> - </div> - {{if $.RenderedDescription}}<div class="render-content markup">{{$.RenderedDescription|Str2html}}</div>{{end}} - <div class="text grey meta"> - {{if .Org.Location}}<div class="flex-text-block">{{svg "octicon-location"}} <span>{{.Org.Location}}</span></div>{{end}} - {{if .Org.Website}}<div class="flex-text-block">{{svg "octicon-link"}} <a target="_blank" rel="noopener noreferrer me" href="{{.Org.Website}}">{{.Org.Website}}</a></div>{{end}} - {{if $.IsSigned}} - {{if .Org.Email}}<div class="flex-text-block">{{svg "octicon-mail"}} <a class="muted" href="mailto:{{.Org.Email}}">{{.Org.Email}}</a></div>{{end}} - {{end}} - </div> - </div> - <div class="right menu"> - {{if .EnableFeed}} - <a class="ui basic label button gt-mr-0" href="{{$.Org.HomeLink}}.rss" data-tooltip-content="{{ctx.Locale.Tr "rss_feed"}}"> - {{svg "octicon-rss" 24}} - </a> - {{end}} - {{if .IsSigned}} - {{template "org/follow_unfollow" .}} - {{end}} - </div> - </div> - - {{template "org/menu" .}} + {{template "org/header" .}} <div class="ui container"> <div class="ui mobile reversed stackable grid"> diff --git a/templates/org/member/members.tmpl b/templates/org/member/members.tmpl index 03509ec93e..64f1aaa7d2 100644 --- a/templates/org/member/members.tmpl +++ b/templates/org/member/members.tmpl @@ -1,5 +1,5 @@ {{template "base/head" .}} -<div role="main" aria-label="{{.Title}}" class="page-content organization"> +<div role="main" aria-label="{{.Title}}" class="page-content organization members"> {{template "org/header" .}} <div class="ui container"> {{template "base/alert" .}} diff --git a/templates/org/menu.tmpl b/templates/org/menu.tmpl index 8a97711ce2..f07b26865a 100644 --- a/templates/org/menu.tmpl +++ b/templates/org/menu.tmpl @@ -15,24 +15,24 @@ </a> {{end}} {{if and .IsPackageEnabled .CanReadPackages}} - <a class="item" href="{{$.Org.HomeLink}}/-/packages"> + <a class="{{if .IsPackagesPage}}active {{end}}item" href="{{$.Org.HomeLink}}/-/packages"> {{svg "octicon-package"}} {{ctx.Locale.Tr "packages.title"}} </a> {{end}} {{if and .IsRepoIndexerEnabled .CanReadCode}} - <a class="item" href="{{$.Org.HomeLink}}/-/code"> - {{svg "octicon-code"}} {{ctx.Locale.Tr "org.code"}} + <a class="{{if .IsCodePage}}active {{end}}item" href="{{$.Org.HomeLink}}/-/code"> + {{svg "octicon-code"}} {{ctx.Locale.Tr "org.code"}} </a> {{end}} {{if .NumMembers}} <a class="{{if $.PageIsOrgMembers}}active {{end}}item" href="{{$.OrgLink}}/members"> - {{svg "octicon-person"}} {{ctx.Locale.Tr "org.members"}} + {{svg "octicon-person"}} {{ctx.Locale.Tr "org.members"}} <div class="ui small label">{{.NumMembers}}</div> </a> {{end}} {{if .IsOrganizationMember}} <a class="{{if $.PageIsOrgTeams}}active {{end}}item" href="{{$.OrgLink}}/teams"> - {{svg "octicon-people"}} {{ctx.Locale.Tr "org.teams"}} + {{svg "octicon-people"}} {{ctx.Locale.Tr "org.teams"}} {{if .NumTeams}} <div class="ui small label">{{.NumTeams}}</div> {{end}} diff --git a/templates/org/projects/list.tmpl b/templates/org/projects/list.tmpl index 689091e5e0..97cc6cf66c 100644 --- a/templates/org/projects/list.tmpl +++ b/templates/org/projects/list.tmpl @@ -1,10 +1,9 @@ {{template "base/head" .}} {{if .ContextUser.IsOrganization}} - <div role="main" aria-label="{{.Title}}" class="page-content repository packages"> - {{template "shared/user/org_profile_avatar" .}} + <div role="main" aria-label="{{.Title}}" class="page-content organization projects"> + {{template "org/header" .}} <div class="ui container"> - {{template "user/overview/header" .}} - {{template "projects/list" .}} + {{template "projects/list" .}} </div> </div> {{else}} diff --git a/templates/package/settings.tmpl b/templates/package/settings.tmpl index 6ef62753e2..10e26c7010 100644 --- a/templates/package/settings.tmpl +++ b/templates/package/settings.tmpl @@ -1,8 +1,14 @@ {{template "base/head" .}} -<div role="main" aria-label="{{.Title}}" class="page-content repository settings options"> - {{template "shared/user/org_profile_avatar" .}} +<div role="main" aria-label="{{.Title}}" class="page-content repository settings options{{if .ContextUser.IsOrganization}} organization{{end}}"> + {{if .ContextUser.IsOrganization}} + {{template "org/header" .}} + {{else}} + {{template "shared/user/org_profile_avatar" .}} + {{end}} <div class="ui container"> - {{template "user/overview/header" .}} + {{if not .ContextUser.IsOrganization}} + {{template "user/overview/header" .}} + {{end}} {{template "base/alert" .}} <p><a href="{{.PackageDescriptor.FullWebLink}}">{{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}})</a> / <strong>{{ctx.Locale.Tr "repo.settings"}}</strong></p> <h4 class="ui top attached header"> diff --git a/templates/user/code.tmpl b/templates/user/code.tmpl index da9a3c3a24..f71f55c474 100644 --- a/templates/user/code.tmpl +++ b/templates/user/code.tmpl @@ -1,9 +1,8 @@ {{template "base/head" .}} {{if .ContextUser.IsOrganization}} - <div role="main" aria-label="{{.Title}}" class="page-content repository"> - {{template "shared/user/org_profile_avatar" .}} + <div role="main" aria-label="{{.Title}}" class="page-content organization code"> + {{template "org/header" .}} <div class="ui container"> - {{template "user/overview/header" .}} {{template "code/searchcombo" .}} </div> </div> diff --git a/templates/user/overview/header.tmpl b/templates/user/overview/header.tmpl index c0cbe2561c..4fdaa70d87 100644 --- a/templates/user/overview/header.tmpl +++ b/templates/user/overview/header.tmpl @@ -10,7 +10,7 @@ <div class="ui small label">{{.RepoCount}}</div> {{end}} </a> - {{if or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadProjects)}} + {{if or .ContextUser.IsIndividual .CanReadProjects}} <a href="{{.ContextUser.HomeLink}}/-/projects" class="{{if .PageIsViewProjects}}active {{end}}item"> {{svg "octicon-project-symlink"}} {{ctx.Locale.Tr "user.projects"}} {{if .ProjectCount}} @@ -18,55 +18,30 @@ {{end}} </a> {{end}} - {{if and .IsPackageEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadPackages))}} + {{if and .IsPackageEnabled (or .ContextUser.IsIndividual .CanReadPackages)}} <a href="{{.ContextUser.HomeLink}}/-/packages" class="{{if .IsPackagesPage}}active {{end}}item"> {{svg "octicon-package"}} {{ctx.Locale.Tr "packages.title"}} </a> {{end}} - {{if and .IsRepoIndexerEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadCode))}} + {{if and .IsRepoIndexerEnabled (or .ContextUser.IsIndividual .CanReadCode)}} <a href="{{.ContextUser.HomeLink}}/-/code" class="{{if .IsCodePage}}active {{end}}item"> {{svg "octicon-code"}} {{ctx.Locale.Tr "user.code"}} </a> {{end}} - {{if .ContextUser.IsOrganization}} - {{if .NumMembers}} - <a class="{{if $.PageIsOrgMembers}}active {{end}}item" href="{{$.OrgLink}}/members"> - {{svg "octicon-person"}} {{ctx.Locale.Tr "org.members"}} - <div class="ui small label">{{.NumMembers}}</div> - </a> - {{end}} - {{if .IsOrganizationMember}} - <a class="{{if $.PageIsOrgTeams}}active {{end}}item" href="{{$.OrgLink}}/teams"> - {{svg "octicon-people"}} {{ctx.Locale.Tr "org.teams"}} - {{if .NumTeams}} - <div class="ui small label">{{.NumTeams}}</div> - {{end}} - </a> - {{end}} - - {{if .IsOrganizationOwner}} - <div class="right menu"> - <a class="item" href="{{.OrgLink}}/settings"> - {{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}} - </a> - </div> - {{end}} - {{else}} - <a class="{{if eq .TabName "activity"}}active {{end}}item" href="{{.ContextUser.HomeLink}}?tab=activity"> - {{svg "octicon-rss"}} {{ctx.Locale.Tr "user.activity"}} + <a class="{{if eq .TabName "activity"}}active {{end}}item" href="{{.ContextUser.HomeLink}}?tab=activity"> + {{svg "octicon-rss"}} {{ctx.Locale.Tr "user.activity"}} + </a> + {{if not .DisableStars}} + <a class="{{if eq .TabName "stars"}}active {{end}}item" href="{{.ContextUser.HomeLink}}?tab=stars"> + {{svg "octicon-star"}} {{ctx.Locale.Tr "user.starred"}} + {{if .ContextUser.NumStars}} + <div class="ui small label">{{.ContextUser.NumStars}}</div> + {{end}} + </a> + {{else}} + <a class="{{if eq .TabName "watching"}}active {{end}}item" href="{{.ContextUser.HomeLink}}?tab=watching"> + {{svg "octicon-eye"}} {{ctx.Locale.Tr "user.watched"}} </a> - {{if not .DisableStars}} - <a class="{{if eq .TabName "stars"}}active {{end}}item" href="{{.ContextUser.HomeLink}}?tab=stars"> - {{svg "octicon-star"}} {{ctx.Locale.Tr "user.starred"}} - {{if .ContextUser.NumStars}} - <div class="ui small label">{{.ContextUser.NumStars}}</div> - {{end}} - </a> - {{else}} - <a class="{{if eq .TabName "watching"}}active {{end}}item" href="{{.ContextUser.HomeLink}}?tab=watching"> - {{svg "octicon-eye"}} {{ctx.Locale.Tr "user.watched"}} - </a> - {{end}} {{end}} </div> diff --git a/templates/user/overview/package_versions.tmpl b/templates/user/overview/package_versions.tmpl index 6f740e0e7c..f6f963aecb 100644 --- a/templates/user/overview/package_versions.tmpl +++ b/templates/user/overview/package_versions.tmpl @@ -1,10 +1,9 @@ {{template "base/head" .}} {{if .ContextUser.IsOrganization}} - <div role="main" aria-label="{{.Title}}" class="page-content repository packages"> - {{template "shared/user/org_profile_avatar" .}} + <div role="main" aria-label="{{.Title}}" class="page-content organization packages"> + {{template "org/header" .}} <div class="ui container"> - {{template "user/overview/header" .}} - {{template "package/shared/versionlist" .}} + {{template "package/shared/versionlist" .}} </div> </div> {{else}} diff --git a/templates/user/overview/packages.tmpl b/templates/user/overview/packages.tmpl index 4fd17696d1..30ff871cb2 100644 --- a/templates/user/overview/packages.tmpl +++ b/templates/user/overview/packages.tmpl @@ -1,10 +1,9 @@ {{template "base/head" .}} {{if .ContextUser.IsOrganization}} - <div role="main" aria-label="{{.Title}}" class="page-content repository packages"> - {{template "shared/user/org_profile_avatar" .}} + <div role="main" aria-label="{{.Title}}" class="page-content organization packages"> + {{template "org/header" .}} <div class="ui container"> - {{template "user/overview/header" .}} - {{template "package/shared/list" .}} + {{template "package/shared/list" .}} </div> </div> {{else}} diff --git a/web_src/css/org.css b/web_src/css/org.css index 76512e0077..a1ef8e08ed 100644 --- a/web_src/css/org.css +++ b/web_src/css/org.css @@ -93,46 +93,44 @@ min-width: 300px; } -.organization.profile .org-avatar { - width: 100px; - height: 100px; +.page-content.organization .org-avatar { margin-right: 15px; } -.organization.profile #org-info { +.page-content.organization #org-info { overflow-wrap: anywhere; flex: 1; word-break: break-all; } -.organization.profile #org-info .ui.header { +.page-content.organization #org-info .ui.header { display: flex; align-items: center; font-size: 36px; margin-bottom: 0; } -.organization.profile #org-info .desc { +.page-content.organization #org-info .desc { font-size: 16px; margin-bottom: 10px; } -.organization.profile #org-info .meta { +.page-content.organization #org-info .meta { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; } -.organization.profile .ui.top.header .ui.right { +.page-content.organization .ui.top.header .ui.right { margin-top: 0; } -.organization.profile .teams .item { +.page-content.organization .teams .item { padding: 10px 15px; } -.organization.profile .members .ui.avatar { +.page-content.organization .members .ui.avatar { width: 48px; height: 48px; margin-right: 5px; From 8ff858b94b404506c9adb075d73f6353c047f84f Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 23 Feb 2024 03:18:33 +0100 Subject: [PATCH 31/64] Start to migrate from `util.OptionalBool` to `optional.Option[bool]` (#29329) just create transition helper and migrate two structs (cherry picked from commit 7fbdb60fc1152acc9a040dc04b1b0f5a3475b081) --- cmd/admin_user_create.go | 8 +++--- models/git/branch_list.go | 10 ++++---- models/git/branch_test.go | 4 +-- models/git/protected_branch_list.go | 4 +-- models/user/user.go | 25 ++++++++++--------- modules/context/repo.go | 3 ++- modules/optional/option_test.go | 5 ++-- modules/util/util.go | 18 +++++++++++++ routers/api/v1/admin/user.go | 8 ++---- routers/api/v1/repo/branch.go | 6 ++--- routers/install/install.go | 6 ++--- routers/web/admin/users.go | 2 +- routers/web/auth/oauth.go | 2 +- routers/web/repo/compare.go | 5 ++-- routers/web/repo/pull.go | 3 ++- routers/web/repo/repo.go | 5 ++-- services/auth/reverseproxy.go | 4 +-- .../auth/source/ldap/source_authenticate.go | 5 ++-- services/auth/source/ldap/source_sync.go | 5 ++-- .../auth/source/pam/source_authenticate.go | 4 +-- .../auth/source/smtp/source_authenticate.go | 3 ++- services/auth/sspi.go | 5 ++-- services/repository/adopt.go | 3 ++- services/repository/branch.go | 5 ++-- 24 files changed, 84 insertions(+), 64 deletions(-) diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go index fefe18d39c..a257ce21c8 100644 --- a/cmd/admin_user_create.go +++ b/cmd/admin_user_create.go @@ -10,8 +10,8 @@ import ( auth_model "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" pwd "code.gitea.io/gitea/modules/auth/password" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" "github.com/urfave/cli/v2" ) @@ -123,10 +123,10 @@ func runCreateUser(c *cli.Context) error { changePassword = c.Bool("must-change-password") } - restricted := util.OptionalBoolNone + restricted := optional.None[bool]() if c.IsSet("restricted") { - restricted = util.OptionalBoolOf(c.Bool("restricted")) + restricted = optional.Some(c.Bool("restricted")) } // default user visibility in app.ini @@ -142,7 +142,7 @@ func runCreateUser(c *cli.Context) error { } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsActive: util.OptionalBoolTrue, + IsActive: optional.Some(true), IsRestricted: restricted, } diff --git a/models/git/branch_list.go b/models/git/branch_list.go index 0e8d28038a..8319e5ecd0 100644 --- a/models/git/branch_list.go +++ b/models/git/branch_list.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/optional" "xorm.io/builder" ) @@ -67,7 +67,7 @@ type FindBranchOptions struct { db.ListOptions RepoID int64 ExcludeBranchNames []string - IsDeletedBranch util.OptionalBool + IsDeletedBranch optional.Option[bool] OrderBy string Keyword string } @@ -81,8 +81,8 @@ func (opts FindBranchOptions) ToConds() builder.Cond { if len(opts.ExcludeBranchNames) > 0 { cond = cond.And(builder.NotIn("name", opts.ExcludeBranchNames)) } - if !opts.IsDeletedBranch.IsNone() { - cond = cond.And(builder.Eq{"is_deleted": opts.IsDeletedBranch.IsTrue()}) + if opts.IsDeletedBranch.Has() { + cond = cond.And(builder.Eq{"is_deleted": opts.IsDeletedBranch.Value()}) } if opts.Keyword != "" { cond = cond.And(builder.Like{"name", opts.Keyword}) @@ -92,7 +92,7 @@ func (opts FindBranchOptions) ToConds() builder.Cond { func (opts FindBranchOptions) ToOrders() string { orderBy := opts.OrderBy - if !opts.IsDeletedBranch.IsFalse() { // if deleted branch included, put them at the end + if opts.IsDeletedBranch.ValueOrDefault(true) { // if deleted branch included, put them at the end if orderBy != "" { orderBy += ", " } diff --git a/models/git/branch_test.go b/models/git/branch_test.go index d480e2ec30..b984244cd2 100644 --- a/models/git/branch_test.go +++ b/models/git/branch_test.go @@ -12,7 +12,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/optional" "github.com/stretchr/testify/assert" ) @@ -49,7 +49,7 @@ func TestGetDeletedBranches(t *testing.T) { branches, err := db.Find[git_model.Branch](db.DefaultContext, git_model.FindBranchOptions{ ListOptions: db.ListOptionsAll, RepoID: repo.ID, - IsDeletedBranch: util.OptionalBoolTrue, + IsDeletedBranch: optional.Some(true), }) assert.NoError(t, err) assert.Len(t, branches, 2) diff --git a/models/git/protected_branch_list.go b/models/git/protected_branch_list.go index eeb307e245..613333a5a2 100644 --- a/models/git/protected_branch_list.go +++ b/models/git/protected_branch_list.go @@ -8,7 +8,7 @@ import ( "sort" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/optional" "github.com/gobwas/glob" ) @@ -56,7 +56,7 @@ func FindAllMatchedBranches(ctx context.Context, repoID int64, ruleName string) Page: page, }, RepoID: repoID, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), }) if err != nil { return nil, err diff --git a/models/user/user.go b/models/user/user.go index 51a65ce6f4..9ff4881ec9 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -25,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -585,14 +586,14 @@ func IsUsableUsername(name string) error { // CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation type CreateUserOverwriteOptions struct { - KeepEmailPrivate util.OptionalBool + KeepEmailPrivate optional.Option[bool] Visibility *structs.VisibleType - AllowCreateOrganization util.OptionalBool + AllowCreateOrganization optional.Option[bool] EmailNotificationsPreference *string MaxRepoCreation *int Theme *string - IsRestricted util.OptionalBool - IsActive util.OptionalBool + IsRestricted optional.Option[bool] + IsActive optional.Option[bool] } // CreateUser creates record of a new user. @@ -619,14 +620,14 @@ func CreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOve // overwrite defaults if set if len(overwriteDefault) != 0 && overwriteDefault[0] != nil { overwrite := overwriteDefault[0] - if !overwrite.KeepEmailPrivate.IsNone() { - u.KeepEmailPrivate = overwrite.KeepEmailPrivate.IsTrue() + if overwrite.KeepEmailPrivate.Has() { + u.KeepEmailPrivate = overwrite.KeepEmailPrivate.Value() } if overwrite.Visibility != nil { u.Visibility = *overwrite.Visibility } - if !overwrite.AllowCreateOrganization.IsNone() { - u.AllowCreateOrganization = overwrite.AllowCreateOrganization.IsTrue() + if overwrite.AllowCreateOrganization.Has() { + u.AllowCreateOrganization = overwrite.AllowCreateOrganization.Value() } if overwrite.EmailNotificationsPreference != nil { u.EmailNotificationsPreference = *overwrite.EmailNotificationsPreference @@ -637,11 +638,11 @@ func CreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOve if overwrite.Theme != nil { u.Theme = *overwrite.Theme } - if !overwrite.IsRestricted.IsNone() { - u.IsRestricted = overwrite.IsRestricted.IsTrue() + if overwrite.IsRestricted.Has() { + u.IsRestricted = overwrite.IsRestricted.Value() } - if !overwrite.IsActive.IsNone() { - u.IsActive = overwrite.IsActive.IsTrue() + if overwrite.IsActive.Has() { + u.IsActive = overwrite.IsActive.Value() } } diff --git a/modules/context/repo.go b/modules/context/repo.go index 9d63f9eec3..490d798d50 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -27,6 +27,7 @@ import ( "code.gitea.io/gitea/modules/gitrepo" code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -672,7 +673,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { branchOpts := git_model.FindBranchOptions{ RepoID: ctx.Repo.Repository.ID, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), ListOptions: db.ListOptionsAll, } branchesTotal, err := db.Count[git_model.Branch](ctx, branchOpts) diff --git a/modules/optional/option_test.go b/modules/optional/option_test.go index 7ec345b6ba..bfc4577dbe 100644 --- a/modules/optional/option_test.go +++ b/modules/optional/option_test.go @@ -6,8 +6,6 @@ package optional import ( "testing" - "code.gitea.io/gitea/modules/util" - "github.com/stretchr/testify/assert" ) @@ -30,7 +28,8 @@ func TestOption(t *testing.T) { var ptr *int assert.False(t, FromPtr(ptr).Has()) - opt1 := FromPtr(util.ToPointer(1)) + int1 := 1 + opt1 := FromPtr(&int1) assert.True(t, opt1.Has()) assert.Equal(t, int(1), opt1.Value()) diff --git a/modules/util/util.go b/modules/util/util.go index 0e5c6a4e64..28b549f405 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -11,6 +11,8 @@ import ( "strconv" "strings" + "code.gitea.io/gitea/modules/optional" + "golang.org/x/text/cases" "golang.org/x/text/language" ) @@ -42,6 +44,22 @@ func (o OptionalBool) IsNone() bool { return o == OptionalBoolNone } +// ToGeneric converts OptionalBool to optional.Option[bool] +func (o OptionalBool) ToGeneric() optional.Option[bool] { + if o.IsNone() { + return optional.None[bool]() + } + return optional.Some[bool](o.IsTrue()) +} + +// OptionalBoolFromGeneric converts optional.Option[bool] to OptionalBool +func OptionalBoolFromGeneric(o optional.Option[bool]) OptionalBool { + if o.Has() { + return OptionalBoolOf(o.Value()) + } + return OptionalBoolNone +} + // OptionalBoolOf get the corresponding OptionalBool of a bool func OptionalBoolOf(b bool) OptionalBool { if b { diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 272996f43d..2ce7651a09 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -21,7 +21,6 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" @@ -117,11 +116,8 @@ func CreateUser(ctx *context.APIContext) { } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsActive: util.OptionalBoolTrue, - } - - if form.Restricted != nil { - overwriteDefault.IsRestricted = util.OptionalBoolOf(*form.Restricted) + IsActive: optional.Some(true), + IsRestricted: optional.FromPtr(form.Restricted), } if form.Visibility != "" { diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index bd02a8afc4..2cdbcd25a2 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -17,9 +17,9 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/optional" repo_module "code.gitea.io/gitea/modules/repository" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/convert" @@ -141,7 +141,7 @@ func DeleteBranch(ctx *context.APIContext) { // check whether branches of this repository has been synced totalNumOfBranches, err := db.Count[git_model.Branch](ctx, git_model.FindBranchOptions{ RepoID: ctx.Repo.Repository.ID, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), }) if err != nil { ctx.Error(http.StatusInternalServerError, "CountBranches", err) @@ -340,7 +340,7 @@ func ListBranches(ctx *context.APIContext) { branchOpts := git_model.FindBranchOptions{ ListOptions: listOptions, RepoID: ctx.Repo.Repository.ID, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), } var err error totalNumOfBranches, err = db.Count[git_model.Branch](ctx, branchOpts) diff --git a/routers/install/install.go b/routers/install/install.go index 5c43bd486a..48271a64f2 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -25,11 +25,11 @@ import ( "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/user" - "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/routers/common" @@ -537,8 +537,8 @@ func SubmitInstall(ctx *context.Context) { IsAdmin: true, } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsRestricted: util.OptionalBoolFalse, - IsActive: util.OptionalBoolTrue, + IsRestricted: optional.Some(false), + IsActive: optional.Some(true), } if err = user_model.CreateUser(ctx, u, overwriteDefault); err != nil { diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index af184fa9eb..adb9799c01 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -140,7 +140,7 @@ func NewUserPost(ctx *context.Context) { } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsActive: util.OptionalBoolTrue, + IsActive: optional.Some(true), Visibility: &form.Visibility, } diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index e840e03bcf..4e4079d8ff 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -982,7 +982,7 @@ func SignInOAuthCallback(ctx *context.Context) { } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm && !setting.Service.RegisterManualConfirm), + IsActive: optional.Some(!setting.OAuth2Client.RegisterEmailConfirm && !setting.Service.RegisterManualConfirm), } source := authSource.Cfg.(*oauth2.Source) diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 67d41cf807..df41c750de 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -31,6 +31,7 @@ import ( "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/typesniffer" @@ -700,7 +701,7 @@ func getBranchesAndTagsForRepo(ctx gocontext.Context, repo *repo_model.Repositor ListOptions: db.ListOptions{ ListAll: true, }, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), }) if err != nil { return nil, nil, err @@ -757,7 +758,7 @@ func CompareDiff(ctx *context.Context) { ListOptions: db.ListOptions{ ListAll: true, }, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), }) if err != nil { ctx.ServerError("GetBranches", err) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index fd7e902225..dcb0623504 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -33,6 +33,7 @@ import ( "code.gitea.io/gitea/modules/gitrepo" issue_template "code.gitea.io/gitea/modules/issue/template" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/upload" @@ -193,7 +194,7 @@ func updateForkRepositoryInContext(ctx *context.Context, forkRepo *repo_model.Re ListOptions: db.ListOptions{ ListAll: true, }, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), // Add it as the first option ExcludeBranchNames: []string{ctx.Repo.Repository.DefaultBranch}, }) diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 88c73f65f0..17e5d9b582 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" @@ -685,7 +686,7 @@ type branchTagSearchResponse struct { func GetBranchesList(ctx *context.Context) { branchOpts := git_model.FindBranchOptions{ RepoID: ctx.Repo.Repository.ID, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), ListOptions: db.ListOptions{ ListAll: true, }, @@ -720,7 +721,7 @@ func GetTagList(ctx *context.Context) { func PrepareBranchList(ctx *context.Context) { branchOpts := git_model.FindBranchOptions{ RepoID: ctx.Repo.Repository.ID, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), ListOptions: db.ListOptions{ ListAll: true, }, diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go index 359c1f2473..b6aeb0aed2 100644 --- a/services/auth/reverseproxy.go +++ b/services/auth/reverseproxy.go @@ -10,8 +10,8 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" gouuid "github.com/google/uuid" @@ -161,7 +161,7 @@ func (r *ReverseProxy) newUser(req *http.Request) *user_model.User { } overwriteDefault := user_model.CreateUserOverwriteOptions{ - IsActive: util.OptionalBoolTrue, + IsActive: optional.Some(true), } if err := user_model.CreateUser(req.Context(), user, &overwriteDefault); err != nil { diff --git a/services/auth/source/ldap/source_authenticate.go b/services/auth/source/ldap/source_authenticate.go index 8f641ed541..68ecd16342 100644 --- a/services/auth/source/ldap/source_authenticate.go +++ b/services/auth/source/ldap/source_authenticate.go @@ -13,7 +13,6 @@ import ( user_model "code.gitea.io/gitea/models/user" auth_module "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/util" source_service "code.gitea.io/gitea/services/auth/source" user_service "code.gitea.io/gitea/services/user" ) @@ -85,8 +84,8 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u IsAdmin: sr.IsAdmin, } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsRestricted: util.OptionalBoolOf(sr.IsRestricted), - IsActive: util.OptionalBoolTrue, + IsRestricted: optional.Some(sr.IsRestricted), + IsActive: optional.Some(true), } err := user_model.CreateUser(ctx, user, overwriteDefault) diff --git a/services/auth/source/ldap/source_sync.go b/services/auth/source/ldap/source_sync.go index eee7bb585a..62f052d68c 100644 --- a/services/auth/source/ldap/source_sync.go +++ b/services/auth/source/ldap/source_sync.go @@ -16,7 +16,6 @@ import ( "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/util" source_service "code.gitea.io/gitea/services/auth/source" user_service "code.gitea.io/gitea/services/user" ) @@ -125,8 +124,8 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { IsAdmin: su.IsAdmin, } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsRestricted: util.OptionalBoolOf(su.IsRestricted), - IsActive: util.OptionalBoolTrue, + IsRestricted: optional.Some(su.IsRestricted), + IsActive: optional.Some(true), } err = user_model.CreateUser(ctx, usr, overwriteDefault) diff --git a/services/auth/source/pam/source_authenticate.go b/services/auth/source/pam/source_authenticate.go index 0891a86392..addd1bd2c9 100644 --- a/services/auth/source/pam/source_authenticate.go +++ b/services/auth/source/pam/source_authenticate.go @@ -11,8 +11,8 @@ import ( "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/pam" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" "github.com/google/uuid" ) @@ -60,7 +60,7 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u LoginName: userName, // This is what the user typed in } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsActive: util.OptionalBoolTrue, + IsActive: optional.Some(true), } if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil { diff --git a/services/auth/source/smtp/source_authenticate.go b/services/auth/source/smtp/source_authenticate.go index b244fc7d40..1f0a61c789 100644 --- a/services/auth/source/smtp/source_authenticate.go +++ b/services/auth/source/smtp/source_authenticate.go @@ -12,6 +12,7 @@ import ( auth_model "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/util" ) @@ -75,7 +76,7 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u LoginName: userName, } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsActive: util.OptionalBoolTrue, + IsActive: optional.Some(true), } if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil { diff --git a/services/auth/sspi.go b/services/auth/sspi.go index 0e974fde8f..8c0fc77a96 100644 --- a/services/auth/sspi.go +++ b/services/auth/sspi.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/base" gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" @@ -172,8 +173,8 @@ func (s *SSPI) newUser(ctx context.Context, username string, cfg *sspi.Source) ( } emailNotificationPreference := user_model.EmailNotificationsDisabled overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsActive: util.OptionalBoolOf(cfg.AutoActivateUsers), - KeepEmailPrivate: util.OptionalBoolTrue, + IsActive: optional.Some(cfg.AutoActivateUsers), + KeepEmailPrivate: optional.Some(true), EmailNotificationsPreference: &emailNotificationPreference, } if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil { diff --git a/services/repository/adopt.go b/services/repository/adopt.go index bfb965063f..7ca68776b5 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -154,7 +155,7 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r ListOptions: db.ListOptions{ ListAll: true, }, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), }) found := false diff --git a/services/repository/branch.go b/services/repository/branch.go index d7ac25b7c9..6add9422f4 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/queue" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/timeutil" @@ -59,7 +60,7 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git branchOpts := git_model.FindBranchOptions{ RepoID: repo.ID, - IsDeletedBranch: isDeletedBranch, + IsDeletedBranch: isDeletedBranch.ToGeneric(), ListOptions: db.ListOptions{ Page: page, PageSize: pageSize, @@ -243,7 +244,7 @@ func syncBranchToDB(ctx context.Context, repoID, pusherID int64, branchName stri // we cannot simply insert the branch but need to check we have branches or not hasBranch, err := db.Exist[git_model.Branch](ctx, git_model.FindBranchOptions{ RepoID: repoID, - IsDeletedBranch: util.OptionalBoolFalse, + IsDeletedBranch: optional.Some(false), }.ToConds()) if err != nil { return err From 767e9634d3d02acab27f05e1783391c9c7f6292e Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Fri, 23 Feb 2024 15:24:04 +0800 Subject: [PATCH 32/64] Allow options to disable user deletion from the interface on app.ini (#29275) Extract from #20549 This PR added a new option on app.ini `[admin]USER_DISABLED_FEATURES` to allow the site administrator to disable users visiting deletion user interface or allow. This options are also potentially allowed to define more features in future PRs. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> (cherry picked from commit 3ef6252e06a1f3981f8b7d1717bfc581418b1dc5) Conflicts: custom/conf/app.example.ini docs/content/administration/config-cheat-sheet.en-us.md modules/setting/admin.go context --- custom/conf/app.example.ini | 3 +++ modules/setting/admin.go | 10 +++++++++- routers/web/user/setting/account.go | 6 ++++++ templates/user/settings/account.tmpl | 23 ++++++++++++----------- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index dc1843097f..04714e5502 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1492,6 +1492,9 @@ LEVEL = Info ;DEFAULT_EMAIL_NOTIFICATIONS = enabled ;; Send an email to all admins when a new user signs up to inform the admins about this act. Options: true, false ;SEND_NOTIFICATION_EMAIL_ON_NEW_USER = false +;; Disabled features for users, could be "deletion", more features can be disabled in future +;; - deletion: a user cannot delete their own account +;USER_DISABLED_FEATURES = ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/modules/setting/admin.go b/modules/setting/admin.go index d7f0ee827d..502efd0eb9 100644 --- a/modules/setting/admin.go +++ b/modules/setting/admin.go @@ -3,15 +3,23 @@ package setting +import "code.gitea.io/gitea/modules/container" + // Admin settings var Admin struct { DisableRegularOrgCreation bool DefaultEmailNotification string SendNotificationEmailOnNewUser bool + UserDisabledFeatures container.Set[string] } func loadAdminFrom(rootCfg ConfigProvider) { - mustMapSetting(rootCfg, "admin", &Admin) sec := rootCfg.Section("admin") + Admin.DisableRegularOrgCreation = sec.Key("DISABLE_REGULAR_ORG_CREATION").MustBool(false) Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled") + Admin.UserDisabledFeatures = container.SetOf(sec.Key("USER_DISABLED_FEATURES").Strings(",")...) } + +const ( + UserFeatureDeletion = "deletion" +) diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index 371718ba23..6042e0b6cd 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -242,6 +242,11 @@ func DeleteEmail(ctx *context.Context) { // DeleteAccount render user suicide page and response for delete user himself func DeleteAccount(ctx *context.Context) { + if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureDeletion) { + ctx.Error(http.StatusNotFound) + return + } + ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsAccount"] = true @@ -308,6 +313,7 @@ func loadAccountData(ctx *context.Context) { ctx.Data["EmailNotificationsPreference"] = ctx.Doer.EmailNotificationsPreference ctx.Data["ActivationsPending"] = pendingActivation ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm + ctx.Data["UserDisabledFeatures"] = &setting.Admin.UserDisabledFeatures if setting.Service.UserDeleteWithCommentsMaxTime != 0 { ctx.Data["UserDeleteWithCommentsMaxTime"] = setting.Service.UserDeleteWithCommentsMaxTime.String() diff --git a/templates/user/settings/account.tmpl b/templates/user/settings/account.tmpl index 820d48a94b..c7bf3c0a41 100644 --- a/templates/user/settings/account.tmpl +++ b/templates/user/settings/account.tmpl @@ -128,6 +128,7 @@ {{end}} </div> + {{if not ($.UserDisabledFeatures.Contains "deletion")}} <h4 class="ui top attached error header"> {{ctx.Locale.Tr "settings.delete_account"}} </h4> @@ -151,7 +152,18 @@ </button> </div> </form> + <div class="ui g-modal-confirm delete modal" id="delete-account"> + <div class="header"> + {{svg "octicon-trash"}} + {{ctx.Locale.Tr "settings.delete_account_title"}} + </div> + <div class="content"> + <p>{{ctx.Locale.Tr "settings.delete_account_desc"}}</p> + </div> + {{template "base/modal_actions_confirm" .}} + </div> </div> + {{end}} </div> <div class="ui g-modal-confirm delete modal" id="delete-email"> @@ -165,15 +177,4 @@ {{template "base/modal_actions_confirm" .}} </div> -<div class="ui g-modal-confirm delete modal" id="delete-account"> - <div class="header"> - {{svg "octicon-trash"}} - {{ctx.Locale.Tr "settings.delete_account_title"}} - </div> - <div class="content"> - <p>{{ctx.Locale.Tr "settings.delete_account_desc"}}</p> - </div> - {{template "base/modal_actions_confirm" .}} -</div> - {{template "user/settings/layout_footer" .}} From 826bf12bb499b16f6c9980c54a36c9de4bcd6529 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Sat, 24 Feb 2024 01:49:46 +0800 Subject: [PATCH 33/64] Fix tarball/zipball download bug (#29342) Fix #29249 ~~Use the `/repos/{owner}/{repo}/archive/{archive}` API to download.~~ Apply #26430 to archive download URLs. (cherry picked from commit b762a1f1b1f7941a7db2207552d7b441d868cbe9) --- services/auth/auth.go | 5 +++++ services/auth/oauth2.go | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/services/auth/auth.go b/services/auth/auth.go index 6e22d8298e..e53ff02dcf 100644 --- a/services/auth/auth.go +++ b/services/auth/auth.go @@ -40,6 +40,7 @@ func isContainerPath(req *http.Request) bool { var ( gitRawOrAttachPathRe = regexp.MustCompile(`^/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+/(?:(?:git-(?:(?:upload)|(?:receive))-pack$)|(?:info/refs$)|(?:HEAD$)|(?:objects/)|(?:raw/)|(?:releases/download/)|(?:attachments/))`) lfsPathRe = regexp.MustCompile(`^/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+/info/lfs/`) + archivePathRe = regexp.MustCompile(`^/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+/archive/`) ) func isGitRawOrAttachPath(req *http.Request) bool { @@ -56,6 +57,10 @@ func isGitRawOrAttachOrLFSPath(req *http.Request) bool { return false } +func isArchivePath(req *http.Request) bool { + return archivePathRe.MatchString(req.URL.Path) +} + // handleSignIn clears existing session variables and stores new ones for the specified user object func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore, user *user_model.User) { // We need to regenerate the session... diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go index f2f7858a85..46d8510143 100644 --- a/services/auth/oauth2.go +++ b/services/auth/oauth2.go @@ -133,7 +133,7 @@ func (o *OAuth2) userIDFromToken(ctx context.Context, tokenSHA string, store Dat func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { // These paths are not API paths, but we still want to check for tokens because they maybe in the API returned URLs if !middleware.IsAPIPath(req) && !isAttachmentDownload(req) && !isAuthenticatedTokenRequest(req) && - !isGitRawOrAttachPath(req) { + !isGitRawOrAttachPath(req) && !isArchivePath(req) { return nil, nil } From 7bf905a43c8911e58a99eb8820e89a8caec5a38d Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Fri, 23 Feb 2024 23:19:54 +0200 Subject: [PATCH 34/64] Remove jQuery from the stopwatch (#29351) - Switched to plain JavaScript - Tested the stopwatch functionality and it works as before # Demo using JavaScript without jQuery  Signed-off-by: Yarden Shoham <git@yardenshoham.com> (cherry picked from commit 12d233faf786a54579a33b99b3cd56586c279f56) --- web_src/js/features/stopwatch.js | 38 ++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/web_src/js/features/stopwatch.js b/web_src/js/features/stopwatch.js index e20a983e60..d070f52d30 100644 --- a/web_src/js/features/stopwatch.js +++ b/web_src/js/features/stopwatch.js @@ -1,8 +1,9 @@ -import $ from 'jquery'; import prettyMilliseconds from 'pretty-ms'; import {createTippy} from '../modules/tippy.js'; +import {GET} from '../modules/fetch.js'; +import {hideElem, showElem} from '../utils/dom.js'; -const {appSubUrl, csrfToken, notificationSettings, enableTimeTracking, assetVersionEncoded} = window.config; +const {appSubUrl, notificationSettings, enableTimeTracking, assetVersionEncoded} = window.config; export function initStopwatch() { if (!enableTimeTracking) { @@ -28,7 +29,7 @@ export function initStopwatch() { }); // global stop watch (in the head_navbar), it should always work in any case either the EventSource or the PeriodicPoller is used. - const currSeconds = $('.stopwatch-time').attr('data-seconds'); + const currSeconds = document.querySelector('.stopwatch-time')?.getAttribute('data-seconds'); if (currSeconds) { updateStopwatchTime(currSeconds); } @@ -112,29 +113,31 @@ async function updateStopwatchWithCallback(callback, timeout) { } async function updateStopwatch() { - const data = await $.ajax({ - type: 'GET', - url: `${appSubUrl}/user/stopwatches`, - headers: {'X-Csrf-Token': csrfToken}, - }); + const response = await GET(`${appSubUrl}/user/stopwatches`); + if (!response.ok) { + console.error('Failed to fetch stopwatch data'); + return false; + } + const data = await response.json(); return updateStopwatchData(data); } function updateStopwatchData(data) { const watch = data[0]; - const btnEl = $('.active-stopwatch-trigger'); + const btnEl = document.querySelector('.active-stopwatch-trigger'); if (!watch) { clearStopwatchTimer(); - btnEl.addClass('gt-hidden'); + hideElem(btnEl); } else { const {repo_owner_name, repo_name, issue_index, seconds} = watch; const issueUrl = `${appSubUrl}/${repo_owner_name}/${repo_name}/issues/${issue_index}`; - $('.stopwatch-link').attr('href', issueUrl); - $('.stopwatch-commit').attr('action', `${issueUrl}/times/stopwatch/toggle`); - $('.stopwatch-cancel').attr('action', `${issueUrl}/times/stopwatch/cancel`); - $('.stopwatch-issue').text(`${repo_owner_name}/${repo_name}#${issue_index}`); + document.querySelector('.stopwatch-link')?.setAttribute('href', issueUrl); + document.querySelector('.stopwatch-commit')?.setAttribute('action', `${issueUrl}/times/stopwatch/toggle`); + document.querySelector('.stopwatch-cancel')?.setAttribute('action', `${issueUrl}/times/stopwatch/cancel`); + const stopwatchIssue = document.querySelector('.stopwatch-issue'); + if (stopwatchIssue) stopwatchIssue.textContent = `${repo_owner_name}/${repo_name}#${issue_index}`; updateStopwatchTime(seconds); - btnEl.removeClass('gt-hidden'); + showElem(btnEl); } return Boolean(data.length); } @@ -151,12 +154,13 @@ function updateStopwatchTime(seconds) { if (!Number.isFinite(secs)) return; clearStopwatchTimer(); - const $stopwatch = $('.stopwatch-time'); + const stopwatch = document.querySelector('.stopwatch-time'); + // TODO: replace with <relative-time> similar to how system status up time is shown const start = Date.now(); const updateUi = () => { const delta = Date.now() - start; const dur = prettyMilliseconds(secs * 1000 + delta, {compact: true}); - $stopwatch.text(dur); + if (stopwatch) stopwatch.textContent = dur; }; updateUi(); updateTimeIntervalId = setInterval(updateUi, 1000); From 7db422d98992a4aa9328b18b4ec6391dae4d3c0d Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 23 Feb 2024 22:51:46 +0100 Subject: [PATCH 35/64] Make optional.Option[T] type serializable (#29282) make the generic `Option` type de-/serializable for json and yaml --------- Co-authored-by: KN4CK3R <admin@oldschoolhack.me> (cherry picked from commit 53c7d8908e5ef35818b72b8c3d873b509269bc1a) --- modules/optional/option_test.go | 22 +-- modules/optional/serialization.go | 46 ++++++ modules/optional/serialization_test.go | 190 +++++++++++++++++++++++++ 3 files changed, 248 insertions(+), 10 deletions(-) create mode 100644 modules/optional/serialization.go create mode 100644 modules/optional/serialization_test.go diff --git a/modules/optional/option_test.go b/modules/optional/option_test.go index bfc4577dbe..410fd73577 100644 --- a/modules/optional/option_test.go +++ b/modules/optional/option_test.go @@ -1,47 +1,49 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package optional +package optional_test import ( "testing" + "code.gitea.io/gitea/modules/optional" + "github.com/stretchr/testify/assert" ) func TestOption(t *testing.T) { - var uninitialized Option[int] + var uninitialized optional.Option[int] assert.False(t, uninitialized.Has()) assert.Equal(t, int(0), uninitialized.Value()) assert.Equal(t, int(1), uninitialized.ValueOrDefault(1)) - none := None[int]() + none := optional.None[int]() assert.False(t, none.Has()) assert.Equal(t, int(0), none.Value()) assert.Equal(t, int(1), none.ValueOrDefault(1)) - some := Some[int](1) + some := optional.Some[int](1) assert.True(t, some.Has()) assert.Equal(t, int(1), some.Value()) assert.Equal(t, int(1), some.ValueOrDefault(2)) var ptr *int - assert.False(t, FromPtr(ptr).Has()) + assert.False(t, optional.FromPtr(ptr).Has()) int1 := 1 - opt1 := FromPtr(&int1) + opt1 := optional.FromPtr(&int1) assert.True(t, opt1.Has()) assert.Equal(t, int(1), opt1.Value()) - assert.False(t, FromNonDefault("").Has()) + assert.False(t, optional.FromNonDefault("").Has()) - opt2 := FromNonDefault("test") + opt2 := optional.FromNonDefault("test") assert.True(t, opt2.Has()) assert.Equal(t, "test", opt2.Value()) - assert.False(t, FromNonDefault(0).Has()) + assert.False(t, optional.FromNonDefault(0).Has()) - opt3 := FromNonDefault(1) + opt3 := optional.FromNonDefault(1) assert.True(t, opt3.Has()) assert.Equal(t, int(1), opt3.Value()) } diff --git a/modules/optional/serialization.go b/modules/optional/serialization.go new file mode 100644 index 0000000000..6688e78cd1 --- /dev/null +++ b/modules/optional/serialization.go @@ -0,0 +1,46 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package optional + +import ( + "code.gitea.io/gitea/modules/json" + + "gopkg.in/yaml.v3" +) + +func (o *Option[T]) UnmarshalJSON(data []byte) error { + var v *T + if err := json.Unmarshal(data, &v); err != nil { + return err + } + *o = FromPtr(v) + return nil +} + +func (o Option[T]) MarshalJSON() ([]byte, error) { + if !o.Has() { + return []byte("null"), nil + } + + return json.Marshal(o.Value()) +} + +func (o *Option[T]) UnmarshalYAML(value *yaml.Node) error { + var v *T + if err := value.Decode(&v); err != nil { + return err + } + *o = FromPtr(v) + return nil +} + +func (o Option[T]) MarshalYAML() (interface{}, error) { + if !o.Has() { + return nil, nil + } + + value := new(yaml.Node) + err := value.Encode(o.Value()) + return value, err +} diff --git a/modules/optional/serialization_test.go b/modules/optional/serialization_test.go new file mode 100644 index 0000000000..09a4bddea0 --- /dev/null +++ b/modules/optional/serialization_test.go @@ -0,0 +1,190 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package optional_test + +import ( + std_json "encoding/json" //nolint:depguard + "testing" + + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/optional" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" +) + +type testSerializationStruct struct { + NormalString string `json:"normal_string" yaml:"normal_string"` + NormalBool bool `json:"normal_bool" yaml:"normal_bool"` + OptBool optional.Option[bool] `json:"optional_bool,omitempty" yaml:"optional_bool,omitempty"` + OptString optional.Option[string] `json:"optional_string,omitempty" yaml:"optional_string,omitempty"` + OptTwoBool optional.Option[bool] `json:"optional_two_bool" yaml:"optional_two_bool"` + OptTwoString optional.Option[string] `json:"optional_twostring" yaml:"optional_two_string"` +} + +func TestOptionalToJson(t *testing.T) { + tests := []struct { + name string + obj *testSerializationStruct + want string + }{ + { + name: "empty", + obj: new(testSerializationStruct), + want: `{"normal_string":"","normal_bool":false,"optional_two_bool":null,"optional_twostring":null}`, + }, + { + name: "some", + obj: &testSerializationStruct{ + NormalString: "a string", + NormalBool: true, + OptBool: optional.Some(false), + OptString: optional.Some(""), + OptTwoBool: optional.None[bool](), + OptTwoString: optional.None[string](), + }, + want: `{"normal_string":"a string","normal_bool":true,"optional_bool":false,"optional_string":"","optional_two_bool":null,"optional_twostring":null}`, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + b, err := json.Marshal(tc.obj) + assert.NoError(t, err) + assert.EqualValues(t, tc.want, string(b), "gitea json module returned unexpected") + + b, err = std_json.Marshal(tc.obj) + assert.NoError(t, err) + assert.EqualValues(t, tc.want, string(b), "std json module returned unexpected") + }) + } +} + +func TestOptionalFromJson(t *testing.T) { + tests := []struct { + name string + data string + want testSerializationStruct + }{ + { + name: "empty", + data: `{}`, + want: testSerializationStruct{ + NormalString: "", + }, + }, + { + name: "some", + data: `{"normal_string":"a string","normal_bool":true,"optional_bool":false,"optional_string":"","optional_two_bool":null,"optional_twostring":null}`, + want: testSerializationStruct{ + NormalString: "a string", + NormalBool: true, + OptBool: optional.Some(false), + OptString: optional.Some(""), + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var obj1 testSerializationStruct + err := json.Unmarshal([]byte(tc.data), &obj1) + assert.NoError(t, err) + assert.EqualValues(t, tc.want, obj1, "gitea json module returned unexpected") + + var obj2 testSerializationStruct + err = std_json.Unmarshal([]byte(tc.data), &obj2) + assert.NoError(t, err) + assert.EqualValues(t, tc.want, obj2, "std json module returned unexpected") + }) + } +} + +func TestOptionalToYaml(t *testing.T) { + tests := []struct { + name string + obj *testSerializationStruct + want string + }{ + { + name: "empty", + obj: new(testSerializationStruct), + want: `normal_string: "" +normal_bool: false +optional_two_bool: null +optional_two_string: null +`, + }, + { + name: "some", + obj: &testSerializationStruct{ + NormalString: "a string", + NormalBool: true, + OptBool: optional.Some(false), + OptString: optional.Some(""), + }, + want: `normal_string: a string +normal_bool: true +optional_bool: false +optional_string: "" +optional_two_bool: null +optional_two_string: null +`, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + b, err := yaml.Marshal(tc.obj) + assert.NoError(t, err) + assert.EqualValues(t, tc.want, string(b), "yaml module returned unexpected") + }) + } +} + +func TestOptionalFromYaml(t *testing.T) { + tests := []struct { + name string + data string + want testSerializationStruct + }{ + { + name: "empty", + data: ``, + want: testSerializationStruct{}, + }, + { + name: "empty but init", + data: `normal_string: "" +normal_bool: false +optional_bool: +optional_two_bool: +optional_two_string: +`, + want: testSerializationStruct{}, + }, + { + name: "some", + data: ` +normal_string: a string +normal_bool: true +optional_bool: false +optional_string: "" +optional_two_bool: null +optional_twostring: null +`, + want: testSerializationStruct{ + NormalString: "a string", + NormalBool: true, + OptBool: optional.Some(false), + OptString: optional.Some(""), + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var obj testSerializationStruct + err := yaml.Unmarshal([]byte(tc.data), &obj) + assert.NoError(t, err) + assert.EqualValues(t, tc.want, obj, "yaml module returned unexpected") + }) + } +} From 7143f8fcdd07571af748c1aa8b01bb2b636389e5 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Fri, 23 Feb 2024 23:07:27 +0100 Subject: [PATCH 36/64] Refactor generate-svg.js (#29348) Small refactor to avoid `process` global and to sync it with `generate-images`. (cherry picked from commit 08c1926e1c3e2487f207b5f225d8b0f2831d0708) --- build/generate-svg.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build/generate-svg.js b/build/generate-svg.js index 1d92bc0b19..660ac9157e 100755 --- a/build/generate-svg.js +++ b/build/generate-svg.js @@ -4,15 +4,16 @@ import {optimize} from 'svgo'; import {parse} from 'node:path'; import {readFile, writeFile, mkdir} from 'node:fs/promises'; import {fileURLToPath} from 'node:url'; +import {exit} from 'node:process'; const glob = (pattern) => fastGlob.sync(pattern, { cwd: fileURLToPath(new URL('..', import.meta.url)), absolute: true, }); -function exit(err) { +function doExit(err) { if (err) console.error(err); - process.exit(err ? 1 : 0); + exit(err ? 1 : 0); } async function processFile(file, {prefix, fullName} = {}) { @@ -63,7 +64,7 @@ async function main() { } try { - exit(await main()); + doExit(await main()); } catch (err) { - exit(err); + doExit(err); } From fc384e494eae0264bf1c00c91567cacadd3ace8d Mon Sep 17 00:00:00 2001 From: Carlos Felgueiras <carlosfelgueiras@tecnico.ulisboa.pt> Date: Sat, 24 Feb 2024 00:02:14 +0100 Subject: [PATCH 37/64] Fix validity of the FROM email address not being checked (#29347) Fixes #27188. Introduces a check on the installation that tries to parse the FROM address. If it fails, shows a new error message to the user. --------- Co-authored-by: KN4CK3R <admin@oldschoolhack.me> (cherry picked from commit 6f6120dfa8d549d0b866eeb9317054fea831c844) Conflicts: options/locale/locale_en-US.ini context --- options/locale/locale_en-US.ini | 1 + routers/install/install.go | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 10e96b4a27..7ffb6ef490 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -248,6 +248,7 @@ email_title = Email Settings smtp_addr = SMTP Host smtp_port = SMTP Port smtp_from = Send Email As +smtp_from_invalid = The "Send Email As" address is invalid smtp_from_helper = Email address Forgejo will use. Enter a plain email address or use the "Name" <email@example.com> format. mailer_user = SMTP Username mailer_password = SMTP Password diff --git a/routers/install/install.go b/routers/install/install.go index 48271a64f2..13504953ce 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -7,6 +7,7 @@ package install import ( "fmt" "net/http" + "net/mail" "os" "os/exec" "path/filepath" @@ -423,6 +424,11 @@ func SubmitInstall(ctx *context.Context) { } if len(strings.TrimSpace(form.SMTPAddr)) > 0 { + if _, err := mail.ParseAddress(form.SMTPFrom); err != nil { + ctx.RenderWithErr(ctx.Tr("install.smtp_from_invalid"), tplInstall, &form) + return + } + cfg.Section("mailer").Key("ENABLED").SetValue("true") cfg.Section("mailer").Key("SMTP_ADDR").SetValue(form.SMTPAddr) cfg.Section("mailer").Key("SMTP_PORT").SetValue(form.SMTPPort) From f097799953c5f510b7e3314f1e3e115761f207d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=9Eahin=20Akkaya?= <sahin@sahinakkaya.dev> Date: Sat, 24 Feb 2024 02:41:24 +0300 Subject: [PATCH 38/64] Implement code frequency graph (#29191) ### Overview This is the implementation of Code Frequency page. This feature was mentioned on these issues: #18262, #7392. It adds another tab to Activity page called Code Frequency. Code Frequency tab shows additions and deletions over time since the repository existed. Before: <img width="1296" alt="image" src="https://github.com/go-gitea/gitea/assets/32161460/2603504f-aee7-4929-a8c4-fb3412a7a0f6"> After: <img width="1296" alt="image" src="https://github.com/go-gitea/gitea/assets/32161460/58c03721-729f-4536-a663-9f337f240963"> --- #### Features - See additions deletions over time since repository existed - Click on "Additions" or "Deletions" legend to show only one type of contribution - Use the same cache from Contributors page so that the loading of data will be fast once it is cached by visiting either one of the pages --------- Co-authored-by: Giteabot <teabot@gitea.io> (cherry picked from commit 875f5ea6d83c8371f309df99654ca3556623004c) --- options/locale/locale_en-US.ini | 2 + routers/web/repo/code_frequency.go | 41 +++++ routers/web/web.go | 4 + services/repository/contributors_graph.go | 2 - templates/repo/activity.tmpl | 1 + templates/repo/code_frequency.tmpl | 9 + templates/repo/navbar.tmpl | 3 + web_src/js/components/RepoCodeFrequency.vue | 172 ++++++++++++++++++++ web_src/js/components/RepoContributors.vue | 36 +--- web_src/js/features/code-frequency.js | 21 +++ web_src/js/index.js | 2 + web_src/js/utils.js | 2 + web_src/js/utils/color.js | 14 ++ 13 files changed, 277 insertions(+), 32 deletions(-) create mode 100644 routers/web/repo/code_frequency.go create mode 100644 templates/repo/code_frequency.tmpl create mode 100644 web_src/js/components/RepoCodeFrequency.vue create mode 100644 web_src/js/features/code-frequency.js diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 7ffb6ef490..d4a5ca4517 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1962,6 +1962,7 @@ wiki.original_git_entry_tooltip = View original Git file instead of using friend activity = Activity activity.navbar.pulse = Pulse activity.navbar.contributors = Contributors +activity.navbar.code_frequency = Code Frequency activity.period.filter_label = Period: activity.period.daily = 1 day activity.period.halfweekly = 3 days @@ -2656,6 +2657,7 @@ component_loading = Loading %s... component_loading_failed = Could not load %s component_loading_info = This might take a bit… component_failed_to_load = An unexpected error happened. +code_frequency.what = code frequency contributors.what = contributions [org] diff --git a/routers/web/repo/code_frequency.go b/routers/web/repo/code_frequency.go new file mode 100644 index 0000000000..48ade655b7 --- /dev/null +++ b/routers/web/repo/code_frequency.go @@ -0,0 +1,41 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "errors" + "net/http" + + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" + contributors_service "code.gitea.io/gitea/services/repository" +) + +const ( + tplCodeFrequency base.TplName = "repo/activity" +) + +// CodeFrequency renders the page to show repository code frequency +func CodeFrequency(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("repo.activity.navbar.code_frequency") + + ctx.Data["PageIsActivity"] = true + ctx.Data["PageIsCodeFrequency"] = true + ctx.PageData["repoLink"] = ctx.Repo.RepoLink + + ctx.HTML(http.StatusOK, tplCodeFrequency) +} + +// CodeFrequencyData returns JSON of code frequency data +func CodeFrequencyData(ctx *context.Context) { + if contributorStats, err := contributors_service.GetContributorStats(ctx, ctx.Cache, ctx.Repo.Repository, ctx.Repo.CommitID); err != nil { + if errors.Is(err, contributors_service.ErrAwaitGeneration) { + ctx.Status(http.StatusAccepted) + return + } + ctx.ServerError("GetCodeFrequencyData", err) + } else { + ctx.JSON(http.StatusOK, contributorStats["total"].Weeks) + } +} diff --git a/routers/web/web.go b/routers/web/web.go index 38cf5e92bc..cef563f615 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1448,6 +1448,10 @@ func registerRoutes(m *web.Route) { m.Get("", repo.Contributors) m.Get("/data", repo.ContributorsData) }) + m.Group("/code-frequency", func() { + m.Get("", repo.CodeFrequency) + m.Get("/data", repo.CodeFrequencyData) + }) }, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(unit.TypePullRequests, unit.TypeIssues, unit.TypeReleases)) m.Group("/activity_author_data", func() { diff --git a/services/repository/contributors_graph.go b/services/repository/contributors_graph.go index 8421df8e3a..7c9f535ae0 100644 --- a/services/repository/contributors_graph.go +++ b/services/repository/contributors_graph.go @@ -143,7 +143,6 @@ func getExtendedCommitStats(repo *git.Repository, revision string /*, limit int PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { _ = stdoutWriter.Close() scanner := bufio.NewScanner(stdoutReader) - scanner.Split(bufio.ScanLines) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) @@ -180,7 +179,6 @@ func getExtendedCommitStats(repo *git.Repository, revision string /*, limit int } } commitStats.Total = commitStats.Additions + commitStats.Deletions - scanner.Scan() scanner.Text() // empty line at the end res := &ExtendedCommitStats{ diff --git a/templates/repo/activity.tmpl b/templates/repo/activity.tmpl index 960083d2fb..94f52b0e26 100644 --- a/templates/repo/activity.tmpl +++ b/templates/repo/activity.tmpl @@ -8,6 +8,7 @@ <div class="flex-container-main"> {{if .PageIsPulse}}{{template "repo/pulse" .}}{{end}} {{if .PageIsContributors}}{{template "repo/contributors" .}}{{end}} + {{if .PageIsCodeFrequency}}{{template "repo/code_frequency" .}}{{end}} </div> </div> </div> diff --git a/templates/repo/code_frequency.tmpl b/templates/repo/code_frequency.tmpl new file mode 100644 index 0000000000..50ec1beb6b --- /dev/null +++ b/templates/repo/code_frequency.tmpl @@ -0,0 +1,9 @@ +{{if .Permission.CanRead $.UnitTypeCode}} + <div id="repo-code-frequency-chart" + data-locale-loading-title="{{ctx.Locale.Tr "graphs.component_loading" (ctx.Locale.Tr "graphs.code_frequency.what")}}" + data-locale-loading-title-failed="{{ctx.Locale.Tr "graphs.component_loading_failed" (ctx.Locale.Tr "graphs.code_frequency.what")}}" + data-locale-loading-info="{{ctx.Locale.Tr "graphs.component_loading_info"}}" + data-locale-component-failed-to-load="{{ctx.Locale.Tr "graphs.component_failed_to_load"}}" + > + </div> +{{end}} diff --git a/templates/repo/navbar.tmpl b/templates/repo/navbar.tmpl index a9042ee30d..aa5021e73a 100644 --- a/templates/repo/navbar.tmpl +++ b/templates/repo/navbar.tmpl @@ -5,4 +5,7 @@ <a class="{{if .PageIsContributors}}active {{end}}item" href="{{.RepoLink}}/activity/contributors"> {{ctx.Locale.Tr "repo.activity.navbar.contributors"}} </a> + <a class="{{if .PageIsCodeFrequency}}active{{end}} item" href="{{.RepoLink}}/activity/code-frequency"> + {{ctx.Locale.Tr "repo.activity.navbar.code_frequency"}} + </a> </div> diff --git a/web_src/js/components/RepoCodeFrequency.vue b/web_src/js/components/RepoCodeFrequency.vue new file mode 100644 index 0000000000..ad607a041a --- /dev/null +++ b/web_src/js/components/RepoCodeFrequency.vue @@ -0,0 +1,172 @@ +<script> +import {SvgIcon} from '../svg.js'; +import { + Chart, + Legend, + LinearScale, + TimeScale, + PointElement, + LineElement, + Filler, +} from 'chart.js'; +import {GET} from '../modules/fetch.js'; +import {Line as ChartLine} from 'vue-chartjs'; +import { + startDaysBetween, + firstStartDateAfterDate, + fillEmptyStartDaysWithZeroes, +} from '../utils/time.js'; +import {chartJsColors} from '../utils/color.js'; +import {sleep} from '../utils.js'; +import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; + +const {pageData} = window.config; + +Chart.defaults.color = chartJsColors.text; +Chart.defaults.borderColor = chartJsColors.border; + +Chart.register( + TimeScale, + LinearScale, + Legend, + PointElement, + LineElement, + Filler, +); + +export default { + components: {ChartLine, SvgIcon}, + props: { + locale: { + type: Object, + required: true + }, + }, + data: () => ({ + isLoading: false, + errorText: '', + repoLink: pageData.repoLink || [], + data: [], + }), + mounted() { + this.fetchGraphData(); + }, + methods: { + async fetchGraphData() { + this.isLoading = true; + try { + let response; + do { + response = await GET(`${this.repoLink}/activity/code-frequency/data`); + if (response.status === 202) { + await sleep(1000); // wait for 1 second before retrying + } + } while (response.status === 202); + if (response.ok) { + this.data = await response.json(); + const weekValues = Object.values(this.data); + const start = weekValues[0].week; + const end = firstStartDateAfterDate(new Date()); + const startDays = startDaysBetween(new Date(start), new Date(end)); + this.data = fillEmptyStartDaysWithZeroes(startDays, this.data); + this.errorText = ''; + } else { + this.errorText = response.statusText; + } + } catch (err) { + this.errorText = err.message; + } finally { + this.isLoading = false; + } + }, + + toGraphData(data) { + return { + datasets: [ + { + data: data.map((i) => ({x: i.week, y: i.additions})), + pointRadius: 0, + pointHitRadius: 0, + fill: true, + label: 'Additions', + backgroundColor: chartJsColors['additions'], + borderWidth: 0, + tension: 0.3, + }, + { + data: data.map((i) => ({x: i.week, y: -i.deletions})), + pointRadius: 0, + pointHitRadius: 0, + fill: true, + label: 'Deletions', + backgroundColor: chartJsColors['deletions'], + borderWidth: 0, + tension: 0.3, + }, + ], + }; + }, + + getOptions() { + return { + responsive: true, + maintainAspectRatio: false, + animation: true, + plugins: { + legend: { + display: true, + }, + }, + scales: { + x: { + type: 'time', + grid: { + display: false, + }, + time: { + minUnit: 'month', + }, + ticks: { + maxRotation: 0, + maxTicksLimit: 12 + }, + }, + y: { + ticks: { + maxTicksLimit: 6 + }, + }, + }, + }; + }, + }, +}; +</script> +<template> + <div> + <div class="ui header gt-df gt-ac gt-sb"> + {{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: `Code frequency over the history of ${repoLink.slice(1)}` }} + </div> + <div class="gt-df ui segment main-graph"> + <div v-if="isLoading || errorText !== ''" class="gt-tc gt-m-auto"> + <div v-if="isLoading"> + <SvgIcon name="octicon-sync" class="gt-mr-3 job-status-rotate"/> + {{ locale.loadingInfo }} + </div> + <div v-else class="text red"> + <SvgIcon name="octicon-x-circle-fill"/> + {{ errorText }} + </div> + </div> + <ChartLine + v-memo="data" v-if="data.length !== 0" + :data="toGraphData(data)" :options="getOptions()" + /> + </div> + </div> +</template> +<style scoped> +.main-graph { + height: 440px; +} +</style> diff --git a/web_src/js/components/RepoContributors.vue b/web_src/js/components/RepoContributors.vue index fa1545b3df..84fdcae1f6 100644 --- a/web_src/js/components/RepoContributors.vue +++ b/web_src/js/components/RepoContributors.vue @@ -3,10 +3,7 @@ import {SvgIcon} from '../svg.js'; import { Chart, Title, - Tooltip, - Legend, BarElement, - CategoryScale, LinearScale, TimeScale, PointElement, @@ -21,27 +18,13 @@ import { firstStartDateAfterDate, fillEmptyStartDaysWithZeroes, } from '../utils/time.js'; +import {chartJsColors} from '../utils/color.js'; +import {sleep} from '../utils.js'; import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; import $ from 'jquery'; const {pageData} = window.config; -const colors = { - text: '--color-text', - border: '--color-secondary-alpha-60', - commits: '--color-primary-alpha-60', - additions: '--color-green', - deletions: '--color-red', - title: '--color-secondary-dark-4', -}; - -const styles = window.getComputedStyle(document.documentElement); -const getColor = (name) => styles.getPropertyValue(name).trim(); - -for (const [key, value] of Object.entries(colors)) { - colors[key] = getColor(value); -} - const customEventListener = { id: 'customEventListener', afterEvent: (chart, args, opts) => { @@ -54,17 +37,14 @@ const customEventListener = { } }; -Chart.defaults.color = colors.text; -Chart.defaults.borderColor = colors.border; +Chart.defaults.color = chartJsColors.text; +Chart.defaults.borderColor = chartJsColors.border; Chart.register( TimeScale, - CategoryScale, LinearScale, BarElement, Title, - Tooltip, - Legend, PointElement, LineElement, Filler, @@ -122,7 +102,7 @@ export default { do { response = await GET(`${this.repoLink}/activity/contributors/data`); if (response.status === 202) { - await new Promise((resolve) => setTimeout(resolve, 1000)); // wait for 1 second before retrying + await sleep(1000); // wait for 1 second before retrying } } while (response.status === 202); if (response.ok) { @@ -222,7 +202,7 @@ export default { pointRadius: 0, pointHitRadius: 0, fill: 'start', - backgroundColor: colors[this.type], + backgroundColor: chartJsColors[this.type], borderWidth: 0, tension: 0.3, }, @@ -254,7 +234,6 @@ export default { title: { display: type === 'main', text: 'drag: zoom, shift+drag: pan, double click: reset zoom', - color: colors.title, position: 'top', align: 'center', }, @@ -262,9 +241,6 @@ export default { chartType: type, instance: this, }, - legend: { - display: false, - }, zoom: { pan: { enabled: true, diff --git a/web_src/js/features/code-frequency.js b/web_src/js/features/code-frequency.js new file mode 100644 index 0000000000..103d82f6e3 --- /dev/null +++ b/web_src/js/features/code-frequency.js @@ -0,0 +1,21 @@ +import {createApp} from 'vue'; + +export async function initRepoCodeFrequency() { + const el = document.getElementById('repo-code-frequency-chart'); + if (!el) return; + + const {default: RepoCodeFrequency} = await import(/* webpackChunkName: "code-frequency-graph" */'../components/RepoCodeFrequency.vue'); + try { + const View = createApp(RepoCodeFrequency, { + locale: { + loadingTitle: el.getAttribute('data-locale-loading-title'), + loadingTitleFailed: el.getAttribute('data-locale-loading-title-failed'), + loadingInfo: el.getAttribute('data-locale-loading-info'), + } + }); + View.mount(el); + } catch (err) { + console.error('RepoCodeFrequency failed to load', err); + el.textContent = el.getAttribute('data-locale-component-failed-to-load'); + } +} diff --git a/web_src/js/index.js b/web_src/js/index.js index 117279c3c4..d9cfff4084 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -84,6 +84,7 @@ import {onDomReady} from './utils/dom.js'; import {initRepoIssueList} from './features/repo-issue-list.js'; import {initCommonIssueListQuickGoto} from './features/common-issue-list.js'; import {initRepoContributors} from './features/contributors.js'; +import {initRepoCodeFrequency} from './features/code-frequency.js'; import {initRepoDiffCommitBranchesAndTags} from './features/repo-diff-commit.js'; import {initDirAuto} from './modules/dirauto.js'; @@ -174,6 +175,7 @@ onDomReady(() => { initRepository(); initRepositoryActionView(); initRepoContributors(); + initRepoCodeFrequency(); initCommitStatuses(); initCaptcha(); diff --git a/web_src/js/utils.js b/web_src/js/utils.js index c82e42d349..3a2694335f 100644 --- a/web_src/js/utils.js +++ b/web_src/js/utils.js @@ -139,3 +139,5 @@ export function parseDom(text, contentType) { export function serializeXml(node) { return xmlSerializer.serializeToString(node); } + +export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/web_src/js/utils/color.js b/web_src/js/utils/color.js index 5d9c4ca45d..0ba6af49ee 100644 --- a/web_src/js/utils/color.js +++ b/web_src/js/utils/color.js @@ -19,3 +19,17 @@ function getLuminance(r, g, b) { export function useLightTextOnBackground(r, g, b) { return getLuminance(r, g, b) < 0.453; } + +function resolveColors(obj) { + const styles = window.getComputedStyle(document.documentElement); + const getColor = (name) => styles.getPropertyValue(name).trim(); + return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, getColor(value)])); +} + +export const chartJsColors = resolveColors({ + text: '--color-text', + border: '--color-secondary-alpha-60', + commits: '--color-primary-alpha-60', + additions: '--color-green', + deletions: '--color-red', +}); From 69055400881777148d5e5d3f531c563ebfdb9287 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Sat, 24 Feb 2024 14:55:19 +0800 Subject: [PATCH 39/64] Use the database object format name but not read from git repoisitory everytime and fix possible migration wrong objectformat when migrating a sha256 repository (#29294) Now we can get object format name from git command line or from the database repository table. Assume the column is right, we don't need to read from git command line every time. This also fixed a possible bug that the object format is wrong when migrating a sha256 repository from external. <img width="658" alt="image" src="https://github.com/go-gitea/gitea/assets/81045/6e9a9dcf-13bf-4267-928b-6bf2c2560423"> (cherry picked from commit b79c30435f439af8243ee281310258cdf141e27b) Conflicts: routers/web/repo/blame.go services/agit/agit.go context --- modules/context/api.go | 9 ++------- modules/context/repo.go | 20 ++++++++------------ routers/api/v1/utils/git.go | 2 +- routers/private/hook_pre_receive.go | 2 +- routers/web/repo/blame.go | 5 +---- routers/web/repo/compare.go | 4 ++-- routers/web/repo/setting/lfs.go | 2 +- services/agit/agit.go | 5 +---- services/migrations/gitea_uploader.go | 16 +++++++++++++--- services/pull/check.go | 5 +---- services/pull/merge.go | 2 +- services/release/release.go | 2 +- services/repository/branch.go | 7 ++----- services/repository/files/commit.go | 6 ++---- services/repository/files/tree.go | 2 +- services/repository/lfs.go | 2 +- services/repository/push.go | 6 +----- 17 files changed, 40 insertions(+), 57 deletions(-) diff --git a/modules/context/api.go b/modules/context/api.go index 7557a5f435..fafd49fd42 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -309,12 +309,6 @@ func RepoRefForAPI(next http.Handler) http.Handler { return } - objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat() - if err != nil { - ctx.Error(http.StatusInternalServerError, "GetCommit", err) - return - } - if ref := ctx.FormTrim("ref"); len(ref) > 0 { commit, err := ctx.Repo.GitRepo.GetCommit(ref) if err != nil { @@ -333,6 +327,7 @@ func RepoRefForAPI(next http.Handler) http.Handler { } refName := getRefName(ctx.Base, ctx.Repo, RepoRefAny) + var err error if ctx.Repo.GitRepo.IsBranchExist(refName) { ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName) @@ -348,7 +343,7 @@ func RepoRefForAPI(next http.Handler) http.Handler { return } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() - } else if len(refName) == objectFormat.FullLength() { + } else if len(refName) == ctx.Repo.GetObjectFormat().FullLength() { ctx.Repo.CommitID = refName ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName) if err != nil { diff --git a/modules/context/repo.go b/modules/context/repo.go index 490d798d50..e8ed1134fe 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -83,6 +83,10 @@ func (r *Repository) CanCreateBranch() bool { return r.Permission.CanWrite(unit_model.TypeCode) && r.Repository.CanCreateBranch() } +func (r *Repository) GetObjectFormat() git.ObjectFormat { + return git.ObjectFormatFromName(r.Repository.ObjectFormatName) +} + // RepoMustNotBeArchived checks if a repo is archived func RepoMustNotBeArchived() func(ctx *Context) { return func(ctx *Context) { @@ -831,9 +835,8 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string { } // For legacy and API support only full commit sha parts := strings.Split(path, "/") - objectFormat, _ := repo.GitRepo.GetObjectFormat() - if len(parts) > 0 && len(parts[0]) == objectFormat.FullLength() { + if len(parts) > 0 && len(parts[0]) == git.ObjectFormatFromName(repo.Repository.ObjectFormatName).FullLength() { repo.TreePath = strings.Join(parts[1:], "/") return parts[0] } @@ -877,9 +880,8 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string { return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist) case RepoRefCommit: parts := strings.Split(path, "/") - objectFormat, _ := repo.GitRepo.GetObjectFormat() - if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= objectFormat.FullLength() { + if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= repo.GetObjectFormat().FullLength() { repo.TreePath = strings.Join(parts[1:], "/") return parts[0] } @@ -938,12 +940,6 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context } } - objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat() - if err != nil { - log.Error("Cannot determine objectFormat for repository: %w", err) - ctx.Repo.Repository.MarkAsBrokenEmpty() - } - // Get default branch. if len(ctx.Params("*")) == 0 { refName = ctx.Repo.Repository.DefaultBranch @@ -1010,7 +1006,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context return cancel } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() - } else if len(refName) >= 7 && len(refName) <= objectFormat.FullLength() { + } else if len(refName) >= 7 && len(refName) <= ctx.Repo.GetObjectFormat().FullLength() { ctx.Repo.IsViewCommit = true ctx.Repo.CommitID = refName @@ -1020,7 +1016,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context return cancel } // If short commit ID add canonical link header - if len(refName) < objectFormat.FullLength() { + if len(refName) < ctx.Repo.GetObjectFormat().FullLength() { ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"", util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1)))) } diff --git a/routers/api/v1/utils/git.go b/routers/api/v1/utils/git.go index 2299cdc247..5e80190017 100644 --- a/routers/api/v1/utils/git.go +++ b/routers/api/v1/utils/git.go @@ -72,7 +72,7 @@ func searchRefCommitByType(ctx *context.APIContext, refType, filter string) (str // ConvertToObjectID returns a full-length SHA1 from a potential ID string func ConvertToObjectID(ctx gocontext.Context, repo *context.Repository, commitID string) (git.ObjectID, error) { - objectFormat, _ := repo.GitRepo.GetObjectFormat() + objectFormat := repo.GetObjectFormat() if len(commitID) == objectFormat.FullLength() && objectFormat.IsValid(commitID) { sha, err := git.NewIDFromString(commitID) if err == nil { diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 90d8287f06..f28ae4c0eb 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -145,7 +145,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r repo := ctx.Repo.Repository gitRepo := ctx.Repo.GitRepo - objectFormat, _ := gitRepo.GetObjectFormat() + objectFormat := ctx.Repo.GetObjectFormat() if branchName == repo.DefaultBranch && newCommitID == objectFormat.EmptyObjectID().String() { log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo) diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 49443162e4..2c938dc966 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -112,10 +112,7 @@ type blameResult struct { func performBlame(ctx *context.Context, commit *git.Commit, file string, bypassBlameIgnore bool) (*blameResult, error) { repoPath := ctx.Repo.Repository.RepoPath() - objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat() - if err != nil { - return nil, err - } + objectFormat := ctx.Repo.GetObjectFormat() blameReader, err := git.CreateBlameReader(ctx, objectFormat, repoPath, commit, file, bypassBlameIgnore) if err != nil { diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index df41c750de..535487d5fd 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -312,14 +312,14 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { baseIsCommit := ctx.Repo.GitRepo.IsCommitExist(ci.BaseBranch) baseIsBranch := ctx.Repo.GitRepo.IsBranchExist(ci.BaseBranch) baseIsTag := ctx.Repo.GitRepo.IsTagExist(ci.BaseBranch) - objectFormat, _ := ctx.Repo.GitRepo.GetObjectFormat() + if !baseIsCommit && !baseIsBranch && !baseIsTag { // Check if baseBranch is short sha commit hash if baseCommit, _ := ctx.Repo.GitRepo.GetCommit(ci.BaseBranch); baseCommit != nil { ci.BaseBranch = baseCommit.ID.String() ctx.Data["BaseBranch"] = ci.BaseBranch baseIsCommit = true - } else if ci.BaseBranch == objectFormat.EmptyObjectID().String() { + } else if ci.BaseBranch == ctx.Repo.GetObjectFormat().EmptyObjectID().String() { if isSameRepo { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch)) } else { diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go index e360ae2b8c..53e7b22d1b 100644 --- a/routers/web/repo/setting/lfs.go +++ b/routers/web/repo/setting/lfs.go @@ -388,7 +388,7 @@ func LFSFileFind(ctx *context.Context) { sha := ctx.FormString("sha") ctx.Data["Title"] = oid ctx.Data["PageIsSettingsLFS"] = true - objectFormat, _ := ctx.Repo.GitRepo.GetObjectFormat() + objectFormat := ctx.Repo.GetObjectFormat() var objectID git.ObjectID if len(sha) == 0 { pointer := lfs.Pointer{Oid: oid, Size: size} diff --git a/services/agit/agit.go b/services/agit/agit.go index 4c970ee78a..e46a5771e1 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -28,10 +28,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. title, hasTitle := opts.GitPushOptions["title"] description, hasDesc := opts.GitPushOptions["description"] - objectFormat, err := gitRepo.GetObjectFormat() - if err != nil { - return nil, fmt.Errorf("couldn't get object format of the repository: %w", err) - } + objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) pusher, err := user_model.GetUserByID(ctx, opts.UserID) if err != nil { diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index ebb1313c2b..7920c07056 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -140,8 +140,18 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate if err != nil { return err } - g.gitRepo, err = gitrepo.OpenRepository(g.ctx, r) - return err + g.gitRepo, err = gitrepo.OpenRepository(g.ctx, g.repo) + if err != nil { + return err + } + + // detect object format from git repository and update to database + objectFormat, err := g.gitRepo.GetObjectFormat() + if err != nil { + return err + } + g.repo.ObjectFormatName = objectFormat.Name() + return repo_model.UpdateRepositoryCols(g.ctx, g.repo, "object_format_name") } // Close closes this uploader @@ -901,7 +911,7 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error { comment.UpdatedAt = comment.CreatedAt } - objectFormat, _ := g.gitRepo.GetObjectFormat() + objectFormat := git.ObjectFormatFromName(g.repo.ObjectFormatName) if !objectFormat.IsValid(comment.CommitID) { log.Warn("Invalid comment CommitID[%s] on comment[%d] in PR #%d of %s/%s replaced with %s", comment.CommitID, pr.Index, g.repoOwner, g.repoName, headCommitID) comment.CommitID = headCommitID diff --git a/services/pull/check.go b/services/pull/check.go index dd6c3ed230..f4dd332b14 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -222,10 +222,7 @@ func getMergeCommit(ctx context.Context, pr *issues_model.PullRequest) (*git.Com } defer gitRepo.Close() - objectFormat, err := gitRepo.GetObjectFormat() - if err != nil { - return nil, fmt.Errorf("%-v GetObjectFormat: %w", pr.BaseRepo, err) - } + objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName) // Get the commit from BaseBranch where the pull request got merged mergeCommit, _, err := git.NewCommand(ctx, "rev-list", "--ancestry-path", "--merges", "--reverse"). diff --git a/services/pull/merge.go b/services/pull/merge.go index f09067996c..2112108d45 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -503,7 +503,7 @@ func MergedManually(ctx context.Context, pr *issues_model.PullRequest, doer *use return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: repo_model.MergeStyleManuallyMerged} } - objectFormat, _ := baseGitRepo.GetObjectFormat() + objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName) if len(commitID) != objectFormat.FullLength() { return fmt.Errorf("Wrong commit ID") } diff --git a/services/release/release.go b/services/release/release.go index 4c522c18be..a359e5078e 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -88,7 +88,7 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel created = true rel.LowerTagName = strings.ToLower(rel.TagName) - objectFormat, _ := gitRepo.GetObjectFormat() + objectFormat := git.ObjectFormatFromName(rel.Repo.ObjectFormatName) commits := repository.NewPushCommits() commits.HeadCommit = repository.CommitToPushCommit(commit) commits.CompareURL = rel.Repo.ComposeCompareURL(objectFormat.EmptyObjectID().String(), commit.ID.String()) diff --git a/services/repository/branch.go b/services/repository/branch.go index 6add9422f4..39be3984ae 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -369,11 +369,6 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R return fmt.Errorf("GetBranch: %v", err) } - objectFormat, err := gitRepo.GetObjectFormat() - if err != nil { - return err - } - if rawBranch.IsDeleted { return nil } @@ -395,6 +390,8 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R return err } + objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) + // Don't return error below this if err := PushUpdate( &repo_module.PushUpdateOptions{ diff --git a/services/repository/files/commit.go b/services/repository/files/commit.go index 16a15e06a7..512aec7c81 100644 --- a/services/repository/files/commit.go +++ b/services/repository/files/commit.go @@ -30,10 +30,8 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato } defer closer.Close() - objectFormat, err := gitRepo.GetObjectFormat() - if err != nil { - return fmt.Errorf("GetObjectFormat[%s]: %w", repoPath, err) - } + objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) + commit, err := gitRepo.GetCommit(sha) if err != nil { gitRepo.Close() diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go index 9d3185c3fc..e3a7f3b8b0 100644 --- a/services/repository/files/tree.go +++ b/services/repository/files/tree.go @@ -37,7 +37,7 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git } apiURL := repo.APIURL() apiURLLen := len(apiURL) - objectFormat, _ := gitRepo.GetObjectFormat() + objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) hashLen := objectFormat.FullLength() const gitBlobsPath = "/git/blobs/" diff --git a/services/repository/lfs.go b/services/repository/lfs.go index 4504f796bd..4d48881b87 100644 --- a/services/repository/lfs.go +++ b/services/repository/lfs.go @@ -79,7 +79,7 @@ func GarbageCollectLFSMetaObjectsForRepo(ctx context.Context, repo *repo_model.R store := lfs.NewContentStore() errStop := errors.New("STOPERR") - objectFormat, _ := gitRepo.GetObjectFormat() + objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) err = git_model.IterateLFSMetaObjectsForRepo(ctx, repo.ID, func(ctx context.Context, metaObject *git_model.LFSMetaObject, count int64) error { if opts.NumberToCheckPerRepo > 0 && total > opts.NumberToCheckPerRepo { diff --git a/services/repository/push.go b/services/repository/push.go index 5e2853b27d..bb080e30cc 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -93,11 +93,6 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } defer gitRepo.Close() - objectFormat, err := gitRepo.GetObjectFormat() - if err != nil { - return fmt.Errorf("unknown repository ObjectFormat [%s]: %w", repo.FullName(), err) - } - if err = repo_module.UpdateRepoSize(ctx, repo); err != nil { return fmt.Errorf("Failed to update size for repository: %v", err) } @@ -105,6 +100,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { addTags := make([]string, 0, len(optsList)) delTags := make([]string, 0, len(optsList)) var pusher *user_model.User + objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) for _, opts := range optsList { log.Trace("pushUpdates: %-v %s %s %s", repo, opts.OldCommitID, opts.NewCommitID, opts.RefFullName) From f0acc71ba13713f07602294b4a33028125343d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Br=C3=BCckner?= <code@nik.dev> Date: Sat, 24 Feb 2024 07:49:16 +0000 Subject: [PATCH 40/64] Properly migrate target branch change GitLab comment (#29340) GitLab generates "system notes" whenever an event happens within the platform. Unlike Gitea, those events are stored and retrieved as text comments with no semantic details. The only way to tell whether a comment was generated in this manner is the `system` flag on the note type. This PR adds detection for a new specific kind of event: Changing the target branch of a PR. When detected, it is downloaded using Gitea's type for this event, and eventually uploaded into Gitea in the expected format, i.e. with no text content in the comment. This PR also updates the template used to render comments to add support for migrated comments of this type. ref: https://gitlab.com/gitlab-org/gitlab/-/blob/11bd6dc826e0bea2832324a1d7356949a9398884/app/services/system_notes/merge_requests_service.rb#L102 (cherry picked from commit 6e5966597c2d498d1a8540dad965461d44ff8e57) --- services/migrations/gitea_uploader.go | 10 ++++++++-- services/migrations/gitlab.go | 10 +++++++++- services/migrations/gitlab_test.go | 19 ++++++++++++++++++- .../repo/issue/view_content/comments.tmpl | 19 +++++++++++++++---- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index 7920c07056..99a44dff0f 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -492,10 +492,16 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { } case issues_model.CommentTypeChangeTitle: if comment.Meta["OldTitle"] != nil { - cm.OldTitle = fmt.Sprintf("%s", comment.Meta["OldTitle"]) + cm.OldTitle = fmt.Sprint(comment.Meta["OldTitle"]) } if comment.Meta["NewTitle"] != nil { - cm.NewTitle = fmt.Sprintf("%s", comment.Meta["NewTitle"]) + cm.NewTitle = fmt.Sprint(comment.Meta["NewTitle"]) + } + case issues_model.CommentTypeChangeTargetBranch: + if comment.Meta["OldRef"] != nil && comment.Meta["NewRef"] != nil { + cm.OldRef = fmt.Sprint(comment.Meta["OldRef"]) + cm.NewRef = fmt.Sprint(comment.Meta["NewRef"]) + cm.Content = "" } case issues_model.CommentTypePRScheduledToAutoMerge, issues_model.CommentTypePRUnScheduledToAutoMerge: cm.Content = "" diff --git a/services/migrations/gitlab.go b/services/migrations/gitlab.go index d08eaf0f84..5e49ae6d57 100644 --- a/services/migrations/gitlab.go +++ b/services/migrations/gitlab.go @@ -11,6 +11,7 @@ import ( "net/http" "net/url" "path" + "regexp" "strings" "time" @@ -519,6 +520,8 @@ func (g *GitlabDownloader) GetComments(commentable base.Commentable) ([]*base.Co return allComments, true, nil } +var targetBranchChangeRegexp = regexp.MustCompile("^changed target branch from `(.*?)` to `(.*?)`$") + func (g *GitlabDownloader) convertNoteToComment(localIndex int64, note *gitlab.Note) *base.Comment { comment := &base.Comment{ IssueIndex: localIndex, @@ -528,11 +531,16 @@ func (g *GitlabDownloader) convertNoteToComment(localIndex int64, note *gitlab.N PosterEmail: note.Author.Email, Content: note.Body, Created: *note.CreatedAt, + Meta: map[string]any{}, } // Try to find the underlying event of system notes. if note.System { - if strings.HasPrefix(note.Body, "enabled an automatic merge") { + if match := targetBranchChangeRegexp.FindStringSubmatch(note.Body); match != nil { + comment.CommentType = issues_model.CommentTypeChangeTargetBranch.String() + comment.Meta["OldRef"] = match[1] + comment.Meta["NewRef"] = match[2] + } else if strings.HasPrefix(note.Body, "enabled an automatic merge") { comment.CommentType = issues_model.CommentTypePRScheduledToAutoMerge.String() } else if note.Body == "canceled the automatic merge" { comment.CommentType = issues_model.CommentTypePRUnScheduledToAutoMerge.String() diff --git a/services/migrations/gitlab_test.go b/services/migrations/gitlab_test.go index d941cebd2c..6e5ab86720 100644 --- a/services/migrations/gitlab_test.go +++ b/services/migrations/gitlab_test.go @@ -586,7 +586,8 @@ func TestNoteToComment(t *testing.T) { notes := []gitlab.Note{ makeTestNote(1, "This is a regular comment", false), makeTestNote(2, "enabled an automatic merge for abcd1234", true), - makeTestNote(3, "canceled the automatic merge", true), + makeTestNote(3, "changed target branch from `master` to `main`", true), + makeTestNote(4, "canceled the automatic merge", true), } comments := []base.Comment{{ IssueIndex: 17, @@ -597,6 +598,7 @@ func TestNoteToComment(t *testing.T) { CommentType: "", Content: "This is a regular comment", Created: now, + Meta: map[string]any{}, }, { IssueIndex: 17, Index: 2, @@ -606,15 +608,30 @@ func TestNoteToComment(t *testing.T) { CommentType: "pull_scheduled_merge", Content: "enabled an automatic merge for abcd1234", Created: now, + Meta: map[string]any{}, }, { IssueIndex: 17, Index: 3, PosterID: 72, PosterName: "test", PosterEmail: "test@example.com", + CommentType: "change_target_branch", + Content: "changed target branch from `master` to `main`", + Created: now, + Meta: map[string]any{ + "OldRef": "master", + "NewRef": "main", + }, + }, { + IssueIndex: 17, + Index: 4, + PosterID: 72, + PosterName: "test", + PosterEmail: "test@example.com", CommentType: "pull_cancel_scheduled_merge", Content: "canceled the automatic merge", Created: now, + Meta: map[string]any{}, }} for i, note := range notes { diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index cf9df4dbda..20dbbdc6e4 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -369,8 +369,7 @@ {{else if eq .Type 22}} <div class="timeline-item-group" id="{{.HashTag}}"> <div class="timeline-item event"> - {{if .OriginalAuthor}} - {{else}} + {{if not .OriginalAuthor}} {{/* Some timeline avatars need a offset to correctly align with their speech bubble. The condition depends on review type and for positive reviews whether there is a comment element or not */}} @@ -499,9 +498,21 @@ {{else if eq .Type 25}} <div class="timeline-item event"> <span class="badge">{{svg "octicon-git-branch"}}</span> - {{template "shared/user/avatarlink" dict "user" .Poster}} + {{if not .OriginalAuthor}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + {{end}} <span class="text grey muted-links"> - <a{{if gt .Poster.ID 0}} href="{{.Poster.HomeLink}}"{{end}}>{{.Poster.Name}}</a> + {{if .OriginalAuthor}} + <span class="text black"> + {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} + {{.OriginalAuthor}} + </span> + {{if $.Repository.OriginalURL}} + <span class="migrate">({{ctx.Locale.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname}})</span> + {{end}} + {{else}} + {{template "shared/user/authorlink" .Poster}} + {{end}} {{ctx.Locale.Tr "repo.pulls.change_target_branch_at" (.OldRef|Escape) (.NewRef|Escape) $createdStr}} </span> </div> From 1608ef0ce9ce2ea1c87aef715d111cf441637d01 Mon Sep 17 00:00:00 2001 From: qwerty287 <80460567+qwerty287@users.noreply.github.com> Date: Sat, 24 Feb 2024 09:18:39 +0100 Subject: [PATCH 41/64] Add API to get merged PR of a commit (#29243) Adds a new API `/repos/{owner}/{repo}/commits/{sha}/pull` that allows you to get the merged PR associated to a commit. --------- Co-authored-by: 6543 <6543@obermui.de> (cherry picked from commit 0a426cc575734e5eff410d6a790f40473117f753) --- models/fixtures/pull_request.yml | 1 + models/issues/pull.go | 20 +++++++++++++ models/issues/pull_test.go | 12 ++++++++ routers/api/v1/api.go | 1 + routers/api/v1/repo/commits.go | 51 ++++++++++++++++++++++++++++++++ templates/swagger/v1_json.tmpl | 43 +++++++++++++++++++++++++++ 6 files changed, 128 insertions(+) diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index 560674c370..54590fb830 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -9,6 +9,7 @@ head_branch: branch1 base_branch: master merge_base: 4a357436d925b5c974181ff12a994538ddc5a269 + merged_commit_id: 1a8823cd1a9549fde083f992f6b9b87a7ab74fb3 has_merged: true merger_id: 2 diff --git a/models/issues/pull.go b/models/issues/pull.go index ce2fd9233d..7d299eac27 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -1122,3 +1122,23 @@ func InsertPullRequests(ctx context.Context, prs ...*PullRequest) error { } return committer.Commit() } + +// GetPullRequestByMergedCommit returns a merged pull request by the given commit +func GetPullRequestByMergedCommit(ctx context.Context, repoID int64, sha string) (*PullRequest, error) { + pr := new(PullRequest) + has, err := db.GetEngine(ctx).Where("base_repo_id = ? AND merged_commit_id = ?", repoID, sha).Get(pr) + if err != nil { + return nil, err + } else if !has { + return nil, ErrPullRequestNotExist{0, 0, 0, repoID, "", ""} + } + + if err = pr.LoadAttributes(ctx); err != nil { + return nil, err + } + if err = pr.LoadIssue(ctx); err != nil { + return nil, err + } + + return pr, nil +} diff --git a/models/issues/pull_test.go b/models/issues/pull_test.go index 4702049af2..213838abec 100644 --- a/models/issues/pull_test.go +++ b/models/issues/pull_test.go @@ -425,6 +425,18 @@ func TestGetApprovers(t *testing.T) { assert.EqualValues(t, expected, approvers) } +func TestGetPullRequestByMergedCommit(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + pr, err := issues_model.GetPullRequestByMergedCommit(db.DefaultContext, 1, "1a8823cd1a9549fde083f992f6b9b87a7ab74fb3") + assert.NoError(t, err) + assert.EqualValues(t, 1, pr.ID) + + _, err = issues_model.GetPullRequestByMergedCommit(db.DefaultContext, 0, "1a8823cd1a9549fde083f992f6b9b87a7ab74fb3") + assert.ErrorAs(t, err, &issues_model.ErrPullRequestNotExist{}) + _, err = issues_model.GetPullRequestByMergedCommit(db.DefaultContext, 1, "") + assert.ErrorAs(t, err, &issues_model.ErrPullRequestNotExist{}) +} + func TestMigrate_InsertPullRequests(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) reponame := "repo1" diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index e75d4cc964..afceeefd77 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1300,6 +1300,7 @@ func Routes() *web.Route { m.Group("/{ref}", func() { m.Get("/status", repo.GetCombinedCommitStatusByRef) m.Get("/statuses", repo.GetCommitStatusesByRef) + m.Get("/pull", repo.GetCommitPullRequest) }, context.ReferencesGitRepo()) }, reqRepoReader(unit.TypeCode)) m.Group("/git", func() { diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go index 43b6400009..d01cf6b8bc 100644 --- a/routers/api/v1/repo/commits.go +++ b/routers/api/v1/repo/commits.go @@ -10,6 +10,7 @@ import ( "net/http" "strconv" + issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" @@ -323,3 +324,53 @@ func DownloadCommitDiffOrPatch(ctx *context.APIContext) { return } } + +// GetCommitPullRequest returns the pull request of the commit +func GetCommitPullRequest(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/commits/{sha}/pull repository repoGetCommitPullRequest + // --- + // summary: Get the pull request of the commit + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: sha + // in: path + // description: SHA of the commit to get + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/PullRequest" + // "404": + // "$ref": "#/responses/notFound" + + pr, err := issues_model.GetPullRequestByMergedCommit(ctx, ctx.Repo.Repository.ID, ctx.Params(":sha")) + if err != nil { + if issues_model.IsErrPullRequestNotExist(err) { + ctx.Error(http.StatusNotFound, "GetPullRequestByMergedCommit", err) + } else { + ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err) + } + return + } + + if err = pr.LoadBaseRepo(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err) + return + } + if err = pr.LoadHeadRepo(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) + return + } + ctx.JSON(http.StatusOK, convert.ToAPIPullRequest(ctx, pr, ctx.Doer)) +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 973759604b..1bceee0802 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4686,6 +4686,49 @@ } } }, + "/repos/{owner}/{repo}/commits/{sha}/pull": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Get the pull request of the commit", + "operationId": "repoGetCommitPullRequest", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "SHA of the commit to get", + "name": "sha", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/PullRequest" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/contents": { "get": { "produces": [ From 428008ac19185125b7cb1e3d379254d7b1932529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=9Eahin=20Akkaya?= <sahin@sahinakkaya.dev> Date: Sat, 24 Feb 2024 13:22:51 +0300 Subject: [PATCH 42/64] Implement recent commits graph (#29210) This is the implementation of Recent Commits page. This feature was mentioned on #18262. It adds another tab to Activity page called Recent Commits. Recent Commits tab shows number of commits since last year for the repository. (cherry picked from commit d3982bcd814bac93e3cbce1c7eb749b17e413fbd) --- options/locale/locale_en-US.ini | 4 +- routers/web/repo/recent_commits.go | 41 ++++++ routers/web/web.go | 4 + templates/repo/activity.tmpl | 1 + templates/repo/navbar.tmpl | 3 + templates/repo/recent_commits.tmpl | 9 ++ web_src/js/components/RepoRecentCommits.vue | 149 ++++++++++++++++++++ web_src/js/features/recent-commits.js | 21 +++ web_src/js/index.js | 2 + 9 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 routers/web/repo/recent_commits.go create mode 100644 templates/repo/recent_commits.tmpl create mode 100644 web_src/js/components/RepoRecentCommits.vue create mode 100644 web_src/js/features/recent-commits.js diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index d4a5ca4517..3e4872420f 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1961,8 +1961,9 @@ wiki.original_git_entry_tooltip = View original Git file instead of using friend activity = Activity activity.navbar.pulse = Pulse -activity.navbar.contributors = Contributors activity.navbar.code_frequency = Code Frequency +activity.navbar.contributors = Contributors +activity.navbar.recent_commits = Recent Commits activity.period.filter_label = Period: activity.period.daily = 1 day activity.period.halfweekly = 3 days @@ -2659,6 +2660,7 @@ component_loading_info = This might take a bit… component_failed_to_load = An unexpected error happened. code_frequency.what = code frequency contributors.what = contributions +recent_commits.what = recent commits [org] org_name_holder = Organization Name diff --git a/routers/web/repo/recent_commits.go b/routers/web/repo/recent_commits.go new file mode 100644 index 0000000000..3507cb8752 --- /dev/null +++ b/routers/web/repo/recent_commits.go @@ -0,0 +1,41 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "errors" + "net/http" + + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" + contributors_service "code.gitea.io/gitea/services/repository" +) + +const ( + tplRecentCommits base.TplName = "repo/activity" +) + +// RecentCommits renders the page to show recent commit frequency on repository +func RecentCommits(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("repo.activity.navbar.recent_commits") + + ctx.Data["PageIsActivity"] = true + ctx.Data["PageIsRecentCommits"] = true + ctx.PageData["repoLink"] = ctx.Repo.RepoLink + + ctx.HTML(http.StatusOK, tplRecentCommits) +} + +// RecentCommitsData returns JSON of recent commits data +func RecentCommitsData(ctx *context.Context) { + if contributorStats, err := contributors_service.GetContributorStats(ctx, ctx.Cache, ctx.Repo.Repository, ctx.Repo.CommitID); err != nil { + if errors.Is(err, contributors_service.ErrAwaitGeneration) { + ctx.Status(http.StatusAccepted) + return + } + ctx.ServerError("RecentCommitsData", err) + } else { + ctx.JSON(http.StatusOK, contributorStats["total"].Weeks) + } +} diff --git a/routers/web/web.go b/routers/web/web.go index cef563f615..6f4a7543e7 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1452,6 +1452,10 @@ func registerRoutes(m *web.Route) { m.Get("", repo.CodeFrequency) m.Get("/data", repo.CodeFrequencyData) }) + m.Group("/recent-commits", func() { + m.Get("", repo.RecentCommits) + m.Get("/data", repo.RecentCommitsData) + }) }, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(unit.TypePullRequests, unit.TypeIssues, unit.TypeReleases)) m.Group("/activity_author_data", func() { diff --git a/templates/repo/activity.tmpl b/templates/repo/activity.tmpl index 94f52b0e26..a19fb66261 100644 --- a/templates/repo/activity.tmpl +++ b/templates/repo/activity.tmpl @@ -9,6 +9,7 @@ {{if .PageIsPulse}}{{template "repo/pulse" .}}{{end}} {{if .PageIsContributors}}{{template "repo/contributors" .}}{{end}} {{if .PageIsCodeFrequency}}{{template "repo/code_frequency" .}}{{end}} + {{if .PageIsRecentCommits}}{{template "repo/recent_commits" .}}{{end}} </div> </div> </div> diff --git a/templates/repo/navbar.tmpl b/templates/repo/navbar.tmpl index aa5021e73a..b2471dc17e 100644 --- a/templates/repo/navbar.tmpl +++ b/templates/repo/navbar.tmpl @@ -8,4 +8,7 @@ <a class="{{if .PageIsCodeFrequency}}active{{end}} item" href="{{.RepoLink}}/activity/code-frequency"> {{ctx.Locale.Tr "repo.activity.navbar.code_frequency"}} </a> + <a class="{{if .PageIsRecentCommits}}active{{end}} item" href="{{.RepoLink}}/activity/recent-commits"> + {{ctx.Locale.Tr "repo.activity.navbar.recent_commits"}} + </a> </div> diff --git a/templates/repo/recent_commits.tmpl b/templates/repo/recent_commits.tmpl new file mode 100644 index 0000000000..5c241d635c --- /dev/null +++ b/templates/repo/recent_commits.tmpl @@ -0,0 +1,9 @@ +{{if .Permission.CanRead $.UnitTypeCode}} + <div id="repo-recent-commits-chart" + data-locale-loading-title="{{ctx.Locale.Tr "graphs.component_loading" (ctx.Locale.Tr "graphs.recent_commits.what")}}" + data-locale-loading-title-failed="{{ctx.Locale.Tr "graphs.component_loading_failed" (ctx.Locale.Tr "graphs.recent_commits.what")}}" + data-locale-loading-info="{{ctx.Locale.Tr "graphs.component_loading_info"}}" + data-locale-component-failed-to-load="{{ctx.Locale.Tr "graphs.component_failed_to_load"}}" + > + </div> +{{end}} diff --git a/web_src/js/components/RepoRecentCommits.vue b/web_src/js/components/RepoRecentCommits.vue new file mode 100644 index 0000000000..77697cd413 --- /dev/null +++ b/web_src/js/components/RepoRecentCommits.vue @@ -0,0 +1,149 @@ +<script> +import {SvgIcon} from '../svg.js'; +import { + Chart, + Tooltip, + BarElement, + LinearScale, + TimeScale, +} from 'chart.js'; +import {GET} from '../modules/fetch.js'; +import {Bar} from 'vue-chartjs'; +import { + startDaysBetween, + firstStartDateAfterDate, + fillEmptyStartDaysWithZeroes, +} from '../utils/time.js'; +import {chartJsColors} from '../utils/color.js'; +import {sleep} from '../utils.js'; +import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; + +const {pageData} = window.config; + +Chart.defaults.color = chartJsColors.text; +Chart.defaults.borderColor = chartJsColors.border; + +Chart.register( + TimeScale, + LinearScale, + BarElement, + Tooltip, +); + +export default { + components: {Bar, SvgIcon}, + props: { + locale: { + type: Object, + required: true + }, + }, + data: () => ({ + isLoading: false, + errorText: '', + repoLink: pageData.repoLink || [], + data: [], + }), + mounted() { + this.fetchGraphData(); + }, + methods: { + async fetchGraphData() { + this.isLoading = true; + try { + let response; + do { + response = await GET(`${this.repoLink}/activity/recent-commits/data`); + if (response.status === 202) { + await sleep(1000); // wait for 1 second before retrying + } + } while (response.status === 202); + if (response.ok) { + const data = await response.json(); + const start = Object.values(data)[0].week; + const end = firstStartDateAfterDate(new Date()); + const startDays = startDaysBetween(new Date(start), new Date(end)); + this.data = fillEmptyStartDaysWithZeroes(startDays, data).slice(-52); + this.errorText = ''; + } else { + this.errorText = response.statusText; + } + } catch (err) { + this.errorText = err.message; + } finally { + this.isLoading = false; + } + }, + + toGraphData(data) { + return { + datasets: [ + { + data: data.map((i) => ({x: i.week, y: i.commits})), + label: 'Commits', + backgroundColor: chartJsColors['commits'], + borderWidth: 0, + tension: 0.3, + }, + ], + }; + }, + + getOptions() { + return { + responsive: true, + maintainAspectRatio: false, + animation: true, + scales: { + x: { + type: 'time', + grid: { + display: false, + }, + time: { + minUnit: 'week', + }, + ticks: { + maxRotation: 0, + maxTicksLimit: 52 + }, + }, + y: { + ticks: { + maxTicksLimit: 6 + }, + }, + }, + }; + }, + }, +}; +</script> +<template> + <div> + <div class="ui header gt-df gt-ac gt-sb"> + {{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: "Number of commits in the past year" }} + </div> + <div class="gt-df ui segment main-graph"> + <div v-if="isLoading || errorText !== ''" class="gt-tc gt-m-auto"> + <div v-if="isLoading"> + <SvgIcon name="octicon-sync" class="gt-mr-3 job-status-rotate"/> + {{ locale.loadingInfo }} + </div> + <div v-else class="text red"> + <SvgIcon name="octicon-x-circle-fill"/> + {{ errorText }} + </div> + </div> + <Bar + v-memo="data" v-if="data.length !== 0" + :data="toGraphData(data)" :options="getOptions()" + /> + </div> + </div> +</template> +<style scoped> +.main-graph { + height: 250px; +} +</style> diff --git a/web_src/js/features/recent-commits.js b/web_src/js/features/recent-commits.js new file mode 100644 index 0000000000..ded10d39be --- /dev/null +++ b/web_src/js/features/recent-commits.js @@ -0,0 +1,21 @@ +import {createApp} from 'vue'; + +export async function initRepoRecentCommits() { + const el = document.getElementById('repo-recent-commits-chart'); + if (!el) return; + + const {default: RepoRecentCommits} = await import(/* webpackChunkName: "recent-commits-graph" */'../components/RepoRecentCommits.vue'); + try { + const View = createApp(RepoRecentCommits, { + locale: { + loadingTitle: el.getAttribute('data-locale-loading-title'), + loadingTitleFailed: el.getAttribute('data-locale-loading-title-failed'), + loadingInfo: el.getAttribute('data-locale-loading-info'), + } + }); + View.mount(el); + } catch (err) { + console.error('RepoRecentCommits failed to load', err); + el.textContent = el.getAttribute('data-locale-component-failed-to-load'); + } +} diff --git a/web_src/js/index.js b/web_src/js/index.js index d9cfff4084..b7f3ba99a0 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -85,6 +85,7 @@ import {initRepoIssueList} from './features/repo-issue-list.js'; import {initCommonIssueListQuickGoto} from './features/common-issue-list.js'; import {initRepoContributors} from './features/contributors.js'; import {initRepoCodeFrequency} from './features/code-frequency.js'; +import {initRepoRecentCommits} from './features/recent-commits.js'; import {initRepoDiffCommitBranchesAndTags} from './features/repo-diff-commit.js'; import {initDirAuto} from './modules/dirauto.js'; @@ -176,6 +177,7 @@ onDomReady(() => { initRepositoryActionView(); initRepoContributors(); initRepoCodeFrequency(); + initRepoRecentCommits(); initCommitStatuses(); initCaptcha(); From 64ef7d365872b3a6160488c9fb5f652ec3e6413c Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Sat, 24 Feb 2024 12:45:59 +0100 Subject: [PATCH 43/64] Do not double close reader (#29354) Fixes #29346 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> (cherry picked from commit 553d46e6f6a144905266d58315a2b0ff2e976380) --- modules/git/blob_nogogit.go | 12 +++++++++++- routers/web/repo/editor.go | 3 --- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/modules/git/blob_nogogit.go b/modules/git/blob_nogogit.go index 9e1c2a0376..945a6bc432 100644 --- a/modules/git/blob_nogogit.go +++ b/modules/git/blob_nogogit.go @@ -102,7 +102,17 @@ func (b *blobReader) Read(p []byte) (n int, err error) { // Close implements io.Closer func (b *blobReader) Close() error { + if b.rd == nil { + return nil + } + defer b.cancel() - return DiscardFull(b.rd, b.n+1) + if err := DiscardFull(b.rd, b.n+1); err != nil { + return err + } + + b.rd = nil + + return nil } diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 7a0501604e..93decc085b 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -183,9 +183,6 @@ func editFile(ctx *context.Context, isNewFile bool) { } d, _ := io.ReadAll(dataRc) - if err := dataRc.Close(); err != nil { - log.Error("Error whilst closing blob data: %v", err) - } buf = append(buf, d...) if content, err := charset.ToUTF8(buf, charset.ConvertOpts{KeepBOM: true}); err != nil { From e91b9486133bf38acc75bf16819c4bce7d2789b0 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sat, 24 Feb 2024 14:03:53 +0200 Subject: [PATCH 44/64] Remove jQuery from the issue reference context popup (#29367) - Removed all jQuery calls - Tested the context popup functionality and it works as before # Demo without jQuery  --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: Giteabot <teabot@gitea.io> (cherry picked from commit 267dbb4e938cc42dc09a4a893cca631b2f755557) --- web_src/js/components/ContextPopup.vue | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index d9e6da316c..3a1b828cca 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -1,8 +1,8 @@ <script> -import $ from 'jquery'; import {SvgIcon} from '../svg.js'; import {useLightTextOnBackground} from '../utils/color.js'; import tinycolor from 'tinycolor2'; +import {GET} from '../modules/fetch.js'; const {appSubUrl, i18n} = window.config; @@ -80,20 +80,23 @@ export default { }); }, methods: { - load(data) { + async load(data) { this.loading = true; this.i18nErrorMessage = null; - $.get(`${appSubUrl}/${data.owner}/${data.repo}/issues/${data.index}/info`).done((issue) => { - this.issue = issue; - }).fail((jqXHR) => { - if (jqXHR.responseJSON && jqXHR.responseJSON.message) { - this.i18nErrorMessage = jqXHR.responseJSON.message; - } else { - this.i18nErrorMessage = i18n.network_error; + + try { + const response = await GET(`${appSubUrl}/${data.owner}/${data.repo}/issues/${data.index}/info`); + const respJson = await response.json(); + if (!response.ok) { + this.i18nErrorMessage = respJson.message ?? i18n.network_error; + return; } - }).always(() => { + this.issue = respJson; + } catch { + this.i18nErrorMessage = i18n.network_error; + } finally { this.loading = false; - }); + } } } }; From 77c56e29ded5665bdc09d0a568159aa7127b44b1 Mon Sep 17 00:00:00 2001 From: Zettat123 <zettat123@gmail.com> Date: Sat, 24 Feb 2024 20:38:43 +0800 Subject: [PATCH 45/64] Allow non-admin users to delete review requests (#29057) Fix #14459 The following users can add/remove review requests of a PR - the poster of the PR - the owner or collaborators of the repository - members with read permission on the pull requests unit (cherry picked from commit c42083a33950be6ee9f822c6d0de3c3a79d1f51b) Conflicts: models/repo/repo_list_test.go tests/integration/api_nodeinfo_test.go tests/integration/api_repo_test.go shared fixture counts --- models/fixtures/access.yml | 24 +++ models/fixtures/collaboration.yml | 6 + models/fixtures/email_address.yml | 24 +++ models/fixtures/issue.yml | 34 ++++ models/fixtures/org_user.yml | 18 +++ models/fixtures/pull_request.yml | 18 +++ models/fixtures/repo_unit.yml | 42 +++++ models/fixtures/repository.yml | 62 ++++++++ models/fixtures/team.yml | 22 +++ models/fixtures/team_repo.yml | 12 ++ models/fixtures/team_unit.yml | 36 +++++ models/fixtures/team_user.yml | 18 +++ models/fixtures/user.yml | 148 ++++++++++++++++++ models/issues/issue_test.go | 2 +- models/repo/repo_list_test.go | 6 +- models/user/user_test.go | 6 +- modules/indexer/issues/indexer_test.go | 14 +- routers/web/repo/issue.go | 21 +-- services/issue/assignee.go | 145 ++++++++++------- .../org41/repo61.git/HEAD | 1 + .../org41/repo61.git/config | 6 + .../org41/repo61.git/description | 1 + .../org41/repo61.git/info/exclude | 6 + .../user40/repo60.git/HEAD | 1 + .../user40/repo60.git/config | 6 + .../user40/repo60.git/description | 1 + .../user40/repo60.git/info/exclude | 6 + tests/integration/api_issue_test.go | 8 +- tests/integration/api_nodeinfo_test.go | 4 +- tests/integration/api_org_test.go | 4 +- tests/integration/api_pull_review_test.go | 43 +++++ tests/integration/api_repo_test.go | 6 +- tests/integration/issue_test.go | 8 +- 33 files changed, 656 insertions(+), 103 deletions(-) create mode 100644 tests/gitea-repositories-meta/org41/repo61.git/HEAD create mode 100644 tests/gitea-repositories-meta/org41/repo61.git/config create mode 100644 tests/gitea-repositories-meta/org41/repo61.git/description create mode 100644 tests/gitea-repositories-meta/org41/repo61.git/info/exclude create mode 100644 tests/gitea-repositories-meta/user40/repo60.git/HEAD create mode 100644 tests/gitea-repositories-meta/user40/repo60.git/config create mode 100644 tests/gitea-repositories-meta/user40/repo60.git/description create mode 100644 tests/gitea-repositories-meta/user40/repo60.git/info/exclude diff --git a/models/fixtures/access.yml b/models/fixtures/access.yml index 1bb6a9a8ac..641c453eb7 100644 --- a/models/fixtures/access.yml +++ b/models/fixtures/access.yml @@ -135,3 +135,27 @@ user_id: 31 repo_id: 28 mode: 4 + +- + id: 24 + user_id: 38 + repo_id: 60 + mode: 2 + +- + id: 25 + user_id: 38 + repo_id: 61 + mode: 1 + +- + id: 26 + user_id: 39 + repo_id: 61 + mode: 1 + +- + id: 27 + user_id: 40 + repo_id: 61 + mode: 4 diff --git a/models/fixtures/collaboration.yml b/models/fixtures/collaboration.yml index ef77d22b24..7603bdad32 100644 --- a/models/fixtures/collaboration.yml +++ b/models/fixtures/collaboration.yml @@ -45,3 +45,9 @@ repo_id: 22 user_id: 18 mode: 2 # write + +- + id: 9 + repo_id: 60 + user_id: 38 + mode: 2 # write diff --git a/models/fixtures/email_address.yml b/models/fixtures/email_address.yml index 67a99f43e2..b2a0432635 100644 --- a/models/fixtures/email_address.yml +++ b/models/fixtures/email_address.yml @@ -293,3 +293,27 @@ lower_email: user37@example.com is_activated: true is_primary: true + +- + id: 38 + uid: 38 + email: user38@example.com + lower_email: user38@example.com + is_activated: true + is_primary: true + +- + id: 39 + uid: 39 + email: user39@example.com + lower_email: user39@example.com + is_activated: true + is_primary: true + +- + id: 40 + uid: 40 + email: user40@example.com + lower_email: user40@example.com + is_activated: true + is_primary: true diff --git a/models/fixtures/issue.yml b/models/fixtures/issue.yml index 0c9b6ff406..ca5b1c6cd1 100644 --- a/models/fixtures/issue.yml +++ b/models/fixtures/issue.yml @@ -338,3 +338,37 @@ created_unix: 978307210 updated_unix: 978307210 is_locked: false + +- + id: 21 + repo_id: 60 + index: 1 + poster_id: 39 + original_author_id: 0 + name: repo60 pull1 + content: content for the 1st issue + milestone_id: 0 + priority: 0 + is_closed: false + is_pull: true + num_comments: 0 + created_unix: 1707270422 + updated_unix: 1707270422 + is_locked: false + +- + id: 22 + repo_id: 61 + index: 1 + poster_id: 40 + original_author_id: 0 + name: repo61 pull1 + content: content for the 1st issue + milestone_id: 0 + priority: 0 + is_closed: false + is_pull: true + num_comments: 0 + created_unix: 1707270422 + updated_unix: 1707270422 + is_locked: false diff --git a/models/fixtures/org_user.yml b/models/fixtures/org_user.yml index 8d58169a32..a7fbcb2c5a 100644 --- a/models/fixtures/org_user.yml +++ b/models/fixtures/org_user.yml @@ -99,3 +99,21 @@ uid: 5 org_id: 36 is_public: true + +- + id: 18 + uid: 38 + org_id: 41 + is_public: true + +- + id: 19 + uid: 39 + org_id: 41 + is_public: true + +- + id: 20 + uid: 40 + org_id: 41 + is_public: true diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index 54590fb830..3fc8ce630d 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -99,3 +99,21 @@ index: 1 head_repo_id: 23 base_repo_id: 23 + +- + id: 9 + type: 0 # gitea pull request + status: 2 # mergable + issue_id: 21 + index: 1 + head_repo_id: 60 + base_repo_id: 60 + +- + id: 10 + type: 0 # gitea pull request + status: 2 # mergable + issue_id: 22 + index: 1 + head_repo_id: 61 + base_repo_id: 61 diff --git a/models/fixtures/repo_unit.yml b/models/fixtures/repo_unit.yml index e3590b06f0..e4fc5d9d00 100644 --- a/models/fixtures/repo_unit.yml +++ b/models/fixtures/repo_unit.yml @@ -708,3 +708,45 @@ type: 1 config: "{}" created_unix: 946684810 + +- + id: 102 + repo_id: 60 + type: 1 + config: "{}" + created_unix: 946684810 + +- + id: 103 + repo_id: 60 + type: 2 + config: "{\"EnableTimetracker\":true,\"AllowOnlyContributorsToTrackTime\":true}" + created_unix: 946684810 + +- + id: 104 + repo_id: 60 + type: 3 + config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowRebaseMerge\":true,\"AllowSquash\":true}" + created_unix: 946684810 + +- + id: 105 + repo_id: 61 + type: 1 + config: "{}" + created_unix: 946684810 + +- + id: 106 + repo_id: 61 + type: 2 + config: "{\"EnableTimetracker\":true,\"AllowOnlyContributorsToTrackTime\":true}" + created_unix: 946684810 + +- + id: 107 + repo_id: 61 + type: 3 + config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowRebaseMerge\":true,\"AllowSquash\":true}" + created_unix: 946684810 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 8ef58b64ac..9d08c7bb0a 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -1720,3 +1720,65 @@ is_private: true status: 0 num_issues: 0 + +- + id: 60 + owner_id: 40 + owner_name: user40 + lower_name: repo60 + name: repo60 + default_branch: main + num_watches: 0 + num_stars: 0 + num_forks: 0 + num_issues: 0 + num_closed_issues: 0 + num_pulls: 1 + num_closed_pulls: 0 + num_milestones: 0 + num_closed_milestones: 0 + num_projects: 0 + num_closed_projects: 0 + is_private: false + is_empty: false + is_archived: false + is_mirror: false + status: 0 + is_fork: false + fork_id: 0 + is_template: false + template_id: 0 + size: 0 + is_fsck_enabled: true + close_issues_via_commit_in_any_branch: false + +- + id: 61 + owner_id: 41 + owner_name: org41 + lower_name: repo61 + name: repo61 + default_branch: main + num_watches: 0 + num_stars: 0 + num_forks: 0 + num_issues: 0 + num_closed_issues: 0 + num_pulls: 1 + num_closed_pulls: 0 + num_milestones: 0 + num_closed_milestones: 0 + num_projects: 0 + num_closed_projects: 0 + is_private: false + is_empty: false + is_archived: false + is_mirror: false + status: 0 + is_fork: false + fork_id: 0 + is_template: false + template_id: 0 + size: 0 + is_fsck_enabled: true + close_issues_via_commit_in_any_branch: false diff --git a/models/fixtures/team.yml b/models/fixtures/team.yml index 295e51e39c..149fe90888 100644 --- a/models/fixtures/team.yml +++ b/models/fixtures/team.yml @@ -217,3 +217,25 @@ num_members: 1 includes_all_repositories: false can_create_org_repo: true + +- + id: 21 + org_id: 41 + lower_name: owners + name: Owners + authorize: 4 # owner + num_repos: 1 + num_members: 1 + includes_all_repositories: true + can_create_org_repo: true + +- + id: 22 + org_id: 41 + lower_name: team1 + name: Team1 + authorize: 1 # read + num_repos: 1 + num_members: 2 + includes_all_repositories: false + can_create_org_repo: false diff --git a/models/fixtures/team_repo.yml b/models/fixtures/team_repo.yml index 8497720892..a29078107e 100644 --- a/models/fixtures/team_repo.yml +++ b/models/fixtures/team_repo.yml @@ -63,3 +63,15 @@ org_id: 17 team_id: 9 repo_id: 24 + +- + id: 12 + org_id: 41 + team_id: 21 + repo_id: 61 + +- + id: 13 + org_id: 41 + team_id: 22 + repo_id: 61 diff --git a/models/fixtures/team_unit.yml b/models/fixtures/team_unit.yml index c5531aa57a..de0e8d738b 100644 --- a/models/fixtures/team_unit.yml +++ b/models/fixtures/team_unit.yml @@ -286,3 +286,39 @@ team_id: 2 type: 8 access_mode: 2 + +- + id: 49 + team_id: 21 + type: 1 + access_mode: 4 + +- + id: 50 + team_id: 21 + type: 2 + access_mode: 4 + +- + id: 51 + team_id: 21 + type: 3 + access_mode: 4 + +- + id: 52 + team_id: 22 + type: 1 + access_mode: 1 + +- + id: 53 + team_id: 22 + type: 2 + access_mode: 1 + +- + id: 54 + team_id: 22 + type: 3 + access_mode: 1 diff --git a/models/fixtures/team_user.yml b/models/fixtures/team_user.yml index 9142fe609a..02d57ae644 100644 --- a/models/fixtures/team_user.yml +++ b/models/fixtures/team_user.yml @@ -129,3 +129,21 @@ org_id: 17 team_id: 9 uid: 15 + +- + id: 23 + org_id: 41 + team_id: 21 + uid: 40 + +- + id: 24 + org_id: 41 + team_id: 22 + uid: 38 + +- + id: 25 + org_id: 41 + team_id: 22 + uid: 39 diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml index 16aa2a3ff1..07df059dc5 100644 --- a/models/fixtures/user.yml +++ b/models/fixtures/user.yml @@ -1369,3 +1369,151 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false + +- + id: 38 + lower_name: user38 + name: user38 + full_name: User38 + email: user38@example.com + keep_email_private: false + email_notifications_preference: enabled + passwd: ZogKvWdyEx:password + passwd_hash_algo: dummy + must_change_password: false + login_source: 0 + login_name: user38 + type: 0 + salt: ZogKvWdyEx + max_repo_creation: -1 + is_active: true + is_admin: false + is_restricted: false + allow_git_hook: false + allow_import_local: false + allow_create_organization: true + prohibit_login: false + avatar: avatar38 + avatar_email: user38@example.com + use_custom_avatar: false + num_followers: 0 + num_following: 0 + num_stars: 0 + num_repos: 0 + num_teams: 0 + num_members: 0 + visibility: 0 + repo_admin_change_team_access: false + theme: "" + keep_activity_private: false + +- + id: 39 + lower_name: user39 + name: user39 + full_name: User39 + email: user39@example.com + keep_email_private: false + email_notifications_preference: enabled + passwd: ZogKvWdyEx:password + passwd_hash_algo: dummy + must_change_password: false + login_source: 0 + login_name: user39 + type: 0 + salt: ZogKvWdyEx + max_repo_creation: -1 + is_active: true + is_admin: false + is_restricted: false + allow_git_hook: false + allow_import_local: false + allow_create_organization: true + prohibit_login: false + avatar: avatar39 + avatar_email: user39@example.com + use_custom_avatar: false + num_followers: 0 + num_following: 0 + num_stars: 0 + num_repos: 0 + num_teams: 0 + num_members: 0 + visibility: 0 + repo_admin_change_team_access: false + theme: "" + keep_activity_private: false + +- + id: 40 + lower_name: user40 + name: user40 + full_name: User40 + email: user40@example.com + keep_email_private: false + email_notifications_preference: onmention + passwd: ZogKvWdyEx:password + passwd_hash_algo: dummy + must_change_password: false + login_source: 0 + login_name: user40 + type: 0 + salt: ZogKvWdyEx + max_repo_creation: -1 + is_active: true + is_admin: false + is_restricted: false + allow_git_hook: false + allow_import_local: false + allow_create_organization: true + prohibit_login: false + avatar: avatar40 + avatar_email: user40@example.com + use_custom_avatar: false + num_followers: 0 + num_following: 0 + num_stars: 0 + num_repos: 1 + num_teams: 0 + num_members: 0 + visibility: 0 + repo_admin_change_team_access: false + theme: "" + keep_activity_private: false + +- + id: 41 + lower_name: org41 + name: org41 + full_name: Org41 + email: org41@example.com + keep_email_private: false + email_notifications_preference: onmention + passwd: ZogKvWdyEx:password + passwd_hash_algo: dummy + must_change_password: false + login_source: 0 + login_name: org41 + type: 1 + salt: ZogKvWdyEx + max_repo_creation: -1 + is_active: false + is_admin: false + is_restricted: false + allow_git_hook: false + allow_import_local: false + allow_create_organization: true + prohibit_login: false + avatar: avatar41 + avatar_email: org41@example.com + use_custom_avatar: false + num_followers: 0 + num_following: 0 + num_stars: 0 + num_repos: 1 + num_teams: 2 + num_members: 3 + visibility: 0 + repo_admin_change_team_access: false + theme: "" + keep_activity_private: false diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index 2b20ede173..044666a3f0 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -381,7 +381,7 @@ func TestCountIssues(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) count, err := issues_model.CountIssues(db.DefaultContext, &issues_model.IssuesOptions{}) assert.NoError(t, err) - assert.EqualValues(t, 20, count) + assert.EqualValues(t, 22, count) } func TestIssueLoadAttributes(t *testing.T) { diff --git a/models/repo/repo_list_test.go b/models/repo/repo_list_test.go index a8b958109c..8006289460 100644 --- a/models/repo/repo_list_test.go +++ b/models/repo/repo_list_test.go @@ -138,12 +138,12 @@ func getTestCases() []struct { { name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative", opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse}, - count: 32, + count: 34, }, { name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative", opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse}, - count: 37, + count: 39, }, { name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName", @@ -158,7 +158,7 @@ func getTestCases() []struct { { name: "AllPublic/PublicRepositoriesOfOrganization", opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse}, - count: 32, + count: 34, }, { name: "AllTemplates", diff --git a/models/user/user_test.go b/models/user/user_test.go index 411d1ab830..87a842a4d3 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -89,7 +89,7 @@ func TestSearchUsers(t *testing.T) { []int64{19, 25}) testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 4, PageSize: 2}}, - []int64{26}) + []int64{26, 41}) testOrgSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 5, PageSize: 2}}, []int64{}) @@ -101,13 +101,13 @@ func TestSearchUsers(t *testing.T) { } testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}}, - []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37}) + []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40}) testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse}, []int64{9}) testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, - []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37}) + []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40}) testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, []int64{1, 10, 11, 12, 13, 14, 15, 16, 18}) diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index da4fc9b878..3b96686d98 100644 --- a/modules/indexer/issues/indexer_test.go +++ b/modules/indexer/issues/indexer_test.go @@ -218,7 +218,7 @@ func searchIssueIsPull(t *testing.T) { SearchOptions{ IsPull: util.OptionalBoolTrue, }, - []int64{12, 11, 20, 19, 9, 8, 3, 2}, + []int64{22, 21, 12, 11, 20, 19, 9, 8, 3, 2}, }, } for _, test := range tests { @@ -239,7 +239,7 @@ func searchIssueIsClosed(t *testing.T) { SearchOptions{ IsClosed: util.OptionalBoolFalse, }, - []int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1}, + []int64{22, 21, 17, 16, 15, 14, 13, 12, 11, 20, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1}, }, { SearchOptions{ @@ -305,7 +305,7 @@ func searchIssueByLabelID(t *testing.T) { SearchOptions{ ExcludedLabelIDs: []int64{1}, }, - []int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3}, + []int64{22, 21, 17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3}, }, } for _, test := range tests { @@ -329,7 +329,7 @@ func searchIssueByTime(t *testing.T) { SearchOptions{ UpdatedAfterUnix: int64Pointer(0), }, - []int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1}, + []int64{22, 21, 17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1}, }, } for _, test := range tests { @@ -350,7 +350,7 @@ func searchIssueWithOrder(t *testing.T) { SearchOptions{ SortBy: internal.SortByCreatedAsc, }, - []int64{1, 2, 3, 8, 9, 4, 7, 10, 18, 19, 5, 6, 20, 11, 12, 13, 14, 15, 16, 17}, + []int64{1, 2, 3, 8, 9, 4, 7, 10, 18, 19, 5, 6, 20, 11, 12, 13, 14, 15, 16, 17, 21, 22}, }, } for _, test := range tests { @@ -410,8 +410,8 @@ func searchIssueWithPaginator(t *testing.T) { PageSize: 5, }, }, - []int64{17, 16, 15, 14, 13}, - 20, + []int64{22, 21, 17, 16, 15}, + 22, }, } for _, test := range tests { diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index f4e9203c9f..1a598029c1 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -717,16 +717,12 @@ func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, is tmp.ItemID = -review.ReviewerTeamID } - if ctx.Repo.IsAdmin() { - // Admin can dismiss or re-request any review requests + if canChooseReviewer { + // Users who can choose reviewers can also remove review requests tmp.CanChange = true } else if ctx.Doer != nil && ctx.Doer.ID == review.ReviewerID && review.Type == issues_model.ReviewTypeRequest { // A user can refuse review requests tmp.CanChange = true - } else if (canChooseReviewer || (ctx.Doer != nil && ctx.Doer.ID == issue.PosterID)) && review.Type != issues_model.ReviewTypeRequest && - ctx.Doer.ID != review.ReviewerID { - // The poster of the PR, a manager, or official reviewers can re-request review from other reviewers - tmp.CanChange = true } pullReviews = append(pullReviews, tmp) @@ -1534,18 +1530,9 @@ func ViewIssue(ctx *context.Context) { } if issue.IsPull { - canChooseReviewer := ctx.Repo.CanWrite(unit.TypePullRequests) + canChooseReviewer := false if ctx.Doer != nil && ctx.IsSigned { - if !canChooseReviewer { - canChooseReviewer = ctx.Doer.ID == issue.PosterID - } - if !canChooseReviewer { - canChooseReviewer, err = issues_model.IsOfficialReviewer(ctx, issue, ctx.Doer) - if err != nil { - ctx.ServerError("IsOfficialReviewer", err) - return - } - } + canChooseReviewer = issue_service.CanDoerChangeReviewRequests(ctx, ctx.Doer, repo, issue) } RetrieveRepoReviewers(ctx, repo, issue, canChooseReviewer) diff --git a/services/issue/assignee.go b/services/issue/assignee.go index 27fc695533..b5f472ba53 100644 --- a/services/issue/assignee.go +++ b/services/issue/assignee.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -113,10 +114,10 @@ func IsValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, return err } - var pemResult bool + canDoerChangeReviewRequests := CanDoerChangeReviewRequests(ctx, doer, issue.Repo, issue) + if isAdd { - pemResult = permReviewer.CanAccessAny(perm.AccessModeRead, unit.TypePullRequests) - if !pemResult { + if !permReviewer.CanAccessAny(perm.AccessModeRead, unit.TypePullRequests) { return issues_model.ErrNotValidReviewRequest{ Reason: "Reviewer can't read", UserID: doer.ID, @@ -124,28 +125,6 @@ func IsValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, } } - if doer.ID == issue.PosterID && issue.OriginalAuthorID == 0 && lastreview != nil && lastreview.Type != issues_model.ReviewTypeRequest { - return nil - } - - pemResult = doer.ID == issue.PosterID - if !pemResult { - pemResult = permDoer.CanAccessAny(perm.AccessModeWrite, unit.TypePullRequests) - } - if !pemResult { - pemResult, err = issues_model.IsOfficialReviewer(ctx, issue, doer) - if err != nil { - return err - } - if !pemResult { - return issues_model.ErrNotValidReviewRequest{ - Reason: "Doer can't choose reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } - } - } - if reviewer.ID == issue.PosterID && issue.OriginalAuthorID == 0 { return issues_model.ErrNotValidReviewRequest{ Reason: "poster of pr can't be reviewer", @@ -153,22 +132,35 @@ func IsValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, RepoID: issue.Repo.ID, } } - } else { - if lastreview != nil && lastreview.Type == issues_model.ReviewTypeRequest && lastreview.ReviewerID == doer.ID { + + if canDoerChangeReviewRequests { return nil } - pemResult = permDoer.IsAdmin() - if !pemResult { - return issues_model.ErrNotValidReviewRequest{ - Reason: "Doer is not admin", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } + if doer.ID == issue.PosterID && issue.OriginalAuthorID == 0 && lastreview != nil && lastreview.Type != issues_model.ReviewTypeRequest { + return nil + } + + return issues_model.ErrNotValidReviewRequest{ + Reason: "Doer can't choose reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, } } - return nil + if canDoerChangeReviewRequests { + return nil + } + + if lastreview != nil && lastreview.Type == issues_model.ReviewTypeRequest && lastreview.ReviewerID == doer.ID { + return nil + } + + return issues_model.ErrNotValidReviewRequest{ + Reason: "Doer can't remove reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } } // IsValidTeamReviewRequest Check permission for ReviewRequest Team @@ -181,11 +173,7 @@ func IsValidTeamReviewRequest(ctx context.Context, reviewer *organization.Team, } } - permission, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) - if err != nil { - log.Error("Unable to GetUserRepoPermission for %-v in %-v#%d", doer, issue.Repo, issue.Index) - return err - } + canDoerChangeReviewRequests := CanDoerChangeReviewRequests(ctx, doer, issue.Repo, issue) if isAdd { if issue.Repo.IsPrivate { @@ -200,30 +188,26 @@ func IsValidTeamReviewRequest(ctx context.Context, reviewer *organization.Team, } } - doerCanWrite := permission.CanAccessAny(perm.AccessModeWrite, unit.TypePullRequests) - if !doerCanWrite && doer.ID != issue.PosterID { - official, err := issues_model.IsOfficialReviewer(ctx, issue, doer) - if err != nil { - log.Error("Unable to Check if IsOfficialReviewer for %-v in %-v#%d", doer, issue.Repo, issue.Index) - return err - } - if !official { - return issues_model.ErrNotValidReviewRequest{ - Reason: "Doer can't choose reviewer", - UserID: doer.ID, - RepoID: issue.Repo.ID, - } - } + if canDoerChangeReviewRequests { + return nil } - } else if !permission.IsAdmin() { + return issues_model.ErrNotValidReviewRequest{ - Reason: "Only admin users can remove team requests. Doer is not admin", + Reason: "Doer can't choose reviewer", UserID: doer.ID, RepoID: issue.Repo.ID, } } - return nil + if canDoerChangeReviewRequests { + return nil + } + + return issues_model.ErrNotValidReviewRequest{ + Reason: "Doer can't remove reviewer", + UserID: doer.ID, + RepoID: issue.Repo.ID, + } } // TeamReviewRequest add or remove a review request from a team for this PR, and make comment for it. @@ -264,3 +248,50 @@ func TeamReviewRequest(ctx context.Context, issue *issues_model.Issue, doer *use return comment, err } + +// CanDoerChangeReviewRequests returns if the doer can add/remove review requests of a PR +func CanDoerChangeReviewRequests(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue) bool { + // The poster of the PR can change the reviewers + if doer.ID == issue.PosterID { + return true + } + + // The owner of the repo can change the reviewers + if doer.ID == repo.OwnerID { + return true + } + + // Collaborators of the repo can change the reviewers + isCollaborator, err := repo_model.IsCollaborator(ctx, repo.ID, doer.ID) + if err != nil { + log.Error("IsCollaborator: %v", err) + return false + } + if isCollaborator { + return true + } + + // If the repo's owner is an organization, members of teams with read permission on pull requests can change reviewers + if repo.Owner.IsOrganization() { + teams, err := organization.GetTeamsWithAccessToRepo(ctx, repo.OwnerID, repo.ID, perm.AccessModeRead) + if err != nil { + log.Error("GetTeamsWithAccessToRepo: %v", err) + return false + } + for _, team := range teams { + if !team.UnitEnabled(ctx, unit.TypePullRequests) { + continue + } + isMember, err := organization.IsTeamMember(ctx, repo.OwnerID, team.ID, doer.ID) + if err != nil { + log.Error("IsTeamMember: %v", err) + continue + } + if isMember { + return true + } + } + } + + return false +} diff --git a/tests/gitea-repositories-meta/org41/repo61.git/HEAD b/tests/gitea-repositories-meta/org41/repo61.git/HEAD new file mode 100644 index 0000000000..cb089cd89a --- /dev/null +++ b/tests/gitea-repositories-meta/org41/repo61.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/gitea-repositories-meta/org41/repo61.git/config b/tests/gitea-repositories-meta/org41/repo61.git/config new file mode 100644 index 0000000000..64280b806c --- /dev/null +++ b/tests/gitea-repositories-meta/org41/repo61.git/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = true + symlinks = false + ignorecase = true diff --git a/tests/gitea-repositories-meta/org41/repo61.git/description b/tests/gitea-repositories-meta/org41/repo61.git/description new file mode 100644 index 0000000000..498b267a8c --- /dev/null +++ b/tests/gitea-repositories-meta/org41/repo61.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests/gitea-repositories-meta/org41/repo61.git/info/exclude b/tests/gitea-repositories-meta/org41/repo61.git/info/exclude new file mode 100644 index 0000000000..a5196d1be8 --- /dev/null +++ b/tests/gitea-repositories-meta/org41/repo61.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests/gitea-repositories-meta/user40/repo60.git/HEAD b/tests/gitea-repositories-meta/user40/repo60.git/HEAD new file mode 100644 index 0000000000..cb089cd89a --- /dev/null +++ b/tests/gitea-repositories-meta/user40/repo60.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/gitea-repositories-meta/user40/repo60.git/config b/tests/gitea-repositories-meta/user40/repo60.git/config new file mode 100644 index 0000000000..64280b806c --- /dev/null +++ b/tests/gitea-repositories-meta/user40/repo60.git/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = true + symlinks = false + ignorecase = true diff --git a/tests/gitea-repositories-meta/user40/repo60.git/description b/tests/gitea-repositories-meta/user40/repo60.git/description new file mode 100644 index 0000000000..498b267a8c --- /dev/null +++ b/tests/gitea-repositories-meta/user40/repo60.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests/gitea-repositories-meta/user40/repo60.git/info/exclude b/tests/gitea-repositories-meta/user40/repo60.git/info/exclude new file mode 100644 index 0000000000..a5196d1be8 --- /dev/null +++ b/tests/gitea-repositories-meta/user40/repo60.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests/integration/api_issue_test.go b/tests/integration/api_issue_test.go index f7035f8fd3..849535ff8e 100644 --- a/tests/integration/api_issue_test.go +++ b/tests/integration/api_issue_test.go @@ -368,7 +368,7 @@ func TestAPISearchIssues(t *testing.T) { defer tests.PrepareTestEnv(t)() // as this API was used in the frontend, it uses UI page size - expectedIssueCount := 18 // from the fixtures + expectedIssueCount := 20 // from the fixtures if expectedIssueCount > setting.UI.IssuePagingNum { expectedIssueCount = setting.UI.IssuePagingNum } @@ -408,7 +408,7 @@ func TestAPISearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.EqualValues(t, "20", resp.Header().Get("X-Total-Count")) + assert.EqualValues(t, "22", resp.Header().Get("X-Total-Count")) assert.Len(t, apiIssues, 20) query.Add("limit", "10") @@ -416,7 +416,7 @@ func TestAPISearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.EqualValues(t, "20", resp.Header().Get("X-Total-Count")) + assert.EqualValues(t, "22", resp.Header().Get("X-Total-Count")) assert.Len(t, apiIssues, 10) query = url.Values{"assigned": {"true"}, "state": {"all"}} @@ -466,7 +466,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) { defer tests.PrepareTestEnv(t)() // as this API was used in the frontend, it uses UI page size - expectedIssueCount := 18 // from the fixtures + expectedIssueCount := 20 // from the fixtures if expectedIssueCount > setting.UI.IssuePagingNum { expectedIssueCount = setting.UI.IssuePagingNum } diff --git a/tests/integration/api_nodeinfo_test.go b/tests/integration/api_nodeinfo_test.go index fd641d5dbd..598d38fb64 100644 --- a/tests/integration/api_nodeinfo_test.go +++ b/tests/integration/api_nodeinfo_test.go @@ -32,8 +32,8 @@ func TestNodeinfo(t *testing.T) { DecodeJSON(t, resp, &nodeinfo) assert.True(t, nodeinfo.OpenRegistrations) assert.Equal(t, "forgejo", nodeinfo.Software.Name) - assert.Equal(t, 26, nodeinfo.Usage.Users.Total) - assert.Equal(t, 20, nodeinfo.Usage.LocalPosts) + assert.Equal(t, 29, nodeinfo.Usage.Users.Total) + assert.Equal(t, 22, nodeinfo.Usage.LocalPosts) assert.Equal(t, 3, nodeinfo.Usage.LocalComments) }) } diff --git a/tests/integration/api_org_test.go b/tests/integration/api_org_test.go index 1cd82fe4e0..70d3a446f7 100644 --- a/tests/integration/api_org_test.go +++ b/tests/integration/api_org_test.go @@ -177,7 +177,7 @@ func TestAPIGetAll(t *testing.T) { var apiOrgList []*api.Organization DecodeJSON(t, resp, &apiOrgList) - assert.Len(t, apiOrgList, 11) + assert.Len(t, apiOrgList, 12) assert.Equal(t, "Limited Org 36", apiOrgList[1].FullName) assert.Equal(t, "limited", apiOrgList[1].Visibility) @@ -186,7 +186,7 @@ func TestAPIGetAll(t *testing.T) { resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiOrgList) - assert.Len(t, apiOrgList, 7) + assert.Len(t, apiOrgList, 8) assert.Equal(t, "org 17", apiOrgList[0].FullName) assert.Equal(t, "public", apiOrgList[0].Visibility) } diff --git a/tests/integration/api_pull_review_test.go b/tests/integration/api_pull_review_test.go index cb02baa083..bc536b4f7a 100644 --- a/tests/integration/api_pull_review_test.go +++ b/tests/integration/api_pull_review_test.go @@ -401,6 +401,49 @@ func TestAPIPullReviewRequest(t *testing.T) { }).AddTokenAuth(token) MakeRequest(t, req, http.StatusNoContent) + // a collaborator can add/remove a review request + pullIssue21 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 21}) + assert.NoError(t, pullIssue21.LoadAttributes(db.DefaultContext)) + pull21Repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue21.RepoID}) // repo60 + user38Session := loginUser(t, "user38") + user38Token := getTokenForLoggedInUser(t, user38Session, auth_model.AccessTokenScopeWriteRepository) + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers", pull21Repo.OwnerName, pull21Repo.Name, pullIssue21.Index), &api.PullReviewRequestOptions{ + Reviewers: []string{"user4@example.com"}, + }).AddTokenAuth(user38Token) + MakeRequest(t, req, http.StatusCreated) + + req = NewRequestWithJSON(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers", pull21Repo.OwnerName, pull21Repo.Name, pullIssue21.Index), &api.PullReviewRequestOptions{ + Reviewers: []string{"user4@example.com"}, + }).AddTokenAuth(user38Token) + MakeRequest(t, req, http.StatusNoContent) + + // the poster of the PR can add/remove a review request + user39Session := loginUser(t, "user39") + user39Token := getTokenForLoggedInUser(t, user39Session, auth_model.AccessTokenScopeWriteRepository) + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers", pull21Repo.OwnerName, pull21Repo.Name, pullIssue21.Index), &api.PullReviewRequestOptions{ + Reviewers: []string{"user8"}, + }).AddTokenAuth(user39Token) + MakeRequest(t, req, http.StatusCreated) + + req = NewRequestWithJSON(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers", pull21Repo.OwnerName, pull21Repo.Name, pullIssue21.Index), &api.PullReviewRequestOptions{ + Reviewers: []string{"user8"}, + }).AddTokenAuth(user39Token) + MakeRequest(t, req, http.StatusNoContent) + + // user with read permission on pull requests unit can add/remove a review request + pullIssue22 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 22}) + assert.NoError(t, pullIssue22.LoadAttributes(db.DefaultContext)) + pull22Repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue22.RepoID}) // repo61 + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers", pull22Repo.OwnerName, pull22Repo.Name, pullIssue22.Index), &api.PullReviewRequestOptions{ + Reviewers: []string{"user38"}, + }).AddTokenAuth(user39Token) // user39 is from a team with read permission on pull requests unit + MakeRequest(t, req, http.StatusCreated) + + req = NewRequestWithJSON(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers", pull22Repo.OwnerName, pull22Repo.Name, pullIssue22.Index), &api.PullReviewRequestOptions{ + Reviewers: []string{"user38"}, + }).AddTokenAuth(user39Token) // user39 is from a team with read permission on pull requests unit + MakeRequest(t, req, http.StatusNoContent) + // Test team review request pullIssue12 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 12}) assert.NoError(t, pullIssue12.LoadAttributes(db.DefaultContext)) diff --git a/tests/integration/api_repo_test.go b/tests/integration/api_repo_test.go index 04c1f29649..8ae2622976 100644 --- a/tests/integration/api_repo_test.go +++ b/tests/integration/api_repo_test.go @@ -93,9 +93,9 @@ func TestAPISearchRepo(t *testing.T) { }{ { name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50&private=false", expectedResults: expectedResults{ - nil: {count: 34}, - user: {count: 34}, - user2: {count: 34}, + nil: {count: 36}, + user: {count: 36}, + user2: {count: 36}, }, }, { diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index 7c00c4f958..6c1da4f4a5 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -458,7 +458,7 @@ func TestSearchIssues(t *testing.T) { session := loginUser(t, "user2") - expectedIssueCount := 18 // from the fixtures + expectedIssueCount := 20 // from the fixtures if expectedIssueCount > setting.UI.IssuePagingNum { expectedIssueCount = setting.UI.IssuePagingNum } @@ -495,7 +495,7 @@ func TestSearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()) resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.EqualValues(t, "20", resp.Header().Get("X-Total-Count")) + assert.EqualValues(t, "22", resp.Header().Get("X-Total-Count")) assert.Len(t, apiIssues, 20) query.Add("limit", "5") @@ -503,7 +503,7 @@ func TestSearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()) resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.EqualValues(t, "20", resp.Header().Get("X-Total-Count")) + assert.EqualValues(t, "22", resp.Header().Get("X-Total-Count")) assert.Len(t, apiIssues, 5) query = url.Values{"assigned": {"true"}, "state": {"all"}} @@ -552,7 +552,7 @@ func TestSearchIssues(t *testing.T) { func TestSearchIssuesWithLabels(t *testing.T) { defer tests.PrepareTestEnv(t)() - expectedIssueCount := 18 // from the fixtures + expectedIssueCount := 20 // from the fixtures if expectedIssueCount > setting.UI.IssuePagingNum { expectedIssueCount = setting.UI.IssuePagingNum } From 003a3589496125e6cb1759005219d0060cff8cb9 Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Sat, 24 Feb 2024 22:14:48 +0800 Subject: [PATCH 46/64] Users with `read` permission of pull requests can be assigned too (#27263) This PR will also keep the consistent between list assigned users and check assigned users. (cherry picked from commit 98ab9445d1020c515c3c789f0b27d952903a2978) --- models/perm/access/repo_permission.go | 4 ++-- models/repo/user_repo.go | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 0b66e62d7d..7e39627a75 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -356,7 +356,6 @@ func HasAccessUnit(ctx context.Context, user *user_model.User, repo *repo_model. // CanBeAssigned return true if user can be assigned to issue or pull requests in repo // Currently any write access (code, issues or pr's) is assignable, to match assignee list in user interface. -// FIXME: user could send PullRequest also could be assigned??? func CanBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model.Repository, _ bool) (bool, error) { if user.IsOrganization() { return false, fmt.Errorf("Organization can't be added as assignee [user_id: %d, repo_id: %d]", user.ID, repo.ID) @@ -365,7 +364,8 @@ func CanBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model. if err != nil { return false, err } - return perm.CanAccessAny(perm_model.AccessModeWrite, unit.TypeCode, unit.TypeIssues, unit.TypePullRequests), nil + return perm.CanAccessAny(perm_model.AccessModeWrite, unit.AllRepoUnitTypes...) || + perm.CanAccessAny(perm_model.AccessModeRead, unit.TypePullRequests), nil } // HasAccess returns true if user has access to repo diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go index 5d6e24e2a5..219f4ff25d 100644 --- a/models/repo/user_repo.go +++ b/models/repo/user_repo.go @@ -8,6 +8,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" api "code.gitea.io/gitea/modules/structs" @@ -78,7 +79,8 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us if err = e.Table("team_user"). Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id"). Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id"). - Where("`team_repo`.repo_id = ? AND `team_unit`.access_mode >= ?", repo.ID, perm.AccessModeWrite). + Where("`team_repo`.repo_id = ? AND (`team_unit`.access_mode >= ? OR (`team_unit`.access_mode = ? AND `team_unit`.`type` = ?))", + repo.ID, perm.AccessModeWrite, perm.AccessModeRead, unit.TypePullRequests). Distinct("`team_user`.uid"). Select("`team_user`.uid"). Find(&additionalUserIDs); err != nil { From 757567d3bd33efacdb224b2f3f22275e26321d8e Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sat, 24 Feb 2024 21:11:51 +0200 Subject: [PATCH 47/64] Remove jQuery from the Unicode escape button (#29369) - Switched to plain JavaScript - Tested the Unicode escape button functionality and it works as before # Demo using JavaScript without jQuery  --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> (cherry picked from commit c86d033a3ec0514efcd9524d03dce1b6551e487f) --- web_src/js/features/repo-unicode-escape.js | 46 ++++++++++------------ web_src/js/utils/dom.js | 4 ++ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/web_src/js/features/repo-unicode-escape.js b/web_src/js/features/repo-unicode-escape.js index 6a201ec4d1..d878532001 100644 --- a/web_src/js/features/repo-unicode-escape.js +++ b/web_src/js/features/repo-unicode-escape.js @@ -1,31 +1,27 @@ -import $ from 'jquery'; -import {hideElem, showElem} from '../utils/dom.js'; +import {hideElem, queryElemSiblings, showElem, toggleElem} from '../utils/dom.js'; export function initUnicodeEscapeButton() { - $(document).on('click', '.escape-button', (e) => { + document.addEventListener('click', (e) => { + const btn = e.target.closest('.escape-button, .unescape-button, .toggle-escape-button'); + if (!btn) return; + e.preventDefault(); - $(e.target).parents('.file-content, .non-diff-file-content').find('.file-code, .file-view').addClass('unicode-escaped'); - hideElem($(e.target)); - showElem($(e.target).siblings('.unescape-button')); - }); - $(document).on('click', '.unescape-button', (e) => { - e.preventDefault(); - $(e.target).parents('.file-content, .non-diff-file-content').find('.file-code, .file-view').removeClass('unicode-escaped'); - hideElem($(e.target)); - showElem($(e.target).siblings('.escape-button')); - }); - $(document).on('click', '.toggle-escape-button', (e) => { - e.preventDefault(); - const fileContent = $(e.target).parents('.file-content, .non-diff-file-content'); - const fileView = fileContent.find('.file-code, .file-view'); - if (fileView.hasClass('unicode-escaped')) { - fileView.removeClass('unicode-escaped'); - hideElem(fileContent.find('.unescape-button')); - showElem(fileContent.find('.escape-button')); - } else { - fileView.addClass('unicode-escaped'); - showElem(fileContent.find('.unescape-button')); - hideElem(fileContent.find('.escape-button')); + + const fileContent = btn.closest('.file-content, .non-diff-file-content'); + const fileView = fileContent?.querySelectorAll('.file-code, .file-view'); + if (btn.matches('.escape-button')) { + for (const el of fileView) el.classList.add('unicode-escaped'); + hideElem(btn); + showElem(queryElemSiblings(btn, '.unescape-button')); + } else if (btn.matches('.unescape-button')) { + for (const el of fileView) el.classList.remove('unicode-escaped'); + hideElem(btn); + showElem(queryElemSiblings(btn, '.escape-button')); + } else if (btn.matches('.toggle-escape-button')) { + const isEscaped = fileView[0]?.classList.contains('unicode-escaped'); + for (const el of fileView) el.classList.toggle('unicode-escaped', !isEscaped); + toggleElem(fileContent.querySelectorAll('.unescape-button'), !isEscaped); + toggleElem(fileContent.querySelectorAll('.escape-button'), isEscaped); } }); } diff --git a/web_src/js/utils/dom.js b/web_src/js/utils/dom.js index 1f6066acab..f9f5737554 100644 --- a/web_src/js/utils/dom.js +++ b/web_src/js/utils/dom.js @@ -51,6 +51,10 @@ export function isElemHidden(el) { return res[0]; } +export function queryElemSiblings(el, selector) { + return Array.from(el.parentNode.children).filter((child) => child !== el && child.matches(selector)); +} + export function onDomReady(cb) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', cb); From f92c3de9653a68fb0eed877fd76c20e431f58c97 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 25 Feb 2024 06:34:51 +0800 Subject: [PATCH 48/64] Remove RenderEmojiPlain from template helper (#29375) RenderEmojiPlain(emoji.ReplaceAliases) should be called explicitly for some contents, but not for everything. Actually in modern days, in most cases it doesn't need such "ReplaceAliases". So only keep it for issue/PR titles. If anyone really needs to do ReplaceAliases for some contents, I will propose a following fix. (cherry picked from commit 10c7996b5a5c705964fc6cc9c1817eea1fc436ef) Conflicts: templates/base/head.tmpl context --- modules/templates/helper.go | 12 ------------ routers/web/repo/issue.go | 3 ++- routers/web/repo/pull.go | 3 ++- templates/base/head.tmpl | 2 +- templates/repo/issue/choose.tmpl | 8 ++++---- templates/repo/settings/lfs_file_find.tmpl | 2 +- 6 files changed, 10 insertions(+), 20 deletions(-) diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 3bf1919b4a..d2fe6a28cd 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -14,7 +14,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/svg" @@ -162,7 +161,6 @@ func NewFuncMap() template.FuncMap { "RenderCodeBlock": RenderCodeBlock, "RenderIssueTitle": RenderIssueTitle, "RenderEmoji": RenderEmoji, - "RenderEmojiPlain": RenderEmojiPlain, "ReactionToEmoji": ReactionToEmoji, "RenderMarkdownToHtml": RenderMarkdownToHtml, @@ -218,16 +216,6 @@ func JSEscapeSafe(s string) template.HTML { return template.HTML(template.JSEscapeString(s)) } -func RenderEmojiPlain(s any) any { - switch v := s.(type) { - case string: - return emoji.ReplaceAliases(v) - case template.HTML: - return template.HTML(emoji.ReplaceAliases(string(v))) - } - panic(fmt.Sprintf("unexpected type %T", s)) -} - // DotEscape wraps a dots in names with ZWJ [U+200D] in order to prevent autolinkers from detecting these as urls func DotEscape(raw string) string { return strings.ReplaceAll(raw, ".", "\u200d.\u200d") diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 1a598029c1..05db107545 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -32,6 +32,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/git" issue_indexer "code.gitea.io/gitea/modules/indexer/issues" issue_template "code.gitea.io/gitea/modules/issue/template" @@ -1444,7 +1445,7 @@ func ViewIssue(ctx *context.Context) { return } - ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title) + ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, emoji.ReplaceAliases(issue.Title)) iw := new(issues_model.IssueWatch) if ctx.Doer != nil { diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index dcb0623504..949962ad68 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -29,6 +29,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" issue_template "code.gitea.io/gitea/modules/issue/template" @@ -346,7 +347,7 @@ func getPullInfo(ctx *context.Context) (issue *issues_model.Issue, ok bool) { ctx.ServerError("LoadRepo", err) return nil, false } - ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title) + ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, emoji.ReplaceAliases(issue.Title)) ctx.Data["Issue"] = issue if !issue.IsPull { diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index a202ad7dd1..ad3419793e 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -3,7 +3,7 @@ <head> <meta name="viewport" content="width=device-width, initial-scale=1"> {{/* Display `- .Repsository.FullName` only if `.Title` does not already start with that. */}} - <title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if and (.Repository.Name) (not (StringUtils.HasPrefix .Title .Repository.FullName))}}{{.Repository.FullName}} - {{end}}{{AppName}}</title> + <title>{{if .Title}}{{.Title}} - {{end}}{{if and (.Repository.Name) (not (StringUtils.HasPrefix .Title .Repository.FullName))}}{{.Repository.FullName}} - {{end}}{{AppName}}</title> {{if .ManifestData}}<link rel="manifest" href="data:{{.ManifestData}}">{{end}} <meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}"> <meta name="description" content="{{if .Repository}}{{.Repository.Name}}{{if .Repository.Description}} - {{.Repository.Description}}{{end}}{{else}}{{MetaDescription}}{{end}}"> diff --git a/templates/repo/issue/choose.tmpl b/templates/repo/issue/choose.tmpl index 127b9d7d87..a8037482be 100644 --- a/templates/repo/issue/choose.tmpl +++ b/templates/repo/issue/choose.tmpl @@ -11,8 +11,8 @@ <div class="ui attached segment"> <div class="ui two column grid"> <div class="column left aligned"> - <strong>{{.Name | RenderEmojiPlain}}</strong> - <br>{{.About | RenderEmojiPlain}} + <strong>{{.Name}}</strong> + <br>{{.About}} </div> <div class="column right aligned"> <a href="{{$.RepoLink}}/issues/new?template={{.FileName}}{{if $.milestone}}&milestone={{$.milestone}}{{end}}{{if $.project}}&project={{$.project}}{{end}}" class="ui primary button">{{ctx.Locale.Tr "repo.issues.choose.get_started"}}</a> @@ -24,8 +24,8 @@ <div class="ui attached segment"> <div class="ui two column grid"> <div class="column left aligned"> - <strong>{{.Name | RenderEmojiPlain}}</strong> - <br>{{.About | RenderEmojiPlain}} + <strong>{{.Name}}</strong> + <br>{{.About}} </div> <div class="column right aligned"> <a href="{{.URL}}" class="ui primary button">{{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.issues.choose.open_external_link"}}</a> diff --git a/templates/repo/settings/lfs_file_find.tmpl b/templates/repo/settings/lfs_file_find.tmpl index fea9aa323f..809a028b2c 100644 --- a/templates/repo/settings/lfs_file_find.tmpl +++ b/templates/repo/settings/lfs_file_find.tmpl @@ -14,7 +14,7 @@ </td> <td class="message"> <span class="truncate"> - <a href="{{$.RepoLink}}/commit/{{.SHA}}" title="{{.Summary | RenderEmojiPlain}}"> + <a href="{{$.RepoLink}}/commit/{{.SHA}}" title="{{.Summary}}"> {{.Summary | RenderEmoji $.Context}} </a> </span> From 5362ce7a42fddadeaa9d67de9309004b18861d9a Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 25 Feb 2024 01:08:51 +0200 Subject: [PATCH 49/64] Remove jQuery AJAX from repo collaborator mode dropdown (#29371) - Removed all jQuery AJAX calls and replaced with our fetch wrapper - Tested the repo collaborator mode dropdown functionality and it works as before # Demo using `fetch` instead of jQuery AJAX  --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: Giteabot <teabot@gitea.io> (cherry picked from commit 15d071f4f81a0ad09f260de83cb6402875b4de27) --- web_src/js/features/repo-settings.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/web_src/js/features/repo-settings.js b/web_src/js/features/repo-settings.js index 75e624a6a7..0418f3a14a 100644 --- a/web_src/js/features/repo-settings.js +++ b/web_src/js/features/repo-settings.js @@ -2,6 +2,7 @@ import $ from 'jquery'; import {minimatch} from 'minimatch'; import {createMonaco} from './codeeditor.js'; import {onInputDebounce, toggleElem} from '../utils/dom.js'; +import {POST} from '../modules/fetch.js'; const {appSubUrl, csrfToken} = window.config; @@ -11,18 +12,19 @@ export function initRepoSettingsCollaboration() { const $dropdown = $(e); const $text = $dropdown.find('> .text'); $dropdown.dropdown({ - action(_text, value) { + async action(_text, value) { const lastValue = $dropdown.attr('data-last-value'); - $.post($dropdown.attr('data-url'), { - _csrf: csrfToken, - uid: $dropdown.attr('data-uid'), - mode: value, - }).fail(() => { + try { + $dropdown.attr('data-last-value', value); + $dropdown.dropdown('hide'); + const data = new FormData(); + data.append('uid', $dropdown.attr('data-uid')); + data.append('mode', value); + await POST($dropdown.attr('data-url'), {data}); + } catch { $text.text('(error)'); // prevent from misleading users when error occurs $dropdown.attr('data-last-value', lastValue); - }); - $dropdown.attr('data-last-value', value); - $dropdown.dropdown('hide'); + } }, onChange(_value, text, _$choice) { $text.text(text); // update the text when using keyboard navigating From 110b06f88b1327edb5f7a14e654f8f5c172fce72 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 25 Feb 2024 06:09:55 +0200 Subject: [PATCH 50/64] Remove jQuery AJAX from the repo commit graph (#29373) - Removed all jQuery AJAX calls and replaced with our fetch wrapper - Tested the repo collaborator mode dropdown functionality and it works as before # Demo using `fetch` instead of jQuery AJAX  Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: Giteabot <teabot@gitea.io> (cherry picked from commit b616f666b89f57f3c285b70c11693f50ba38bcaa) --- web_src/js/features/repo-graph.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web_src/js/features/repo-graph.js b/web_src/js/features/repo-graph.js index e445ae1103..c83f448b76 100644 --- a/web_src/js/features/repo-graph.js +++ b/web_src/js/features/repo-graph.js @@ -1,4 +1,5 @@ import $ from 'jquery'; +import {GET} from '../modules/fetch.js'; export function initRepoGraphGit() { const graphContainer = document.getElementById('git-graph-container'); @@ -60,7 +61,9 @@ export function initRepoGraphGit() { $('#rev-container').addClass('gt-hidden'); $('#loading-indicator').removeClass('gt-hidden'); (async () => { - const div = $(await $.ajax(String(ajaxUrl))); + const response = await GET(String(ajaxUrl)); + const html = await response.text(); + const div = $(html); $('#pagination').html(div.find('#pagination').html()); $('#rel-container').html(div.find('#rel-container').html()); $('#rev-container').html(div.find('#rev-container').html()); From 29517c54e61511aab04888f815905ce6a733269a Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 25 Feb 2024 12:17:11 +0800 Subject: [PATCH 51/64] Refactor `copy` button event handler (#29379) Use "closest" instead of "for-loop" (cherry picked from commit 736c98be5c2bed26cef9f7f679c49a95af8161ef) --- web_src/js/features/clipboard.js | 41 +++++++++++++------------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/web_src/js/features/clipboard.js b/web_src/js/features/clipboard.js index 224628658e..8be5505c8b 100644 --- a/web_src/js/features/clipboard.js +++ b/web_src/js/features/clipboard.js @@ -5,37 +5,30 @@ import {clippie} from 'clippie'; const {copy_success, copy_error} = window.config.i18n; // Enable clipboard copy from HTML attributes. These properties are supported: -// - data-clipboard-text: Direct text to copy, has highest precedence +// - data-clipboard-text: Direct text to copy // - data-clipboard-target: Holds a selector for a <input> or <textarea> whose content is copied // - data-clipboard-text-type: When set to 'url' will convert relative to absolute urls export function initGlobalCopyToClipboardListener() { - document.addEventListener('click', (e) => { - let target = e.target; - // In case <button data-clipboard-text><svg></button>, so we just search - // up to 3 levels for performance - for (let i = 0; i < 3 && target; i++) { - let text = target.getAttribute('data-clipboard-text'); + document.addEventListener('click', async (e) => { + const target = e.target.closest('[data-clipboard-text], [data-clipboard-target]'); + if (!target) return; - if (!text && target.getAttribute('data-clipboard-target')) { - text = document.querySelector(target.getAttribute('data-clipboard-target'))?.value; - } + e.preventDefault(); - if (text && target.getAttribute('data-clipboard-text-type') === 'url') { - text = toAbsoluteUrl(text); - } + let text; + if (target.hasAttribute('data-clipboard-text')) { + text = target.getAttribute('data-clipboard-text'); + } else { + text = document.querySelector(target.getAttribute('data-clipboard-target'))?.value; + } - if (text) { - e.preventDefault(); + if (text && target.getAttribute('data-clipboard-text-type') === 'url') { + text = toAbsoluteUrl(text); + } - (async() => { - const success = await clippie(text); - showTemporaryTooltip(target, success ? copy_success : copy_error); - })(); - - break; - } - - target = target.parentElement; + if (text) { + const success = await clippie(text); + showTemporaryTooltip(target, success ? copy_success : copy_error); } }); } From 4a08726c96c25a54af0cedea552bc1daaeefd224 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 25 Feb 2024 06:42:29 +0200 Subject: [PATCH 52/64] Remove jQuery AJAX from the markdown editor preview (#29384) - Removed all jQuery AJAX calls and replaced with our fetch wrapper - Tested the markdown editor preview button functionality and it works as before # Demo using `fetch` instead of jQuery AJAX  Signed-off-by: Yarden Shoham <git@yardenshoham.com> (cherry picked from commit 1f6de13897fa0ac74087b2d1ec00cbef06caf2f7) --- .../js/features/comp/ComboMarkdownEditor.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/web_src/js/features/comp/ComboMarkdownEditor.js b/web_src/js/features/comp/ComboMarkdownEditor.js index d209f11ab2..4c973358e3 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.js +++ b/web_src/js/features/comp/ComboMarkdownEditor.js @@ -9,6 +9,7 @@ import {renderPreviewPanelContent} from '../repo-editor.js'; import {easyMDEToolbarActions} from './EasyMDEToolbarActions.js'; import {initTextExpander} from './TextExpander.js'; import {showErrorToast} from '../../modules/toast.js'; +import {POST} from '../../modules/fetch.js'; let elementIdCounter = 0; @@ -147,16 +148,15 @@ class ComboMarkdownEditor { this.previewContext = $tabPreviewer.attr('data-preview-context'); this.previewMode = this.options.previewMode ?? 'comment'; this.previewWiki = this.options.previewWiki ?? false; - $tabPreviewer.on('click', () => { - $.post(this.previewUrl, { - _csrf: window.config.csrfToken, - mode: this.previewMode, - context: this.previewContext, - text: this.value(), - wiki: this.previewWiki, - }, (data) => { - renderPreviewPanelContent($panelPreviewer, data); - }); + $tabPreviewer.on('click', async () => { + const formData = new FormData(); + formData.append('mode', this.previewMode); + formData.append('context', this.previewContext); + formData.append('text', this.value()); + formData.append('wiki', this.previewWiki); + const response = await POST(this.previewUrl, {data: formData}); + const data = await response.text(); + renderPreviewPanelContent($panelPreviewer, data); }); } From 30fe3d8d4c7ddcf42bd16d54fe76179a886f87a1 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 25 Feb 2024 07:07:23 +0200 Subject: [PATCH 53/64] Remove jQuery from the code diff expansion buttons (#29385) - Removed all jQuery AJAX calls and replaced with htmx - Tested the code diff expansion buttons functionality and it works as before plus a loading indicator # Demo using `htmx` instead of jQuery AJAX  Signed-off-by: Yarden Shoham <git@yardenshoham.com> (cherry picked from commit 4e3d81e44ee3f504f7262966533305561e04101f) --- templates/repo/diff/blob_excerpt.tmpl | 12 ++++++------ templates/repo/diff/section_split.tmpl | 6 +++--- templates/repo/diff/section_unified.tmpl | 6 +++--- web_src/js/features/repo-code.js | 8 -------- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl index 2dff28a965..353f6db705 100644 --- a/templates/repo/diff/blob_excerpt.tmpl +++ b/templates/repo/diff/blob_excerpt.tmpl @@ -5,17 +5,17 @@ <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"> <div class="gt-df"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} - <button class="code-expander-button" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.PageIsWiki}}" data-anchor="{{$.Anchor}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.PageIsWiki}}&anchor={{$.Anchor}}"> {{svg "octicon-fold-down"}} </button> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} - <button class="code-expander-button" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.PageIsWiki}}" data-anchor="{{$.Anchor}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.PageIsWiki}}&anchor={{$.Anchor}}"> {{svg "octicon-fold-up"}} </button> {{end}} {{if eq $line.GetExpandDirection 2}} - <button class="code-expander-button" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.PageIsWiki}}" data-anchor="{{$.Anchor}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.PageIsWiki}}&anchor={{$.Anchor}}"> {{svg "octicon-fold"}} </button> {{end}} @@ -51,17 +51,17 @@ <td colspan="2" class="lines-num"> <div class="gt-df"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} - <button class="code-expander-button" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.PageIsWiki}}" data-anchor="{{$.Anchor}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}?data-query={{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.PageIsWiki}}&anchor={{$.Anchor}}"> {{svg "octicon-fold-down"}} </button> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} - <button class="code-expander-button" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.PageIsWiki}}" data-anchor="{{$.Anchor}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}?data-query={{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.PageIsWiki}}&anchor={{$.Anchor}}"> {{svg "octicon-fold-up"}} </button> {{end}} {{if eq $line.GetExpandDirection 2}} - <button class="code-expander-button" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.PageIsWiki}}" data-anchor="{{$.Anchor}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}?data-query={{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.PageIsWiki}}&anchor={{$.Anchor}}"> {{svg "octicon-fold"}} </button> {{end}} diff --git a/templates/repo/diff/section_split.tmpl b/templates/repo/diff/section_split.tmpl index 5137e0e838..5a1c8cce64 100644 --- a/templates/repo/diff/section_split.tmpl +++ b/templates/repo/diff/section_split.tmpl @@ -18,17 +18,17 @@ <td class="lines-num lines-num-old"> <div class="gt-df"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} - <button class="code-expander-button" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.root.PageIsWiki}}" data-anchor="diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-down"}} </button> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} - <button class="code-expander-button" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.root.PageIsWiki}}" data-anchor="diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-up"}} </button> {{end}} {{if eq $line.GetExpandDirection 2}} - <button class="code-expander-button" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.root.PageIsWiki}}" data-anchor="diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold"}} </button> {{end}} diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl index 7e00677121..ae97dc6db6 100644 --- a/templates/repo/diff/section_unified.tmpl +++ b/templates/repo/diff/section_unified.tmpl @@ -14,17 +14,17 @@ <td colspan="2" class="lines-num"> <div class="gt-df"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} - <button class="code-expander-button" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.root.PageIsWiki}}" data-anchor="diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-down"}} </button> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} - <button class="code-expander-button" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.root.PageIsWiki}}" data-anchor="diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-up"}} </button> {{end}} {{if eq $line.GetExpandDirection 2}} - <button class="code-expander-button" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.root.PageIsWiki}}" data-anchor="diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> + <button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold"}} </button> {{end}} diff --git a/web_src/js/features/repo-code.js b/web_src/js/features/repo-code.js index a142313211..c4a81ea165 100644 --- a/web_src/js/features/repo-code.js +++ b/web_src/js/features/repo-code.js @@ -186,14 +186,6 @@ export function initRepoCodeView() { $(document).on('click', '.fold-file', ({currentTarget}) => { invertFileFolding(currentTarget.closest('.file-content'), currentTarget); }); - $(document).on('click', '.code-expander-button', async ({currentTarget}) => { - const url = currentTarget.getAttribute('data-url'); - const query = currentTarget.getAttribute('data-query'); - const anchor = currentTarget.getAttribute('data-anchor'); - if (!url) return; - const blob = await $.get(`${url}?${query}&anchor=${anchor}`); - currentTarget.closest('tr').outerHTML = blob; - }); $(document).on('click', '.copy-line-permalink', async ({currentTarget}) => { await clippie(toAbsoluteUrl(currentTarget.getAttribute('data-url'))); }); From 90a62b87c0fa07fa1e7cc4943753e81e3eda36d2 Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 25 Feb 2024 18:45:56 +0800 Subject: [PATCH 54/64] Refactor Safe modifier (#29392) After this PR: no need to play with the Safe/Escape tricks anymore. See the changes for more details. (cherry picked from commit f9207b09479df964872d68842469991042b5497f) Conflicts: templates/repo/issue/view_title.tmpl templates/user/settings/applications.tmpl context --- modules/templates/helper.go | 25 ++++++++++++++++--- modules/templates/helper_test.go | 5 ++++ templates/admin/packages/list.tmpl | 2 +- templates/admin/repo/list.tmpl | 2 +- templates/admin/stacktrace.tmpl | 2 +- templates/mail/issue/assigned.tmpl | 8 +++--- templates/mail/issue/default.tmpl | 8 +++--- templates/mail/notify/repo_transfer.tmpl | 4 +-- templates/mail/release.tmpl | 6 ++--- templates/org/member/members.tmpl | 4 +-- templates/org/team/members.tmpl | 2 +- templates/org/team/sidebar.tmpl | 2 +- templates/org/team/teams.tmpl | 2 +- templates/repo/commit_page.tmpl | 4 +-- templates/repo/editor/cherry_pick.tmpl | 6 ++--- .../repo/issue/view_content/comments.tmpl | 14 +++++------ templates/repo/issue/view_content/pull.tmpl | 2 +- templates/repo/issue/view_title.tmpl | 16 ++++++------ templates/repo/migrate/migrate.tmpl | 2 +- templates/repo/settings/lfs_file.tmpl | 4 +-- templates/repo/settings/webhook/settings.tmpl | 2 +- templates/repo/wiki/view.tmpl | 8 +++--- templates/user/settings/applications.tmpl | 2 +- templates/user/settings/organization.tmpl | 2 +- 24 files changed, 79 insertions(+), 55 deletions(-) diff --git a/modules/templates/helper.go b/modules/templates/helper.go index d2fe6a28cd..8e891bdc24 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -9,6 +9,7 @@ import ( "html" "html/template" "net/url" + "slices" "strings" "time" @@ -34,7 +35,8 @@ func NewFuncMap() template.FuncMap { // html/template related functions "dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names. "Eval": Eval, - "Safe": Safe, + "SafeHTML": SafeHTML, + "HTMLFormat": HTMLFormat, "Escape": Escape, "QueryEscape": url.QueryEscape, "JSEscape": JSEscapeSafe, @@ -180,8 +182,25 @@ func NewFuncMap() template.FuncMap { } } -// Safe render raw as HTML -func Safe(s any) template.HTML { +func HTMLFormat(s string, rawArgs ...any) template.HTML { + args := slices.Clone(rawArgs) + for i, v := range args { + switch v := v.(type) { + case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, template.HTML: + // for most basic types (including template.HTML which is safe), just do nothing and use it + case string: + args[i] = template.HTMLEscapeString(v) + case fmt.Stringer: + args[i] = template.HTMLEscapeString(v.String()) + default: + args[i] = template.HTMLEscapeString(fmt.Sprint(v)) + } + } + return template.HTML(fmt.Sprintf(s, args...)) +} + +// SafeHTML render raw as HTML +func SafeHTML(s any) template.HTML { switch v := s.(type) { case string: return template.HTML(v) diff --git a/modules/templates/helper_test.go b/modules/templates/helper_test.go index 739a92f34f..8f5d633d4f 100644 --- a/modules/templates/helper_test.go +++ b/modules/templates/helper_test.go @@ -4,6 +4,7 @@ package templates import ( + "html/template" "testing" "github.com/stretchr/testify/assert" @@ -56,3 +57,7 @@ func TestSubjectBodySeparator(t *testing.T) { func TestJSEscapeSafe(t *testing.T) { assert.EqualValues(t, `\u0026\u003C\u003E\'\"`, JSEscapeSafe(`&<>'"`)) } + +func TestHTMLFormat(t *testing.T) { + assert.Equal(t, template.HTML("<a>< < 1</a>"), HTMLFormat("<a>%s %s %d</a>", "<", template.HTML("<"), 1)) +} diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl index 04f76748d0..cf860dab2a 100644 --- a/templates/admin/packages/list.tmpl +++ b/templates/admin/packages/list.tmpl @@ -88,7 +88,7 @@ {{ctx.Locale.Tr "packages.settings.delete"}} </div> <div class="content"> - {{ctx.Locale.Tr "packages.settings.delete.notice" (`<span class="name"></span>`|Safe) (`<span class="dataVersion"></span>`|Safe)}} + {{ctx.Locale.Tr "packages.settings.delete.notice" (`<span class="name"></span>`|SafeHTML) (`<span class="dataVersion"></span>`|SafeHTML)}} </div> {{template "base/modal_actions_confirm" .}} </div> diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index c7a6ec7e4e..e11247aed4 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -101,7 +101,7 @@ </div> <div class="content"> <p>{{ctx.Locale.Tr "repo.settings.delete_desc"}}</p> - {{ctx.Locale.Tr "repo.settings.delete_notices_2" (`<span class="name"></span>`|Safe)}}<br> + {{ctx.Locale.Tr "repo.settings.delete_notices_2" (`<span class="name"></span>`|SafeHTML)}}<br> {{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}<br> </div> {{template "base/modal_actions_confirm" .}} diff --git a/templates/admin/stacktrace.tmpl b/templates/admin/stacktrace.tmpl index aa5e810cd7..42944615c3 100644 --- a/templates/admin/stacktrace.tmpl +++ b/templates/admin/stacktrace.tmpl @@ -39,7 +39,7 @@ {{ctx.Locale.Tr "admin.monitor.process.cancel"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "admin.monitor.process.cancel_notices" (`<span class="name"></span>`|Safe)}}</p> + <p>{{ctx.Locale.Tr "admin.monitor.process.cancel_notices" (`<span class="name"></span>`|SafeHTML)}}</p> <p>{{ctx.Locale.Tr "admin.monitor.process.cancel_desc"}}</p> </div> {{template "base/modal_actions_confirm" .}} diff --git a/templates/mail/issue/assigned.tmpl b/templates/mail/issue/assigned.tmpl index e80bd2fc31..5720319ee8 100644 --- a/templates/mail/issue/assigned.tmpl +++ b/templates/mail/issue/assigned.tmpl @@ -8,14 +8,14 @@ <title>{{.Subject}}</title> </head> -{{$repo_url := printf "<a href='%s'>%s</a>" (Escape .Issue.Repo.HTMLURL) (Escape .Issue.Repo.FullName)}} -{{$link := printf "<a href='%s'>#%d</a>" (Escape .Link) .Issue.Index}} +{{$repo_url := HTMLFormat "<a href='%s'>%s</a>" .Issue.Repo.HTMLURL .Issue.Repo.FullName}} +{{$link := HTMLFormat "<a href='%s'>#%d</a>" .Link .Issue.Index}} <body> <p> {{if .IsPull}} - {{.locale.Tr "mail.issue_assigned.pull" .Doer.Name ($link|Safe) ($repo_url|Safe)}} + {{.locale.Tr "mail.issue_assigned.pull" .Doer.Name $link $repo_url}} {{else}} - {{.locale.Tr "mail.issue_assigned.issue" .Doer.Name ($link|Safe) ($repo_url|Safe)}} + {{.locale.Tr "mail.issue_assigned.issue" .Doer.Name $link $repo_url}} {{end}} </p> <div class="footer"> diff --git a/templates/mail/issue/default.tmpl b/templates/mail/issue/default.tmpl index b5a7ab95cf..ef90433c3a 100644 --- a/templates/mail/issue/default.tmpl +++ b/templates/mail/issue/default.tmpl @@ -22,13 +22,13 @@ {{if .Comment.IsForcePush}} {{$oldCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.HTMLURL .Comment.OldCommit}} {{$oldShortSha := ShortSha .Comment.OldCommit}} - {{$oldCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $oldCommitUrl) (Escape $oldShortSha)}} + {{$oldCommitLink := HTMLFormat "<a href='%[1]s'><b>%[2]s</b></a>" $oldCommitUrl $oldShortSha}} {{$newCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.HTMLURL .Comment.NewCommit}} {{$newShortSha := ShortSha .Comment.NewCommit}} - {{$newCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $newCommitUrl) (Escape $newShortSha)}} + {{$newCommitLink := HTMLFormat "<a href='%[1]s'><b>%[2]s</b></a>" $newCommitUrl $newShortSha}} - {{.locale.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch ($oldCommitLink|Safe) ($newCommitLink|Safe)}} + {{.locale.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch $oldCommitLink $newCommitLink}} {{else}} {{.locale.TrN (len .Comment.Commits) "mail.issue.action.push_1" "mail.issue.action.push_n" .Doer.Name .Comment.Issue.PullRequest.HeadBranch (len .Comment.Commits) | Str2html}} {{end}} @@ -65,7 +65,7 @@ {{$.locale.Tr "mail.issue.in_tree_path" .TreePath}} <div class="review"> <pre>{{.Patch}}</pre> - <div>{{.RenderedContent | Safe}}</div> + <div>{{.RenderedContent | SafeHTML}}</div> </div> {{end -}} {{if eq .ActionName "push"}} diff --git a/templates/mail/notify/repo_transfer.tmpl b/templates/mail/notify/repo_transfer.tmpl index 1b23593f6b..597048ddf4 100644 --- a/templates/mail/notify/repo_transfer.tmpl +++ b/templates/mail/notify/repo_transfer.tmpl @@ -5,10 +5,10 @@ <title>{{.Subject}}</title> </head> -{{$url := printf "<a href='%[1]s'>%[2]s</a>" (Escape .Link) (Escape .Repo)}} +{{$url := HTMLFormat "<a href='%[1]s'>%[2]s</a>" .Link .Repo)}} <body> <p>{{.Subject}}. - {{.locale.Tr "mail.repo.transfer.body" ($url|Safe)}} + {{.locale.Tr "mail.repo.transfer.body" $url}} </p> <p> --- diff --git a/templates/mail/release.tmpl b/templates/mail/release.tmpl index 96dc769993..62a16573c6 100644 --- a/templates/mail/release.tmpl +++ b/templates/mail/release.tmpl @@ -11,11 +11,11 @@ </head> -{{$release_url := printf "<a href='%s'>%s</a>" (.Release.HTMLURL | Escape) (.Release.TagName | Escape)}} -{{$repo_url := printf "<a href='%s'>%s</a>" (.Release.Repo.HTMLURL | Escape) (.Release.Repo.FullName | Escape)}} +{{$release_url := HTMLFormat "<a href='%s'>%s</a>" .Release.HTMLURL .Release.TagName}} +{{$repo_url := HTMLFormat "<a href='%s'>%s</a>" .Release.Repo.HTMLURL .Release.Repo.FullName}} <body> <p> - {{.locale.Tr "mail.release.new.text" .Release.Publisher.Name ($release_url|Safe) ($repo_url|Safe)}} + {{.locale.Tr "mail.release.new.text" .Release.Publisher.Name $release_url $repo_url}} </p> <h4>{{.locale.Tr "mail.release.title" .Release.Title}}</h4> <p> diff --git a/templates/org/member/members.tmpl b/templates/org/member/members.tmpl index 64f1aaa7d2..54f84450eb 100644 --- a/templates/org/member/members.tmpl +++ b/templates/org/member/members.tmpl @@ -73,7 +73,7 @@ {{ctx.Locale.Tr "org.members.leave"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "org.members.leave.detail" (`<span class="dataOrganizationName"></span>`|Safe)}}</p> + <p>{{ctx.Locale.Tr "org.members.leave.detail" (`<span class="dataOrganizationName"></span>`|SafeHTML)}}</p> </div> {{template "base/modal_actions_confirm" .}} </div> @@ -82,7 +82,7 @@ {{ctx.Locale.Tr "org.members.remove"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "org.members.remove.detail" (`<span class="name"></span>`|Safe) (`<span class="dataOrganizationName"></span>`|Safe)}}</p> + <p>{{ctx.Locale.Tr "org.members.remove.detail" (`<span class="name"></span>`|SafeHTML) (`<span class="dataOrganizationName"></span>`|SafeHTML)}}</p> </div> {{template "base/modal_actions_confirm" .}} </div> diff --git a/templates/org/team/members.tmpl b/templates/org/team/members.tmpl index dd4ece1433..adaf83ae15 100644 --- a/templates/org/team/members.tmpl +++ b/templates/org/team/members.tmpl @@ -81,7 +81,7 @@ {{ctx.Locale.Tr "org.members.remove"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "org.members.remove.detail" (`<span class="name"></span>`|Safe) (`<span class="dataTeamName"></span>`|Safe)}}</p> + <p>{{ctx.Locale.Tr "org.members.remove.detail" (`<span class="name"></span>`|SafeHTML) (`<span class="dataTeamName"></span>`|SafeHTML)}}</p> </div> {{template "base/modal_actions_confirm" .}} </div> diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index 37550ab71f..509c6382d8 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -88,7 +88,7 @@ {{ctx.Locale.Tr "org.teams.leave"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "org.teams.leave.detail" (`<span class="name"></span>`|Safe)}}</p> + <p>{{ctx.Locale.Tr "org.teams.leave.detail" (`<span class="name"></span>`|SafeHTML)}}</p> </div> {{template "base/modal_actions_confirm" .}} </div> diff --git a/templates/org/team/teams.tmpl b/templates/org/team/teams.tmpl index b518d7d9d7..53c909ee9c 100644 --- a/templates/org/team/teams.tmpl +++ b/templates/org/team/teams.tmpl @@ -49,7 +49,7 @@ {{ctx.Locale.Tr "org.teams.leave"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "org.teams.leave.detail" (`<span class="name"></span>`|Safe)}}</p> + <p>{{ctx.Locale.Tr "org.teams.leave.detail" (`<span class="name"></span>`|SafeHTML)}}</p> </div> {{template "base/modal_actions_confirm" .}} </div> diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index fbfaa19411..115ee92955 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -88,7 +88,7 @@ {{.CsrfTokenHtml}} <div class="field"> <label> - {{ctx.Locale.Tr "repo.branch.new_branch_from" (`<span class="text" id="modal-create-branch-from-span"></span>`|Safe)}} + {{ctx.Locale.Tr "repo.branch.new_branch_from" (`<span class="text" id="modal-create-branch-from-span"></span>`|SafeHTML)}} </label> </div> <div class="required field"> @@ -113,7 +113,7 @@ <input type="hidden" name="create_tag" value="true"> <div class="field"> <label> - {{ctx.Locale.Tr "repo.tag.create_tag_from" (`<span class="text" id="modal-create-tag-from-span"></span>`|Safe)}} + {{ctx.Locale.Tr "repo.tag.create_tag_from" (`<span class="text" id="modal-create-tag-from-span"></span>`|SafeHTML)}} </label> </div> <div class="required field"> diff --git a/templates/repo/editor/cherry_pick.tmpl b/templates/repo/editor/cherry_pick.tmpl index b65c3a3033..f9c9eef5aa 100644 --- a/templates/repo/editor/cherry_pick.tmpl +++ b/templates/repo/editor/cherry_pick.tmpl @@ -11,11 +11,11 @@ <div class="repo-editor-header"> <div class="ui breadcrumb field {{if .Err_TreePath}}error{{end}}"> {{$shaurl := printf "%s/commit/%s" $.RepoLink (PathEscape .SHA)}} - {{$shalink := printf `<a class="ui primary sha label" href="%s">%s</a>` (Escape $shaurl) (ShortSha .SHA)}} + {{$shalink := HTMLFormat `<a class="ui primary sha label" href="%s">%s</a>` $shaurl (ShortSha .SHA)}} {{if eq .CherryPickType "revert"}} - {{ctx.Locale.Tr "repo.editor.revert" ($shalink|Safe)}} + {{ctx.Locale.Tr "repo.editor.revert" $shalink}} {{else}} - {{ctx.Locale.Tr "repo.editor.cherry_pick" ($shalink|Safe)}} + {{ctx.Locale.Tr "repo.editor.cherry_pick" $shalink}} {{end}} <a class="section" href="{{$.RepoLink}}">{{.Repository.FullName}}</a> <div class="breadcrumb-divider">:</div> diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 20dbbdc6e4..96b0c5ba03 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -112,9 +112,9 @@ {{template "shared/user/authorlink" .Poster}} {{$link := printf "%s/commit/%s" $.Repository.Link ($.Issue.PullRequest.MergedCommitID|PathEscape)}} {{if eq $.Issue.PullRequest.Status 3}} - {{ctx.Locale.Tr "repo.issues.comment_manually_pull_merged_at" (printf `<a class="ui sha" href="%[1]s"><b>%[2]s</b></a>` ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) | Safe) (printf "<b>%[1]s</b>" ($.BaseTarget|Escape) | Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.comment_manually_pull_merged_at" (HTMLFormat `<a class="ui sha" href="%[1]s"><b>%[2]s</b></a>` $link (ShortSha $.Issue.PullRequest.MergedCommitID)) (HTMLFormat "<b>%[1]s</b>" $.BaseTarget) $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.comment_pull_merged_at" (printf `<a class="ui sha" href="%[1]s"><b>%[2]s</b></a>` ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) | Safe) (printf "<b>%[1]s</b>" ($.BaseTarget|Escape) | Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.comment_pull_merged_at" (HTMLFormat `<a class="ui sha" href="%[1]s"><b>%[2]s</b></a>` $link (ShortSha $.Issue.PullRequest.MergedCommitID)) (HTMLFormat "<b>%[1]s</b>" $.BaseTarget) $createdStr}} {{end}} </span> </div> @@ -599,19 +599,19 @@ {{$oldProjectDisplayHtml := "Unknown Project"}} {{if .OldProject}} {{$trKey := printf "projects.type-%d.display_name" .OldProject.Type}} - {{$oldProjectDisplayHtml = printf `<span data-tooltip-content="%s">%s</span>` (ctx.Locale.Tr $trKey | Escape) (.OldProject.Title | Escape)}} + {{$oldProjectDisplayHtml = HTMLFormat `<span data-tooltip-content="%s">%s</span>` (ctx.Locale.Tr $trKey) .OldProject.Title}} {{end}} {{$newProjectDisplayHtml := "Unknown Project"}} {{if .Project}} {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} - {{$newProjectDisplayHtml = printf `<span data-tooltip-content="%s">%s</span>` (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}} + {{$newProjectDisplayHtml = HTMLFormat `<span data-tooltip-content="%s">%s</span>` (ctx.Locale.Tr $trKey) .Project.Title}} {{end}} {{if and (gt .OldProjectID 0) (gt .ProjectID 0)}} - {{ctx.Locale.Tr "repo.issues.change_project_at" ($oldProjectDisplayHtml|Safe) ($newProjectDisplayHtml|Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.change_project_at" $oldProjectDisplayHtml $newProjectDisplayHtml $createdStr}} {{else if gt .OldProjectID 0}} - {{ctx.Locale.Tr "repo.issues.remove_project_at" ($oldProjectDisplayHtml|Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.remove_project_at" $oldProjectDisplayHtml $createdStr}} {{else if gt .ProjectID 0}} - {{ctx.Locale.Tr "repo.issues.add_project_at" ($newProjectDisplayHtml|Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.add_project_at" $newProjectDisplayHtml $createdStr}} {{end}} </span> </div> diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 13d49b61b7..371c9db6f0 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -39,7 +39,7 @@ {{ctx.Locale.Tr "repo.pulls.merged_success"}} </h3> <div class="merge-section-info"> - {{ctx.Locale.Tr "repo.pulls.merged_info_text" (printf "<code>%s</code>" (.HeadTarget | Escape) | Safe)}} + {{ctx.Locale.Tr "repo.pulls.merged_info_text" (HTMLFormat "<code>%s</code>" .HeadTarget)}} </div> </div> <div class="item-section-right"> diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index c6c86124a1..d6c8146451 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -43,33 +43,33 @@ {{end}} <div class="gt-ml-3"> {{if .Issue.IsPull}} - {{$headHref := .HeadTarget|Escape}} + {{$headHref := .HeadTarget}} {{if .HeadBranchLink}} - {{$headHref = printf `<a href="%s">%s</a>` (.HeadBranchLink | Escape) $headHref}} + {{$headHref = HTMLFormat `<a href="%s">%s</a>` .HeadBranchLink $headHref}} {{end}} {{if not .MadeUsingAGit}} - {{$headHref = printf `%s <button class="btn interact-fg" data-tooltip-content="%s" data-clipboard-text="%s">%s</button>` $headHref (ctx.Locale.Tr "copy_branch") (.HeadTarget | Escape) (svg "octicon-copy" 14)}} + {{$headHref = HTMLFormat `%s <button class="btn interact-fg" data-tooltip-content="%s" data-clipboard-text="%s">%s</button>` $headHref (ctx.Locale.Tr "copy_branch") .HeadTarget (svg "octicon-copy" 14)}} {{end}} {{$baseHref := .BaseTarget|Escape}} {{if .BaseBranchLink}} - {{$baseHref = printf `<a href="%s">%s</a>` (.BaseBranchLink | Escape) $baseHref}} + {{$baseHref = HTMLFormat `<a href="%s">%s</a>` .BaseBranchLink $baseHref}} {{end}} {{if .Issue.PullRequest.HasMerged}} {{$mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix ctx.Locale}} {{if .Issue.OriginalAuthor}} {{.Issue.OriginalAuthor}} - <span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe) $mergedStr}}</span> + <span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr}}</span> {{else}} <a {{if gt .Issue.PullRequest.Merger.ID 0}}href="{{.Issue.PullRequest.Merger.HomeLink}}"{{end}}>{{.Issue.PullRequest.Merger.GetDisplayName}}</a> - <span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe) $mergedStr}}</span> + <span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr}}</span> {{end}} {{else}} {{if .Issue.OriginalAuthor}} - <span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe)}}</span> + <span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}}</span> {{else}} <span id="pull-desc" class="pull-desc"> <a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a> - {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe)}} + {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}} </span> {{end}} {{if .MadeUsingAGit}} diff --git a/templates/repo/migrate/migrate.tmpl b/templates/repo/migrate/migrate.tmpl index c686f0b832..d1abb15374 100644 --- a/templates/repo/migrate/migrate.tmpl +++ b/templates/repo/migrate/migrate.tmpl @@ -20,7 +20,7 @@ {{.Title}} </div> <div class="description gt-text-center"> - {{(printf "repo.migrate.%s.description" .Name) | ctx.Locale.Tr}} + {{ctx.Locale.Tr (printf "repo.migrate.%s.description" .Name)}} </div> </div> </a> diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl index 0aeb2af178..7f1d07e46f 100644 --- a/templates/repo/settings/lfs_file.tmpl +++ b/templates/repo/settings/lfs_file.tmpl @@ -15,9 +15,9 @@ {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}} <div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextFile}} code-view{{end}}"> {{if .IsMarkup}} - {{if .FileContent}}{{.FileContent | Safe}}{{end}} + {{if .FileContent}}{{.FileContent | SafeHTML}}{{end}} {{else if .IsPlainText}} - <pre>{{if .FileContent}}{{.FileContent | Safe}}{{end}}</pre> + <pre>{{if .FileContent}}{{.FileContent | SafeHTML}}{{end}}</pre> {{else if not .IsTextFile}} <div class="view-raw"> {{if .IsImageFile}} diff --git a/templates/repo/settings/webhook/settings.tmpl b/templates/repo/settings/webhook/settings.tmpl index 8e2387067e..6836e695ed 100644 --- a/templates/repo/settings/webhook/settings.tmpl +++ b/templates/repo/settings/webhook/settings.tmpl @@ -263,7 +263,7 @@ <label for="authorization_header">{{ctx.Locale.Tr "repo.settings.authorization_header"}}</label> <input id="authorization_header" name="authorization_header" type="text" value="{{.Webhook.HeaderAuthorization}}"{{if eq .HookType "matrix"}} placeholder="Bearer $access_token" required{{end}}> {{if ne .HookType "matrix"}}{{/* Matrix doesn't make the authorization optional but it is implied by the help string, should be changed.*/}} - <span class="help">{{ctx.Locale.Tr "repo.settings.authorization_header_desc" ("<code>Bearer token123456</code>, <code>Basic YWxhZGRpbjpvcGVuc2VzYW1l</code>" | Safe)}}</span> + <span class="help">{{ctx.Locale.Tr "repo.settings.authorization_header_desc" ("<code>Bearer token123456</code>, <code>Basic YWxhZGRpbjpvcGVuc2VzYW1l</code>" | SafeHTML)}}</span> {{end}} </div> diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index 5b296dc2af..f3b6be97cf 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -67,13 +67,13 @@ <div class="wiki-content-parts"> {{if .sidebarTocContent}} <div class="markup wiki-content-sidebar wiki-content-toc"> - {{.sidebarTocContent | Safe}} + {{.sidebarTocContent | SafeHTML}} </div> {{end}} <div class="markup wiki-content-main {{if or .sidebarTocContent .sidebarPresent}}with-sidebar{{end}}"> {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}} - {{.content | Safe}} + {{.content | SafeHTML}} </div> {{if .sidebarPresent}} @@ -82,7 +82,7 @@ <a class="gt-float-right muted" href="{{.RepoLink}}/wiki/_Sidebar?action=_edit" aria-label="{{ctx.Locale.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a> {{end}} {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .sidebarEscapeStatus "root" $}} - {{.sidebarContent | Safe}} + {{.sidebarContent | SafeHTML}} </div> {{end}} @@ -94,7 +94,7 @@ <a class="gt-float-right muted" href="{{.RepoLink}}/wiki/_Footer?action=_edit" aria-label="{{ctx.Locale.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a> {{end}} {{template "repo/unicode_escape_prompt" dict "footerEscapeStatus" .sidebarEscapeStatus "root" $}} - {{.footerContent | Safe}} + {{.footerContent | SafeHTML}} </div> {{end}} </div> diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index e7eb6c8180..7ce9a4b70f 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -75,7 +75,7 @@ {{ctx.Locale.Tr "settings.select_permissions"}} </summary> <p class="activity meta"> - <i>{{ctx.Locale.Tr "settings.access_token_desc" (printf `href="/api/swagger" target="_blank"`) (printf `href="https://docs.gitea.com/development/oauth2-provider#scopes" target="_blank"`) | Str2html}}</i> + <i>{{ctx.Locale.Tr "settings.access_token_desc" (`href="/api/swagger" target="_blank"`|SafeHTML) (`href="https://docs.gitea.com/development/oauth2-provider#scopes" target="_blank"`|SafeHTML)}}</i> </p> <div class="scoped-access-token-mount"> <scoped-access-token-selector diff --git a/templates/user/settings/organization.tmpl b/templates/user/settings/organization.tmpl index 102ff2e95b..16c27b52cd 100644 --- a/templates/user/settings/organization.tmpl +++ b/templates/user/settings/organization.tmpl @@ -47,7 +47,7 @@ {{ctx.Locale.Tr "org.members.leave"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "org.members.leave.detail" (`<span class="dataOrganizationName"></span>`|Safe)}}</p> + <p>{{ctx.Locale.Tr "org.members.leave.detail" (`<span class="dataOrganizationName"></span>`|SafeHTML)}}</p> </div> {{template "base/modal_actions_confirm" .}} </div> From 3723caf7624166b36fa80fd4adca4f094cda6427 Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 25 Feb 2024 14:36:11 +0200 Subject: [PATCH 55/64] Remove jQuery AJAX from the notice selection deletion button (#29381) - Removed all jQuery AJAX calls and replaced with our fetch wrapper - Tested the repo notice selection deletion button functionality and it works as before Signed-off-by: Yarden Shoham <git@yardenshoham.com> (cherry picked from commit 0676bf52f95b9c9ac6f5679bd263d844e6a83fa1) --- web_src/js/features/admin/common.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/web_src/js/features/admin/common.js b/web_src/js/features/admin/common.js index 044976ea7b..5354216e3d 100644 --- a/web_src/js/features/admin/common.js +++ b/web_src/js/features/admin/common.js @@ -1,8 +1,9 @@ import $ from 'jquery'; import {checkAppUrl} from '../common-global.js'; import {hideElem, showElem, toggleElem} from '../../utils/dom.js'; +import {POST} from '../../modules/fetch.js'; -const {csrfToken, appSubUrl} = window.config; +const {appSubUrl} = window.config; export function initAdminCommon() { if ($('.page-content.admin').length === 0) { @@ -204,22 +205,18 @@ export function initAdminCommon() { break; } }); - $('#delete-selection').on('click', function (e) { + $('#delete-selection').on('click', async function (e) { e.preventDefault(); const $this = $(this); $this.addClass('loading disabled'); - const ids = []; + const data = new FormData(); $checkboxes.each(function () { if ($(this).checkbox('is checked')) { - ids.push($(this).data('id')); + data.append('ids[]', $(this).data('id')); } }); - $.post($this.data('link'), { - _csrf: csrfToken, - ids - }).done(() => { - window.location.href = $this.data('redirect'); - }); + await POST($this.data('link'), {data}); + window.location.href = $this.data('redirect'); }); } } From 753f9711e92187aacd4b977edfd1fcf32f09e08f Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Sun, 25 Feb 2024 14:05:23 +0100 Subject: [PATCH 56/64] Add `io.Closer` guidelines (#29387) Co-authored-by: Yarden Shoham <git@yardenshoham.com> (cherry picked from commit ad0a34b492c3d41952ff4648c8bfb7b54c376151) --- docs/content/contributing/guidelines-backend.en-us.md | 4 ++++ modules/git/blame.go | 4 ++++ modules/git/repo_base_gogit.go | 7 ++++--- modules/git/repo_base_nogogit.go | 4 ++-- modules/indexer/internal/bleve/indexer.go | 2 +- modules/indexer/internal/meilisearch/indexer.go | 3 --- modules/util/filebuffer/file_backed_buffer.go | 1 + 7 files changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/content/contributing/guidelines-backend.en-us.md b/docs/content/contributing/guidelines-backend.en-us.md index 084b3886e8..3159a5ff7d 100644 --- a/docs/content/contributing/guidelines-backend.en-us.md +++ b/docs/content/contributing/guidelines-backend.en-us.md @@ -101,6 +101,10 @@ i.e. `services/user`, `models/repository`. Since there are some packages which use the same package name, it is possible that you find packages like `modules/user`, `models/user`, and `services/user`. When these packages are imported in one Go file, it's difficult to know which package we are using and if it's a variable name or an import name. So, we always recommend to use import aliases. To differ from package variables which are commonly in camelCase, just use **snake_case** for import aliases. i.e. `import user_service "code.gitea.io/gitea/services/user"` +### Implementing `io.Closer` + +If a type implements `io.Closer`, calling `Close` multiple times must not fail or `panic` but return an error or `nil`. + ### Important Gotchas - Never write `x.Update(exemplar)` without an explicit `WHERE` clause: diff --git a/modules/git/blame.go b/modules/git/blame.go index 64095a218a..69e1b08f93 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -115,6 +115,10 @@ func (r *BlameReader) NextPart() (*BlamePart, error) { // Close BlameReader - don't run NextPart after invoking that func (r *BlameReader) Close() error { + if r.bufferedReader == nil { + return nil + } + err := <-r.done r.bufferedReader = nil _ = r.reader.Close() diff --git a/modules/git/repo_base_gogit.go b/modules/git/repo_base_gogit.go index 9270bb70f0..3ca5eb36c6 100644 --- a/modules/git/repo_base_gogit.go +++ b/modules/git/repo_base_gogit.go @@ -88,16 +88,17 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) { } // Close this repository, in particular close the underlying gogitStorage if this is not nil -func (repo *Repository) Close() (err error) { +func (repo *Repository) Close() error { if repo == nil || repo.gogitStorage == nil { - return + return nil } if err := repo.gogitStorage.Close(); err != nil { gitealog.Error("Error closing storage: %v", err) } + repo.gogitStorage = nil repo.LastCommitCache = nil repo.tagCache = nil - return + return nil } // GoGitRepo gets the go-git repo representation diff --git a/modules/git/repo_base_nogogit.go b/modules/git/repo_base_nogogit.go index 8c6eae5897..86b6a93567 100644 --- a/modules/git/repo_base_nogogit.go +++ b/modules/git/repo_base_nogogit.go @@ -103,7 +103,7 @@ func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError } } -func (repo *Repository) Close() (err error) { +func (repo *Repository) Close() error { if repo == nil { return nil } @@ -123,5 +123,5 @@ func (repo *Repository) Close() (err error) { } repo.LastCommitCache = nil repo.tagCache = nil - return err + return nil } diff --git a/modules/indexer/internal/bleve/indexer.go b/modules/indexer/internal/bleve/indexer.go index 531866ad0f..a168e0cb9b 100644 --- a/modules/indexer/internal/bleve/indexer.go +++ b/modules/indexer/internal/bleve/indexer.go @@ -91,7 +91,7 @@ func (i *Indexer) Ping(_ context.Context) error { } func (i *Indexer) Close() { - if i == nil { + if i == nil || i.Indexer == nil { return } diff --git a/modules/indexer/internal/meilisearch/indexer.go b/modules/indexer/internal/meilisearch/indexer.go index b037249d43..f4004849c1 100644 --- a/modules/indexer/internal/meilisearch/indexer.go +++ b/modules/indexer/internal/meilisearch/indexer.go @@ -87,8 +87,5 @@ func (i *Indexer) Close() { if i == nil { return } - if i.Client == nil { - return - } i.Client = nil } diff --git a/modules/util/filebuffer/file_backed_buffer.go b/modules/util/filebuffer/file_backed_buffer.go index 6b07bd0413..739543e297 100644 --- a/modules/util/filebuffer/file_backed_buffer.go +++ b/modules/util/filebuffer/file_backed_buffer.go @@ -149,6 +149,7 @@ func (b *FileBackedBuffer) Close() error { if b.file != nil { err := b.file.Close() os.Remove(b.file.Name()) + b.file = nil return err } return nil From 630d3f929ec23e2eac683e6df081d4023a54ab8f Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 25 Feb 2024 21:37:35 +0800 Subject: [PATCH 57/64] Make actions animation rotate counterclockwisely (#29378) Because the icon is:  So it must rotate counterclockwisely (cherry picked from commit ea164aba4b697aa08e4d20d896a8f318c09a6523) --- web_src/js/components/RepoActionView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index c4a7389bc5..3801848519 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -760,7 +760,7 @@ export function initRepositoryActionView() { @keyframes job-status-rotate-keyframes { 100% { - transform: rotate(360deg); + transform: rotate(-360deg); } } From 70f3c32b91d82e3b726fd2eef73030ab7862062c Mon Sep 17 00:00:00 2001 From: wxiaoguang <wxiaoguang@gmail.com> Date: Sun, 25 Feb 2024 22:02:20 +0800 Subject: [PATCH 58/64] Remove incorrect and unnecessary Escape from templates (#29394) Follow #29165 * some of them are incorrect, which would lead to double escaping (eg: `(print (Escape $.RepoLink)`) * other of them are not necessary, because `Tr` handles strings&HTML automatically Suggest to review by "unified view": https://github.com/go-gitea/gitea/pull/29394/files?diff=unified&w=0 (cherry picked from commit d2f6588b66549b33adf8bac7044d03c89d668470) Conflicts: templates/code/searchcombo.tmpl templates/mail/auth/register_notify.tmpl templates/mail/issue/default.tmpl templates/repo/code/recently_pushed_new_branches.tmpl templates/repo/search.tmpl templates/repo/settings/protected_branch.tmpl templates/user/auth/activate.tmpl templates/user/auth/forgot_passwd.tmpl templates/user/dashboard/feeds.tmpl context --- modules/templates/helper.go | 4 +- templates/code/searchcombo.tmpl | 2 +- templates/explore/repo_search.tmpl | 2 +- templates/mail/auth/register_notify.tmpl | 2 +- templates/mail/issue/default.tmpl | 18 +++---- templates/package/shared/list.tmpl | 4 +- templates/package/shared/versionlist.tmpl | 2 +- templates/package/view.tmpl | 4 +- .../code/recently_pushed_new_branches.tmpl | 2 +- templates/repo/create_helper.tmpl | 2 +- templates/repo/diff/comments.tmpl | 6 +-- templates/repo/diff/compare.tmpl | 8 ++-- templates/repo/editor/commit_form.tmpl | 2 +- templates/repo/issue/card.tmpl | 6 +-- templates/repo/issue/new_form.tmpl | 2 +- templates/repo/issue/view_content.tmpl | 8 ++-- .../repo/issue/view_content/comments.tmpl | 38 +++++++-------- .../repo/issue/view_content/conversation.tmpl | 2 +- templates/repo/issue/view_content/pull.tmpl | 4 +- .../repo/issue/view_content/sidebar.tmpl | 8 ++-- templates/repo/issue/view_title.tmpl | 6 +-- templates/repo/search.tmpl | 2 +- templates/repo/settings/protected_branch.tmpl | 2 +- templates/repo/wiki/view.tmpl | 2 +- templates/shared/issuelist.tmpl | 6 +-- templates/user/auth/activate.tmpl | 6 +-- templates/user/auth/forgot_passwd.tmpl | 2 +- templates/user/dashboard/feeds.tmpl | 48 +++++++++---------- 28 files changed, 100 insertions(+), 100 deletions(-) diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 8e891bdc24..708de57c91 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -37,7 +37,7 @@ func NewFuncMap() template.FuncMap { "Eval": Eval, "SafeHTML": SafeHTML, "HTMLFormat": HTMLFormat, - "Escape": Escape, + "HTMLEscape": HTMLEscape, "QueryEscape": url.QueryEscape, "JSEscape": JSEscapeSafe, "Str2html": Str2html, // TODO: rename it to SanitizeHTML @@ -221,7 +221,7 @@ func Str2html(s any) template.HTML { panic(fmt.Sprintf("unexpected type %T", s)) } -func Escape(s any) template.HTML { +func HTMLEscape(s any) template.HTML { switch v := s.(type) { case string: return template.HTML(html.EscapeString(v)) diff --git a/templates/code/searchcombo.tmpl b/templates/code/searchcombo.tmpl index 48dc13b47b..d451bc0ad8 100644 --- a/templates/code/searchcombo.tmpl +++ b/templates/code/searchcombo.tmpl @@ -7,7 +7,7 @@ </div> {{else if .SearchResults}} <h3> - {{ctx.Locale.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html}} + {{ctx.Locale.Tr "explore.code_search_results" .Keyword}} </h3> {{template "code/searchresults" .}} {{else if .Keyword}} diff --git a/templates/explore/repo_search.tmpl b/templates/explore/repo_search.tmpl index d8044767a2..1fd891cca2 100644 --- a/templates/explore/repo_search.tmpl +++ b/templates/explore/repo_search.tmpl @@ -38,7 +38,7 @@ </div> {{if and .PageIsExploreRepositories .OnlyShowRelevant}} <div class="ui message explore-relevancy-note"> - <span data-tooltip-content="{{ctx.Locale.Tr "explore.relevant_repositories_tooltip"}}">{{ctx.Locale.Tr "explore.relevant_repositories" ((printf "?only_show_relevant=0&sort=%s&q=%s&language=%s" $.SortType (QueryEscape $.Keyword) (QueryEscape $.Language))|Escape)}}</span> + <span data-tooltip-content="{{ctx.Locale.Tr "explore.relevant_repositories_tooltip"}}">{{ctx.Locale.Tr "explore.relevant_repositories" (printf "?only_show_relevant=0&sort=%s&q=%s&language=%s" $.SortType (QueryEscape $.Keyword) (QueryEscape $.Language))}}</span> </div> {{end}} <div class="divider"></div> diff --git a/templates/mail/auth/register_notify.tmpl b/templates/mail/auth/register_notify.tmpl index 3cdb456fb3..224c845452 100644 --- a/templates/mail/auth/register_notify.tmpl +++ b/templates/mail/auth/register_notify.tmpl @@ -11,7 +11,7 @@ <p>{{.locale.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}</p><br> <p>{{.locale.Tr "mail.register_notify.text_1" AppName}}</p><br> <p>{{.locale.Tr "mail.register_notify.text_2" .Username}}</p><p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p><br> - <p>{{.locale.Tr "mail.register_notify.text_3" ($set_pwd_url | Escape) | Str2html}}</p><br> + <p>{{.locale.Tr "mail.register_notify.text_3" $set_pwd_url}}</p><br> <p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p> </body> diff --git a/templates/mail/issue/default.tmpl b/templates/mail/issue/default.tmpl index ef90433c3a..49887e1e1d 100644 --- a/templates/mail/issue/default.tmpl +++ b/templates/mail/issue/default.tmpl @@ -36,26 +36,26 @@ {{end}} <p> {{if eq .ActionName "close"}} - {{.locale.Tr "mail.issue.action.close" (Escape .Doer.Name) .Issue.Index | Str2html}} + {{.locale.Tr "mail.issue.action.close" .Doer.Name .Issue.Index}} {{else if eq .ActionName "reopen"}} - {{.locale.Tr "mail.issue.action.reopen" (Escape .Doer.Name) .Issue.Index | Str2html}} + {{.locale.Tr "mail.issue.action.reopen" .Doer.Name .Issue.Index}} {{else if eq .ActionName "merge"}} - {{.locale.Tr "mail.issue.action.merge" (Escape .Doer.Name) .Issue.Index (Escape .Issue.PullRequest.BaseBranch) | Str2html}} + {{.locale.Tr "mail.issue.action.merge" .Doer.Name .Issue.Index .Issue.PullRequest.BaseBranch}} {{else if eq .ActionName "approve"}} - {{.locale.Tr "mail.issue.action.approve" (Escape .Doer.Name) | Str2html}} + {{.locale.Tr "mail.issue.action.approve" .Doer.Name}} {{else if eq .ActionName "reject"}} - {{.locale.Tr "mail.issue.action.reject" (Escape .Doer.Name) | Str2html}} + {{.locale.Tr "mail.issue.action.reject" .Doer.Name}} {{else if eq .ActionName "review"}} - {{.locale.Tr "mail.issue.action.review" (Escape .Doer.Name) | Str2html}} + {{.locale.Tr "mail.issue.action.review" .Doer.Name}} {{else if eq .ActionName "review_dismissed"}} - {{.locale.Tr "mail.issue.action.review_dismissed" (Escape .Doer.Name) (Escape .Comment.Review.Reviewer.Name) | Str2html}} + {{.locale.Tr "mail.issue.action.review_dismissed" .Doer.Name .Comment.Review.Reviewer.Name}} {{else if eq .ActionName "ready_for_review"}} - {{.locale.Tr "mail.issue.action.ready_for_review" (Escape .Doer.Name) | Str2html}} + {{.locale.Tr "mail.issue.action.ready_for_review" .Doer.Name}} {{end}} {{- if eq .Body ""}} {{if eq .ActionName "new"}} - {{.locale.Tr "mail.issue.action.new" (Escape .Doer.Name) .Issue.Index | Str2html}} + {{.locale.Tr "mail.issue.action.new" .Doer.Name .Issue.Index}} {{end}} {{else}} {{.Body | Str2html}} diff --git a/templates/package/shared/list.tmpl b/templates/package/shared/list.tmpl index 78f9edea39..67c686675c 100644 --- a/templates/package/shared/list.tmpl +++ b/templates/package/shared/list.tmpl @@ -30,9 +30,9 @@ {{$hasRepositoryAccess = index $.RepositoryAccessMap .Repository.ID}} {{end}} {{if $hasRepositoryAccess}} - {{ctx.Locale.Tr "packages.published_by_in" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) .Repository.Link (.Repository.FullName | Escape)}} + {{ctx.Locale.Tr "packages.published_by_in" $timeStr .Creator.HomeLink .Creator.GetDisplayName .Repository.Link .Repository.FullName}} {{else}} - {{ctx.Locale.Tr "packages.published_by" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape)}} + {{ctx.Locale.Tr "packages.published_by" $timeStr .Creator.HomeLink .Creator.GetDisplayName}} {{end}} </div> </div> diff --git a/templates/package/shared/versionlist.tmpl b/templates/package/shared/versionlist.tmpl index 4b22dc22b2..eee952c096 100644 --- a/templates/package/shared/versionlist.tmpl +++ b/templates/package/shared/versionlist.tmpl @@ -25,7 +25,7 @@ <div class="flex-item-main"> <a class="flex-item-title" href="{{.FullWebLink}}">{{.Version.LowerVersion}}</a> <div class="flex-item-body"> - {{ctx.Locale.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix ctx.Locale) .Creator.HomeLink (.Creator.GetDisplayName | Escape)}} + {{ctx.Locale.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix ctx.Locale) .Creator.HomeLink .Creator.GetDisplayName}} </div> </div> </div> diff --git a/templates/package/view.tmpl b/templates/package/view.tmpl index 65502a6e4d..0fa23d67fd 100644 --- a/templates/package/view.tmpl +++ b/templates/package/view.tmpl @@ -10,9 +10,9 @@ <div> {{$timeStr := TimeSinceUnix .PackageDescriptor.Version.CreatedUnix ctx.Locale}} {{if .HasRepositoryAccess}} - {{ctx.Locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) .PackageDescriptor.Repository.Link (.PackageDescriptor.Repository.FullName | Escape)}} + {{ctx.Locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink .PackageDescriptor.Creator.GetDisplayName .PackageDescriptor.Repository.Link .PackageDescriptor.Repository.FullName}} {{else}} - {{ctx.Locale.Tr "packages.published_by" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape)}} + {{ctx.Locale.Tr "packages.published_by" $timeStr .PackageDescriptor.Creator.HomeLink .PackageDescriptor.Creator.GetDisplayName}} {{end}} </div> </div> diff --git a/templates/repo/code/recently_pushed_new_branches.tmpl b/templates/repo/code/recently_pushed_new_branches.tmpl index 85b78118d5..eac9d0e243 100644 --- a/templates/repo/code/recently_pushed_new_branches.tmpl +++ b/templates/repo/code/recently_pushed_new_branches.tmpl @@ -8,7 +8,7 @@ {{$name = (print $repo.FullName ":" .Name)}} {{end}} {{$branchLink := (print ($repo.Link) "/src/branch/" (PathEscapeSegments .Name))}} - {{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" (Escape $name) $timeSince $branchLink}} + {{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" $name $timeSince $branchLink}} </div> <a role="button" class="ui compact positive button gt-m-0" href="{{$.Repository.ComposeBranchCompareURL $.Repository.BaseRepo $name}}"> {{ctx.Locale.Tr "repo.pulls.compare_changes"}} diff --git a/templates/repo/create_helper.tmpl b/templates/repo/create_helper.tmpl index 6ca691592c..70c28b72e8 100644 --- a/templates/repo/create_helper.tmpl +++ b/templates/repo/create_helper.tmpl @@ -1,3 +1,3 @@ {{if not $.DisableMigrations}} - <p class="ui center">{{ctx.Locale.Tr "repo.new_repo_helper" ((print AppSubUrl "/repo/migrate")|Escape)}}</p> + <p class="ui center">{{ctx.Locale.Tr "repo.new_repo_helper" (print AppSubUrl "/repo/migrate")}}</p> {{end}} diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index b3d06ed6bc..7cabeabd57 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -16,17 +16,17 @@ {{.OriginalAuthor}} </span> <span class="text grey muted-links"> - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdStr}} </span> <span class="text migrate"> {{if $.root.Repository.OriginalURL}} - ({{ctx.Locale.Tr "repo.migrated_from" ($.root.Repository.OriginalURL | Escape) ($.root.Repository.GetOriginalURLHostname | Escape)}}) + ({{ctx.Locale.Tr "repo.migrated_from" $.root.Repository.OriginalURL $.root.Repository.GetOriginalURLHostname}}) {{end}} </span> {{else}} <span class="text grey muted-links"> {{template "shared/user/namelink" .Poster}} - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdStr}} </span> {{end}} </div> diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index b18908577a..65b85b9686 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -194,7 +194,7 @@ {{if .HasPullRequest}} <div class="ui segment grid title"> <div class="twelve wide column issue-title"> - {{ctx.Locale.Tr "repo.pulls.has_pull_request" (print (Escape $.RepoLink) "/pulls/" .PullRequest.Issue.Index) (Escape $.RepoRelPath) .PullRequest.Index}} + {{ctx.Locale.Tr "repo.pulls.has_pull_request" (print $.RepoLink "/pulls/" .PullRequest.Issue.Index) $.RepoRelPath .PullRequest.Index}} <h1> <span id="issue-title">{{RenderIssueTitle $.Context .PullRequest.Issue.Title ($.Repository.ComposeMetas ctx)}}</span> <span class="index">#{{.PullRequest.Issue.Index}}</span> @@ -202,11 +202,11 @@ </div> <div class="four wide column middle aligned text right"> {{- if .PullRequest.HasMerged -}} - <a href="{{Escape $.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button purple show-form">{{svg "octicon-git-merge" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> + <a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button purple show-form">{{svg "octicon-git-merge" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> {{else if .Issue.IsClosed}} - <a href="{{Escape $.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button red show-form">{{svg "octicon-issue-closed" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> + <a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button red show-form">{{svg "octicon-issue-closed" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> {{else}} - <a href="{{Escape $.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button primary show-form">{{svg "octicon-git-pull-request" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> + <a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button primary show-form">{{svg "octicon-git-pull-request" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> {{end}} </div> </div> diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl index 87b2286319..2c9bdb44b5 100644 --- a/templates/repo/editor/commit_form.tmpl +++ b/templates/repo/editor/commit_form.tmpl @@ -26,7 +26,7 @@ <input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="direct" button_text="{{ctx.Locale.Tr "repo.editor.commit_changes"}}" {{if eq .commit_choice "direct"}}checked{{end}}> <label> {{svg "octicon-git-commit"}} - {{ctx.Locale.Tr "repo.editor.commit_directly_to_this_branch" (.BranchName|Escape)}} + {{ctx.Locale.Tr "repo.editor.commit_directly_to_this_branch" .BranchName}} {{if not .CanCommitToBranch.CanCommitToBranch}} <div class="ui visible small warning message"> {{ctx.Locale.Tr "repo.editor.no_commit_to_branch"}} diff --git a/templates/repo/issue/card.tmpl b/templates/repo/issue/card.tmpl index 7b71bd724e..7fb3d82827 100644 --- a/templates/repo/issue/card.tmpl +++ b/templates/repo/issue/card.tmpl @@ -23,11 +23,11 @@ {{if not $.Page.Repository}}{{.Repo.FullName}}{{end}}#{{.Index}} {{$timeStr := TimeSinceUnix .GetLastEventTimestamp ctx.Locale}} {{if .OriginalAuthor}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape)}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor}} {{else if gt .Poster.ID 0}} - {{ctx.Locale.Tr .GetLastEventLabel $timeStr (.Poster.HomeLink|Escape) (.Poster.GetDisplayName | Escape)}} + {{ctx.Locale.Tr .GetLastEventLabel $timeStr .Poster.HomeLink .Poster.GetDisplayName}} {{else}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape)}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .Poster.GetDisplayName}} {{end}} </span> </div> diff --git a/templates/repo/issue/new_form.tmpl b/templates/repo/issue/new_form.tmpl index d1cbba6873..8e4310f0bb 100644 --- a/templates/repo/issue/new_form.tmpl +++ b/templates/repo/issue/new_form.tmpl @@ -13,7 +13,7 @@ <div class="field"> <input name="title" id="issue_title" placeholder="{{ctx.Locale.Tr "repo.milestones.title"}}" value="{{if .TitleQuery}}{{.TitleQuery}}{{else if .IssueTemplateTitle}}{{.IssueTemplateTitle}}{{else}}{{.title}}{{end}}" autofocus required maxlength="255" autocomplete="off"> {{if .PageIsComparePull}} - <div class="title_wip_desc" data-wip-prefixes="{{JsonUtils.EncodeToString .PullRequestWorkInProgressPrefixes}}">{{ctx.Locale.Tr "repo.pulls.title_wip_desc" (index .PullRequestWorkInProgressPrefixes 0| Escape)}}</div> + <div class="title_wip_desc" data-wip-prefixes="{{JsonUtils.EncodeToString .PullRequestWorkInProgressPrefixes}}">{{ctx.Locale.Tr "repo.pulls.title_wip_desc" (index .PullRequestWorkInProgressPrefixes 0)}}</div> {{end}} </div> {{if .Fields}} diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index 793772ecd0..91db68c810 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -28,10 +28,10 @@ {{.Issue.OriginalAuthor}} </span> <span class="text grey muted-links"> - {{ctx.Locale.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr}} </span> <span class="text migrate"> - {{if .Repository.OriginalURL}} ({{ctx.Locale.Tr "repo.migrated_from" (.Repository.OriginalURL|Escape) (.Repository.GetOriginalURLHostname|Escape)}}){{end}} + {{if .Repository.OriginalURL}} ({{ctx.Locale.Tr "repo.migrated_from" .Repository.OriginalURL .Repository.GetOriginalURLHostname}}){{end}} </span> {{else}} <a class="inline-timeline-avatar" href="{{.Issue.Poster.HomeLink}}"> @@ -39,7 +39,7 @@ </a> <span class="text grey muted-links"> {{template "shared/user/authorlink" .Issue.Poster}} - {{ctx.Locale.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr}} </span> {{end}} </div> @@ -133,7 +133,7 @@ </div> {{else}} <div class="ui warning message"> - {{ctx.Locale.Tr "repo.issues.sign_in_require_desc" (.SignInLink|Escape)}} + {{ctx.Locale.Tr "repo.issues.sign_in_require_desc" .SignInLink}} </div> {{end}} {{end}}{{/* end if: .IsSigned */}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 96b0c5ba03..b37d1e069f 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -33,10 +33,10 @@ {{.OriginalAuthor}} </span> <span class="text grey muted-links"> - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr}} {{if $.Repository.OriginalURL}} + {{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdStr}} {{if $.Repository.OriginalURL}} </span> <span class="text migrate"> - ({{ctx.Locale.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape)}}){{end}} + ({{ctx.Locale.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname}}){{end}} </span> {{else}} {{if gt .Poster.ID 0}} @@ -46,7 +46,7 @@ {{end}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdStr}} </span> {{end}} </div> @@ -121,7 +121,7 @@ {{else if eq .Type 3 5 6}} {{$refFrom:= ""}} {{if ne .RefRepoID .Issue.RepoID}} - {{$refFrom = ctx.Locale.Tr "repo.issues.ref_from" (.RefRepo.FullName|Escape)}} + {{$refFrom = ctx.Locale.Tr "repo.issues.ref_from" .RefRepo.FullName}} {{end}} {{$refTr := "repo.issues.ref_issue_from"}} {{if .Issue.IsPull}} @@ -138,7 +138,7 @@ {{if eq .RefAction 3}}<del>{{end}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr $refTr (.EventTag|Escape) $createdStr ((.RefCommentLink ctx)|Escape) $refFrom}} + {{ctx.Locale.Tr $refTr .EventTag $createdStr (.RefCommentLink ctx) $refFrom}} </span> {{if eq .RefAction 3}}</del>{{end}} @@ -186,7 +186,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{if gt .OldMilestoneID 0}}{{if gt .MilestoneID 0}}{{ctx.Locale.Tr "repo.issues.change_milestone_at" (.OldMilestone.Name|Escape) (.Milestone.Name|Escape) $createdStr}}{{else}}{{ctx.Locale.Tr "repo.issues.remove_milestone_at" (.OldMilestone.Name|Escape) $createdStr}}{{end}}{{else if gt .MilestoneID 0}}{{ctx.Locale.Tr "repo.issues.add_milestone_at" (.Milestone.Name|Escape) $createdStr}}{{end}} + {{if gt .OldMilestoneID 0}}{{if gt .MilestoneID 0}}{{ctx.Locale.Tr "repo.issues.change_milestone_at" .OldMilestone.Name .Milestone.Name $createdStr}}{{else}}{{ctx.Locale.Tr "repo.issues.remove_milestone_at" .OldMilestone.Name $createdStr}}{{end}}{{else if gt .MilestoneID 0}}{{ctx.Locale.Tr "repo.issues.add_milestone_at" .Milestone.Name $createdStr}}{{end}} </span> </div> {{else if and (eq .Type 9) (gt .AssigneeID 0)}} @@ -199,7 +199,7 @@ {{if eq .Poster.ID .Assignee.ID}} {{ctx.Locale.Tr "repo.issues.remove_self_assignment" $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.remove_assignee_at" (.Poster.GetDisplayName|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.remove_assignee_at" .Poster.GetDisplayName $createdStr}} {{end}} </span> {{else}} @@ -209,7 +209,7 @@ {{if eq .Poster.ID .AssigneeID}} {{ctx.Locale.Tr "repo.issues.self_assign_at" $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.add_assignee_at" (.Poster.GetDisplayName|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.add_assignee_at" .Poster.GetDisplayName $createdStr}} {{end}} </span> {{end}} @@ -229,7 +229,7 @@ {{template "shared/user/avatarlink" dict "user" .Poster}} <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} - {{ctx.Locale.Tr "repo.issues.delete_branch_at" (.OldRef|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.delete_branch_at" .OldRef $createdStr}} </span> </div> {{else if eq .Type 12}} @@ -422,7 +422,7 @@ {{.OriginalAuthor}} </span> <span class="text grey muted-links"> {{if $.Repository.OriginalURL}}</span> - <span class="text migrate">({{ctx.Locale.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape)}}){{end}}</span> + <span class="text migrate">({{ctx.Locale.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname}}){{end}}</span> {{else}} {{template "shared/user/authorlink" .Poster}} {{end}} @@ -513,7 +513,7 @@ {{else}} {{template "shared/user/authorlink" .Poster}} {{end}} - {{ctx.Locale.Tr "repo.pulls.change_target_branch_at" (.OldRef|Escape) (.NewRef|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.pulls.change_target_branch_at" .OldRef .NewRef $createdStr}} </span> </div> {{else if eq .Type 26}} @@ -546,10 +546,10 @@ {{if eq .PosterID .AssigneeID}} {{ctx.Locale.Tr "repo.issues.review.remove_review_request_self" $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.review.remove_review_request" (.Assignee.GetDisplayName|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.review.remove_review_request" .Assignee.GetDisplayName $createdStr}} {{end}} {{else}} - {{ctx.Locale.Tr "repo.issues.review.add_review_request" (.Assignee.GetDisplayName|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.review.add_review_request" .Assignee.GetDisplayName $createdStr}} {{end}} {{else}} <!-- If the assigned team is deleted, just displaying "Ghost Team" in the comment --> @@ -558,9 +558,9 @@ {{$teamName = .AssigneeTeam.Name}} {{end}} {{if .RemovedAssignee}} - {{ctx.Locale.Tr "repo.issues.review.remove_review_request" ($teamName|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.review.remove_review_request" $teamName $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.review.add_review_request" ($teamName|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.review.add_review_request" $teamName $createdStr}} {{end}} {{end}} </span> @@ -575,7 +575,7 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} {{if .IsForcePush}} - {{ctx.Locale.Tr "repo.issues.force_push_codes" ($.Issue.PullRequest.HeadBranch|Escape) (ShortSha .OldCommit) (($.Issue.Repo.CommitLink .OldCommit)|Escape) (ShortSha .NewCommit) (($.Issue.Repo.CommitLink .NewCommit)|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.force_push_codes" $.Issue.PullRequest.HeadBranch (ShortSha .OldCommit) ($.Issue.Repo.CommitLink .OldCommit) (ShortSha .NewCommit) ($.Issue.Repo.CommitLink .NewCommit) $createdStr}} {{else}} {{ctx.Locale.TrN (len .Commits) "repo.issues.push_commit_1" "repo.issues.push_commits_n" (len .Commits) $createdStr}} {{end}} @@ -667,11 +667,11 @@ <span class="text grey muted-links"> {{template "shared/user/authorlink" .Poster}} {{if and .OldRef .NewRef}} - {{ctx.Locale.Tr "repo.issues.change_ref_at" (.OldRef|Escape) (.NewRef|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.change_ref_at" .OldRef .NewRef $createdStr}} {{else if .OldRef}} - {{ctx.Locale.Tr "repo.issues.remove_ref_at" (.OldRef|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.remove_ref_at" .OldRef $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.add_ref_at" (.NewRef|Escape) $createdStr}} + {{ctx.Locale.Tr "repo.issues.add_ref_at" .NewRef $createdStr}} {{end}} </span> </div> diff --git a/templates/repo/issue/view_content/conversation.tmpl b/templates/repo/issue/view_content/conversation.tmpl index 1bc850d8cf..dbc8249068 100644 --- a/templates/repo/issue/view_content/conversation.tmpl +++ b/templates/repo/issue/view_content/conversation.tmpl @@ -73,7 +73,7 @@ {{else}} {{template "shared/user/authorlink" .Poster}} {{end}} - {{ctx.Locale.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdSubStr}} + {{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdSubStr}} </span> </div> <div class="comment-header-right actions gt-df gt-ac"> diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 371c9db6f0..c8e8038438 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -81,14 +81,14 @@ {{ctx.Locale.Tr "repo.pulls.data_broken"}} </div> {{else if .IsPullWorkInProgress}} - <div class="item toggle-wip" data-title="{{.Issue.Title}}" data-wip-prefix="{{(.WorkInProgressPrefix|Escape)}}" data-update-url="{{.Issue.Link}}/title"> + <div class="item toggle-wip" data-title="{{.Issue.Title}}" data-wip-prefix="{{.WorkInProgressPrefix}}" data-update-url="{{.Issue.Link}}/title"> <div class="item-section-left flex-text-inline gt-f1"> {{svg "octicon-x"}} {{ctx.Locale.Tr "repo.pulls.cannot_merge_work_in_progress"}} </div> {{if or .HasIssuesOrPullsWritePermission .IsIssuePoster}} <button class="ui compact button"> - {{ctx.Locale.Tr "repo.pulls.remove_prefix" (.WorkInProgressPrefix|Escape)}} + {{ctx.Locale.Tr "repo.pulls.remove_prefix" .WorkInProgressPrefix}} </button> {{end}} </div> diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index bb45b07421..f5b6751d6d 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -101,7 +101,7 @@ {{range .OriginalReviews}} <div class="item gt-df gt-ac gt-py-3"> <div class="gt-df gt-ac gt-f1"> - <a class="muted" href="{{$.Repository.OriginalURL}}" data-tooltip-content="{{ctx.Locale.Tr "repo.migrated_from_fake" ($.Repository.GetOriginalURLHostname|Escape)}}"> + <a class="muted" href="{{$.Repository.OriginalURL}}" data-tooltip-content="{{ctx.Locale.Tr "repo.migrated_from_fake" $.Repository.GetOriginalURLHostname}}"> {{svg (MigrationIcon $.Repository.GetOriginalURLHostname) 20 "gt-mr-3"}} {{.OriginalAuthor}} </a> @@ -114,9 +114,9 @@ </div> </div> {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .HasMerged) (not .Issue.IsClosed) (not .IsPullWorkInProgress)}} - <div class="toggle-wip" data-title="{{.Issue.Title}}" data-wip-prefix="{{(index .PullRequestWorkInProgressPrefixes 0| Escape)}}" data-update-url="{{.Issue.Link}}/title"> + <div class="toggle-wip" data-title="{{.Issue.Title}}" data-wip-prefix="{{index .PullRequestWorkInProgressPrefixes 0}}" data-update-url="{{.Issue.Link}}/title"> <a class="muted"> - {{ctx.Locale.Tr "repo.pulls.still_in_progress"}} {{ctx.Locale.Tr "repo.pulls.add_prefix" (index .PullRequestWorkInProgressPrefixes 0| Escape)}} + {{ctx.Locale.Tr "repo.pulls.still_in_progress"}} {{ctx.Locale.Tr "repo.pulls.add_prefix" (index .PullRequestWorkInProgressPrefixes 0)}} </a> </div> {{end}} @@ -300,7 +300,7 @@ {{else}} {{if .HasUserStopwatch}} <div class="ui warning message"> - {{ctx.Locale.Tr "repo.issues.tracking_already_started" (.OtherStopwatchURL|Escape)}} + {{ctx.Locale.Tr "repo.issues.tracking_already_started" .OtherStopwatchURL}} </div> {{end}} <button class="ui fluid button issue-start-time" data-tooltip-content='{{ctx.Locale.Tr "repo.issues.start_tracking"}}'> diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index d6c8146451..6a60c68ec3 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -112,11 +112,11 @@ {{$createdStr:= TimeSinceUnix .Issue.CreatedUnix ctx.Locale}} <span class="time-desc"> {{if .Issue.OriginalAuthor}} - {{ctx.Locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.OriginalAuthor|Escape)}} + {{ctx.Locale.Tr "repo.issues.opened_by_fake" $createdStr .Issue.OriginalAuthor}} {{else if gt .Issue.Poster.ID 0}} - {{ctx.Locale.Tr "repo.issues.opened_by" $createdStr (.Issue.Poster.HomeLink|Escape) (.Issue.Poster.GetDisplayName|Escape)}} + {{ctx.Locale.Tr "repo.issues.opened_by" $createdStr .Issue.Poster.HomeLink .Issue.Poster.GetDisplayName}} {{else}} - {{ctx.Locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.Poster.GetDisplayName|Escape)}} + {{ctx.Locale.Tr "repo.issues.opened_by_fake" $createdStr .Issue.Poster.GetDisplayName}} {{end}} · {{ctx.Locale.TrN .Issue.NumComments "repo.issues.num_comments_1" "repo.issues.num_comments" .Issue.NumComments}} diff --git a/templates/repo/search.tmpl b/templates/repo/search.tmpl index 3b5c212af3..d0d376f1c4 100644 --- a/templates/repo/search.tmpl +++ b/templates/repo/search.tmpl @@ -26,7 +26,7 @@ </div> {{else if .Keyword}} <h3> - {{ctx.Locale.Tr "repo.search.results" (.Keyword|Escape) (.RepoLink|Escape) (.RepoName|Escape) | Str2html}} + {{ctx.Locale.Tr "repo.search.results" .Keyword .RepoLink .RepoName}} </h3> {{if .SearchResults}} <div class="flex-text-block gt-fw"> diff --git a/templates/repo/settings/protected_branch.tmpl b/templates/repo/settings/protected_branch.tmpl index e2f841f758..6bbcc9f6ec 100644 --- a/templates/repo/settings/protected_branch.tmpl +++ b/templates/repo/settings/protected_branch.tmpl @@ -2,7 +2,7 @@ <div class="repo-setting-content"> <form class="ui form" action="{{.Link}}" method="post"> <h4 class="ui top attached header"> - {{ctx.Locale.Tr "repo.settings.branch_protection" (.Rule.RuleName|Escape) | Str2html}} + {{ctx.Locale.Tr "repo.settings.branch_protection" .Rule.RuleName}} </h4> <div class="ui attached segment branch-protection"> <h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.protect_patterns"}}</h5> diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index f3b6be97cf..9fa05b5b5c 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -107,7 +107,7 @@ {{ctx.Locale.Tr "repo.wiki.delete_page_button"}} </div> <div class="content"> - <p>{{ctx.Locale.Tr "repo.wiki.delete_page_notice_1" ($title|Escape)}}</p> + <p>{{ctx.Locale.Tr "repo.wiki.delete_page_notice_1" $title}}</p> </div> {{template "base/modal_actions_confirm" .}} </div> diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index 7940234ccc..e8a0079c1c 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -62,11 +62,11 @@ </a> {{$timeStr := TimeSinceUnix .GetLastEventTimestamp ctx.Locale}} {{if .OriginalAuthor}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape)}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor}} {{else if gt .Poster.ID 0}} - {{ctx.Locale.Tr .GetLastEventLabel $timeStr (.Poster.HomeLink|Escape) (.Poster.GetDisplayName | Escape)}} + {{ctx.Locale.Tr .GetLastEventLabel $timeStr .Poster.HomeLink .Poster.GetDisplayName}} {{else}} - {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape)}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .Poster.GetDisplayName}} {{end}} {{if .IsPull}} <div class="branches flex-text-inline"> diff --git a/templates/user/auth/activate.tmpl b/templates/user/auth/activate.tmpl index d8a737e996..c9ee8cac33 100644 --- a/templates/user/auth/activate.tmpl +++ b/templates/user/auth/activate.tmpl @@ -15,7 +15,7 @@ {{else if .ResendLimited}} <p class="center">{{ctx.Locale.Tr "auth.resent_limit_prompt"}}</p> {{else}} - <p>{{ctx.Locale.Tr "auth.confirmation_mail_sent_prompt" (.SignedUser.Email|Escape) .ActiveCodeLives | Str2html}}</p> + <p>{{ctx.Locale.Tr "auth.confirmation_mail_sent_prompt" .SignedUser.Email .ActiveCodeLives}}</p> {{end}} {{else}} {{if .NeedsPassword}} @@ -29,7 +29,7 @@ </div> <input id="code" name="code" type="hidden" value="{{.Code}}"> {{else if .IsSendRegisterMail}} - <p>{{ctx.Locale.Tr "auth.confirmation_mail_sent_prompt" (.Email|Escape) .ActiveCodeLives | Str2html}}</p> + <p>{{ctx.Locale.Tr "auth.confirmation_mail_sent_prompt" .Email .ActiveCodeLives}}</p> {{else if .IsCodeInvalid}} <p>{{ctx.Locale.Tr "auth.invalid_code"}}</p> {{else if .IsPasswordInvalid}} @@ -37,7 +37,7 @@ {{else if .ManualActivationOnly}} <p class="center">{{ctx.Locale.Tr "auth.manual_activation_only"}}</p> {{else}} - <p>{{ctx.Locale.Tr "auth.has_unconfirmed_mail" (.SignedUser.Name|Escape) (.SignedUser.Email|Escape) | Str2html}}</p> + <p>{{ctx.Locale.Tr "auth.has_unconfirmed_mail" .SignedUser.Name .SignedUser.Email}}</p> <div class="divider"></div> <details class="inline field"> <summary>{{ctx.Locale.Tr "auth.change_unconfirmed_email_summary"}}</summary> diff --git a/templates/user/auth/forgot_passwd.tmpl b/templates/user/auth/forgot_passwd.tmpl index dde4c8f6fe..21a630ec5e 100644 --- a/templates/user/auth/forgot_passwd.tmpl +++ b/templates/user/auth/forgot_passwd.tmpl @@ -10,7 +10,7 @@ <div class="ui attached segment"> {{template "base/alert" .}} {{if .IsResetSent}} - <p>{{ctx.Locale.Tr "auth.reset_password_mail_sent_prompt" (Escape .Email) .ResetPwdCodeLives | Str2html}}</p> + <p>{{ctx.Locale.Tr "auth.reset_password_mail_sent_prompt" .Email .ResetPwdCodeLives}}</p> {{else if .IsResetRequest}} <div class="required inline field {{if .Err_Email}}error{{end}}"> <label for="email">{{ctx.Locale.Tr "email"}}</label> diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl index a51365e4d6..6dec610e93 100644 --- a/templates/user/dashboard/feeds.tmpl +++ b/templates/user/dashboard/feeds.tmpl @@ -12,71 +12,71 @@ {{.ShortActUserName ctx}} {{end}} {{if .GetOpType.InActions "create_repo"}} - {{ctx.Locale.Tr "action.create_repo" ((.GetRepoLink ctx)|Escape) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.create_repo" (.GetRepoLink ctx) (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "rename_repo"}} - {{ctx.Locale.Tr "action.rename_repo" (.GetContent|Escape) ((.GetRepoLink ctx)|Escape) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.rename_repo" .GetContent (.GetRepoLink ctx) (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "commit_repo"}} {{if .Content}} - {{ctx.Locale.Tr "action.commit_repo" ((.GetRepoLink ctx)|Escape) ((.GetRefLink ctx)|Escape) (Escape .GetBranch) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.commit_repo" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}} {{else}} - {{ctx.Locale.Tr "action.create_branch" ((.GetRepoLink ctx)|Escape) ((.GetRefLink ctx)|Escape) (Escape .GetBranch) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.create_branch" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}} {{end}} {{else if .GetOpType.InActions "create_issue"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.create_issue" ((printf "%s/issues/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.create_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "create_pull_request"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.create_pull_request" ((printf "%s/pulls/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.create_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "transfer_repo"}} - {{ctx.Locale.Tr "action.transfer_repo" .GetContent ((.GetRepoLink ctx)|Escape) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.transfer_repo" .GetContent (.GetRepoLink ctx) (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "push_tag"}} - {{ctx.Locale.Tr "action.push_tag" ((.GetRepoLink ctx)|Escape) ((.GetRefLink ctx)|Escape) (.GetTag|Escape) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.push_tag" (.GetRepoLink ctx) (.GetRefLink ctx) .GetTag (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "comment_issue"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.comment_issue" ((printf "%s/issues/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.comment_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "merge_pull_request"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.merge_pull_request" ((printf "%s/pulls/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.merge_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "close_issue"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.close_issue" ((printf "%s/issues/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.close_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "reopen_issue"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.reopen_issue" ((printf "%s/issues/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.reopen_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "close_pull_request"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.close_pull_request" ((printf "%s/pulls/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.close_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "reopen_pull_request"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.reopen_pull_request" ((printf "%s/pulls/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.reopen_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "delete_tag"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.delete_tag" ((.GetRepoLink ctx)|Escape) (.GetTag|Escape) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.delete_tag" (.GetRepoLink ctx) .GetTag (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "delete_branch"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.delete_branch" ((.GetRepoLink ctx)|Escape) (.GetBranch|Escape) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.delete_branch" (.GetRepoLink ctx) .GetBranch (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "mirror_sync_push"}} - {{ctx.Locale.Tr "action.mirror_sync_push" ((.GetRepoLink ctx)|Escape) ((.GetRefLink ctx)|Escape) (.GetBranch|Escape) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.mirror_sync_push" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "mirror_sync_create"}} - {{ctx.Locale.Tr "action.mirror_sync_create" ((.GetRepoLink ctx)|Escape) ((.GetRefLink ctx)|Escape) (.GetBranch|Escape) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.mirror_sync_create" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "mirror_sync_delete"}} - {{ctx.Locale.Tr "action.mirror_sync_delete" ((.GetRepoLink ctx)|Escape) (.GetBranch|Escape) ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.mirror_sync_delete" (.GetRepoLink ctx) .GetBranch (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "approve_pull_request"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.approve_pull_request" ((printf "%s/pulls/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.approve_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "reject_pull_request"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.reject_pull_request" ((printf "%s/pulls/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.reject_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "comment_pull"}} {{$index := index .GetIssueInfos 0}} - {{ctx.Locale.Tr "action.comment_pull" ((printf "%s/pulls/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) | Str2html}} + {{ctx.Locale.Tr "action.comment_pull" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}} {{else if .GetOpType.InActions "publish_release"}} {{$linkText := .Content | RenderEmoji $.Context}} - {{ctx.Locale.Tr "action.publish_release" ((.GetRepoLink ctx)|Escape) ((printf "%s/releases/tag/%s" (.GetRepoLink ctx) .GetTag)|Escape) ((.ShortRepoPath ctx)|Escape) $linkText | Str2html}} + {{ctx.Locale.Tr "action.publish_release" (.GetRepoLink ctx) (printf "%s/releases/tag/%s" (.GetRepoLink ctx) .GetTag) (.ShortRepoPath ctx) $linkText}} {{else if .GetOpType.InActions "review_dismissed"}} {{$index := index .GetIssueInfos 0}} {{$reviewer := index .GetIssueInfos 1}} - {{ctx.Locale.Tr "action.review_dismissed" ((printf "%s/pulls/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) $reviewer | Str2html}} + {{ctx.Locale.Tr "action.review_dismissed" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx) $reviewer}} {{end}} {{TimeSince .GetCreate ctx.Locale}} </div> From 4662f4feacaf6e99e8e163829a7a78fb7aeef717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Niclas=20Oelschl=C3=A4ger?= <72873130+zokkis@users.noreply.github.com> Date: Sun, 25 Feb 2024 15:31:15 +0100 Subject: [PATCH 59/64] enforce maxlength in frontend (#29389) Set maxlength attribute in frontend to long file-name   (same for branch-name and commit-summary) (cherry picked from commit 756b952c52f1efbb137df36d5b97b370c8a45565) --- templates/repo/editor/commit_form.tmpl | 4 ++-- templates/repo/editor/edit.tmpl | 2 +- templates/repo/editor/patch.tmpl | 2 +- templates/repo/editor/upload.tmpl | 2 +- web_src/js/utils.js | 7 ++++--- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl index 2c9bdb44b5..72af3e9ef3 100644 --- a/templates/repo/editor/commit_form.tmpl +++ b/templates/repo/editor/commit_form.tmpl @@ -9,7 +9,7 @@ {{ctx.Locale.Tr "repo.editor.commit_changes"}} {{- end}}</h3> <div class="field"> - <input name="commit_summary" placeholder="{{if .PageIsDelete}}{{ctx.Locale.Tr "repo.editor.delete" .TreePath}}{{else if .PageIsUpload}}{{ctx.Locale.Tr "repo.editor.upload_files_to_dir" .TreePath}}{{else if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.add_tmpl"}}{{else if .PageIsPatch}}{{ctx.Locale.Tr "repo.editor.patch"}}{{else}}{{ctx.Locale.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}" autofocus> + <input name="commit_summary" maxlength="100" placeholder="{{if .PageIsDelete}}{{ctx.Locale.Tr "repo.editor.delete" .TreePath}}{{else if .PageIsUpload}}{{ctx.Locale.Tr "repo.editor.upload_files_to_dir" .TreePath}}{{else if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.add_tmpl"}}{{else if .PageIsPatch}}{{ctx.Locale.Tr "repo.editor.patch"}}{{else}}{{ctx.Locale.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}" autofocus> </div> <div class="field"> <textarea name="commit_message" placeholder="{{ctx.Locale.Tr "repo.editor.commit_message_desc"}}" rows="5">{{.commit_message}}</textarea> @@ -60,7 +60,7 @@ <div class="quick-pull-branch-name {{if not (eq .commit_choice "commit-to-new-branch")}}gt-hidden{{end}}"> <div class="new-branch-name-input field {{if .Err_NewBranchName}}error{{end}}"> {{svg "octicon-git-branch"}} - <input type="text" name="new_branch_name" value="{{.new_branch_name}}" class="input-contrast gt-mr-2 js-quick-pull-new-branch-name" placeholder="{{ctx.Locale.Tr "repo.editor.new_branch_name_desc"}}" {{if eq .commit_choice "commit-to-new-branch"}}required{{end}} title="{{ctx.Locale.Tr "repo.editor.new_branch_name"}}"> + <input type="text" name="new_branch_name" maxlength="100" value="{{.new_branch_name}}" class="input-contrast gt-mr-2 js-quick-pull-new-branch-name" placeholder="{{ctx.Locale.Tr "repo.editor.new_branch_name_desc"}}" {{if eq .commit_choice "commit-to-new-branch"}}required{{end}} title="{{ctx.Locale.Tr "repo.editor.new_branch_name"}}"> <span class="text-muted js-quick-pull-normalization-info"></span> </div> </div> diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index cfc266731b..a6dce81c08 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -15,7 +15,7 @@ {{range $i, $v := .TreeNames}} <div class="breadcrumb-divider">/</div> {{if eq $i $l}} - <input id="file-name" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.name_your_file"}}" data-editorconfig="{{$.EditorconfigJson}}" required autofocus> + <input id="file-name" maxlength="500" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.name_your_file"}}" data-editorconfig="{{$.EditorconfigJson}}" required autofocus> <span data-tooltip-content="{{ctx.Locale.Tr "repo.editor.filename_help"}}">{{svg "octicon-info"}}</span> {{else}} <span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span> diff --git a/templates/repo/editor/patch.tmpl b/templates/repo/editor/patch.tmpl index b9ca530058..3de219014b 100644 --- a/templates/repo/editor/patch.tmpl +++ b/templates/repo/editor/patch.tmpl @@ -15,7 +15,7 @@ <a class="section" href="{{$.BranchLink}}">{{.BranchName}}</a> <span>{{ctx.Locale.Tr "repo.editor.or"}} <a href="{{$.BranchLink}}">{{ctx.Locale.Tr "repo.editor.cancel_lower"}}</a></span> <input type="hidden" id="tree_path" name="tree_path" value="patch" required> - <input id="file-name" type="hidden" value="diff.patch"> + <input id="file-name" maxlength="500" type="hidden" value="diff.patch"> </div> </div> <div class="field"> diff --git a/templates/repo/editor/upload.tmpl b/templates/repo/editor/upload.tmpl index d362a5602a..0a7c49dae3 100644 --- a/templates/repo/editor/upload.tmpl +++ b/templates/repo/editor/upload.tmpl @@ -13,7 +13,7 @@ {{range $i, $v := .TreeNames}} <div class="breadcrumb-divider">/</div> {{if eq $i $l}} - <input type="text" id="file-name" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.add_subdir"}}" autofocus> + <input type="text" id="file-name" maxlength="500" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.add_subdir"}}" autofocus> <span data-tooltip-content="{{ctx.Locale.Tr "repo.editor.filename_help"}}">{{svg "octicon-info"}}</span> {{else}} <span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span> diff --git a/web_src/js/utils.js b/web_src/js/utils.js index 3a2694335f..ce0fb66343 100644 --- a/web_src/js/utils.js +++ b/web_src/js/utils.js @@ -2,13 +2,14 @@ import {encode, decode} from 'uint8-to-base64'; // transform /path/to/file.ext to file.ext export function basename(path = '') { - return path ? path.replace(/^.*\//, '') : ''; + const lastSlashIndex = path.lastIndexOf('/'); + return lastSlashIndex < 0 ? path : path.substring(lastSlashIndex + 1); } // transform /path/to/file.ext to .ext export function extname(path = '') { - const [_, ext] = /.+(\.[^.]+)$/.exec(path) || []; - return ext || ''; + const lastPointIndex = path.lastIndexOf('.'); + return lastPointIndex < 0 ? '' : path.substring(lastPointIndex); } // test whether a variable is an object From 359e1a74e2b13c838545f6499bf841a6ffdb6877 Mon Sep 17 00:00:00 2001 From: KN4CK3R <admin@oldschoolhack.me> Date: Sun, 25 Feb 2024 16:42:36 +0100 Subject: [PATCH 60/64] Add missing space (#29393) (cherry picked from commit 4ccf5ab330c9ce8959aa6734c2e6fee282619ba5) --- templates/repo/diff/options_dropdown.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/diff/options_dropdown.tmpl b/templates/repo/diff/options_dropdown.tmpl index 3bcb877cc6..b7c46dd846 100644 --- a/templates/repo/diff/options_dropdown.tmpl +++ b/templates/repo/diff/options_dropdown.tmpl @@ -13,7 +13,7 @@ <a class="item" href="{{$.RepoLink}}/commit/{{PathEscape .Commit.ID.String}}.diff" download="{{ShortSha .Commit.ID.String}}.diff">{{ctx.Locale.Tr "repo.diff.download_diff"}}</a> {{end}} <a id="expand-files-btn" class="item">{{ctx.Locale.Tr "repo.pulls.expand_files"}}</a> - <a id="collapse-files-btn"class="item">{{ctx.Locale.Tr "repo.pulls.collapse_files"}}</a> + <a id="collapse-files-btn" class="item">{{ctx.Locale.Tr "repo.pulls.collapse_files"}}</a> {{if .Issue.Index}} {{if .ShowOutdatedComments}} <a class="item" href="?style={{if $.IsSplitStyle}}split{{else}}unified{{end}}&whitespace={{$.WhitespaceBehavior}}&show-outdated=false"> From cfda925862f4073f2d20f16ffcbd671975221c79 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 25 Feb 2024 17:46:46 +0100 Subject: [PATCH 61/64] Add tailwindcss (#29357) This will get tailwindcss working on a basic level. It provides only the utility classes, e.g. no tailwind base which we don't need because we have our own CSS reset. Without the base, we also do not have their CSS variables so a small amount of features do not work and I removed the generated classes for them. ***Note for future developers: This currently uses a `tw-` prefix, so we use it like `tw-p-3`.*** <details> <summary>Currently added CSS, all false-positives</summary> ``` .\!visible{ visibility: visible !important } .visible{ visibility: visible } .invisible{ visibility: hidden } .collapse{ visibility: collapse } .static{ position: static } .\!fixed{ position: fixed !important } .absolute{ position: absolute } .relative{ position: relative } .sticky{ position: sticky } .left-10{ left: 2.5rem } .isolate{ isolation: isolate } .float-right{ float: right } .float-left{ float: left } .mr-2{ margin-right: 0.5rem } .mr-3{ margin-right: 0.75rem } .\!block{ display: block !important } .block{ display: block } .inline-block{ display: inline-block } .inline{ display: inline } .flex{ display: flex } .inline-flex{ display: inline-flex } .\!table{ display: table !important } .inline-table{ display: inline-table } .table-caption{ display: table-caption } .table-cell{ display: table-cell } .table-column{ display: table-column } .table-column-group{ display: table-column-group } .table-footer-group{ display: table-footer-group } .table-header-group{ display: table-header-group } .table-row-group{ display: table-row-group } .table-row{ display: table-row } .flow-root{ display: flow-root } .inline-grid{ display: inline-grid } .contents{ display: contents } .list-item{ display: list-item } .\!hidden{ display: none !important } .hidden{ display: none } .flex-shrink{ flex-shrink: 1 } .shrink{ flex-shrink: 1 } .flex-grow{ flex-grow: 1 } .grow{ flex-grow: 1 } .border-collapse{ border-collapse: collapse } .select-all{ user-select: all } .resize{ resize: both } .flex-wrap{ flex-wrap: wrap } .overflow-visible{ overflow: visible } .rounded{ border-radius: 0.25rem } .border{ border-width: 1px } .text-justify{ text-align: justify } .uppercase{ text-transform: uppercase } .lowercase{ text-transform: lowercase } .capitalize{ text-transform: capitalize } .italic{ font-style: italic } .text-red{ color: var(--color-red) } .text-shadow{ color: var(--color-shadow) } .underline{ text-decoration-line: underline } .overline{ text-decoration-line: overline } .line-through{ text-decoration-line: line-through } .outline{ outline-style: solid } .ease-in{ transition-timing-function: cubic-bezier(0.4, 0, 1, 1) } .ease-in-out{ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1) } .ease-out{ transition-timing-function: cubic-bezier(0, 0, 0.2, 1) } ``` </details> --------- Co-authored-by: Giteabot <teabot@gitea.io> (cherry picked from commit f4b92578b4601bc6e9b631b9a5a5f3766c27b0cb) --- .stylelintrc.yaml | 2 +- Makefile | 2 +- package-lock.json | 514 ++++++++++++++++++++++++++++---- package.json | 4 + tailwind.config.js | 39 +++ templates/devtest/gitea-ui.tmpl | 6 + web_src/css/base.css | 8 + web_src/css/index.css | 2 + webpack.config.js | 11 + 9 files changed, 530 insertions(+), 58 deletions(-) create mode 100644 tailwind.config.js diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml index a44294ee76..7dd0a566f2 100644 --- a/.stylelintrc.yaml +++ b/.stylelintrc.yaml @@ -98,7 +98,7 @@ rules: at-rule-allowed-list: null at-rule-disallowed-list: null at-rule-empty-line-before: null - at-rule-no-unknown: true + at-rule-no-unknown: [true, {ignoreAtRules: [tailwind]}] at-rule-no-vendor-prefix: true at-rule-property-required-list: null block-no-empty: true diff --git a/Makefile b/Makefile index 602f42fe4b..9dd0abb492 100644 --- a/Makefile +++ b/Makefile @@ -107,7 +107,7 @@ GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/m FOMANTIC_WORK_DIR := web_src/fomantic WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f) -WEBPACK_CONFIGS := webpack.config.js +WEBPACK_CONFIGS := webpack.config.js tailwind.config.js WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css WEBPACK_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts public/assets/img/webpack diff --git a/package-lock.json b/package-lock.json index 23dcb84da6..c833670f72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "chartjs-plugin-zoom": "2.0.1", "clippie": "4.0.6", "css-loader": "6.10.0", + "css-variables-parser": "1.0.1", "dayjs": "1.11.10", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", @@ -41,9 +42,12 @@ "monaco-editor": "0.46.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", + "postcss": "8.4.35", + "postcss-loader": "8.1.0", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", "swagger-ui-dist": "5.11.6", + "tailwindcss": "3.4.1", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", "tippy.js": "6.3.7", @@ -105,6 +109,17 @@ "node": ">=0.10.0" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@asyncapi/specs": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-4.3.1.tgz", @@ -118,7 +133,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dev": true, "dependencies": { "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" @@ -131,7 +145,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -143,7 +156,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -157,7 +169,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -165,14 +176,12 @@ "node_modules/@babel/code-frame/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -181,7 +190,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -190,7 +198,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -202,7 +209,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -211,7 +217,6 @@ "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -225,7 +230,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -237,7 +241,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -251,7 +254,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -259,14 +261,12 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -275,7 +275,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -283,14 +282,12 @@ "node_modules/@babel/highlight/node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/@babel/highlight/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -1111,7 +1108,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1128,7 +1124,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -1140,7 +1135,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -1151,14 +1145,12 @@ "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -1175,7 +1167,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -1190,7 +1181,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -1381,7 +1371,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" @@ -3086,6 +3075,28 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3400,6 +3411,14 @@ "node": "*" } }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -3534,11 +3553,18 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001587", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz", @@ -3646,6 +3672,40 @@ "node": "*" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -3857,7 +3917,6 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -3975,6 +4034,35 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/css-variables-parser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-variables-parser/-/css-variables-parser-1.0.1.tgz", + "integrity": "sha512-GWaqrwGtAWVr/yjjE17iyvbcy+W3voe0vko1/xLCwFeYd3kTLstzUdVH+g5TTXejrtlsb1FS4L9rP6PmeTa8wQ==", + "dependencies": { + "postcss": "^7.0.36" + } + }, + "node_modules/css-variables-parser/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "node_modules/css-variables-parser/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -4661,6 +4749,11 @@ "node": ">=6" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -4690,6 +4783,11 @@ "node": ">=8" } }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -4774,8 +4872,7 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/easymde": { "version": "2.18.0", @@ -4839,7 +4936,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, "engines": { "node": ">=6" } @@ -4859,7 +4955,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -6154,7 +6249,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -6203,7 +6297,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -6390,7 +6483,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -6815,7 +6907,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -6935,8 +7026,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-async-function": { "version": "2.0.0", @@ -6965,6 +7055,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -7377,7 +7478,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -7418,6 +7518,14 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/jquery": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", @@ -7779,11 +7887,18 @@ "node": ">=8" } }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/linkify-it": { "version": "5.0.0", @@ -8707,7 +8822,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -8759,6 +8873,16 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -8902,7 +9026,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8969,6 +9092,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -9148,7 +9279,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -9160,7 +9290,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -9230,7 +9359,6 @@ "version": "1.10.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", - "dev": true, "dependencies": { "lru-cache": "^9.1.1 || ^10.0.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -9246,7 +9374,6 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "dev": true, "engines": { "node": "14 || >=16.14" } @@ -9296,6 +9423,22 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -9462,6 +9605,70 @@ "node": "^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.0.tgz", + "integrity": "sha512-AbperNcX3rlob7Ay7A/HQcrofug1caABBkopoFeOQMspZBqcqj6giYn1Bwey/0uiOPAcR+NQD0I2HC7rXzk91w==", + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, "node_modules/postcss-modules-extract-imports": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", @@ -9517,6 +9724,24 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/postcss-resolve-nested-selector": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", @@ -9754,6 +9979,14 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -9856,6 +10089,17 @@ "node": ">=8" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -10037,7 +10281,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -10398,7 +10641,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -10609,7 +10851,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10680,7 +10921,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10999,6 +11239,56 @@ "node": ">= 8" } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/superstruct": { "version": "0.10.13", "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.10.13.tgz", @@ -11144,6 +11434,87 @@ "node": ">=10.0.0" } }, + "node_modules/tailwindcss": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -11258,6 +11629,25 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/throttle-debounce": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.0.tgz", @@ -11380,6 +11770,11 @@ "node": ">=6.10" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -12431,7 +12826,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -12569,6 +12963,14 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.3.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", diff --git a/package.json b/package.json index fdea78ca29..3f0f9103cf 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "chartjs-plugin-zoom": "2.0.1", "clippie": "4.0.6", "css-loader": "6.10.0", + "css-variables-parser": "1.0.1", "dayjs": "1.11.10", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", @@ -40,9 +41,12 @@ "monaco-editor": "0.46.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", + "postcss": "8.4.35", + "postcss-loader": "8.1.0", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", "swagger-ui-dist": "5.11.6", + "tailwindcss": "3.4.1", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", "tippy.js": "6.3.7", diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000000..8c474c33a8 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,39 @@ +import {readFileSync} from 'node:fs'; +import {env} from 'node:process'; +import {parse} from 'css-variables-parser'; + +const isProduction = env.NODE_ENV !== 'development'; + +export default { + prefix: 'tw-', + content: [ + isProduction && '!./templates/devtest/**/*', + isProduction && '!./web_src/js/standalone/devtest.js', + './templates/**/*.tmpl', + './web_src/**/*.{js,vue}', + ].filter(Boolean), + blocklist: [ + // classes that don't work without CSS variables from "@tailwind base" which we don't use + 'transform', 'shadow', 'ring', 'blur', 'grayscale', 'invert', '!invert', 'filter', '!filter', + 'backdrop-filter', + // unneeded classes + '[-a-zA-Z:0-9_.]', + ], + theme: { + colors: { + // make `tw-bg-red` etc work with our CSS variables + ...Object.fromEntries( + Object.keys(parse([ + readFileSync(new URL('web_src/css/themes/theme-gitea-light.css', import.meta.url), 'utf8'), + readFileSync(new URL('web_src/css/themes/theme-gitea-dark.css', import.meta.url), 'utf8'), + ].join('\n'), {})).filter((prop) => prop.startsWith('color-')).map((prop) => { + const color = prop.substring(6); + return [color, `var(--color-${color})`]; + }) + ), + inherit: 'inherit', + current: 'currentcolor', + transparent: 'transparent', + }, + }, +}; diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index 73293ddf48..ccf188609c 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -275,6 +275,12 @@ <div>ps: no JS code attached, so just a layout</div> {{template "shared/combomarkdowneditor" .}} </div> + + <h1>Tailwind CSS Demo</h1> + <div> + <button class="{{if true}}tw-bg-red{{end}} tw-p-5 tw-border tw-rounded hover:tw-bg-blue active:tw-bg-yellow">Button</button> + </div> + <script src="{{AssetUrlPrefix}}/js/devtest.js?v={{AssetVersion}}"></script> </div> {{template "base/footer" .}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 6f51ad57ab..9cad9c5d23 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -29,6 +29,14 @@ --fonts-regular: var(--fonts-override, var(--fonts-proportional)), "Noto Sans", "Liberation Sans", sans-serif, var(--fonts-emoji); } +*, ::before, ::after { + /* these are needed for tailwind borders to work because we do not load tailwind's base + https://github.com/tailwindlabs/tailwindcss/blob/master/src/css/preflight.css */ + border-width: 0; + border-style: solid; + border-color: currentcolor; +} + textarea { font-family: var(--fonts-regular); } diff --git a/web_src/css/index.css b/web_src/css/index.css index f893531b78..ab925a4aa0 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -59,4 +59,6 @@ @import "./explore.css"; @import "./review.css"; @import "./actions.css"; + +@tailwind utilities; @import "./helpers.css"; diff --git a/webpack.config.js b/webpack.config.js index d4700ebe2b..896d541113 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,6 +11,8 @@ import webpack from 'webpack'; import {fileURLToPath} from 'node:url'; import {readFileSync} from 'node:fs'; import {env} from 'node:process'; +import tailwindcss from 'tailwindcss'; +import tailwindConfig from './tailwind.config.js'; const {EsbuildPlugin} = EsBuildLoader; const {SourceMapDevToolPlugin, DefinePlugin} = webpack; @@ -149,6 +151,15 @@ export default { import: {filter: filterCssImport}, }, }, + { + loader: 'postcss-loader', + options: { + postcssOptions: { + map: false, // https://github.com/postcss/postcss/issues/1914 + plugins: [tailwindcss(tailwindConfig)], + }, + }, + } ], }, { From 8a25361d9ab3bff1ed630e138aa6bb767a5ae1fe Mon Sep 17 00:00:00 2001 From: Yarden Shoham <git@yardenshoham.com> Date: Sun, 25 Feb 2024 18:53:44 +0200 Subject: [PATCH 62/64] Remove jQuery AJAX from the archive download links (#29380) - Removed all jQuery AJAX calls and replaced with our fetch wrapper - Tested the repo archive download links dropdown functionality and it works as before # Demo using `fetch` instead of jQuery AJAX  --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> (cherry picked from commit ed3892d8430652c2bc8e2af21844d14769825e8a) --- web_src/js/features/repo-common.js | 58 ++++++++++++++---------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/web_src/js/features/repo-common.js b/web_src/js/features/repo-common.js index 3573e4d50b..a8221bbea8 100644 --- a/web_src/js/features/repo-common.js +++ b/web_src/js/features/repo-common.js @@ -1,38 +1,34 @@ import $ from 'jquery'; import {hideElem, showElem} from '../utils/dom.js'; +import {POST} from '../modules/fetch.js'; -const {csrfToken} = window.config; - -function getArchive($target, url, first) { - $.ajax({ - url, - type: 'POST', - data: { - _csrf: csrfToken, - }, - complete(xhr) { - if (xhr.status === 200) { - if (!xhr.responseJSON) { - // XXX Shouldn't happen? - $target.closest('.dropdown').children('i').removeClass('loading'); - return; - } - - if (!xhr.responseJSON.complete) { - $target.closest('.dropdown').children('i').addClass('loading'); - // Wait for only three quarters of a second initially, in case it's - // quickly archived. - setTimeout(() => { - getArchive($target, url, false); - }, first ? 750 : 2000); - } else { - // We don't need to continue checking. - $target.closest('.dropdown').children('i').removeClass('loading'); - window.location.href = url; - } +async function getArchive($target, url, first) { + try { + const response = await POST(url); + if (response.status === 200) { + const data = await response.json(); + if (!data) { + // XXX Shouldn't happen? + $target.closest('.dropdown').children('i').removeClass('loading'); + return; } - }, - }); + + if (!data.complete) { + $target.closest('.dropdown').children('i').addClass('loading'); + // Wait for only three quarters of a second initially, in case it's + // quickly archived. + setTimeout(() => { + getArchive($target, url, false); + }, first ? 750 : 2000); + } else { + // We don't need to continue checking. + $target.closest('.dropdown').children('i').removeClass('loading'); + window.location.href = url; + } + } + } catch { + $target.closest('.dropdown').children('i').removeClass('loading'); + } } export function initRepoArchiveLinks() { From 6ed19cc00d1f8affe9f834db2246db99c628b357 Mon Sep 17 00:00:00 2001 From: Earl Warren <contact@earl-warren.org> Date: Sun, 25 Feb 2024 21:36:45 +0100 Subject: [PATCH 63/64] templates: Safe & Escape no longer exist --- templates/repo/issue/view_title.tmpl | 2 +- templates/repo/settings/options.tmpl | 2 +- templates/shared/blocked_users_list.tmpl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index 6a60c68ec3..3f93f3ba35 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -50,7 +50,7 @@ {{if not .MadeUsingAGit}} {{$headHref = HTMLFormat `%s <button class="btn interact-fg" data-tooltip-content="%s" data-clipboard-text="%s">%s</button>` $headHref (ctx.Locale.Tr "copy_branch") .HeadTarget (svg "octicon-copy" 14)}} {{end}} - {{$baseHref := .BaseTarget|Escape}} + {{$baseHref := .BaseTarget}} {{if .BaseBranchLink}} {{$baseHref = HTMLFormat `<a href="%s">%s</a>` .BaseBranchLink $baseHref}} {{end}} diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 128f553d3d..b0fa5aee89 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -691,7 +691,7 @@ <div class="content"> <div class="ui warning message"> <ul> - <li>{{ctx.Locale.Tr "repo.settings.wiki_rename_branch_main_notices_1" | Safe}}</li> + <li>{{ctx.Locale.Tr "repo.settings.wiki_rename_branch_main_notices_1"}}</li> <li>{{ctx.Locale.Tr "repo.settings.wiki_rename_branch_main_notices_2" .Repository.Name}}</li> </ul> </div> diff --git a/templates/shared/blocked_users_list.tmpl b/templates/shared/blocked_users_list.tmpl index 392947e80c..409b7f4aa5 100644 --- a/templates/shared/blocked_users_list.tmpl +++ b/templates/shared/blocked_users_list.tmpl @@ -9,7 +9,7 @@ {{template "shared/user/name" .}} </div> <div class="flex-item-body"> - <span>{{ctx.Locale.Tr "settings.blocked_since" (DateTime "short" .CreatedUnix) | Safe}}</span> + <span>{{ctx.Locale.Tr "settings.blocked_since" (DateTime "short" .CreatedUnix)}}</span> </div> </div> <div class="flex-item-trailing"> From 0f098d1ad71605831ef2a9259abb2ca089079d74 Mon Sep 17 00:00:00 2001 From: Earl Warren <contact@earl-warren.org> Date: Mon, 26 Feb 2024 00:12:19 +0100 Subject: [PATCH 64/64] [DEADCODE] update --- .deadcode-out | 1 + 1 file changed, 1 insertion(+) diff --git a/.deadcode-out b/.deadcode-out index 3290e6102a..8fca0d96bb 100644 --- a/.deadcode-out +++ b/.deadcode-out @@ -296,6 +296,7 @@ package "code.gitea.io/gitea/modules/translation" package "code.gitea.io/gitea/modules/util" func UnsafeStringToBytes + func OptionalBoolFromGeneric package "code.gitea.io/gitea/modules/util/filebuffer" func CreateFromReader