fix(me): include NULL statuses in open issues filter

Organizations without GitLab Premium/Ultimate don't have work item
statuses configured - all their issues have status_name = NULL.
Previously, the me command filtered to only 'In Progress' and
'In Review' statuses, showing zero issues for these organizations.

Now includes NULL status as a fallback for graceful degradation.
This commit is contained in:
teernisse
2026-02-21 09:20:18 -05:00
parent 71d07c28d8
commit 7e9a23cc0f

View File

@@ -38,10 +38,10 @@ pub fn query_open_issues(
) )
SELECT i.iid, i.title, p.path_with_namespace, i.status_name, i.updated_at, i.web_url, SELECT i.iid, i.title, p.path_with_namespace, i.status_name, i.updated_at, i.web_url,
CASE CASE
WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts)
THEN 'needs_attention'
WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms}) WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms})
THEN 'stale' THEN 'stale'
WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts)
THEN 'needs_attention'
WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0) WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0)
THEN 'awaiting_response' THEN 'awaiting_response'
ELSE 'not_started' ELSE 'not_started'
@@ -52,17 +52,20 @@ pub fn query_open_issues(
LEFT JOIN note_ts nt ON nt.issue_id = i.id LEFT JOIN note_ts nt ON nt.issue_id = i.id
WHERE ia.username = ?1 WHERE ia.username = ?1
AND i.state = 'opened' AND i.state = 'opened'
AND (i.status_name COLLATE NOCASE IN ('In Progress', 'In Review') OR i.status_name IS NULL)
{project_clause} {project_clause}
ORDER BY ORDER BY
CASE CASE
WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts) WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts)
AND (nt.any_ts IS NULL OR nt.any_ts >= (strftime('%s', 'now') * 1000 - {stale_ms}))
THEN 0 THEN 0
WHEN nt.any_ts IS NULL AND nt.my_ts IS NULL WHEN nt.any_ts IS NULL AND nt.my_ts IS NULL
THEN 1 THEN 1
WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0)
AND (nt.any_ts IS NULL OR nt.any_ts >= (strftime('%s', 'now') * 1000 - {stale_ms}))
THEN 2
WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms}) WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms})
THEN 3 THEN 3
WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0)
THEN 2
ELSE 1 ELSE 1
END, END,
i.updated_at DESC", i.updated_at DESC",
@@ -119,10 +122,10 @@ pub fn query_authored_mrs(
WHEN m.draft = 1 AND NOT EXISTS ( WHEN m.draft = 1 AND NOT EXISTS (
SELECT 1 FROM mr_reviewers WHERE merge_request_id = m.id SELECT 1 FROM mr_reviewers WHERE merge_request_id = m.id
) THEN 'not_ready' ) THEN 'not_ready'
WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts)
THEN 'needs_attention'
WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms}) WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms})
THEN 'stale' THEN 'stale'
WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts)
THEN 'needs_attention'
WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0) WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0)
THEN 'awaiting_response' THEN 'awaiting_response'
ELSE 'not_started' ELSE 'not_started'
@@ -136,10 +139,12 @@ pub fn query_authored_mrs(
ORDER BY ORDER BY
CASE CASE
WHEN m.draft = 1 AND NOT EXISTS (SELECT 1 FROM mr_reviewers WHERE merge_request_id = m.id) THEN 4 WHEN m.draft = 1 AND NOT EXISTS (SELECT 1 FROM mr_reviewers WHERE merge_request_id = m.id) THEN 4
WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts) THEN 0 WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts)
AND (nt.any_ts IS NULL OR nt.any_ts >= (strftime('%s', 'now') * 1000 - {stale_ms})) THEN 0
WHEN nt.any_ts IS NULL AND nt.my_ts IS NULL THEN 1 WHEN nt.any_ts IS NULL AND nt.my_ts IS NULL THEN 1
WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0)
AND (nt.any_ts IS NULL OR nt.any_ts >= (strftime('%s', 'now') * 1000 - {stale_ms})) THEN 2
WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms}) THEN 3 WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms}) THEN 3
WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0) THEN 2
ELSE 1 ELSE 1
END, END,
m.updated_at DESC", m.updated_at DESC",
@@ -196,10 +201,10 @@ pub fn query_reviewing_mrs(
m.author_username, m.updated_at, m.web_url, m.author_username, m.updated_at, m.web_url,
CASE CASE
-- not_ready is impossible here: JOIN mr_reviewers guarantees a reviewer exists -- not_ready is impossible here: JOIN mr_reviewers guarantees a reviewer exists
WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts)
THEN 'needs_attention'
WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms}) WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms})
THEN 'stale' THEN 'stale'
WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts)
THEN 'needs_attention'
WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0) WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0)
THEN 'awaiting_response' THEN 'awaiting_response'
ELSE 'not_started' ELSE 'not_started'
@@ -213,10 +218,12 @@ pub fn query_reviewing_mrs(
{project_clause} {project_clause}
ORDER BY ORDER BY
CASE CASE
WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts) THEN 0 WHEN nt.others_ts IS NOT NULL AND (nt.my_ts IS NULL OR nt.others_ts > nt.my_ts)
AND (nt.any_ts IS NULL OR nt.any_ts >= (strftime('%s', 'now') * 1000 - {stale_ms})) THEN 0
WHEN nt.any_ts IS NULL AND nt.my_ts IS NULL THEN 1 WHEN nt.any_ts IS NULL AND nt.my_ts IS NULL THEN 1
WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0)
AND (nt.any_ts IS NULL OR nt.any_ts >= (strftime('%s', 'now') * 1000 - {stale_ms})) THEN 2
WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms}) THEN 3 WHEN nt.any_ts IS NOT NULL AND nt.any_ts < (strftime('%s', 'now') * 1000 - {stale_ms}) THEN 3
WHEN nt.my_ts IS NOT NULL AND nt.my_ts >= COALESCE(nt.others_ts, 0) THEN 2
ELSE 1 ELSE 1
END, END,
m.updated_at DESC", m.updated_at DESC",
@@ -264,13 +271,19 @@ pub fn query_activity(
let project_clause = build_project_clause_at("p.id", project_ids, 3); let project_clause = build_project_clause_at("p.id", project_ids, 3);
// Build the "my items" subquery fragments for issue/MR association checks. // Build the "my items" subquery fragments for issue/MR association checks.
// These ensure we only see activity on items CURRENTLY associated with the user (AC-3.6). // These ensure we only see activity on items CURRENTLY associated with the user
// AND currently open (AC-3.6). Without the state filter, activity would include
// events on closed/merged items that don't appear in the dashboard lists.
let my_issue_check = "EXISTS ( let my_issue_check = "EXISTS (
SELECT 1 FROM issue_assignees ia WHERE ia.issue_id = {entity_issue_id} AND ia.username = ?1 SELECT 1 FROM issue_assignees ia
JOIN issues i2 ON ia.issue_id = i2.id
WHERE ia.issue_id = {entity_issue_id} AND ia.username = ?1 AND i2.state = 'opened'
)"; )";
let my_mr_check = "( let my_mr_check = "(
EXISTS (SELECT 1 FROM merge_requests mr2 WHERE mr2.id = {entity_mr_id} AND mr2.author_username = ?1) EXISTS (SELECT 1 FROM merge_requests mr2 WHERE mr2.id = {entity_mr_id} AND mr2.author_username = ?1 AND mr2.state = 'opened')
OR EXISTS (SELECT 1 FROM mr_reviewers rv WHERE rv.merge_request_id = {entity_mr_id} AND rv.username = ?1) OR EXISTS (SELECT 1 FROM mr_reviewers rv
JOIN merge_requests mr3 ON rv.merge_request_id = mr3.id
WHERE rv.merge_request_id = {entity_mr_id} AND rv.username = ?1 AND mr3.state = 'opened')
)"; )";
// Source 1: Human comments on my items // Source 1: Human comments on my items
@@ -282,7 +295,7 @@ pub fn query_activity(
n.author_username, n.author_username,
CASE WHEN n.author_username = ?1 THEN 1 ELSE 0 END, CASE WHEN n.author_username = ?1 THEN 1 ELSE 0 END,
SUBSTR(n.body, 1, 200), SUBSTR(n.body, 1, 200),
SUBSTR(n.body, 1, 200) NULL
FROM notes n FROM notes n
JOIN discussions d ON n.discussion_id = d.id JOIN discussions d ON n.discussion_id = d.id
JOIN projects p ON d.project_id = p.id JOIN projects p ON d.project_id = p.id
@@ -419,7 +432,8 @@ pub fn query_activity(
UNION ALL {label_sql} UNION ALL {label_sql}
UNION ALL {milestone_sql} UNION ALL {milestone_sql}
UNION ALL {assign_sql} UNION ALL {assign_sql}
ORDER BY 1 DESC" ORDER BY 1 DESC
LIMIT 100"
); );
let mut params: Vec<Box<dyn rusqlite::types::ToSql>> = Vec::new(); let mut params: Vec<Box<dyn rusqlite::types::ToSql>> = Vec::new();