diff --git a/src/__mocks__/mockedData.ts b/src/__mocks__/mockedData.ts index 3fedecffe..59f046f34 100644 --- a/src/__mocks__/mockedData.ts +++ b/src/__mocks__/mockedData.ts @@ -291,6 +291,8 @@ export const mockedGraphQLResponse: GraphQLSearch = { viewerSubscription: 'SUBSCRIBED', title: '1.16.0', + isAnswered: false, + stateReason: null, url: 'https://github.com/manosim/notifications-test/discussions/612', comments: { nodes: [ @@ -369,6 +371,8 @@ export const mockedGraphQLResponse: GraphQLSearch = { viewerSubscription: 'IGNORED', title: '1.16.0', + isAnswered: false, + stateReason: null, url: 'https://github.com/manosim/notifications-test/discussions/612', comments: { nodes: [ diff --git a/src/hooks/useNotifications.test.ts b/src/hooks/useNotifications.test.ts index 6e245c9c8..4b020c8f3 100644 --- a/src/hooks/useNotifications.test.ts +++ b/src/hooks/useNotifications.test.ts @@ -256,14 +256,12 @@ describe('hooks/useNotifications.ts', () => { .reply(200, { data: { search: { - edges: [ + nodes: [ { - node: { - title: 'This is an answered discussion', - viewerSubscription: 'SUBSCRIBED', - stateReason: null, - isAnswered: true, - }, + title: 'This is an answered discussion', + viewerSubscription: 'SUBSCRIBED', + stateReason: null, + isAnswered: true, }, ], }, diff --git a/src/typesGithub.ts b/src/typesGithub.ts index a60293913..d2654a8d5 100644 --- a/src/typesGithub.ts +++ b/src/typesGithub.ts @@ -248,16 +248,11 @@ export interface GraphQLSearch { }; } -export interface DiscussionStateSearchResultNode { +export interface DiscussionSearchResultNode { viewerSubscription: ViewerSubscription; title: string; stateReason: DiscussionStateType; isAnswered: boolean; -} - -export interface DiscussionSearchResultNode { - viewerSubscription: ViewerSubscription; - title: string; url: string; comments: { nodes: DiscussionCommentNode[]; diff --git a/src/utils/helpers.test.ts b/src/utils/helpers.test.ts index ce5cd5198..d61e0006c 100644 --- a/src/utils/helpers.test.ts +++ b/src/utils/helpers.test.ts @@ -398,7 +398,7 @@ describe('utils/helpers.ts', () => { const requestPromise = new Promise((resolve) => resolve({ - data: {}, + data: { data: { search: { nodes: [] } } }, } as AxiosResponse), ) as AxiosPromise; diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index fdb9109e6..62a72a746 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -126,27 +126,56 @@ async function getDiscussionUrl( ): Promise { let url = `${notification.repository.html_url}/discussions`; + const discussion = await fetchDiscussion(notification, token, true); + + if (discussion) { + url = discussion.url; + + let comments = discussion.comments.nodes; + + let latestCommentId: string | number; + + if (comments?.length) { + latestCommentId = getLatestDiscussionCommentId(comments); + url += `#discussioncomment-${latestCommentId}`; + } + } + + return url; +} + +export async function fetchDiscussion( + notification: Notification, + token: string, + includeComments: boolean, +): Promise { const response: GraphQLSearch = await apiRequestAuth(`https://api.github.com/graphql`, 'POST', token, { - query: `{ - search(query:"${formatSearchQueryString( - notification.repository.full_name, - notification.subject.title, - notification.updated_at, - )}", type: DISCUSSION, first: 10) { - nodes { - ... on Discussion { - viewerSubscription - title - url - comments(last: 100) { - nodes { - databaseId - createdAt - replies(last: 1) { - nodes { - databaseId - createdAt + query: `query fetchDiscussions( + $includeComments: Boolean!, + $queryStatement: String!, + $type: SearchType!, + $firstDiscussions: Int, + $lastComments: Int, + $firstReplies: Int + ) { + search(query:$queryStatement, type: $type, first: $firstDiscussions) { + nodes { + ... on Discussion { + viewerSubscription + title + stateReason + isAnswered + url + comments(last: $lastComments) @include(if: $includeComments){ + nodes { + databaseId + createdAt + replies(last: $firstReplies) { + nodes { + databaseId + createdAt + } } } } @@ -154,11 +183,23 @@ async function getDiscussionUrl( } } } - }`, + `, + variables: { + queryStatement: formatSearchQueryString( + notification.repository.full_name, + notification.subject.title, + notification.updated_at, + ), + type: 'DISCUSSION', + firstDiscussions: 10, + lastComments: 100, + firstReplies: 1, + includeComments: includeComments, + }, }); let discussions = - response?.data?.data?.search?.nodes?.filter( + response?.data?.data.search.nodes.filter( (discussion) => discussion.title === notification.subject.title, ) || []; @@ -167,29 +208,17 @@ async function getDiscussionUrl( (discussion) => discussion.viewerSubscription === 'SUBSCRIBED', ); - if (discussions[0]) { - const discussion = discussions[0]; - url = discussion.url; - - let comments = discussion.comments.nodes; - - let latestCommentId: string | number; - if (comments?.length) { - latestCommentId = getLatestDiscussionCommentId(comments); - url += `#discussioncomment-${latestCommentId}`; - } - } - - return url; + return discussions[0]; } -export const getLatestDiscussionCommentId = ( +export function getLatestDiscussionCommentId( comments: DiscussionCommentNode[], -) => - comments +) { + return comments .flatMap((comment) => comment.replies.nodes) .concat([comments.at(-1)]) .reduce((a, b) => (a.createdAt > b.createdAt ? a : b))?.databaseId; +} export async function generateGitHubWebUrl( notification: Notification, diff --git a/src/utils/state.ts b/src/utils/state.ts index 9680f133b..0e750573f 100644 --- a/src/utils/state.ts +++ b/src/utils/state.ts @@ -1,10 +1,8 @@ -import { formatSearchQueryString } from './helpers'; +import { fetchDiscussion } from './helpers'; import { CheckSuiteAttributes, CheckSuiteStatus, - DiscussionStateSearchResultNode, DiscussionStateType, - GraphQLSearch, Issue, IssueStateReasonType, IssueStateType, @@ -84,39 +82,9 @@ export async function getDiscussionState( notification: Notification, token: string, ): Promise { - const response: GraphQLSearch = - await apiRequestAuth(`https://api.github.com/graphql`, 'POST', token, { - query: `{ - search(query:"${formatSearchQueryString( - notification.repository.full_name, - notification.subject.title, - notification.updated_at, - )}", type: DISCUSSION, first: 10) { - nodes { - ... on Discussion { - viewerSubscription - title - stateReason - isAnswered - } - } - } - }`, - }); - - let discussions = - response?.data?.data?.search?.nodes?.filter( - (discussion) => discussion.title === notification.subject.title, - ) || []; - - if (discussions.length > 1) { - discussions = discussions.filter( - (discussion) => discussion.viewerSubscription === 'SUBSCRIBED', - ); - } + const discussion = await fetchDiscussion(notification, token, false); - if (discussions[0]) { - const discussion = discussions[0]; + if (discussion) { if (discussion.isAnswered) { return 'ANSWERED'; }