fix(linear): list issue comments oldest first (#25622)

Linear returns an issue's comments newest first and getIssueComments
passed that order through, so the activity feed showed the newest comment
on top while comments posted from Orca were appended at the bottom and
jumped to the top on reload. Sort by createdAt, oldest first, like the
GitLab notes path does.

Fixes #25573

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
This commit is contained in:
Suat Kocar
2026-10-23 19:20:34 -07:00
committed by GitHub
co-authored by Neil
parent fea8bb7f5b
commit ad4c25cda2
2 changed files with 56 additions and 1 deletions
@@ -0,0 +1,53 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
const rawRequest = vi.fn()
const getClients = vi.fn()
vi.mock('./linear-request-concurrency', () => ({
acquire: vi.fn().mockResolvedValue(undefined),
release: vi.fn()
}))
vi.mock('./linear-token-store', () => ({
clearToken: vi.fn()
}))
vi.mock('./client', () => ({
getClients: (...args: unknown[]) => getClients(...args),
getPublicFileUrlClient: () => ({ client: { rawRequest } }),
isAuthError: () => false
}))
function rawComment(id: string, body: string, createdAt: string) {
return { id, body, createdAt, user: { displayName: 'Ada', avatarUrl: null } }
}
describe('getIssueComments', () => {
beforeEach(() => {
vi.clearAllMocks()
getClients.mockReturnValue([
{ workspace: { id: 'workspace-1' }, client: { client: { rawRequest } } }
])
})
it('returns comments oldest first, although Linear sends them newest first', async () => {
rawRequest.mockResolvedValueOnce({
data: {
issue: {
comments: {
nodes: [
rawComment('comment-3', 'Third', '2026-01-02T03:06:05.000Z'),
rawComment('comment-2', 'Second', '2026-01-02T03:05:05.000Z'),
rawComment('comment-1', 'First', '2026-01-02T03:04:05.000Z')
]
}
}
}
})
const { getIssueComments } = await import('./linear-issue-comments')
const comments = await getIssueComments('issue-uuid', 'workspace-1')
expect(comments.map((comment) => comment.body)).toEqual(['First', 'Second', 'Third'])
})
})
+3 -1
View File
@@ -243,7 +243,7 @@ export async function getIssueComments(
LinearRawVariables
>(ISSUE_COMMENTS_QUERY, { id: issueId })
const nodes = result.data?.issue?.comments?.nodes ?? []
return nodes.map((node) => ({
const comments = nodes.map((node) => ({
id: node.id,
body: node.body ?? '',
createdAt: node.createdAt ?? '',
@@ -254,6 +254,8 @@ export async function getIssueComments(
}
: undefined
}))
// Why: Linear sends newest first; oldest-first matches linear.app and where new comments land.
return comments.sort((a, b) => a.createdAt.localeCompare(b.createdAt))
} catch (error) {
if (isAuthError(error)) {
clearToken(entry.workspace.id)