Skip to content

Commit fc37b54

Browse files
committed
refactor(api): use graphql api for issue and pull request enrichment
Signed-off-by: Adam Setch <[email protected]>
1 parent cb2b01b commit fc37b54

File tree

11 files changed

+96
-144
lines changed

11 files changed

+96
-144
lines changed

src/renderer/typesGitHub.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
IssueState,
55
IssueStateReason,
66
MilestoneFieldsFragment,
7+
PullRequestReviewState,
78
PullRequestState,
89
} from './utils/api/graphql/generated/graphql';
910

@@ -87,13 +88,6 @@ export type CheckSuiteStatus =
8788
| 'timed_out'
8889
| 'waiting';
8990

90-
export type PullRequestReviewState =
91-
| 'APPROVED'
92-
| 'CHANGES_REQUESTED'
93-
| 'COMMENTED'
94-
| 'DISMISSED'
95-
| 'PENDING';
96-
9791
export type PullRequestReviewAuthorAssociation =
9892
| 'COLLABORATOR'
9993
| 'CONTRIBUTOR'
@@ -278,19 +272,6 @@ export interface GitifyPullRequestReview {
278272
users: string[];
279273
}
280274

281-
export interface PullRequestReview {
282-
id: number;
283-
node_id: string;
284-
user: User;
285-
body: string;
286-
state: PullRequestReviewState;
287-
html_url: Link;
288-
pull_request_url: Link;
289-
author_association: PullRequestReviewAuthorAssociation;
290-
submitted_at: string;
291-
commit_id: string;
292-
}
293-
294275
export interface Commit {
295276
sha: string;
296277
node_id: string;

src/renderer/utils/api/__mocks__/response-mocks.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import {
44
} from '../../../__mocks__/account-mocks';
55
import type { Link } from '../../../types';
66
import type { Notification, Repository, User } from '../../../typesGitHub';
7-
import type { FetchDiscussionByNumberQuery } from '../graphql/generated/graphql';
7+
import {
8+
type FetchDiscussionByNumberQuery,
9+
PullRequestReviewState,
10+
} from '../graphql/generated/graphql';
811

912
export const mockNotificationUser: User = {
1013
login: 'octocat',
@@ -59,15 +62,15 @@ export const mockGitHubNotifications: Notification[] = [
5962
},
6063
reviews: [
6164
{
62-
state: 'APPROVED',
65+
state: PullRequestReviewState.Approved,
6366
users: ['octocat'],
6467
},
6568
{
66-
state: 'CHANGES_REQUESTED',
69+
state: PullRequestReviewState.ChangesRequested,
6770
users: ['gitify-app'],
6871
},
6972
{
70-
state: 'PENDING',
73+
state: PullRequestReviewState.Pending,
7174
users: ['gitify-user'],
7275
},
7376
],

src/renderer/utils/api/graphql/generated/gql.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ type Documents = {
1818
"fragment AuthorFields on Actor {\n login\n html_url: url\n avatar_url: avatarUrl\n type: __typename\n}": typeof types.AuthorFieldsFragmentDoc,
1919
"query FetchDiscussionByNumber($owner: String!, $name: String!, $number: Int!, $lastComments: Int, $lastReplies: Int, $firstLabels: Int, $includeIsAnswered: Boolean!) {\n repository(owner: $owner, name: $name) {\n discussion(number: $number) {\n __typename\n number\n title\n stateReason\n isAnswered @include(if: $includeIsAnswered)\n url\n author {\n ...AuthorFields\n }\n comments(last: $lastComments) {\n totalCount\n nodes {\n ...CommentFields\n replies(last: $lastReplies) {\n nodes {\n ...CommentFields\n }\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n }\n }\n}\n\nfragment CommentFields on DiscussionComment {\n databaseId\n createdAt\n author {\n ...AuthorFields\n }\n url\n}": typeof types.FetchDiscussionByNumberDocument,
2020
"query FetchIssueByNumber($owner: String!, $name: String!, $number: Int!, $firstLabels: Int) {\n repository(owner: $owner, name: $name) {\n issue(number: $number) {\n __typename\n number\n title\n url\n state\n stateReason\n milestone {\n ...MilestoneFields\n }\n author {\n ...AuthorFields\n }\n comments(last: 1) {\n totalCount\n nodes {\n url\n author {\n ...AuthorFields\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n }\n }\n}\n\nfragment MilestoneFields on Milestone {\n state\n title\n}": typeof types.FetchIssueByNumberDocument,
21-
"query FetchPullByNumber($owner: String!, $name: String!, $number: Int!, $firstLabels: Int) {\n repository(owner: $owner, name: $name) {\n pullRequest(number: $number) {\n __typename\n number\n title\n url\n state\n merged\n isDraft\n isInMergeQueue\n milestone {\n ...MilestoneFields\n }\n author {\n ...AuthorFields\n }\n comments(last: 1) {\n totalCount\n nodes {\n url\n author {\n ...AuthorFields\n }\n }\n }\n reviews(last: 1) {\n totalCount\n nodes {\n url\n createdAt\n author {\n login\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n closingIssuesReferences(first: 50) {\n nodes {\n number\n }\n }\n }\n }\n}\n\nfragment MilestoneFields on Milestone {\n state\n title\n}": typeof types.FetchPullByNumberDocument,
21+
"query FetchPullByNumber($owner: String!, $name: String!, $number: Int!, $firstLabels: Int) {\n repository(owner: $owner, name: $name) {\n pullRequest(number: $number) {\n __typename\n number\n title\n url\n state\n merged\n isDraft\n isInMergeQueue\n milestone {\n ...MilestoneFields\n }\n author {\n ...AuthorFields\n }\n comments(last: 1) {\n totalCount\n nodes {\n url\n author {\n ...AuthorFields\n }\n }\n }\n reviews(last: 100) {\n totalCount\n nodes {\n state\n author {\n login\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n closingIssuesReferences(first: 50) {\n nodes {\n number\n }\n }\n }\n }\n}\n\nfragment MilestoneFields on Milestone {\n state\n title\n}": typeof types.FetchPullByNumberDocument,
2222
};
2323
const documents: Documents = {
2424
"fragment AuthorFields on Actor {\n login\n html_url: url\n avatar_url: avatarUrl\n type: __typename\n}": types.AuthorFieldsFragmentDoc,
2525
"query FetchDiscussionByNumber($owner: String!, $name: String!, $number: Int!, $lastComments: Int, $lastReplies: Int, $firstLabels: Int, $includeIsAnswered: Boolean!) {\n repository(owner: $owner, name: $name) {\n discussion(number: $number) {\n __typename\n number\n title\n stateReason\n isAnswered @include(if: $includeIsAnswered)\n url\n author {\n ...AuthorFields\n }\n comments(last: $lastComments) {\n totalCount\n nodes {\n ...CommentFields\n replies(last: $lastReplies) {\n nodes {\n ...CommentFields\n }\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n }\n }\n}\n\nfragment CommentFields on DiscussionComment {\n databaseId\n createdAt\n author {\n ...AuthorFields\n }\n url\n}": types.FetchDiscussionByNumberDocument,
2626
"query FetchIssueByNumber($owner: String!, $name: String!, $number: Int!, $firstLabels: Int) {\n repository(owner: $owner, name: $name) {\n issue(number: $number) {\n __typename\n number\n title\n url\n state\n stateReason\n milestone {\n ...MilestoneFields\n }\n author {\n ...AuthorFields\n }\n comments(last: 1) {\n totalCount\n nodes {\n url\n author {\n ...AuthorFields\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n }\n }\n}\n\nfragment MilestoneFields on Milestone {\n state\n title\n}": types.FetchIssueByNumberDocument,
27-
"query FetchPullByNumber($owner: String!, $name: String!, $number: Int!, $firstLabels: Int) {\n repository(owner: $owner, name: $name) {\n pullRequest(number: $number) {\n __typename\n number\n title\n url\n state\n merged\n isDraft\n isInMergeQueue\n milestone {\n ...MilestoneFields\n }\n author {\n ...AuthorFields\n }\n comments(last: 1) {\n totalCount\n nodes {\n url\n author {\n ...AuthorFields\n }\n }\n }\n reviews(last: 1) {\n totalCount\n nodes {\n url\n createdAt\n author {\n login\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n closingIssuesReferences(first: 50) {\n nodes {\n number\n }\n }\n }\n }\n}\n\nfragment MilestoneFields on Milestone {\n state\n title\n}": types.FetchPullByNumberDocument,
27+
"query FetchPullByNumber($owner: String!, $name: String!, $number: Int!, $firstLabels: Int) {\n repository(owner: $owner, name: $name) {\n pullRequest(number: $number) {\n __typename\n number\n title\n url\n state\n merged\n isDraft\n isInMergeQueue\n milestone {\n ...MilestoneFields\n }\n author {\n ...AuthorFields\n }\n comments(last: 1) {\n totalCount\n nodes {\n url\n author {\n ...AuthorFields\n }\n }\n }\n reviews(last: 100) {\n totalCount\n nodes {\n state\n author {\n login\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n closingIssuesReferences(first: 50) {\n nodes {\n number\n }\n }\n }\n }\n}\n\nfragment MilestoneFields on Milestone {\n state\n title\n}": types.FetchPullByNumberDocument,
2828
};
2929

3030
/**
@@ -42,7 +42,7 @@ export function graphql(source: "query FetchIssueByNumber($owner: String!, $name
4242
/**
4343
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
4444
*/
45-
export function graphql(source: "query FetchPullByNumber($owner: String!, $name: String!, $number: Int!, $firstLabels: Int) {\n repository(owner: $owner, name: $name) {\n pullRequest(number: $number) {\n __typename\n number\n title\n url\n state\n merged\n isDraft\n isInMergeQueue\n milestone {\n ...MilestoneFields\n }\n author {\n ...AuthorFields\n }\n comments(last: 1) {\n totalCount\n nodes {\n url\n author {\n ...AuthorFields\n }\n }\n }\n reviews(last: 1) {\n totalCount\n nodes {\n url\n createdAt\n author {\n login\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n closingIssuesReferences(first: 50) {\n nodes {\n number\n }\n }\n }\n }\n}\n\nfragment MilestoneFields on Milestone {\n state\n title\n}"): typeof import('./graphql').FetchPullByNumberDocument;
45+
export function graphql(source: "query FetchPullByNumber($owner: String!, $name: String!, $number: Int!, $firstLabels: Int) {\n repository(owner: $owner, name: $name) {\n pullRequest(number: $number) {\n __typename\n number\n title\n url\n state\n merged\n isDraft\n isInMergeQueue\n milestone {\n ...MilestoneFields\n }\n author {\n ...AuthorFields\n }\n comments(last: 1) {\n totalCount\n nodes {\n url\n author {\n ...AuthorFields\n }\n }\n }\n reviews(last: 100) {\n totalCount\n nodes {\n state\n author {\n login\n }\n }\n }\n labels(first: $firstLabels) {\n nodes {\n name\n }\n }\n closingIssuesReferences(first: 50) {\n nodes {\n number\n }\n }\n }\n }\n}\n\nfragment MilestoneFields on Milestone {\n state\n title\n}"): typeof import('./graphql').FetchPullByNumberDocument;
4646

4747

4848
export function graphql(source: string) {

src/renderer/utils/api/graphql/generated/graphql.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36269,7 +36269,7 @@ export type FetchPullByNumberQuery = { __typename?: 'Query', repository?: { __ty
3626936269
| { __typename?: 'Mannequin', login: string, html_url: any, avatar_url: any, type: 'Mannequin' }
3627036270
| { __typename?: 'Organization', login: string, html_url: any, avatar_url: any, type: 'Organization' }
3627136271
| { __typename?: 'User', login: string, html_url: any, avatar_url: any, type: 'User' }
36272-
| null } | null> | null }, reviews?: { __typename?: 'PullRequestReviewConnection', totalCount: number, nodes?: Array<{ __typename?: 'PullRequestReview', url: any, createdAt: any, author?:
36272+
| null } | null> | null }, reviews?: { __typename?: 'PullRequestReviewConnection', totalCount: number, nodes?: Array<{ __typename?: 'PullRequestReview', state: PullRequestReviewState, author?:
3627336273
| { __typename?: 'Bot', login: string }
3627436274
| { __typename?: 'EnterpriseUserAccount', login: string }
3627536275
| { __typename?: 'Mannequin', login: string }
@@ -36440,11 +36440,10 @@ export const FetchPullByNumberDocument = new TypedDocumentString(`
3644036440
}
3644136441
}
3644236442
}
36443-
reviews(last: 1) {
36443+
reviews(last: 100) {
3644436444
totalCount
3644536445
nodes {
36446-
url
36447-
createdAt
36446+
state
3644836447
author {
3644936448
login
3645036449
}

src/renderer/utils/api/graphql/pull.graphql

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,10 @@ query FetchPullByNumber(
2929
}
3030
}
3131
}
32-
reviews(last: 1) {
32+
reviews(last: 100) {
3333
totalCount
3434
nodes {
35-
url
36-
createdAt
35+
state
3736
author {
3837
login
3938
}

src/renderer/utils/icons.test.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99

1010
import { IconColor } from '../types';
1111
import type { GitifyPullRequestReview } from '../typesGitHub';
12+
import { PullRequestReviewState } from './api/graphql/generated/graphql';
1213
import {
1314
getAuthMethodIcon,
1415
getDefaultUserIcon,
@@ -23,18 +24,18 @@ describe('renderer/utils/icons.ts', () => {
2324

2425
beforeEach(() => {
2526
mockReviewSingleReviewer = {
26-
state: 'APPROVED',
27+
state: PullRequestReviewState.Approved,
2728
users: ['user1'],
2829
};
2930
mockReviewMultipleReviewer = {
30-
state: 'APPROVED',
31+
state: PullRequestReviewState.Approved,
3132
users: ['user1', 'user2'],
3233
};
3334
});
3435

3536
it('approved', () => {
36-
mockReviewSingleReviewer.state = 'APPROVED';
37-
mockReviewMultipleReviewer.state = 'APPROVED';
37+
mockReviewSingleReviewer.state = PullRequestReviewState.Approved;
38+
mockReviewMultipleReviewer.state = PullRequestReviewState.Approved;
3839

3940
expect(getPullRequestReviewIcon(mockReviewSingleReviewer)).toEqual({
4041
type: CheckIcon,
@@ -50,8 +51,9 @@ describe('renderer/utils/icons.ts', () => {
5051
});
5152

5253
it('changes requested', () => {
53-
mockReviewSingleReviewer.state = 'CHANGES_REQUESTED';
54-
mockReviewMultipleReviewer.state = 'CHANGES_REQUESTED';
54+
mockReviewSingleReviewer.state = PullRequestReviewState.ChangesRequested;
55+
mockReviewMultipleReviewer.state =
56+
PullRequestReviewState.ChangesRequested;
5557

5658
expect(getPullRequestReviewIcon(mockReviewSingleReviewer)).toEqual({
5759
type: FileDiffIcon,
@@ -67,8 +69,8 @@ describe('renderer/utils/icons.ts', () => {
6769
});
6870

6971
it('commented', () => {
70-
mockReviewSingleReviewer.state = 'COMMENTED';
71-
mockReviewMultipleReviewer.state = 'COMMENTED';
72+
mockReviewSingleReviewer.state = PullRequestReviewState.Commented;
73+
mockReviewMultipleReviewer.state = PullRequestReviewState.Commented;
7274

7375
expect(getPullRequestReviewIcon(mockReviewSingleReviewer)).toEqual({
7476
type: CommentIcon,
@@ -84,8 +86,8 @@ describe('renderer/utils/icons.ts', () => {
8486
});
8587

8688
it('dismissed', () => {
87-
mockReviewSingleReviewer.state = 'DISMISSED';
88-
mockReviewMultipleReviewer.state = 'DISMISSED';
89+
mockReviewSingleReviewer.state = PullRequestReviewState.Dismissed;
90+
mockReviewMultipleReviewer.state = PullRequestReviewState.Dismissed;
8991

9092
expect(getPullRequestReviewIcon(mockReviewSingleReviewer)).toEqual({
9193
type: CommentIcon,
@@ -101,8 +103,8 @@ describe('renderer/utils/icons.ts', () => {
101103
});
102104

103105
it('pending', () => {
104-
mockReviewSingleReviewer.state = 'PENDING';
105-
mockReviewMultipleReviewer.state = 'PENDING';
106+
mockReviewSingleReviewer.state = PullRequestReviewState.Pending;
107+
mockReviewMultipleReviewer.state = PullRequestReviewState.Pending;
106108

107109
expect(getPullRequestReviewIcon(mockReviewSingleReviewer)).toBeNull();
108110

src/renderer/utils/links.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ import type { Account, Hostname, Link } from '../types';
55
import type { Notification, Repository, SubjectUser } from '../typesGitHub';
66
import { getDeveloperSettingsURL } from './auth/utils';
77
import { openExternalLink } from './comms';
8-
import {
9-
generateGitHubWebUrl,
10-
generateNotificationReferrerId,
11-
} from './helpers';
8+
import { generateGitHubWebUrl } from './helpers';
129

1310
export function openGitifyReleaseNotes(version: string) {
1411
openExternalLink(
@@ -58,14 +55,8 @@ export function openRepository(repository: Repository) {
5855
}
5956

6057
export async function openNotification(notification: Notification) {
61-
const url = new URL(await generateGitHubWebUrl(notification));
62-
63-
url.searchParams.set(
64-
'notification_referrer_id',
65-
generateNotificationReferrerId(notification),
66-
);
67-
68-
openExternalLink(url.toString() as Link);
58+
const url = await generateGitHubWebUrl(notification);
59+
openExternalLink(url);
6960
}
7061

7162
export function openGitHubParticipatingDocs() {

src/renderer/utils/notifications/handlers/discussion.ts

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import type {
1616
GitifySubject,
1717
Notification,
1818
Subject,
19-
SubjectUser,
2019
} from '../../../typesGitHub';
2120
import { fetchDiscussionByNumber } from '../../api/client';
2221
import type {
@@ -25,6 +24,7 @@ import type {
2524
} from '../../api/graphql/generated/graphql';
2625
import { isStateFilteredOut } from '../filters/filter';
2726
import { DefaultHandler } from './default';
27+
import { getSubjectAuthor } from './utils';
2828

2929
type DiscussionComment = NonNullable<
3030
NonNullable<
@@ -57,9 +57,7 @@ class DiscussionHandler extends DefaultHandler {
5757

5858
if (discussion.isAnswered) {
5959
discussionState = 'ANSWERED';
60-
}
61-
62-
if (discussion.stateReason) {
60+
} else if (discussion.stateReason) {
6361
discussionState = discussion.stateReason;
6462
}
6563

@@ -73,26 +71,13 @@ class DiscussionHandler extends DefaultHandler {
7371
discussion.comments.nodes,
7472
);
7573

76-
let discussionUser: SubjectUser = {
77-
login: discussion.author.login,
78-
html_url: discussion.author.html_url,
79-
avatar_url: discussion.author.avatar_url,
80-
type: discussion.author.type,
81-
};
82-
83-
if (latestDiscussionComment) {
84-
discussionUser = {
85-
login: latestDiscussionComment.author.login,
86-
html_url: latestDiscussionComment.author.html_url,
87-
avatar_url: latestDiscussionComment.author.avatar_url,
88-
type: latestDiscussionComment.author.type,
89-
};
90-
}
91-
9274
return {
9375
number: discussion.number,
9476
state: discussionState,
95-
user: discussionUser,
77+
user: getSubjectAuthor([
78+
latestDiscussionComment.author,
79+
discussion.author,
80+
]),
9681
comments: discussion.comments.totalCount,
9782
labels: discussion.labels?.nodes.map((label) => label.name) ?? [],
9883
htmlUrl: latestDiscussionComment.url ?? discussion.url,

0 commit comments

Comments
 (0)