From 64476867923ada4dccd74187353cfe55bd376e90 Mon Sep 17 00:00:00 2001 From: mohamedamara1 Date: Sat, 26 Apr 2025 22:46:04 +0100 Subject: [PATCH 1/4] the closingIssues are are received successfully in the sidebar props --- src/github/githubRepository.ts | 1 + src/github/graphql.ts | 8 ++++ src/github/interface.ts | 1 + src/github/pullRequestModel.ts | 3 ++ src/github/pullRequestOverview.ts | 3 +- src/github/queries.gql | 7 ++++ src/github/utils.ts | 15 ++++++++ src/github/views.ts | 1 + webviews/components/sidebar.tsx | 38 ++++++++++++++++++- .../editorWebview/test/builder/pullRequest.ts | 1 + 10 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/github/githubRepository.ts b/src/github/githubRepository.ts index 39b7d274b1..348c989e71 100644 --- a/src/github/githubRepository.ts +++ b/src/github/githubRepository.ts @@ -988,6 +988,7 @@ export class GitHubRepository extends Disposable { number: id, }, }, true); + console.log('data:', data); if (data.repository === null) { Logger.error('Unexpected null repository when getting PR', this.id); return; diff --git a/src/github/graphql.ts b/src/github/graphql.ts index 8959383941..0f2f613f4a 100644 --- a/src/github/graphql.ts +++ b/src/github/graphql.ts @@ -632,6 +632,14 @@ export interface PullRequest extends Issue { viewerCanDisableAutoMerge: boolean; isDraft?: boolean; suggestedReviewers: SuggestedReviewerResponse[]; + closingIssuesReferences?: { + nodes: { + id: number, + title: string, + number: number + + }[]; + }; } export enum DefaultCommitTitle { diff --git a/src/github/interface.ts b/src/github/interface.ts index 71e4f156be..0e93aa1a45 100644 --- a/src/github/interface.ts +++ b/src/github/interface.ts @@ -223,6 +223,7 @@ export interface PullRequest extends Issue { mergeCommitMeta?: { title: string, description: string }; squashCommitMeta?: { title: string, description: string }; suggestedReviewers?: ISuggestedReviewer[]; + closingIssues?: Pick[] hasComments?: boolean; } diff --git a/src/github/pullRequestModel.ts b/src/github/pullRequestModel.ts index a11d43e7af..298a452777 100644 --- a/src/github/pullRequestModel.ts +++ b/src/github/pullRequestModel.ts @@ -57,6 +57,7 @@ import { IGitTreeItem, IRawFileChange, IRawFileContent, + Issue, ISuggestedReviewer, ITeam, MergeMethod, @@ -121,6 +122,7 @@ export class PullRequestModel extends IssueModel implements IPullRe public conflicts?: string[]; public suggestedReviewers?: ISuggestedReviewer[]; public hasChangesSinceLastReview?: boolean; + public closingIssues: Pick[]; private _showChangesSinceReview: boolean; private _hasPendingReview: boolean = false; private _onDidChangePendingReviewState: vscode.EventEmitter = new vscode.EventEmitter(); @@ -248,6 +250,7 @@ export class PullRequestModel extends IssueModel implements IPullRe super.update(item); this.isDraft = item.isDraft; this.suggestedReviewers = item.suggestedReviewers; + this.closingIssues = item.closingIssues ?? []; if (item.isRemoteHeadDeleted != null) { this.isRemoteHeadDeleted = item.isRemoteHeadDeleted; diff --git a/src/github/pullRequestOverview.ts b/src/github/pullRequestOverview.ts index 62657bd527..961fbb6f75 100644 --- a/src/github/pullRequestOverview.ts +++ b/src/github/pullRequestOverview.ts @@ -283,7 +283,8 @@ export class PullRequestOverviewPanel extends IssueOverviewPanel | undefined +): Array<{ id: number, number: number, title: string }> { + if (!closingIssuesReferences) { + return []; + } + + return closingIssuesReferences.map(issue => ({ + id: issue.id, + number: issue.number, + title: issue.title + })); +} + /** * Used for case insensitive sort by login */ diff --git a/src/github/views.ts b/src/github/views.ts index 0f261208f2..5e06c60cee 100644 --- a/src/github/views.ts +++ b/src/github/views.ts @@ -96,6 +96,7 @@ export interface PullRequest extends Issue { lastReviewType?: ReviewType; revertable?: boolean; busy?: boolean; + closingIssues: Pick[]; } export interface ProjectItemsReply { diff --git a/webviews/components/sidebar.tsx b/webviews/components/sidebar.tsx index eeb5d6cf24..84e22caf08 100644 --- a/webviews/components/sidebar.tsx +++ b/webviews/components/sidebar.tsx @@ -14,7 +14,7 @@ import { AuthorLink, Avatar } from '../components/user'; import { closeIcon, copilotIcon, settingsIcon } from './icon'; import { Reviewer } from './reviewer'; -export default function Sidebar({ reviewers, labels, hasWritePermission, isIssue, projectItems: projects, milestone, assignees, canAssignCopilot }: PullRequest) { +export default function Sidebar({ reviewers, labels, closingIssues, hasWritePermission, isIssue, projectItems: projects, milestone, assignees, canAssignCopilot }: PullRequest) { const { addReviewers, addAssignees, @@ -199,9 +199,32 @@ export default function Sidebar({ reviewers, labels, hasWritePermission, isIssue {milestone ? ( ) : ( -
No milestone
+ <> +
No milestoooone
+ + )} + {/*
+
{ + const newMilestone = await addMilestone(); + updatePR({ milestone: newMilestone.added }); + }}> +
Linked issues
+
+ {closingIssues.length ? ( +
+ {closingIssues.map(issue => ( + + ))} +
+ ) : ( +
None yet
+ )} +
*/} ); } @@ -273,3 +296,14 @@ function Project(project: IProjectItem & { canDelete: boolean }) { ); } + +function Issue(issue: any) { + return ( +
+
+

{issue.title}

+ {/* Add more details about the issue as needed */} +
+
+ ); +} diff --git a/webviews/editorWebview/test/builder/pullRequest.ts b/webviews/editorWebview/test/builder/pullRequest.ts index af776ab9a2..9ba3703cf0 100644 --- a/webviews/editorWebview/test/builder/pullRequest.ts +++ b/webviews/editorWebview/test/builder/pullRequest.ts @@ -57,5 +57,6 @@ export const PullRequestBuilder = createBuilderClass()({ hasReviewDraft: { default: false }, busy: { default: undefined }, lastReviewType: { default: undefined }, + closingIssues: { default: [] }, canAssignCopilot: { default: false }, }); From d714138c62adcbc6f09f4e510cb767fcd49a7008 Mon Sep 17 00:00:00 2001 From: mohamedamara1 Date: Sat, 26 Apr 2025 22:53:42 +0100 Subject: [PATCH 2/4] removed console.log --- src/github/githubRepository.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/github/githubRepository.ts b/src/github/githubRepository.ts index 348c989e71..39b7d274b1 100644 --- a/src/github/githubRepository.ts +++ b/src/github/githubRepository.ts @@ -988,7 +988,6 @@ export class GitHubRepository extends Disposable { number: id, }, }, true); - console.log('data:', data); if (data.repository === null) { Logger.error('Unexpected null repository when getting PR', this.id); return; From dc5e5584017269b0b8fba5198262a4529a7e980f Mon Sep 17 00:00:00 2001 From: mohamedamara1 Date: Sun, 27 Apr 2025 00:31:12 +0100 Subject: [PATCH 3/4] the closing issues (linked issues) are listed in the UI; only the icons are missing --- src/github/graphql.ts | 4 +-- src/github/interface.ts | 2 +- src/github/pullRequestModel.ts | 9 ++--- src/github/queries.gql | 1 + src/github/utils.ts | 8 +++-- src/github/views.ts | 2 +- webviews/components/sidebar.tsx | 64 +++++++++++++++++++-------------- 7 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/github/graphql.ts b/src/github/graphql.ts index 0f2f613f4a..632083453b 100644 --- a/src/github/graphql.ts +++ b/src/github/graphql.ts @@ -636,8 +636,8 @@ export interface PullRequest extends Issue { nodes: { id: number, title: string, - number: number - + number: number, + state: 'CLOSED' | 'OPEN' }[]; }; } diff --git a/src/github/interface.ts b/src/github/interface.ts index 0e93aa1a45..2723bf7120 100644 --- a/src/github/interface.ts +++ b/src/github/interface.ts @@ -223,7 +223,7 @@ export interface PullRequest extends Issue { mergeCommitMeta?: { title: string, description: string }; squashCommitMeta?: { title: string, description: string }; suggestedReviewers?: ISuggestedReviewer[]; - closingIssues?: Pick[] + closingIssues?: Pick[] hasComments?: boolean; } diff --git a/src/github/pullRequestModel.ts b/src/github/pullRequestModel.ts index 298a452777..ec663dad50 100644 --- a/src/github/pullRequestModel.ts +++ b/src/github/pullRequestModel.ts @@ -57,7 +57,6 @@ import { IGitTreeItem, IRawFileChange, IRawFileContent, - Issue, ISuggestedReviewer, ITeam, MergeMethod, @@ -122,7 +121,7 @@ export class PullRequestModel extends IssueModel implements IPullRe public conflicts?: string[]; public suggestedReviewers?: ISuggestedReviewer[]; public hasChangesSinceLastReview?: boolean; - public closingIssues: Pick[]; + public closingIssues: Pick[]; private _showChangesSinceReview: boolean; private _hasPendingReview: boolean = false; private _onDidChangePendingReviewState: vscode.EventEmitter = new vscode.EventEmitter(); @@ -250,8 +249,10 @@ export class PullRequestModel extends IssueModel implements IPullRe super.update(item); this.isDraft = item.isDraft; this.suggestedReviewers = item.suggestedReviewers; - this.closingIssues = item.closingIssues ?? []; - + this.closingIssues = (item.closingIssues ?? []).map(issue => ({ + ...issue, + state: issue.state as GithubItemStateEnum + })); if (item.isRemoteHeadDeleted != null) { this.isRemoteHeadDeleted = item.isRemoteHeadDeleted; } diff --git a/src/github/queries.gql b/src/github/queries.gql index 8625f479ed..357d33a1a2 100644 --- a/src/github/queries.gql +++ b/src/github/queries.gql @@ -209,6 +209,7 @@ fragment PullRequestFragment on PullRequest { id number title + state } } merged diff --git a/src/github/utils.ts b/src/github/utils.ts index e062677500..29b32ba996 100644 --- a/src/github/utils.ts +++ b/src/github/utils.ts @@ -26,6 +26,7 @@ import { GitHubRepository, ViewerPermission } from './githubRepository'; import * as GraphQL from './graphql'; import { AccountType, + GithubItemStateEnum, IAccount, IActor, IGitHubRef, @@ -924,8 +925,8 @@ function parseSuggestedReviewers( } function parseClosingIssuesReferences( - closingIssuesReferences: Array<{ id: number, number: number, title: string }> | undefined -): Array<{ id: number, number: number, title: string }> { + closingIssuesReferences: Array<{ id: number, number: number, title: string, state: 'CLOSED' | 'OPEN' }> | undefined +): Array<{ id: number, number: number, title: string, state: GithubItemStateEnum }> { if (!closingIssuesReferences) { return []; } @@ -933,7 +934,8 @@ function parseClosingIssuesReferences( return closingIssuesReferences.map(issue => ({ id: issue.id, number: issue.number, - title: issue.title + title: issue.title, + state: issue.state as GithubItemStateEnum })); } diff --git a/src/github/views.ts b/src/github/views.ts index 5e06c60cee..70ebc0fab4 100644 --- a/src/github/views.ts +++ b/src/github/views.ts @@ -96,7 +96,7 @@ export interface PullRequest extends Issue { lastReviewType?: ReviewType; revertable?: boolean; busy?: boolean; - closingIssues: Pick[]; + closingIssues: Pick[]; } export interface ProjectItemsReply { diff --git a/webviews/components/sidebar.tsx b/webviews/components/sidebar.tsx index 84e22caf08..fd0aa8420e 100644 --- a/webviews/components/sidebar.tsx +++ b/webviews/components/sidebar.tsx @@ -6,7 +6,7 @@ import React, { useContext } from 'react'; import { COPILOT_LOGINS } from '../../src/common/copilot'; import { gitHubLabelColor } from '../../src/common/utils'; -import { IMilestone, IProjectItem, reviewerId } from '../../src/github/interface'; +import { IMilestone, IProjectItem, Issue, reviewerId, } from '../../src/github/interface'; import { PullRequest } from '../../src/github/views'; import PullRequestContext from '../common/context'; import { Label } from '../common/label'; @@ -54,7 +54,7 @@ export default function Sidebar({ reviewers, labels, closingIssues, hasWritePerm {reviewers && reviewers.length ? ( reviewers.map(state => ( - + )) ) : (
None yet
@@ -199,32 +199,29 @@ export default function Sidebar({ reviewers, labels, closingIssues, hasWritePerm {milestone ? ( ) : ( - <> -
No milestoooone
- - + <> +
No milestone
+ )} - {/*
-
{ - const newMilestone = await addMilestone(); - updatePR({ milestone: newMilestone.added }); - }}> -
Linked issues
+
+
+
Linked Issues
- {closingIssues.length ? ( -
+ {closingIssues.length > 0 ? ( +
{closingIssues.map(issue => ( - +
+
+ +
+
))}
) : ( -
None yet
+
None yet
)} -
*/} +
); } @@ -297,13 +294,26 @@ function Project(project: IProjectItem & { canDelete: boolean }) { ); } -function Issue(issue: any) { +function IssueItem({ issue }: { issue: Pick }) { return ( -
-
-

{issue.title}

- {/* Add more details about the issue as needed */} -
-
+ <> + + {issue.title} + + ); } + +function IssueStateIcon({ state }: { state: string }) { + const normalizedState = state.toLowerCase().trim(); + + switch (normalizedState) { + case 'open': + return settingsIcon; + case 'closed': + return closeIcon; + default: + return closeIcon; + } +} + From 41842abf73b9a103d98882ccb0d373154918cb84 Mon Sep 17 00:00:00 2001 From: Alex Ross <38270282+alexr00@users.noreply.github.com> Date: Wed, 7 May 2025 12:55:34 +0200 Subject: [PATCH 4/4] Refactor out state and an `IssueReference` --- src/github/interface.ts | 9 ++++++++- src/github/issueModel.ts | 8 ++------ src/github/pullRequestModel.ts | 18 ++++++------------ src/github/utils.ts | 14 ++++++++++++-- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/github/interface.ts b/src/github/interface.ts index 2723bf7120..d388af9be7 100644 --- a/src/github/interface.ts +++ b/src/github/interface.ts @@ -204,6 +204,13 @@ export interface Issue { reactionCount: number; } +export interface IssueReference { + id: number; + number: number; + title: string; + state: GithubItemStateEnum; +} + export interface PullRequest extends Issue { isDraft?: boolean; isRemoteHeadDeleted?: boolean; @@ -223,7 +230,7 @@ export interface PullRequest extends Issue { mergeCommitMeta?: { title: string, description: string }; squashCommitMeta?: { title: string, description: string }; suggestedReviewers?: ISuggestedReviewer[]; - closingIssues?: Pick[] + closingIssues?: IssueReference[] hasComments?: boolean; } diff --git a/src/github/issueModel.ts b/src/github/issueModel.ts index 39e903e374..8a6a58d172 100644 --- a/src/github/issueModel.ts +++ b/src/github/issueModel.ts @@ -18,7 +18,7 @@ import { UpdateIssueResponse, } from './graphql'; import { GithubItemStateEnum, IAccount, IIssueEditData, IMilestone, IProject, IProjectItem, Issue } from './interface'; -import { parseGraphQlIssueComment, parseGraphQLTimelineEvents } from './utils'; +import { parseGraphQlIssueComment, parseGraphQLTimelineEvents, parsePullRequestState } from './utils'; export class IssueModel { static ID = 'IssueModel'; @@ -104,11 +104,7 @@ export class IssueModel { } protected updateState(state: string) { - if (state.toLowerCase() === 'open') { - this.state = GithubItemStateEnum.Open; - } else { - this.state = GithubItemStateEnum.Closed; - } + this.state = parsePullRequestState(state); } update(issue: TItem): void { diff --git a/src/github/pullRequestModel.ts b/src/github/pullRequestModel.ts index ec663dad50..19cb2ae19b 100644 --- a/src/github/pullRequestModel.ts +++ b/src/github/pullRequestModel.ts @@ -57,6 +57,7 @@ import { IGitTreeItem, IRawFileChange, IRawFileContent, + IssueReference, ISuggestedReviewer, ITeam, MergeMethod, @@ -83,6 +84,7 @@ import { parseGraphQLTimelineEvents, parseMergeability, parseMergeQueueEntry, + parsePullRequestState, restPaginate, } from './utils'; @@ -121,7 +123,7 @@ export class PullRequestModel extends IssueModel implements IPullRe public conflicts?: string[]; public suggestedReviewers?: ISuggestedReviewer[]; public hasChangesSinceLastReview?: boolean; - public closingIssues: Pick[]; + public closingIssues: IssueReference[]; private _showChangesSinceReview: boolean; private _hasPendingReview: boolean = false; private _onDidChangePendingReviewState: vscode.EventEmitter = new vscode.EventEmitter(); @@ -236,23 +238,15 @@ export class PullRequestModel extends IssueModel implements IPullRe public base: GitHubRef; protected override updateState(state: string) { - if (state.toLowerCase() === 'open') { - this.state = GithubItemStateEnum.Open; - } else if (state.toLowerCase() === 'merged' || this.item.merged) { - this.state = GithubItemStateEnum.Merged; - } else { - this.state = GithubItemStateEnum.Closed; - } + const newState = parsePullRequestState(state); + this.state = this.item.merged ? GithubItemStateEnum.Merged : newState; } override update(item: PullRequest): void { super.update(item); this.isDraft = item.isDraft; this.suggestedReviewers = item.suggestedReviewers; - this.closingIssues = (item.closingIssues ?? []).map(issue => ({ - ...issue, - state: issue.state as GithubItemStateEnum - })); + this.closingIssues = item.closingIssues ?? []; if (item.isRemoteHeadDeleted != null) { this.isRemoteHeadDeleted = item.isRemoteHeadDeleted; } diff --git a/src/github/utils.ts b/src/github/utils.ts index 29b32ba996..3b65723440 100644 --- a/src/github/utils.ts +++ b/src/github/utils.ts @@ -742,6 +742,16 @@ export function parseMergeability(mergeability: 'UNKNOWN' | 'MERGEABLE' | 'CONFL return parsed; } +export function parsePullRequestState(state: string): GithubItemStateEnum { + if (state.toLowerCase() === 'open') { + return GithubItemStateEnum.Open; + } else if (state.toLowerCase() === 'merged') { + return GithubItemStateEnum.Merged; + } else { + return GithubItemStateEnum.Closed; + } +} + export function parseGraphQLPullRequest( graphQLPullRequest: GraphQL.PullRequest, githubRepository: GitHubRepository, @@ -925,7 +935,7 @@ function parseSuggestedReviewers( } function parseClosingIssuesReferences( - closingIssuesReferences: Array<{ id: number, number: number, title: string, state: 'CLOSED' | 'OPEN' }> | undefined + closingIssuesReferences: Array<{ id: number, number: number, title: string, state: string }> | undefined ): Array<{ id: number, number: number, title: string, state: GithubItemStateEnum }> { if (!closingIssuesReferences) { return []; @@ -935,7 +945,7 @@ function parseClosingIssuesReferences( id: issue.id, number: issue.number, title: issue.title, - state: issue.state as GithubItemStateEnum + state: parsePullRequestState(issue.state) })); }