fix(issue): make issue action (issue list batch operation) elements have correct attributes (#38575)

The "Clear projects" action in the issue list batch operations doesn't
work. When users select multiple issues and choose to clear their
project assignments, the operation fails because:

1. The frontend sends a project ID of `0` to represent "no project"
2. The backend passes this invalid ID directly to
`IssueAssignOrRemoveProject` without filtering
3. The backend tries to look up a project with ID `0`, which doesn't
exist, resulting in a `project 0 not found` error
4. Selected issues remain assigned to their projects instead of being
removed

Fixes #38571 

## Root Cause

The issue is a regression from the multi-project feature (#36784). The
frontend was using `data-element-id="0"` to represent "clear" actions,
but the backend doesn't filter out this invalid ID before validation.

## Solution

### Template Changes (`templates/repo/issue/filter_actions.tmpl`)
- Changed `data-element-id="0"` to `data-element-id=""` for the "Clear
projects" action (line 78)
- Changed `data-element-id="0"` to `data-element-id=""` for the "Clear
milestone" action (line 47)
- Removed the duplicate "no select" assignee option that was using
`data-element-id="0"` (lines 116-118)

### Frontend Logic Changes (`web_src/js/features/repo-issue-list.ts`)
- Made `elementId` a `const` instead of `let` (line 60) to prevent
mutations
- Removed the workaround code that was trying to handle
`data-element-id="0"` for assignees (lines 65-69)
- Updated comment from "for toggle" to "for label toggle" for clarity
(line 71)

---------

Signed-off-by: Sudhanshu Singh <sudhanshuwriterblc@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Shudhanshu Singh
2026-07-22 16:44:27 +00:00
committed by GitHub
co-authored by wxiaoguang
parent c8df67c0d0
commit 48e067e4b3
2 changed files with 4 additions and 13 deletions
+2 -5
View File
@@ -44,7 +44,7 @@
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<div class="item issue-action" data-element-id="0" data-url="{{$.Link}}/milestone">
<div class="item issue-action" data-element-id="" data-url="{{$.Link}}/milestone">
{{ctx.Locale.Tr "repo.issues.action_milestone_no_select"}}
</div>
{{if .OpenMilestones}}
@@ -75,7 +75,7 @@
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<div class="item issue-action" data-element-id="0" data-url="{{$.Link}}/projects">
<div class="item issue-action" data-element-id="" data-url="{{$.Link}}/projects">
{{ctx.Locale.Tr "repo.issues.new.clear_projects"}}
</div>
{{if .OpenProjects}}
@@ -113,9 +113,6 @@
<div class="item issue-action" data-action="clear" data-url="{{$.Link}}/assignee">
{{ctx.Locale.Tr "repo.issues.new.clear_assignees"}}
</div>
<div class="item issue-action" data-element-id="0" data-url="{{$.Link}}/assignee">
{{ctx.Locale.Tr "repo.issues.action_assignee_no_select"}}
</div>
{{range .Assignees}}
<div class="item issue-action" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/assignee">
{{ctx.AvatarUtils.Avatar . 20}} {{.GetDisplayName}}
+2 -8
View File
@@ -57,18 +57,12 @@ function initRepoIssueListCheckboxes() {
const url = el.getAttribute('data-url')!;
let action = el.getAttribute('data-action')!;
let elementId = el.getAttribute('data-element-id')!;
const elementId = el.getAttribute('data-element-id')!;
const issueIDList: string[] = Array.from(document.querySelectorAll('.issue-checkbox:checked'), (el) => (el.getAttribute('data-issue-id')!));
const issueIDs = issueIDList.join(',');
if (!issueIDs) return;
// for assignee
if (elementId === '0' && url.endsWith('/assignee')) {
elementId = '';
action = 'clear';
}
// for toggle
// for label toggle
if (action === 'toggle' && e.altKey) {
action = 'toggle-alt';
}