From cd0a8033411d3cbcb841f40ff2d9d91c9aa290d5 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sun, 31 May 2026 13:31:11 -0500 Subject: [PATCH] fix(issues): deprecate Issue.Ref branch selector UI (#307) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the branch/tag selector from the issue sidebar and new issue form. The Issue.Ref field was added 8 years ago and provides minimal value — it only saves a branch name and optionally restricts which branch's commits can auto-close the issue. Removed: - Branch selector template (branch_selector_field.tmpl) - Sidebar and new-form includes - Ref badge from issue lists - POST /{index}/ref web route and UpdateIssueRef handler - GetRefEndNamesAndURLs calls from list renderers - JS handler for branch selector dropdown Preserved: - DB column (Issue.Ref) — still used by commit-close logic - API response still includes ref for backward compatibility Closes #307 Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 7 ++ routers/web/repo/issue.go | 22 ------- routers/web/repo/issue_list.go | 2 - routers/web/repo/issue_new.go | 6 -- routers/web/repo/issue_view.go | 2 - routers/web/user/home.go | 2 - routers/web/user/notification.go | 1 - routers/web/web.go | 1 - .../repo/issue/branch_selector_field.tmpl | 64 +------------------ templates/repo/issue/new_form.tmpl | 2 - .../repo/issue/view_content/sidebar.tmpl | 2 - templates/shared/issuelist.tmpl | 8 +-- web_src/js/features/repo-issue-sidebar.ts | 28 -------- 13 files changed, 9 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d0abb20d8..d192977f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.com). ## [v1.26.1-moko.05.15.00] - 2026-05-31 +* BREAKING CHANGES + * Deprecated Issue.Ref branch selector UI (#307) + * Removed branch/tag selector from issue sidebar and new issue form + * Removed ref badge from issue lists + * Removed POST /ref web route and UpdateIssueRef handler + * DB column and commit-close logic preserved for backward compatibility + * API create/edit still accept `ref` field (no-op) for backward compat * FEATURES * feat(ui): add generic combo-multiselect component (#361) * Reusable dropdown with search, checkable items, and selected-items display diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index f8632dcbf0..a6cd381dd2 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -306,29 +306,7 @@ func UpdateIssueTitle(ctx *context.Context) { }) } -// UpdateIssueRef change issue's ref (branch) -func UpdateIssueRef(ctx *context.Context) { - issue := GetActionIssue(ctx) - if ctx.Written() { - return - } - if !ctx.IsSigned || (!issue.IsPoster(ctx.Doer.ID) && !ctx.Repo.Permission.CanWriteIssuesOrPulls(issue.IsPull)) || issue.IsPull { - ctx.HTTPError(http.StatusForbidden) - return - } - - ref := ctx.FormTrim("ref") - - if err := issue_service.ChangeIssueRef(ctx, issue, ctx.Doer, ref); err != nil { - ctx.ServerError("ChangeRef", err) - return - } - - ctx.JSON(http.StatusOK, map[string]any{ - "ref": ref, - }) -} // UpdateIssueContent change issue's content func UpdateIssueContent(ctx *context.Context) { diff --git a/routers/web/repo/issue_list.go b/routers/web/repo/issue_list.go index 950d352880..d5f213740a 100644 --- a/routers/web/repo/issue_list.go +++ b/routers/web/repo/issue_list.go @@ -672,8 +672,6 @@ func prepareIssueFilterAndList(ctx *context.Context, milestoneID int64, projectI } ctx.Data["Assignees"] = shared_user.MakeSelfOnTop(ctx.Doer, assigneeUsers) - ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, ctx.Repo.RepoLink) - ctx.Data["ApprovalCounts"] = func(issueID int64, typ string) int64 { counts, ok := approvalCounts[issueID] if !ok || len(counts) == 0 { diff --git a/routers/web/repo/issue_new.go b/routers/web/repo/issue_new.go index 7c9cc4abe5..07d7a74f20 100644 --- a/routers/web/repo/issue_new.go +++ b/routers/web/repo/issue_new.go @@ -85,12 +85,6 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles } metaData.AssigneesData.SelectedAssigneeIDs = strings.Join(selectedAssigneeIDStrings, ",") - if template.Ref != "" && !strings.HasPrefix(template.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/ - template.Ref = git.BranchPrefix + template.Ref - } - - ctx.Data["Reference"] = template.Ref - ctx.Data["RefEndName"] = git.RefName(template.Ref).ShortName() return true, templateErrs } return false, templateErrs diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 6a9abb7ad9..444d1c0944 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -397,14 +397,12 @@ func ViewIssue(ctx *context.Context) { } } - ctx.Data["Reference"] = issue.Ref ctx.Data["SignInLink"] = middleware.RedirectLinkUserLogin(ctx.Req) ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.Doer.ID) ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.Permission.CanWriteIssuesOrPulls(issue.IsPull) ctx.Data["HasProjectsWritePermission"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects) ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.Permission.IsAdmin() || ctx.Doer.IsAdmin) ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons - ctx.Data["RefEndName"] = git.RefName(issue.Ref).ShortName() tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) if err != nil { diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 88c8512d44..065c1fd489 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -587,8 +587,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { ctx.Data["IsShowClosed"] = isShowClosed - ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, ctx.FormString("RepoLink")) - if err := issues.LoadAttributes(ctx); err != nil { ctx.ServerError("issues.LoadAttributes", err) return diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index 01e79d89fd..95c3bd4f14 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -255,7 +255,6 @@ func NotificationSubscriptions(ctx *context.Context) { ctx.Data["CommitLastStatus"] = lastStatus ctx.Data["CommitStatuses"] = commitStatuses ctx.Data["Issues"] = issues - ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, "") approvalCounts, err := issues.GetApprovalCounts(ctx) if err != nil { diff --git a/routers/web/web.go b/routers/web/web.go index 34164528f9..5298c5ada4 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1352,7 +1352,6 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Post("/content", repo.UpdateIssueContent) m.Post("/deadline", repo.UpdateIssueDeadline) m.Post("/watch", repo.IssueWatch) - m.Post("/ref", repo.UpdateIssueRef) m.Post("/pin", reqRepoAdmin, repo.IssuePinOrUnpin) m.Post("/viewed-files", repo.UpdateViewedFiles) m.Group("/dependency", func() { diff --git a/templates/repo/issue/branch_selector_field.tmpl b/templates/repo/issue/branch_selector_field.tmpl index 2f3e792d64..656e6eda60 100644 --- a/templates/repo/issue/branch_selector_field.tmpl +++ b/templates/repo/issue/branch_selector_field.tmpl @@ -1,63 +1 @@ -{{/* TODO: RemoveIssueRef: the Issue.Ref will be removed in 1.24 or 1.25 if no end user really needs it or there could be better alternative then. -PR: https://github.com/go-gitea/gitea/pull/32744 - -The Issue.Ref was added by Add possibility to record branch or tag information in an issue (#780) -After 8 years, this "branch selector" does nothing more than saving the branch/tag name into database and displays it, -or sometimes auto-close a ref-matched issue by a commit message when CloseIssuesViaCommitInAnyBranch=false. - -There are still users using it: -* @didim99: it is a really useful feature to specify a branch in which issue found. - -Still needs to figure out: -* Could the "recording branch/tag name" be replaced by other approaches? - * Write the branch name in the issue title/body then it will still be displayed, eg: `[bug] (fix/ui-broken-bug) there is a bug ....` -* Is "GitHub-like development sidebar (`#31899`)" good enough (or better) for your usage? -*/}} -{{if and (not .Issue.IsPull) (not .PageIsComparePull)}} - - -
-{{end}} +{{/* Issue.Ref branch selector removed — the field is deprecated. The DB column is kept for commit-close logic. */}} diff --git a/templates/repo/issue/new_form.tmpl b/templates/repo/issue/new_form.tmpl index 7d669fe4a7..f6ee548e15 100644 --- a/templates/repo/issue/new_form.tmpl +++ b/templates/repo/issue/new_form.tmpl @@ -47,8 +47,6 @@
- {{template "repo/issue/branch_selector_field" $}}{{/* TODO: RemoveIssueRef: template "repo/issue/branch_selector_field" $*/}} - {{if .PageIsComparePull}} {{template "repo/issue/sidebar/reviewer_list" $.IssuePageMetaData}}
diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 4dff508495..6427d10968 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -1,6 +1,4 @@
- {{template "repo/issue/branch_selector_field" $}}{{/* TODO: RemoveIssueRef: template "repo/issue/branch_selector_field" $*/}} - {{if .Issue.IsPull}} {{template "repo/issue/sidebar/reviewer_list" $.IssuePageMetaData}} {{template "repo/issue/sidebar/wip_switch" $}} diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index 278860d35f..a45f997e8e 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -82,13 +82,7 @@ {{$project.Title}} {{end}} - {{if .Ref}}{{/* TODO: RemoveIssueRef: see "repo/issue/branch_selector_field.tmpl" */}} - - {{svg "octicon-git-branch" 14}} - {{index $.IssueRefEndNames .ID}} - - {{end}} - {{$tasks := .GetTasks}} + {{$tasks := .GetTasks}} {{if gt $tasks 0}} {{$tasksDone := .GetTasksDone}} diff --git a/web_src/js/features/repo-issue-sidebar.ts b/web_src/js/features/repo-issue-sidebar.ts index 2983b6e1af..3a043a24fa 100644 --- a/web_src/js/features/repo-issue-sidebar.ts +++ b/web_src/js/features/repo-issue-sidebar.ts @@ -9,33 +9,6 @@ import {showTemporaryTooltip} from '../modules/tippy.ts'; const {appSubUrl} = window.config; -function initRepoIssueBranchSelector(elSidebar: HTMLElement) { - // TODO: RemoveIssueRef: see "repo/issue/branch_selector_field.tmpl" - const elSelectBranch = elSidebar.querySelector('.ui.dropdown.select-branch.branch-selector-dropdown'); - if (!elSelectBranch) return; - const urlUpdateIssueRef = elSelectBranch.getAttribute('data-url-update-issueref'); - const elBranchMenu = elSelectBranch.querySelector('.reference-list-menu')!; - queryElems(elBranchMenu, '.item:not(.no-select)', (el) => el.addEventListener('click', async function (e) { - e.preventDefault(); - const selectedValue = this.getAttribute('data-id')!; // eg: "refs/heads/my-branch" - const selectedText = this.getAttribute('data-name'); // eg: "my-branch" - if (urlUpdateIssueRef) { - // for existing issue, send request to update issue ref, and reload page - try { - await POST(urlUpdateIssueRef, {data: new URLSearchParams({ref: selectedValue})}); - window.location.reload(); - } catch (error) { - console.error(error); - } - } else { - // for new issue, only update UI&form, do not send request/reload - const selectedHiddenSelector = this.getAttribute('data-id-selector')!; - document.querySelector(selectedHiddenSelector)!.value = selectedValue; - elSelectBranch.querySelector('.text-branch-name')!.textContent = selectedText; - } - })); -} - function initRepoIssueDue(elSidebar: HTMLElement) { const form = elSidebar.querySelector('.issue-due-form'); if (!form) return; @@ -109,7 +82,6 @@ export function initRepoPullRequestAllowMaintainerEdit(elSidebar: HTMLElement) { export function initRepoIssueSidebar() { registerGlobalInitFunc('initRepoIssueSidebar', (elSidebar) => { - initRepoIssueBranchSelector(elSidebar); initRepoIssueDue(elSidebar); initRepoIssueSidebarDependency(elSidebar); initRepoPullRequestAllowMaintainerEdit(elSidebar);