Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/github/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,15 @@ export interface PullRequest extends Issue {
suggestedReviewers: SuggestedReviewerResponse[];
additions?: number;
deletions?: number;
closingIssuesReferences?: {
Comment thread
alexr00 marked this conversation as resolved.
nodes: {
id: number,
title: string,
number: number,
state: 'CLOSED' | 'OPEN',
url: string,
}[];
Comment thread
alexr00 marked this conversation as resolved.
};
}

export enum DefaultCommitTitle {
Expand Down
9 changes: 9 additions & 0 deletions src/github/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,14 @@ export interface Issue {
reactions: Reaction[];
}

export interface IssueReference {
id: number;
number: number;
title: string;
state: GithubItemStateEnum;
url: string;
}

export interface PullRequest extends Issue {
isDraft?: boolean;
isRemoteHeadDeleted?: boolean;
Expand All @@ -242,6 +250,7 @@ export interface PullRequest extends Issue {
mergeCommitMeta?: { title: string, description: string };
squashCommitMeta?: { title: string, description: string };
suggestedReviewers?: ISuggestedReviewer[];
closingIssues?: IssueReference[]
Comment thread
alexr00 marked this conversation as resolved.
hasComments?: boolean;
additions?: number;
deletions?: number;
Expand Down
4 changes: 3 additions & 1 deletion src/github/pullRequestModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import {
IGitTreeItem,
IRawFileChange,
IRawFileContent,
IssueReference,
ISuggestedReviewer,
ITeam,
MergeMethod,
Expand Down Expand Up @@ -137,6 +138,7 @@ export class PullRequestModel extends IssueModel<PullRequest> implements IPullRe
public conflicts?: string[];
public suggestedReviewers?: ISuggestedReviewer[];
public hasChangesSinceLastReview?: boolean;
public closingIssues: IssueReference[] = [];
private _showChangesSinceReview: boolean;
private _hasPendingReview: boolean = false;
private _onDidChangePendingReviewState: vscode.EventEmitter<boolean> = this._register(new vscode.EventEmitter<boolean>());
Expand Down Expand Up @@ -265,7 +267,7 @@ export class PullRequestModel extends IssueModel<PullRequest> implements IPullRe
}

this.suggestedReviewers = item.suggestedReviewers;

this.closingIssues = item.closingIssues ?? [];
if (item.isRemoteHeadDeleted != null) {
this.isRemoteHeadDeleted = item.isRemoteHeadDeleted;
}
Expand Down
3 changes: 2 additions & 1 deletion src/github/pullRequestOverview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,8 @@ export class PullRequestOverviewPanel extends IssueOverviewPanel<PullRequestMode
currentUserReviewState: reviewState,
revertable: pullRequest.state === GithubItemStateEnum.Merged,
isCopilotOnMyBehalf: await isCopilotOnMyBehalf(pullRequest, currentUser, coAuthors),
generateDescriptionTitle: this.getGenerateDescriptionTitle()
generateDescriptionTitle: this.getGenerateDescriptionTitle(),
closingIssues: pullRequest.closingIssues,
};
this._postMessage({
command: 'pr.initialize',
Expand Down
9 changes: 9 additions & 0 deletions src/github/queries.gql
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,15 @@ fragment PullRequestFragment on PullRequest {
mergeCommitMessage
mergeCommitTitle
}
closingIssuesReferences(first: 50) {
Comment thread
alexr00 marked this conversation as resolved.
nodes {
id
number
title
state
url
}
Comment thread
alexr00 marked this conversation as resolved.
}
merged
mergeable
mergeQueueEntry {
Expand Down
17 changes: 17 additions & 0 deletions src/github/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,7 @@ export async function parseGraphQLPullRequest(
commentCount: graphQLPullRequest.comments.totalCount,
additions: graphQLPullRequest.additions,
deletions: graphQLPullRequest.deletions,
closingIssues: parseClosingIssuesReferences(graphQLPullRequest.closingIssuesReferences?.nodes),
};
Comment on lines 924 to 928
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New closingIssues parsing/mapping is untested. Since parseGraphQLPullRequest already has unit coverage under src/test (e.g. prsTree.test.ts), consider adding a case that includes closingIssuesReferences to verify state mapping and that the parsed references are propagated correctly.

Copilot generated this review using guidance from repository custom instructions.
pr.mergeCommitMeta = parseCommitMeta(graphQLPullRequest.baseRepository.mergeCommitTitle, graphQLPullRequest.baseRepository.mergeCommitMessage, pr);
pr.squashCommitMeta = parseCommitMeta(graphQLPullRequest.baseRepository.squashMergeCommitTitle, graphQLPullRequest.baseRepository.squashMergeCommitMessage, pr);
Expand Down Expand Up @@ -1068,6 +1069,22 @@ function parseSuggestedReviewers(
return ret.sort(loginComparator);
}

function parseClosingIssuesReferences(
closingIssuesReferences: Array<{ id: number, number: number, title: string, state: string, url: string }> | undefined
): Array<{ id: number, number: number, title: string, state: GithubItemStateEnum, url: string }> {
if (!closingIssuesReferences) {
return [];
}

return closingIssuesReferences.map(issue => ({
id: issue.id,
number: issue.number,
title: issue.title,
state: issue.state === 'OPEN' ? GithubItemStateEnum.Open : GithubItemStateEnum.Closed,
url: issue.url,
}));
Comment thread
alexr00 marked this conversation as resolved.
}

/**
* Used for case insensitive sort by login
*/
Expand Down
8 changes: 8 additions & 0 deletions src/github/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ export enum ReviewType {
RequestChanges = 'requestChanges',
}

export interface IssueReference {
number: number;
title: string;
state: GithubItemStateEnum;
url: string;
}
Comment thread
alexr00 marked this conversation as resolved.

export interface DisplayLabel extends ILabel {
displayName: string;
}
Expand Down Expand Up @@ -112,6 +119,7 @@ export interface PullRequest extends Issue {
busy?: boolean;
loadingCommit?: string;
generateDescriptionTitle?: string;
closingIssues: IssueReference[];
}

export interface ProjectItemsReply {
Expand Down
8 changes: 8 additions & 0 deletions webviews/common/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,14 @@ body img.avatar {
fill: var(--vscode-issues-open);
}

.section-icon.issue-open svg path {
fill: var(--vscode-issues-open);
}

.section-icon.issue-closed svg path {
fill: var(--vscode-issues-closed);
}

.reviewer-icons {
display: flex;
gap: 4px;
Expand Down
2 changes: 2 additions & 0 deletions webviews/components/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export const outputIcon = <Icon src={require('../../resources/icons/codicons/out
export const skipIcon = <Icon src={require('../../resources/icons/codicons/skip.svg')} className='skip' />;

// Other icons
export const issueIcon = <Icon src={require('../../resources/icons/issue_webview.svg')} />;
export const issueClosedIcon = <Icon src={require('../../resources/icons/codicons/pass.svg')} />;
Comment thread
alexr00 marked this conversation as resolved.
Outdated
export const copilotErrorIcon = <Icon className='copilot-icon' src={require('../../resources/icons/copilot-error.svg')} />;
export const copilotInProgressIcon = <Icon className='copilot-icon' src={require('../../resources/icons/copilot-in-progress.svg')} />;
export const copilotSuccessIcon = <Icon className='copilot-icon' src={require('../../resources/icons/copilot-success.svg')} />;
37 changes: 33 additions & 4 deletions webviews/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
*--------------------------------------------------------------------------------------------*/

import React, { useContext, useEffect, useRef, useState } from 'react';
import { closeIcon, copilotIcon, settingsIcon } from './icon';
import { closeIcon, copilotIcon, issueClosedIcon, issueIcon, settingsIcon } from './icon';
import { Reviewer } from './reviewer';
import { COPILOT_LOGINS } from '../../src/common/copilot';
import { gitHubLabelColor } from '../../src/common/utils';
import { IAccount, IMilestone, IProjectItem, isITeam, reviewerId, reviewerLabel, ReviewState } from '../../src/github/interface';
import { ChangeReviewersReply, PullRequest } from '../../src/github/views';
import { GithubItemStateEnum, IAccount, IMilestone, IProjectItem, isITeam, reviewerId, reviewerLabel, ReviewState } from '../../src/github/interface';
import { ChangeReviewersReply, IssueReference, PullRequest } from '../../src/github/views';
import PullRequestContext from '../common/context';
import { Label } from '../common/label';
import { AuthorLink, Avatar } from '../components/user';
Expand Down Expand Up @@ -53,7 +53,7 @@ function Section({
);
}

export default function Sidebar({ reviewers, labels, hasWritePermission, isIssue, projectItems: projects, milestone, assignees, canAssignCopilot, canRequestCopilotReview }: PullRequest) {
export default function Sidebar({ reviewers, labels, closingIssues, hasWritePermission, isIssue, projectItems: projects, milestone, assignees, canAssignCopilot, canRequestCopilotReview }: PullRequest) {
Comment thread
alexr00 marked this conversation as resolved.
const {
addReviewers,
addReviewerCopilot,
Expand Down Expand Up @@ -268,6 +268,22 @@ export default function Sidebar({ reviewers, labels, hasWritePermission, isIssue
<div className="section-placeholder">No milestone</div>
)}
</Section>

<Section
Comment thread
alexr00 marked this conversation as resolved.
Outdated
id="closingIssues"
title="Linked Issues"
hasWritePermission={false}
>
{closingIssues.length ? (
closingIssues.map(issue => (
<div key={issue.number} className="section-item">
<IssueItem issue={issue} />
</div>
))
) : (
<div className="section-placeholder">None yet</div>
)}
</Section>
</div>
);
}
Expand Down Expand Up @@ -577,3 +593,16 @@ function ConvertToDraft() {
</div>
);
}

function IssueItem({ issue }: { issue: IssueReference }) {
const isOpen = issue.state === GithubItemStateEnum.Open;
return (
<div className="avatar-with-author">
Comment thread
alexr00 marked this conversation as resolved.
Outdated
<span className={`section-icon ${isOpen ? 'issue-open' : 'issue-closed'}`}>
{isOpen ? issueIcon : issueClosedIcon}
Comment thread
alexr00 marked this conversation as resolved.
Outdated
</span>
<a href={issue.url} title={issue.url}>#{issue.number} {issue.title}</a>
Comment thread
alexr00 marked this conversation as resolved.
Outdated
</div>
);
}

1 change: 1 addition & 0 deletions webviews/editorWebview/test/builder/pullRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const PullRequestBuilder = createBuilderClass<PullRequest>()({
hasReviewDraft: { default: false },
busy: { default: undefined },
lastReviewType: { default: undefined },
closingIssues: { default: [] },
canAssignCopilot: { default: false },
canRequestCopilotReview: { default: false },
isCopilotOnMyBehalf: { default: false },
Expand Down