feat: render PR comments in the checks panel#1959
Conversation
…render-pr-comments-in-the-right-sidebar # Conflicts: # src/renderer/lib/ui/markdown-renderer.tsx
Greptile SummaryThis PR adds a comments panel to the checks sidebar tab by fetching GitHub issue comments, review comments, and review bodies via three parallel REST API calls, then rendering them with a compact markdown renderer that supports sanitized HTML.
Confidence Score: 3/5Safe to merge after fixing the error-state masking in PrChecksList — all other changes are additive and well-structured. When the comments query fails (network error, rate limit, etc.) and the PR has no checks, the empty-state guard fires before the full layout is rendered, so the "Unable to load comments" message in CommentsList is never reached and the user sees a misleading "No checks or comments" placeholder instead. src/renderer/features/tasks/diff-view/changes-panel/components/pr-entry/checks-list.tsx — the empty-state guard condition needs to account for the error state.
|
| Filename | Overview |
|---|---|
| src/renderer/features/tasks/diff-view/changes-panel/components/pr-entry/checks-list.tsx | Adds a comments query alongside checks in PrChecksList; the empty-state guard doesn't account for the error state, causing a misleading "No checks or comments" message when the comments fetch fails. |
| src/renderer/features/tasks/diff-view/changes-panel/components/pr-entry/comments-list.tsx | New component that renders fetched PR comments; allowHtml is enabled for all comment authors (not just bots) and sort order is descending by updatedAt which reverses conversation chronology. |
| src/main/core/pull-requests/pr-sync-engine.ts | Adds getPullRequestComments fetching three GitHub REST endpoints (issue comments, review comments, reviews) in parallel via Promise.all with rate-limiter and retry; mapping looks correct. |
| src/main/core/pull-requests/controller.ts | Wires getPullRequestComments into the RPC controller; error mapping from parse failure to invalid_repository type is correct. |
| src/renderer/lib/ui/markdown-renderer.tsx | Replaces the variant-based rehype plugin selection with an allowHtml prop (defaulting to variant === 'full'), preserving existing behaviour for all prior callers. |
| src/shared/pull-requests.ts | Adds PullRequestComment type, comments_failed error variant, and exports getPrNumber/pullRequestErrorMessage — clean additions with no issues. |
Sequence Diagram
sequenceDiagram
participant UI as PrChecksList (renderer)
participant RQ as TanStack Query
participant RPC as IPC / RPC
participant Ctrl as PullRequest Controller
participant Eng as PrSyncEngine
participant GH as GitHub REST API
UI->>RQ: useQuery(pull-request-comments)
RQ->>RPC: getPullRequestComments(repositoryUrl, prNumber)
RPC->>Ctrl: getPullRequestComments()
Ctrl->>Eng: getPullRequestComments()
par Fetch in parallel
Eng->>GH: issues.listComments (paginate)
Eng->>GH: pulls.listReviewComments (paginate)
Eng->>GH: pulls.listReviews (paginate)
end
GH-->>Eng: issueComments, reviewComments, reviews
Eng-->>Ctrl: ok(PullRequestComment[])
Ctrl-->>RPC: "ok({ comments })"
RPC-->>RQ: response
RQ-->>UI: comments[]
UI->>UI: render ChecksList + CommentsList
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
src/renderer/features/tasks/diff-view/changes-panel/components/pr-entry/checks-list.tsx:124-126
**Error state masked by empty-state guard**
When the comments query errors (e.g. GitHub API down, rate-limit), `commentsQuery.data` is `undefined` so `comments` is `[]`, and `commentsQuery.isLoading` is `false`. The guard condition therefore evaluates to `true` and returns the `EmptyState` ("No checks or comments") before the full layout — and `CommentsList`'s "Unable to load comments" message — is ever reached. The user sees a false "nothing here" message instead of the actual error state.
Add `!commentsQuery.isError` to the guard:
`checks.length === 0 && comments.length === 0 && !commentsQuery.isLoading && !commentsQuery.isError`
### Issue 2 of 3
src/renderer/features/tasks/diff-view/changes-panel/components/pr-entry/comments-list.tsx:61
`allowHtml` is passed unconditionally for every comment author. The PR description frames this as opt-in for bot-authored HTML snippets, but human-authored comments also go through `rehypeRaw`. While `rehypeSanitize` with `defaultSchema` is applied afterwards and blocks script injection, it does enable rendering of arbitrary HTML constructs (e.g. `<details>`, `<summary>`, embedded SVG-adjacent tags) in any user's comment body, which is broader than the described intent.
```suggestion
<MarkdownRenderer
content={comment.body}
variant="compact"
allowHtml={comment.author?.userName?.endsWith('[bot]') ?? false}
/>
```
### Issue 3 of 3
src/renderer/features/tasks/diff-view/changes-panel/components/pr-entry/comments-list.tsx:82-84
Comments are sorted descending by `updatedAt`, so the most recently edited comment appears first. For a conversation/review panel this reverses the chronological reading order — a comment edited five minutes ago on a thread from last week floats above replies posted after it. Sorting ascending by `createdAt` preserves conversation order, with the most recent activity naturally appearing at the bottom.
```suggestion
[...comments].sort(
(a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
),
```
Reviews (1): Last reviewed commit: "ENG-1071 render PR comments in checks pa..." | Re-trigger Greptile
Summary
Validation