From 377ed1aadd43acbe3fadc916ae363b658573579d Mon Sep 17 00:00:00 2001 From: Daeyoung Jeong Date: Thu, 27 Aug 2026 15:31:54 +0000 Subject: [PATCH 1/2] fix(jira): key task presets on statusCategory instead of resolution --- src/main/jira/jira-issue-search.test.ts | 41 +++++++++++++++++++++++++ src/main/jira/jira-issue-search.ts | 10 +++--- 2 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 src/main/jira/jira-issue-search.test.ts diff --git a/src/main/jira/jira-issue-search.test.ts b/src/main/jira/jira-issue-search.test.ts new file mode 100644 index 000000000000..c5ba72d01150 --- /dev/null +++ b/src/main/jira/jira-issue-search.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from 'vitest' +import type { JiraIssueFilter } from '../../shared/jira-types' +import { filterToJql } from './jira-issue-search' + +const PRESETS: JiraIssueFilter[] = ['assigned', 'reported', 'done', 'all'] + +describe('filterToJql', () => { + it('scopes the assigned preset to open issues by status category', () => { + expect(filterToJql('assigned')).toBe( + 'assignee = currentUser() AND statusCategory != Done ORDER BY updated DESC' + ) + }) + + it('scopes the reported preset to open issues by status category', () => { + expect(filterToJql('reported')).toBe( + 'reporter = currentUser() AND statusCategory != Done ORDER BY updated DESC' + ) + }) + + it('scopes the done preset to completed issues by status category', () => { + expect(filterToJql('done')).toBe( + 'assignee = currentUser() AND statusCategory = Done ORDER BY updated DESC' + ) + }) + + it('scopes the all preset to every open issue by status category', () => { + expect(filterToJql('all')).toBe('statusCategory != Done ORDER BY updated DESC') + }) + + it('never keys a preset on the resolution field', () => { + for (const preset of PRESETS) { + expect(filterToJql(preset)).not.toContain('resolution') + } + }) + + it('keeps every preset sorted by most recently updated', () => { + for (const preset of PRESETS) { + expect(filterToJql(preset)).toContain('ORDER BY updated DESC') + } + }) +}) diff --git a/src/main/jira/jira-issue-search.ts b/src/main/jira/jira-issue-search.ts index 743342f77271..2dd7e4ea6cbd 100644 --- a/src/main/jira/jira-issue-search.ts +++ b/src/main/jira/jira-issue-search.ts @@ -23,17 +23,17 @@ function sortAndLimitIssues(issues: JiraIssue[], limit: number): JiraIssue[] { .slice(0, limit) } -function filterToJql(filter: JiraIssueFilter): string { +export function filterToJql(filter: JiraIssueFilter): string { if (filter === 'assigned') { - return 'assignee = currentUser() AND resolution = Unresolved ORDER BY updated DESC' + return 'assignee = currentUser() AND statusCategory != Done ORDER BY updated DESC' } if (filter === 'reported') { - return 'reporter = currentUser() AND resolution = Unresolved ORDER BY updated DESC' + return 'reporter = currentUser() AND statusCategory != Done ORDER BY updated DESC' } if (filter === 'done') { - return 'assignee = currentUser() AND resolution IS NOT EMPTY ORDER BY updated DESC' + return 'assignee = currentUser() AND statusCategory = Done ORDER BY updated DESC' } - return 'resolution = Unresolved ORDER BY updated DESC' + return 'statusCategory != Done ORDER BY updated DESC' } async function searchIssuesForClient( From 1c1d24fd3e8c720c45a6f9bdb042b99fd2ebaea2 Mon Sep 17 00:00:00 2001 From: Daeyoung Jeong Date: Tue, 8 Sep 2026 08:20:46 +0000 Subject: [PATCH 2/2] docs(jira): document why presets key on statusCategory --- src/main/jira/jira-issue-search.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/jira/jira-issue-search.ts b/src/main/jira/jira-issue-search.ts index 2dd7e4ea6cbd..9be9e59a6631 100644 --- a/src/main/jira/jira-issue-search.ts +++ b/src/main/jira/jira-issue-search.ts @@ -23,6 +23,12 @@ function sortAndLimitIssues(issues: JiraIssue[], limit: number): JiraIssue[] { .slice(0, limit) } +/** + * Build the JQL for a preset issue filter. + * Why: `resolution` is only written by a workflow post-function, so a preset keyed on it + * misreports every project that has none; `statusCategory` is derived from the status + * itself and is always populated. + */ export function filterToJql(filter: JiraIssueFilter): string { if (filter === 'assigned') { return 'assignee = currentUser() AND statusCategory != Done ORDER BY updated DESC'